2.6.7-rc3-mm1
- Includes dm-io, kcopyd, dm-snapshot, dm-mirror and dm-zero.
--- diff/CREDITS	2004-06-11 19:17:20.000000000 +0100
+++ source/CREDITS	2004-06-11 19:22:00.000000000 +0100
@@ -2527,6 +2527,7 @@
 E: mikpe@csd.uu.se
 W: http://www.csd.uu.se/~mikpe/
 D: Miscellaneous fixes
+D: Performance-monitoring counters driver
 
 N: Reed H. Petty
 E: rhp@draper.net
--- diff/Documentation/binfmt_misc.txt	2004-05-19 22:10:50.000000000 +0100
+++ source/Documentation/binfmt_misc.txt	2004-06-11 19:22:00.000000000 +0100
@@ -15,7 +15,7 @@
 	mount binfmt_misc -t binfmt_misc /proc/sys/fs/binfmt_misc 
 
 To actually register a new binary type, you have to set up a string looking like
-:name:type:offset:magic:mask:interpreter: (where you can choose the ':' upon
+:name:type:offset:magic:mask:interpreter:flags (where you can choose the ':' upon
 your needs) and echo it to /proc/sys/fs/binfmt_misc/register.
 Here is what the fields mean:
  - 'name' is an identifier string. A new /proc file will be created with this
@@ -34,6 +34,28 @@
    The mask is anded with the byte sequence of the file.
  - 'interpreter' is the program that should be invoked with the binary as first
    argument (specify the full path)
+ - 'flags' is an optional field that controls several aspects of the invocation
+   of the interpreter. It is a string of capital letters, each controls a certain
+   aspect. The following flags are supported -
+      'P' - preserve-argv[0].  Legacy behavior of binfmt_misc is to overwrite the
+            original argv[0] with the full path to the binary.  When this flag is
+            included, binfmt_misc will add an argument to the argument vector for
+            this purpose, thus preserving the original argv[0].
+      'O' - open-binary. Legacy behavior of binfmt_misc is to pass the full path
+            of the binary to the interpreter as an argument. When this flag is
+            included, binfmt_misc will open the file for reading and pass its
+            descriptor as an argument, instead of the full path, thus allowing
+            the interpreter to execute non-readable binaries. This feature should
+            be used with care - the interpreter has to be trusted not to emit
+            the contents of the non-readable binary.
+      'C' - credentials. Currently, the behavior of binfmt_misc is to calculate
+            the credentials and security token of the new process according to
+            the interpreter. When this flag is included, these attributes are
+            calculated according to the binary. It also implies the 'O' flag.
+            This feature should be used with care as the interpreter
+            will run with root permissions when a setuid binary owned by root
+            is run with binfmt_misc.
+
 
 There are some restrictions:
  - the whole register string may not exceed 255 characters
@@ -83,9 +105,9 @@
 write a wrapper script for it. See Documentation/java.txt for an
 example.
 
-Your interpreter should NOT look in the PATH for the filename; the
-kernel passes it the full filename to use.  Using the PATH can cause
-unexpected behaviour and be a security hazard.
+Your interpreter should NOT look in the PATH for the filename; the kernel
+passes it the full filename (or the file descriptor) to use.  Using $PATH can
+cause unexpected behaviour and can be a security hazard.
 
 
 There is a web page about binfmt_misc at
--- diff/Documentation/fb/framebuffer.txt	2004-05-19 22:10:51.000000000 +0100
+++ source/Documentation/fb/framebuffer.txt	2004-06-11 19:22:00.000000000 +0100
@@ -190,7 +190,7 @@
     1/(32.141E-6 s) = 31.113E3 Hz
 
 A full screen counts 480 (yres) lines, but we have to consider the vertical
-retrace too (e.g. 49 `pixels'). So a full screen will take
+retrace too (e.g. 49 `lines'). So a full screen will take
 
     (480+49)*32.141E-6 s = 17.002E-3 s
 
--- diff/Documentation/filesystems/ntfs.txt	2004-06-11 19:17:21.000000000 +0100
+++ source/Documentation/filesystems/ntfs.txt	2004-06-11 19:22:00.000000000 +0100
@@ -273,6 +273,19 @@
 
 Note, a technical ChangeLog aimed at kernel hackers is in fs/ntfs/ChangeLog.
 
+2.1.13:
+	- Implement writing of inodes (access time updates are not implemented
+	  yet so mounting with -o noatime,nodiratime is enforced).
+	- Enable writing out of resident files so you can now overwrite any
+	  uncompressed, unencrypted, nonsparse file as long as you do not
+	  change the file size.
+	- Add housekeeping of ntfs system files so that ntfsfix no longer needs
+	  to be run after writing to an NTFS volume.
+	  NOTE:  This still leaves quota tracking and user space journalling on
+	  the side but they should not cause data corruption.  In the worst
+	  case the charged quotas will be out of date ($Quota) and some
+	  userspace applications might get confused due to the out of date
+	  userspace journal ($UsnJrnl).
 2.1.12:
 	- Fix the second fix to the decompression engine from the 2.1.9 release
 	  and some further internals cleanups.
--- diff/Documentation/filesystems/proc.txt	2004-06-11 19:17:21.000000000 +0100
+++ source/Documentation/filesystems/proc.txt	2004-06-11 19:22:00.000000000 +0100
@@ -201,7 +201,7 @@
  devices     Available devices (block and character)           
  dma         Used DMS channels                                 
  filesystems Supported filesystems                             
- driver	     Various drivers grouped here, currently rtc	(2.4)
+ driver	     Various drivers grouped here, currently rtc (2.4) and hpet (2.6)
  execdomains Execdomains, related to security			(2.4)
  fb	     Frame Buffer devices				(2.4)
  fs	     File system parameters, currently nfs/exports	(2.4)
--- diff/Documentation/ioctl-number.txt	2004-05-19 22:10:50.000000000 +0100
+++ source/Documentation/ioctl-number.txt	2004-06-11 19:22:01.000000000 +0100
@@ -189,3 +189,5 @@
 					<mailto:michael.klein@puffin.lb.shuttle.de>
 0xDD	00-3F	ZFCP device driver	see drivers/s390/scsi/
 					<mailto:aherrman@de.ibm.com>
+0xF3	00-3F	video/sisfb.h		sisfb (in development)
+					<mailto:thomas@winischhofer.net>
--- diff/Documentation/kernel-parameters.txt	2004-06-11 19:17:21.000000000 +0100
+++ source/Documentation/kernel-parameters.txt	2004-06-11 19:22:01.000000000 +0100
@@ -652,6 +652,12 @@
 
 	mga=		[HW,DRM]
 
+	mousedev.tap_time=
+			[MOUSE] Maximum time between finger touching and
+			leaving touchpad surface for touch to be considered
+			a tap and be reported as a left button click (for
+			touchpads working in absolute mode only).
+			Format: <msecs>
 	mousedev.xres=	[MOUSE] Horizontal screen resolution, used for devices
 			reporting absolute coordinates, such as tablets
 	mousedev.yres=	[MOUSE] Vertical screen resolution, used for devices
--- diff/Documentation/sound/alsa/ALSA-Configuration.txt	2004-06-11 19:17:21.000000000 +0100
+++ source/Documentation/sound/alsa/ALSA-Configuration.txt	2004-06-11 19:22:01.000000000 +0100
@@ -613,7 +613,7 @@
     model       - Use the given board model, one of the following:
 		  delta1010, dio2496, delta66, delta44, audiophile, delta410,
 		  delta1010lt, vx442, ewx2496, ews88mt, ews88mt_new, ews88d,
-		  dmx6fire, dsp24, dsp24_71, ez8
+		  dmx6fire, dsp24, dsp24_value, dsp24_71, ez8
     omni	- Omni I/O support for MidiMan M-Audio Delta44/66
     cs8427_timeout - reset timeout for the CS8427 chip (S/PDIF transciever)
                      in msec resolution, default value is 500 (0.5 sec)
@@ -631,7 +631,8 @@
 			* TerraTec Aureon Sky-5.1, Space-7.1
 
     model       - Use the given board model, one of the following:
-		  revo71, amp2000, prodigy71, aureon51, aureon71
+		  revo71, amp2000, prodigy71, aureon51, aureon71,
+		  k8x800
 
     Module supports up to 8 cards and autoprobe.
 
--- diff/MAINTAINERS	2004-06-11 19:17:21.000000000 +0100
+++ source/MAINTAINERS	2004-06-11 19:22:07.000000000 +0100
@@ -90,6 +90,20 @@
 L:	linux-net@vger.kernel.org
 S:	Maintained
 
+3W-XXXX ATA-RAID CONTROLLER DRIVER
+P:	Adam Radford
+M:	linuxraid@amcc.com
+L:	linux-scsi@vger.kernel.org
+W:	http://www.amcc.com
+S:	Supported
+
+3W-9XXX SATA-RAID CONTROLLER DRIVER
+P:	Adam Radford
+M:	linuxraid@amcc.com
+L:	linux-scsi@vger.kernel.org
+W:	http://www.amcc.com
+S:	Supported
+
 53C700 AND 53C700-66 SCSI DRIVER
 P:	James E.J. Bottomley
 M:	James.Bottomley@HansenPartnership.com
@@ -689,6 +703,12 @@
 L:	blinux-list@redhat.com
 S:	Maintained
 
+DRIVER CORE, KOBJECTS, AND SYSFS
+P:	Greg Kroah-Hartman
+M:	greg@kroah.com
+L:	linux-kernel@vger.kernel.org
+S:	Supported
+
 DRM DRIVERS
 L:	dri-devel@lists.sourceforge.net
 S:	Supported
@@ -1193,6 +1213,12 @@
 W:	http://developer.osdl.org/rddunlap/kj-patches/
 S:	Maintained
 
+KGDB FOR I386 PLATFORM
+P:	George Anzinger
+M:	george@mvista.com
+L:	linux-net@vger.kernel.org
+S:	Supported
+
 KERNEL NFSD
 P:	Neil Brown
 M:	neilb@cse.unsw.edu.au
@@ -1617,6 +1643,12 @@
 L:	linux-net@vger.kernel.org
 S:	Supported
 
+PERFORMANCE-MONITORING COUNTERS DRIVER
+P:	Mikael Pettersson
+M:	mikpe@csd.uu.se
+W:	http://www.csd.uu.se/~mikpe/linux/perfctr/
+S:	Maintained
+
 PNP SUPPORT
 P:	Adam Belay
 M:	ambx1@neo.rr.com
--- diff/Makefile	2004-06-11 19:17:21.000000000 +0100
+++ source/Makefile	2004-06-11 19:22:07.000000000 +0100
@@ -1,7 +1,7 @@
 VERSION = 2
 PATCHLEVEL = 6
 SUBLEVEL = 7
-EXTRAVERSION =-rc3
+EXTRAVERSION =-rc3-mm1
 NAME=Zonked Quokka
 
 # *DOCUMENTATION*
@@ -409,13 +409,6 @@
 
 scripts_basic: include/linux/autoconf.h
 
-
-# That's our default target when none is given on the command line
-# Note that 'modules' will be added as a prerequisite as well, 
-# in the CONFIG_MODULES part below
-
-all:	vmlinux
-
 # Objects we will link into vmlinux / subdirs we need to visit
 init-y		:= init/
 drivers-y	:= drivers/ sound/
@@ -449,6 +442,11 @@
 
 include $(srctree)/arch/$(ARCH)/Makefile
 
+# Let all: depend on target selected in .config
+# Hereby user only have to issue 'make' to build the kernel, including
+# selected kernel
+all: $(subst ",,$(CONFIG_KERNEL_IMAGE))
+
 ifdef CONFIG_CC_OPTIMIZE_FOR_SIZE
 CFLAGS		+= -Os
 else
@@ -461,6 +459,7 @@
 
 ifdef CONFIG_DEBUG_INFO
 CFLAGS		+= -g
+AFLAGS		+= -g
 endif
 
 # warn about C99 declaration after statement
@@ -1062,6 +1061,7 @@
 
 buildcheck:
 	$(PERL) scripts/reference_discarded.pl
+	$(PERL) scripts/reference_init.pl
 
 endif #ifeq ($(config-targets),1)
 endif #ifeq ($(mixed-targets),1)
--- diff/arch/alpha/kernel/init_task.c	2004-05-19 22:10:53.000000000 +0100
+++ source/arch/alpha/kernel/init_task.c	2004-06-11 19:21:56.000000000 +0100
@@ -4,6 +4,7 @@
 #include <linux/init.h>
 #include <linux/init_task.h>
 #include <linux/fs.h>
+#include <linux/mqueue.h>
 #include <asm/uaccess.h>
 
 
--- diff/arch/alpha/kernel/setup.c	2004-06-11 19:17:21.000000000 +0100
+++ source/arch/alpha/kernel/setup.c	2004-06-11 19:21:56.000000000 +0100
@@ -122,7 +122,6 @@
 static void determine_cpu_caches (unsigned int);
 
 static char command_line[COMMAND_LINE_SIZE];
-char saved_command_line[COMMAND_LINE_SIZE];
 
 /*
  * The format of "screen_info" is strange, and due to early
--- diff/arch/arm/kernel/init_task.c	2004-05-19 22:10:55.000000000 +0100
+++ source/arch/arm/kernel/init_task.c	2004-06-11 19:21:56.000000000 +0100
@@ -7,6 +7,7 @@
 #include <linux/sched.h>
 #include <linux/init.h>
 #include <linux/init_task.h>
+#include <linux/mqueue.h>
 
 #include <asm/uaccess.h>
 #include <asm/pgtable.h>
--- diff/arch/arm/kernel/setup.c	2004-06-11 19:17:22.000000000 +0100
+++ source/arch/arm/kernel/setup.c	2004-06-11 19:21:56.000000000 +0100
@@ -95,7 +95,6 @@
 char elf_platform[ELF_PLATFORM_SIZE];
 EXPORT_SYMBOL(elf_platform);
 
-char saved_command_line[COMMAND_LINE_SIZE];
 unsigned long phys_initrd_start __initdata = 0;
 unsigned long phys_initrd_size __initdata = 0;
 
--- diff/arch/arm26/kernel/init_task.c	2004-05-19 22:10:58.000000000 +0100
+++ source/arch/arm26/kernel/init_task.c	2004-06-11 19:21:56.000000000 +0100
@@ -10,6 +10,7 @@
 #include <linux/sched.h>
 #include <linux/init.h>
 #include <linux/init_task.h>
+#include <linux/mqueue.h>
 
 #include <asm/uaccess.h>
 #include <asm/pgtable.h>
--- diff/arch/arm26/kernel/setup.c	2004-05-19 22:10:58.000000000 +0100
+++ source/arch/arm26/kernel/setup.c	2004-06-11 19:21:56.000000000 +0100
@@ -76,7 +76,6 @@
 
 unsigned char aux_device_present;
 char elf_platform[ELF_PLATFORM_SIZE];
-char saved_command_line[COMMAND_LINE_SIZE];
 
 unsigned long phys_initrd_start __initdata = 0;
 unsigned long phys_initrd_size __initdata = 0;
--- diff/arch/cris/kernel/process.c	2004-06-11 19:17:22.000000000 +0100
+++ source/arch/cris/kernel/process.c	2004-06-11 19:21:56.000000000 +0100
@@ -112,6 +112,7 @@
 #include <linux/fs.h>
 #include <linux/user.h>
 #include <linux/elfcore.h>
+#include <linux/mqueue.h>
 
 //#define DEBUG
 
--- diff/arch/cris/kernel/setup.c	2004-06-11 19:17:22.000000000 +0100
+++ source/arch/cris/kernel/setup.c	2004-06-11 19:21:56.000000000 +0100
@@ -29,10 +29,7 @@
 extern int root_mountflags;
 extern char _etext, _edata, _end;
 
-#define COMMAND_LINE_SIZE 256
-
 static char command_line[COMMAND_LINE_SIZE] = { 0, };
-       char saved_command_line[COMMAND_LINE_SIZE];
 
 extern const unsigned long text_start, edata; /* set by the linker script */
 extern unsigned long dram_start, dram_end;
--- diff/arch/h8300/kernel/init_task.c	2004-05-19 22:10:59.000000000 +0100
+++ source/arch/h8300/kernel/init_task.c	2004-06-11 19:21:56.000000000 +0100
@@ -7,6 +7,7 @@
 #include <linux/init.h>
 #include <linux/init_task.h>
 #include <linux/fs.h>
+#include <linux/mqueue.h>
 
 #include <asm/uaccess.h>
 #include <asm/pgtable.h>
--- diff/arch/h8300/kernel/setup.c	2004-06-11 19:17:22.000000000 +0100
+++ source/arch/h8300/kernel/setup.c	2004-06-11 19:21:56.000000000 +0100
@@ -30,6 +30,7 @@
 #include <linux/major.h>
 #include <linux/bootmem.h>
 #include <linux/seq_file.h>
+#include <linux/init.h>
 
 #include <asm/setup.h>
 #include <asm/irq.h>
@@ -54,8 +55,7 @@
 unsigned long memory_start;
 unsigned long memory_end;
 
-char command_line[512];
-char saved_command_line[512];
+char command_line[COMMAND_LINE_SIZE];
 
 extern int _stext, _etext, _sdata, _edata, _sbss, _ebss, _end;
 extern int _ramstart, _ramend;
--- diff/arch/i386/Kconfig	2004-06-11 19:17:22.000000000 +0100
+++ source/arch/i386/Kconfig	2004-06-11 19:21:56.000000000 +0100
@@ -29,6 +29,42 @@
 	bool
 	default y
 
+choice
+	prompt "Default kernel image"
+	default KERNEL_IMAGE_BZIMAGE
+	help
+	  Specify which kernel image to be build when executing 'make' with
+	  no arguments.
+
+config KERNEL_IMAGE_BZIMAGE
+	bool "bzImage - Compressed kernel image"
+	help
+	  bzImage - located at arch/i386/boot/bzImage.
+	  bzImage can accept larger kernels than zImage
+
+config KERNEL_IMAGE_ZIMAGE
+	bool "zImage - Compressed kernel image"
+	help
+	  zImage - located at arch/i386/boot/zImage.
+	  zImage is seldom used. zImage supports smaller kernels than bzImage,
+	  and is only used in special situations.
+
+config KERNEL_IMAGE_VMLINUX
+	bool "vmlinux - the bare kernel"
+	help
+	  vmlinux - located at the root of the kernel tree
+	  vmlinux contains the kernel image with no additional bootloader.
+	  vmlinux is seldom used as target for i386.
+
+endchoice
+
+config KERNEL_IMAGE
+	string
+	default arch/i386/boot/bzImage if KERNEL_IMAGE_BZIMAGE
+	default arch/i386/boot/zImage  if KERNEL_IMAGE_ZIMAGE
+	default vmlinux                if KERNEL_IMAGE_VMLINUX
+
+
 source "init/Kconfig"
 
 
@@ -434,7 +470,8 @@
 	  Choose N to continue using the legacy 8254 timer.
 
 config HPET_EMULATE_RTC
-	def_bool HPET_TIMER && RTC=y
+	bool "Provide RTC interrupt"
+	depends on HPET_TIMER && RTC=y
 
 config SMP
 	bool "Symmetric multi-processing support"
@@ -849,17 +886,9 @@
 	default y
 
 config REGPARM
-	bool "Use register arguments (EXPERIMENTAL)"
-	depends on EXPERIMENTAL
-	default n
-	help
-	Compile the kernel with -mregparm=3. This uses an different ABI
-	and passes the first three arguments of a function call in registers.
-	This will probably break binary only modules.
-
-	This feature is only enabled for gcc-3.0 and later - earlier compilers
-	generate incorrect output with certain kernel constructs when
-	-mregparm=3 is used.
+	def_bool y
+
+source "drivers/perfctr/Kconfig"
 
 endmenu
 
@@ -1255,6 +1284,15 @@
 	  This results in a large slowdown, but helps to find certain types
 	  of memory corruptions.
 
+config SPINLINE
+	bool "Spinlock inlining"
+	depends on DEBUG_KERNEL
+	help
+	  This will change spinlocks from out of line to inline, making them
+	  account cost to the callers in readprofile, rather than the lock
+	  itself (as ".text.lock.filename"). This can be helpful for finding
+	  the callers of locks.
+
 config DEBUG_HIGHMEM
 	bool "Highmem debugging"
 	depends on DEBUG_KERNEL && HIGHMEM
@@ -1271,12 +1309,194 @@
 	  Say Y here only if you plan to use gdb to debug the kernel.
 	  If you don't debug the kernel, you can say N.
 	  
+config LOCKMETER
+	bool "Kernel lock metering"
+	depends on SMP
+	help
+	  Say Y to enable kernel lock metering, which adds overhead to SMP locks,
+	  but allows you to see various statistics using the lockstat command.
+
 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 KGDB
+	bool "Include kgdb kernel debugger"
+	depends on DEBUG_KERNEL
+	help
+	  If you say Y here, the system will be compiled with the debug
+	  option (-g) and a debugging stub will be included in the
+	  kernel.  This stub communicates with gdb on another (host)
+	  computer via a serial port.  The host computer should have
+	  access to the kernel binary file (vmlinux) and a serial port
+	  that is connected to the target machine.  Gdb can be made to
+	  configure the serial port or you can use stty and setserial to
+	  do this. See the 'target' command in gdb. This option also
+	  configures in the ability to request a breakpoint early in the
+	  boot process.  To request the breakpoint just include 'kgdb'
+	  as a boot option when booting the target machine.  The system
+	  will then break as soon as it looks at the boot options.  This
+	  option also installs a breakpoint in panic and sends any
+	  kernel faults to the debugger. For more information see the
+	  Documentation/i386/kgdb/kgdb.txt file.
+
+choice
+	depends on KGDB
+    	prompt "Debug serial port BAUD"
+	default KGDB_115200BAUD
+	help
+	  Gdb and the kernel stub need to agree on the baud rate to be
+	  used.  Some systems (x86 family at this writing) allow this to
+	  be configured.
+
+config KGDB_9600BAUD
+	bool "9600"
+
+config KGDB_19200BAUD
+	bool "19200"
+
+config KGDB_38400BAUD
+	bool "38400"
+
+config KGDB_57600BAUD
+	bool "57600"
+
+config KGDB_115200BAUD
+	bool "115200"
+endchoice
+
+config KGDB_PORT
+	hex "hex I/O port address of the debug serial port"
+	depends on KGDB
+	default  3f8
+	help
+	  Some systems (x86 family at this writing) allow the port
+	  address to be configured.  The number entered is assumed to be
+	  hex, don't put 0x in front of it.  The standard address are:
+	  COM1 3f8 , irq 4 and COM2 2f8 irq 3.  Setserial /dev/ttySx
+	  will tell you what you have.  It is good to test the serial
+	  connection with a live system before trying to debug.
+
+config KGDB_IRQ
+	int "IRQ of the debug serial port"
+	depends on KGDB
+	default 4
+	help
+	  This is the irq for the debug port.  If everything is working
+	  correctly and the kernel has interrupts on a control C to the
+	  port should cause a break into the kernel debug stub.
+
+config DEBUG_INFO
+	bool
+	depends on KGDB
+	default y
+
+config KGDB_MORE
+	bool "Add any additional compile options"
+	depends on KGDB
+	default n
+	help
+	  Saying yes here turns on the ability to enter additional
+	  compile options.
+
+
+config KGDB_OPTIONS
+	depends on KGDB_MORE
+	string "Additional compile arguments"
+	default "-O1"
+	help
+	  This option allows you enter additional compile options for
+	  the whole kernel compile.  Each platform will have a default
+	  that seems right for it.  For example on PPC "-ggdb -O1", and
+	  for i386 "-O1".  Note that by configuring KGDB "-g" is already
+	  turned on.  In addition, on i386 platforms
+	  "-fomit-frame-pointer" is deleted from the standard compile
+	  options.
+
+config NO_KGDB_CPUS
+	int "Number of CPUs"
+	depends on KGDB && SMP
+	default NR_CPUS
+	help
+
+	  This option sets the number of cpus for kgdb ONLY.  It is used
+	  to prune some internal structures so they look "nice" when
+	  displayed with gdb.  This is to overcome possibly larger
+	  numbers that may have been entered above.  Enter the real
+	  number to get nice clean kgdb_info displays.
+
+config KGDB_TS
+	bool "Enable kgdb time stamp macros?"
+	depends on KGDB
+	default n
+	help
+	  Kgdb event macros allow you to instrument your code with calls
+	  to the kgdb event recording function.  The event log may be
+	  examined with gdb at a break point.  Turning on this
+	  capability also allows you to choose how many events to
+	  keep. Kgdb always keeps the lastest events.
+
+choice
+	depends on KGDB_TS
+	prompt "Max number of time stamps to save?"
+	default KGDB_TS_128
+
+config KGDB_TS_64
+	bool "64"
+
+config KGDB_TS_128
+	bool "128"
+
+config KGDB_TS_256
+	bool "256"
+
+config KGDB_TS_512
+	bool "512"
+
+config KGDB_TS_1024
+	bool "1024"
+
+endchoice
+
+config STACK_OVERFLOW_TEST
+	bool "Turn on kernel stack overflow testing?"
+	depends on KGDB
+	default n
+	help
+	  This option enables code in the front line interrupt handlers
+	  to check for kernel stack overflow on interrupts and system
+	  calls.  This is part of the kgdb code on x86 systems.
+
+config KGDB_CONSOLE
+	bool "Enable serial console thru kgdb port"
+	depends on KGDB
+	default n
+	help
+	  This option enables the command line "console=kgdb" option.
+	  When the system is booted with this option in the command line
+	  all kernel printk output is sent to gdb (as well as to other
+	  consoles).  For this to work gdb must be connected.  For this
+	  reason, this command line option will generate a breakpoint if
+	  gdb has not yet connected.  After the gdb continue command is
+	  given all pent up console output will be printed by gdb on the
+	  host machine.  Neither this option, nor KGDB require the
+	  serial driver to be configured.
+
+config KGDB_SYSRQ
+	bool "Turn on SysRq 'G' command to do a break?"
+	depends on KGDB
+	default y
+	help
+	  This option includes an option in the SysRq code that allows
+	  you to enter SysRq G which generates a breakpoint to the KGDB
+	  stub.  This will work if the keyboard is alive and can
+	  interrupt the system.  Because of constraints on when the
+	  serial port interrupt can be enabled, this code may allow you
+	  to interrupt the system before the serial port control C is
+	  available.  Just say yes here.
+
 config FRAME_POINTER
 	bool "Compile the kernel with frame pointers"
 	help
@@ -1294,6 +1514,19 @@
 	  on the VM subsystem for higher order allocations. This option
 	  will also use IRQ stacks to compensate for the reduced stackspace.
 
+config SCHEDSTATS
+	bool "Collect scheduler statistics"
+	depends on PROC_FS
+	default n
+	help
+	  If you say Y here, additional code will be inserted into the
+	  scheduler and related routines to collect statistics about
+	  scheduler behavior and provide them in /proc/schedstat.  These
+	  stats may be useful for both tuning and debugging the scheduler
+	  If you aren't debugging the scheduler or trying to tune a specific
+	  application, you can say N to avoid the very slight overhead
+	  this adds.
+
 config X86_FIND_SMP_CONFIG
 	bool
 	depends on X86_LOCAL_APIC || X86_VOYAGER
@@ -1332,12 +1565,6 @@
 	depends on X86_SMP || (X86_VOYAGER && SMP)
 	default y
 
-# std_resources is overridden for pc9800, but that's not
-# a currently selectable arch choice
-config X86_STD_RESOURCES
-	bool
-	default y
-
 config PC
 	bool
 	depends on X86 && !EMBEDDED
--- diff/arch/i386/Makefile	2004-06-11 19:17:22.000000000 +0100
+++ source/arch/i386/Makefile	2004-06-11 19:21:57.000000000 +0100
@@ -99,6 +99,9 @@
 # default subarch .h files
 mflags-y += -Iinclude/asm-i386/mach-default
 
+mflags-$(CONFIG_KGDB) += -gdwarf-2
+mflags-$(CONFIG_KGDB_MORE) += $(shell echo $(CONFIG_KGDB_OPTIONS) | sed -e 's/"//g')
+
 head-y := arch/i386/kernel/head.o arch/i386/kernel/init_task.o
 
 libs-y 					+= arch/i386/lib/
@@ -116,18 +119,20 @@
 
 boot := arch/i386/boot
 
-.PHONY: zImage bzImage compressed zlilo bzlilo \
-	zdisk bzdisk fdimage fdimage144 fdimage288 install
+# Lot's of documentation refer to these, so keep the short versions for now
+.PHONY: bzImage zImage compressed
+bzImage:    $(boot)/bzImage
+zImage:     $(boot)/zImage
+compressed: $(boot)/zImage
 
-all: bzImage
+# Target's that install the kernel
+.PHONY: zlilo bzlilo zdisk bzdisk fdimage fdimage144 fdimage288 install
 
 BOOTIMAGE=arch/i386/boot/bzImage
-zImage zlilo zdisk: BOOTIMAGE=arch/i386/boot/zImage
-
-zImage bzImage: vmlinux
-	$(Q)$(MAKE) $(build)=$(boot) $(BOOTIMAGE)
+zlilo zdisk: BOOTIMAGE=arch/i386/boot/zImage
 
-compressed: zImage
+$(boot)/zImage $(boot)/bzImage: vmlinux
+	$(Q)$(MAKE) $(build)=$(boot) $@
 
 zlilo bzlilo: vmlinux
 	$(Q)$(MAKE) $(build)=$(boot) BOOTIMAGE=$(BOOTIMAGE) zlilo
--- diff/arch/i386/boot/compressed/misc.c	2004-05-19 22:11:00.000000000 +0100
+++ source/arch/i386/boot/compressed/misc.c	2004-06-11 19:21:56.000000000 +0100
@@ -87,12 +87,11 @@
  */
 static unsigned char *real_mode; /* Pointer to real-mode data */
 
-#define EXT_MEM_K   (*(unsigned short *)(real_mode + 0x2))
+#define RM_EXT_MEM_K   (*(unsigned short *)(real_mode + 0x2))
 #ifndef STANDARD_MEMORY_BIOS_CALL
-#define ALT_MEM_K   (*(unsigned long *)(real_mode + 0x1e0))
+#define RM_ALT_MEM_K   (*(unsigned long *)(real_mode + 0x1e0))
 #endif
-#define SCREEN_INFO (*(struct screen_info *)(real_mode+0))
-#define EDID_INFO   (*(struct edid_info *)(real_mode+0x440))
+#define RM_SCREEN_INFO (*(struct screen_info *)(real_mode+0))
 
 extern char input_data[];
 extern int input_len;
@@ -174,8 +173,8 @@
 	int x,y,pos;
 	char c;
 
-	x = SCREEN_INFO.orig_x;
-	y = SCREEN_INFO.orig_y;
+	x = RM_SCREEN_INFO.orig_x;
+	y = RM_SCREEN_INFO.orig_y;
 
 	while ( ( c = *s++ ) != '\0' ) {
 		if ( c == '\n' ) {
@@ -196,8 +195,8 @@
 		}
 	}
 
-	SCREEN_INFO.orig_x = x;
-	SCREEN_INFO.orig_y = y;
+	RM_SCREEN_INFO.orig_x = x;
+	RM_SCREEN_INFO.orig_y = y;
 
 	pos = (x + cols * y) * 2;	/* Update cursor position */
 	outb_p(14, vidport);
@@ -306,9 +305,9 @@
 static void setup_normal_output_buffer(void)
 {
 #ifdef STANDARD_MEMORY_BIOS_CALL
-	if (EXT_MEM_K < 1024) error("Less than 2MB of memory");
+	if (RM_EXT_MEM_K < 1024) error("Less than 2MB of memory");
 #else
-	if ((ALT_MEM_K > EXT_MEM_K ? ALT_MEM_K : EXT_MEM_K) < 1024) error("Less than 2MB of memory");
+	if ((RM_ALT_MEM_K > RM_EXT_MEM_K ? RM_ALT_MEM_K : RM_EXT_MEM_K) < 1024) error("Less than 2MB of memory");
 #endif
 	output_data = (char *)0x100000; /* Points to 1M */
 	free_mem_end_ptr = (long)real_mode;
@@ -323,9 +322,11 @@
 {
 	high_buffer_start = (uch *)(((ulg)&end) + HEAP_SIZE);
 #ifdef STANDARD_MEMORY_BIOS_CALL
-	if (EXT_MEM_K < (3*1024)) error("Less than 4MB of memory");
+	if (RM_EXT_MEM_K < (3*1024)) error("Less than 4MB of memory");
 #else
-	if ((ALT_MEM_K > EXT_MEM_K ? ALT_MEM_K : EXT_MEM_K) < (3*1024)) error("Less than 4MB of memory");
+	if ((RM_ALT_MEM_K > RM_EXT_MEM_K ? RM_ALT_MEM_K : RM_EXT_MEM_K) <
+			(3*1024))
+		error("Less than 4MB of memory");
 #endif	
 	mv->low_buffer_start = output_data = (char *)LOW_BUFFER_START;
 	low_buffer_end = ((unsigned int)real_mode > LOW_BUFFER_MAX
@@ -358,7 +359,7 @@
 {
 	real_mode = rmode;
 
-	if (SCREEN_INFO.orig_video_mode == 7) {
+	if (RM_SCREEN_INFO.orig_video_mode == 7) {
 		vidmem = (char *) 0xb0000;
 		vidport = 0x3b4;
 	} else {
@@ -366,8 +367,8 @@
 		vidport = 0x3d4;
 	}
 
-	lines = SCREEN_INFO.orig_video_lines;
-	cols = SCREEN_INFO.orig_video_cols;
+	lines = RM_SCREEN_INFO.orig_video_lines;
+	cols = RM_SCREEN_INFO.orig_video_cols;
 
 	if (free_mem_ptr < 0x100000) setup_normal_output_buffer();
 	else setup_output_buffer_if_we_run_high(mv);
--- diff/arch/i386/defconfig	2004-05-19 22:11:00.000000000 +0100
+++ source/arch/i386/defconfig	2004-06-11 19:21:56.000000000 +0100
@@ -18,8 +18,11 @@
 #
 CONFIG_SWAP=y
 CONFIG_SYSVIPC=y
+CONFIG_POSIX_MQUEUE=y
 # CONFIG_BSD_PROCESS_ACCT is not set
 CONFIG_SYSCTL=y
+CONFIG_AUDIT=y
+CONFIG_AUDITSYSCALL=y
 CONFIG_LOG_BUF_SHIFT=15
 CONFIG_HOTPLUG=y
 # CONFIG_IKCONFIG is not set
@@ -30,6 +33,7 @@
 CONFIG_IOSCHED_NOOP=y
 CONFIG_IOSCHED_AS=y
 CONFIG_IOSCHED_DEADLINE=y
+CONFIG_IOSCHED_CFQ=y
 # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
 
 #
@@ -88,6 +92,7 @@
 # CONFIG_HPET_EMULATE_RTC is not set
 CONFIG_SMP=y
 CONFIG_NR_CPUS=8
+CONFIG_SCHED_SMT=y
 CONFIG_PREEMPT=y
 CONFIG_X86_LOCAL_APIC=y
 CONFIG_X86_IO_APIC=y
@@ -200,7 +205,7 @@
 #
 # Generic Driver Options
 #
-# CONFIG_FW_LOADER is not set
+CONFIG_FW_LOADER=m
 
 #
 # Memory Technology Devices (MTD)
@@ -259,7 +264,6 @@
 # CONFIG_BLK_DEV_HD_IDE is not set
 CONFIG_BLK_DEV_IDEDISK=y
 CONFIG_IDEDISK_MULTI_MODE=y
-# CONFIG_IDEDISK_STROKE is not set
 CONFIG_BLK_DEV_IDECD=y
 # CONFIG_BLK_DEV_IDETAPE is not set
 # CONFIG_BLK_DEV_IDEFLOPPY is not set
@@ -307,6 +311,7 @@
 # CONFIG_BLK_DEV_SLC90E66 is not set
 # CONFIG_BLK_DEV_TRM290 is not set
 # CONFIG_BLK_DEV_VIA82CXXX is not set
+# CONFIG_IDE_ARM is not set
 # CONFIG_IDE_CHIPSETS is not set
 CONFIG_BLK_DEV_IDEDMA=y
 # CONFIG_IDEDMA_IVB is not set
@@ -332,7 +337,6 @@
 # Some SCSI devices (e.g. CD jukebox) support multiple LUNs
 #
 # CONFIG_SCSI_MULTI_LUN is not set
-CONFIG_SCSI_REPORT_LUNS=y
 # CONFIG_SCSI_CONSTANTS is not set
 # CONFIG_SCSI_LOGGING is not set
 
@@ -354,6 +358,7 @@
 # CONFIG_SCSI_AIC7XXX is not set
 # CONFIG_SCSI_AIC7XXX_OLD is not set
 # CONFIG_SCSI_AIC79XX is not set
+CONFIG_SCSI_DPT_I2O=m
 # CONFIG_SCSI_ADVANSYS is not set
 # CONFIG_SCSI_IN2000 is not set
 # CONFIG_SCSI_MEGARAID is not set
@@ -361,7 +366,9 @@
 # CONFIG_SCSI_SATA_SVW is not set
 CONFIG_SCSI_ATA_PIIX=y
 # CONFIG_SCSI_SATA_PROMISE is not set
+CONFIG_SCSI_SATA_SX4=m
 # CONFIG_SCSI_SATA_SIL is not set
+CONFIG_SCSI_SATA_SIS=m
 # CONFIG_SCSI_SATA_VIA is not set
 # CONFIG_SCSI_SATA_VITESSE is not set
 # CONFIG_SCSI_BUSLOGIC is not set
@@ -380,6 +387,9 @@
 # CONFIG_SCSI_IMM is not set
 # CONFIG_SCSI_NCR53C406A is not set
 # CONFIG_SCSI_SYM53C8XX_2 is not set
+CONFIG_SCSI_IPR=m
+# CONFIG_SCSI_IPR_TRACE is not set
+# CONFIG_SCSI_IPR_DUMP is not set
 # CONFIG_SCSI_PAS16 is not set
 # CONFIG_SCSI_PSI240I is not set
 # CONFIG_SCSI_QLOGIC_FAS is not set
@@ -484,8 +494,6 @@
 #
 # CONFIG_IP_VS is not set
 # CONFIG_IPV6 is not set
-# CONFIG_DECNET is not set
-# CONFIG_BRIDGE is not set
 CONFIG_NETFILTER=y
 # CONFIG_NETFILTER_DEBUG is not set
 
@@ -539,13 +547,17 @@
 CONFIG_IP_NF_ARPTABLES=y
 CONFIG_IP_NF_ARPFILTER=y
 CONFIG_IP_NF_ARP_MANGLE=y
+CONFIG_IP_NF_TARGET_NOTRACK=m
+CONFIG_IP_NF_RAW=m
 
 #
 # SCTP Configuration (EXPERIMENTAL)
 #
 # CONFIG_IP_SCTP is not set
 # CONFIG_ATM is not set
+# CONFIG_BRIDGE is not set
 # CONFIG_VLAN_8021Q is not set
+# CONFIG_DECNET is not set
 # CONFIG_LLC2 is not set
 # CONFIG_IPX is not set
 # CONFIG_ATALK is not set
@@ -566,12 +578,12 @@
 # Network testing
 #
 # CONFIG_NET_PKTGEN is not set
+# CONFIG_NETPOLL is not set
+# CONFIG_NET_POLL_CONTROLLER is not set
+# CONFIG_HAMRADIO is not set
+# CONFIG_IRDA is not set
+# CONFIG_BT is not set
 CONFIG_NETDEVICES=y
-
-#
-# ARCnet devices
-#
-# CONFIG_ARCNET is not set
 CONFIG_DUMMY=m
 # CONFIG_BONDING is not set
 # CONFIG_EQUALIZER is not set
@@ -579,6 +591,11 @@
 # CONFIG_NET_SB1000 is not set
 
 #
+# ARCnet devices
+#
+# CONFIG_ARCNET is not set
+
+#
 # Ethernet (10 or 100Mbit)
 #
 CONFIG_NET_ETHERNET=y
@@ -619,7 +636,6 @@
 # CONFIG_8139TOO_TUNE_TWISTER is not set
 # CONFIG_8139TOO_8129 is not set
 # CONFIG_8139_OLD_RX_RESET is not set
-CONFIG_8139_RXBUF_IDX=2
 # CONFIG_SIS900 is not set
 # CONFIG_EPIC100 is not set
 # CONFIG_SUNDANCE is not set
@@ -637,7 +653,6 @@
 # CONFIG_HAMACHI is not set
 # CONFIG_YELLOWFIN is not set
 # CONFIG_R8169 is not set
-# CONFIG_SIS190 is not set
 # CONFIG_SK98LIN is not set
 # CONFIG_TIGON3 is not set
 
@@ -645,47 +660,31 @@
 # Ethernet (10000 Mbit)
 #
 # CONFIG_IXGB is not set
-# CONFIG_FDDI is not set
-# CONFIG_HIPPI is not set
-# CONFIG_PLIP is not set
-# CONFIG_PPP is not set
-# CONFIG_SLIP is not set
-
-#
-# Wireless LAN (non-hamradio)
-#
-# CONFIG_NET_RADIO is not set
+CONFIG_S2IO=m
+# CONFIG_S2IO_NAPI is not set
 
 #
 # Token Ring devices
 #
 # CONFIG_TR is not set
-# CONFIG_NET_FC is not set
-# CONFIG_RCPCI is not set
-# CONFIG_SHAPER is not set
-# CONFIG_NETCONSOLE is not set
-
-#
-# Wan interfaces
-#
-# CONFIG_WAN is not set
 
 #
-# Amateur Radio support
-#
-# CONFIG_HAMRADIO is not set
-
-#
-# IrDA (infrared) support
+# Wireless LAN (non-hamradio)
 #
-# CONFIG_IRDA is not set
+# CONFIG_NET_RADIO is not set
 
 #
-# Bluetooth support
+# Wan interfaces
 #
-# CONFIG_BT is not set
-# CONFIG_NETPOLL is not set
-# CONFIG_NET_POLL_CONTROLLER is not set
+# CONFIG_WAN is not set
+# CONFIG_FDDI is not set
+# CONFIG_HIPPI is not set
+# CONFIG_PLIP is not set
+# CONFIG_PPP is not set
+# CONFIG_SLIP is not set
+# CONFIG_NET_FC is not set
+# CONFIG_SHAPER is not set
+# CONFIG_NETCONSOLE is not set
 
 #
 # ISDN subsystem
@@ -803,6 +802,7 @@
 # CONFIG_AGP_AMD is not set
 # CONFIG_AGP_AMD64 is not set
 CONFIG_AGP_INTEL=y
+CONFIG_AGP_INTEL_MCH=m
 # CONFIG_AGP_NVIDIA is not set
 # CONFIG_AGP_SIS is not set
 # CONFIG_AGP_SWORKS is not set
@@ -978,6 +978,7 @@
 #
 CONFIG_USB_EHCI_HCD=y
 # CONFIG_USB_EHCI_SPLIT_ISO is not set
+# CONFIG_USB_EHCI_ROOT_HUB_TT is not set
 # CONFIG_USB_OHCI_HCD is not set
 CONFIG_USB_UHCI_HCD=y
 
@@ -1012,6 +1013,7 @@
 # CONFIG_USB_KBTAB is not set
 # CONFIG_USB_POWERMATE is not set
 # CONFIG_USB_MTOUCH is not set
+CONFIG_USB_EGALAX=m
 # CONFIG_USB_XPAD is not set
 # CONFIG_USB_ATI_REMOTE is not set
 
@@ -1061,6 +1063,8 @@
 # CONFIG_USB_LEGOTOWER is not set
 # CONFIG_USB_LCD is not set
 # CONFIG_USB_LED is not set
+CONFIG_USB_CYTHERM=m
+CONFIG_USB_PHIDGETSERVO=m
 # CONFIG_USB_TEST is not set
 
 #
@@ -1110,6 +1114,7 @@
 #
 CONFIG_PROC_FS=y
 CONFIG_PROC_KCORE=y
+CONFIG_SYSFS=y
 # CONFIG_DEVFS_FS is not set
 # CONFIG_DEVPTS_FS_XATTR is not set
 CONFIG_TMPFS=y
@@ -1152,7 +1157,6 @@
 # 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
 
 #
@@ -1217,6 +1221,7 @@
 CONFIG_EARLY_PRINTK=y
 CONFIG_DEBUG_SPINLOCK_SLEEP=y
 # CONFIG_FRAME_POINTER is not set
+CONFIG_4KSTACKS=y
 CONFIG_X86_FIND_SMP_CONFIG=y
 CONFIG_X86_MPPARSE=y
 
@@ -1234,8 +1239,10 @@
 # Library routines
 #
 CONFIG_CRC32=y
+CONFIG_LIBCRC32C=m
 CONFIG_X86_SMP=y
 CONFIG_X86_HT=y
 CONFIG_X86_BIOS_REBOOT=y
 CONFIG_X86_TRAMPOLINE=y
+CONFIG_X86_STD_RESOURCES=y
 CONFIG_PC=y
--- diff/arch/i386/kernel/Makefile	2004-05-19 22:11:00.000000000 +0100
+++ source/arch/i386/kernel/Makefile	2004-06-11 19:21:57.000000000 +0100
@@ -14,6 +14,7 @@
 obj-$(CONFIG_ACPI_BOOT)		+= acpi/
 obj-$(CONFIG_X86_BIOS_REBOOT)	+= reboot.o
 obj-$(CONFIG_MCA)		+= mca.o
+obj-$(CONFIG_KGDB)		+= kgdb_stub.o
 obj-$(CONFIG_X86_MSR)		+= msr.o
 obj-$(CONFIG_X86_CPUID)		+= cpuid.o
 obj-$(CONFIG_MICROCODE)		+= microcode.o
@@ -31,7 +32,6 @@
 obj-$(CONFIG_HPET_TIMER) 	+= time_hpet.o
 obj-$(CONFIG_EFI) 		+= efi.o efi_stub.o
 obj-$(CONFIG_EARLY_PRINTK)	+= early_printk.o
-obj-$(CONFIG_X86_STD_RESOURCES)	+= std_resources.o
 
 EXTRA_AFLAGS   := -traditional
 
--- diff/arch/i386/kernel/acpi/boot.c	2004-06-11 19:17:22.000000000 +0100
+++ source/arch/i386/kernel/acpi/boot.c	2004-06-11 19:21:56.000000000 +0100
@@ -28,7 +28,9 @@
 #include <linux/acpi.h>
 #include <linux/efi.h>
 #include <linux/irq.h>
-#include <asm/pgalloc.h>
+#include <linux/module.h>
+
+#include <asm/pgtable.h>
 #include <asm/io_apic.h>
 #include <asm/apic.h>
 #include <asm/io.h>
@@ -437,6 +439,36 @@
 	return 0;
 }
 
+unsigned int acpi_register_gsi(u32 gsi, int edge_level, int active_high_low)
+{
+	unsigned int irq;
+
+#ifdef CONFIG_PCI
+	/*
+	 * Make sure all (legacy) PCI IRQs are set as level-triggered.
+	 */
+	if (acpi_irq_model == ACPI_IRQ_MODEL_PIC) {
+		static u16 irq_mask;
+		extern void eisa_set_level_irq(unsigned int irq);
+
+		if ((gsi < 16) && !((1 << gsi) & irq_mask)) {
+			Dprintk(KERN_DEBUG PREFIX "Setting GSI %u as level-triggered\n", gsi);
+			irq_mask |= (1 << gsi);
+			eisa_set_level_irq(gsi);
+		}
+	}
+#endif
+
+#ifdef CONFIG_X86_IO_APIC
+	if (acpi_irq_model == ACPI_IRQ_MODEL_IOAPIC) {
+		mp_register_gsi(gsi, edge_level, active_high_low);
+	}
+#endif
+	acpi_gsi_to_irq(gsi, &irq);
+	return irq;
+}
+EXPORT_SYMBOL(acpi_register_gsi);
+
 static unsigned long __init
 acpi_scan_rsdp (
 	unsigned long		start,
--- diff/arch/i386/kernel/apic.c	2004-05-19 22:11:00.000000000 +0100
+++ source/arch/i386/kernel/apic.c	2004-06-11 19:21:56.000000000 +0100
@@ -31,7 +31,6 @@
 #include <asm/smp.h>
 #include <asm/mtrr.h>
 #include <asm/mpspec.h>
-#include <asm/pgalloc.h>
 #include <asm/desc.h>
 #include <asm/arch_hooks.h>
 #include <asm/hpet.h>
--- diff/arch/i386/kernel/cpu/proc.c	2004-05-19 22:11:00.000000000 +0100
+++ source/arch/i386/kernel/cpu/proc.c	2004-06-11 19:21:56.000000000 +0100
@@ -27,7 +27,7 @@
 		/* AMD-defined */
 		NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
 		NULL, NULL, NULL, "syscall", NULL, NULL, NULL, NULL,
-		NULL, NULL, NULL, "mp", NULL, NULL, "mmxext", NULL,
+		NULL, NULL, NULL, "mp", "nx", NULL, "mmxext", NULL,
 		NULL, NULL, NULL, NULL, NULL, "lm", "3dnowext", "3dnow",
 
 		/* Transmeta-defined */
--- diff/arch/i386/kernel/cpuid.c	2004-06-11 19:17:22.000000000 +0100
+++ source/arch/i386/kernel/cpuid.c	2004-06-11 19:21:56.000000000 +0100
@@ -36,12 +36,17 @@
 #include <linux/fs.h>
 #include <linux/smp_lock.h>
 #include <linux/fs.h>
+#include <linux/device.h>
+#include <linux/cpu.h>
+#include <linux/notifier.h>
 
 #include <asm/processor.h>
 #include <asm/msr.h>
 #include <asm/uaccess.h>
 #include <asm/system.h>
 
+static struct class_simple *cpuid_class;
+
 #ifdef CONFIG_SMP
 
 struct cpuid_command {
@@ -153,20 +158,86 @@
 	.open = cpuid_open,
 };
 
+static void cpuid_class_simple_device_remove(void)
+{
+	int i = 0;
+	for_each_online_cpu(i)
+		class_simple_device_remove(MKDEV(CPUID_MAJOR, i));
+	return;
+}
+
+static int cpuid_class_simple_device_add(int i) 
+{
+	int err = 0;
+	struct class_device *class_err;
+
+	class_err = class_simple_device_add(cpuid_class, MKDEV(CPUID_MAJOR, i), NULL, "cpu%d",i);
+	if (IS_ERR(class_err)) {
+		err = PTR_ERR(class_err);
+	}
+	return err;
+}
+static int __devinit cpuid_class_cpu_callback(struct notifier_block *nfb, unsigned long action, void *hcpu)
+{
+	unsigned int cpu = (unsigned long)hcpu;
+
+	switch(action) {
+	case CPU_ONLINE:
+		cpuid_class_simple_device_add(cpu);
+		break;
+	case CPU_DEAD:
+		cpuid_class_simple_device_remove();
+		break;
+	}
+	return NOTIFY_OK;
+}
+
+static struct notifier_block cpuid_class_cpu_notifier =
+{
+	.notifier_call = cpuid_class_cpu_callback,
+};
+
 int __init cpuid_init(void)
 {
+	int i, err = 0;
+	i = 0;
+
 	if (register_chrdev(CPUID_MAJOR, "cpu/cpuid", &cpuid_fops)) {
 		printk(KERN_ERR "cpuid: unable to get major %d for cpuid\n",
 		       CPUID_MAJOR);
-		return -EBUSY;
+		err = -EBUSY;
+		goto out;
+	}
+	cpuid_class = class_simple_create(THIS_MODULE, "cpuid");
+	if (IS_ERR(cpuid_class)) {
+		err = PTR_ERR(cpuid_class);
+		goto out_chrdev;
+	}
+	for_each_online_cpu(i) {
+		err = cpuid_class_simple_device_add(i);
+		if (err != 0) 
+			goto out_class;
 	}
+	register_cpu_notifier(&cpuid_class_cpu_notifier);
 
-	return 0;
+	err = 0;
+	goto out;
+
+out_class:
+	cpuid_class_simple_device_remove();
+	class_simple_destroy(cpuid_class);
+out_chrdev:
+	unregister_chrdev(CPUID_MAJOR, "cpu/cpuid");	
+out:
+	return err;
 }
 
 void __exit cpuid_exit(void)
 {
+	cpuid_class_simple_device_remove();
+	class_simple_destroy(cpuid_class);
 	unregister_chrdev(CPUID_MAJOR, "cpu/cpuid");
+	unregister_cpu_notifier(&cpuid_class_cpu_notifier);
 }
 
 module_init(cpuid_init);
--- diff/arch/i386/kernel/dmi_scan.c	2004-06-11 19:17:22.000000000 +0100
+++ source/arch/i386/kernel/dmi_scan.c	2004-06-11 19:21:56.000000000 +0100
@@ -10,11 +10,15 @@
 #include <asm/io.h>
 #include <linux/pm.h>
 #include <asm/system.h>
+#include <linux/dmi.h>
 #include <linux/bootmem.h>
 
 unsigned long dmi_broken;
 EXPORT_SYMBOL(dmi_broken);
 
+unsigned int i8042_dmi_noloop = 0;
+EXPORT_SYMBOL(i8042_dmi_noloop);
+
 int is_sony_vaio_laptop;
 int is_unsafe_smbus;
 int es7000_plat = 0;
@@ -139,21 +143,6 @@
 	return -1;
 }
 
-
-enum
-{
-	DMI_BIOS_VENDOR,
-	DMI_BIOS_VERSION,
-	DMI_BIOS_DATE,
-	DMI_SYS_VENDOR,
-	DMI_PRODUCT_NAME,
-	DMI_PRODUCT_VERSION,
-	DMI_BOARD_VENDOR,
-	DMI_BOARD_NAME,
-	DMI_BOARD_VERSION,
-	DMI_STRING_MAX
-};
-
 static char *dmi_ident[DMI_STRING_MAX];
 
 /*
@@ -176,26 +165,11 @@
 }
 
 /*
- *	DMI callbacks for problem boards
+ * Ugly compatibility crap.
  */
-
-struct dmi_strmatch
-{
-	u8 slot;
-	char *substr;
-};
-
-#define NONE	255
-
-struct dmi_blacklist
-{
-	int (*callback)(struct dmi_blacklist *);
-	char *ident;
-	struct dmi_strmatch matches[4];
-};
-
-#define NO_MATCH	{ NONE, NULL}
-#define MATCH(a,b)	{ a, b }
+#define dmi_blacklist	dmi_system_id
+#define NO_MATCH	{ DMI_NONE, NULL}
+#define MATCH		DMI_MATCH
 
 /* 
  * Reboot options and system auto-detection code provided by
@@ -343,22 +317,20 @@
 }
 
 /*
- * Work around broken HP Pavilion Notebooks which assign USB to
- * IRQ 9 even though it is actually wired to IRQ 11
+ * Work around broken Acer TravelMate 360 Notebooks which assign Cardbus to
+ * IRQ 11 even though it is actually wired to IRQ 10
  */
-static __init int fix_broken_hp_bios_irq9(struct dmi_blacklist *d)
+static __init int fix_acer_tm360_irqrouting(struct dmi_blacklist *d)
 {
 #ifdef CONFIG_PCI
-	extern int broken_hp_bios_irq9;
-	if (broken_hp_bios_irq9 == 0)
-	{
-		broken_hp_bios_irq9 = 1;
+	extern int acer_tm360_irqrouting;
+	if (acer_tm360_irqrouting == 0) {
+		acer_tm360_irqrouting = 1;
 		printk(KERN_INFO "%s detected - fixing broken IRQ routing\n", d->ident);
 	}
 #endif
 	return 0;
 }
-
 /*
  *  Check for clue free BIOS implementations who use
  *  the following QA technique
@@ -401,6 +373,17 @@
 }
 
 /*
+ * Several HP Proliant (and maybe other OSB4/ProFusion) systems
+ * shouldn't use the AUX LoopBack command, or they crash or reboot.
+ */
+
+static __init int set_8042_noloop(struct dmi_blacklist *d)
+{
+	i8042_dmi_noloop = 1;
+	return 0;
+}
+
+/*
  * This bios swaps the APM minute reporting bytes over (Many sony laptops
  * have this problem).
  */
@@ -839,12 +822,12 @@
 			NO_MATCH, NO_MATCH
 			} },
 	 
-	{ fix_broken_hp_bios_irq9, "HP Pavilion N5400 Series Laptop", {
-			MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"),
-			MATCH(DMI_BIOS_VERSION, "GE.M1.03"),
-			MATCH(DMI_PRODUCT_VERSION, "HP Pavilion Notebook Model GE"),
-			MATCH(DMI_BOARD_VERSION, "OmniBook N32N-736")
+	{ fix_acer_tm360_irqrouting, "Acer TravelMate 36x Laptop", {
+			MATCH(DMI_SYS_VENDOR, "Acer"),
+			MATCH(DMI_PRODUCT_NAME, "TravelMate 360"),
+			NO_MATCH, NO_MATCH
 			} },
+
  
 
 	/*
@@ -876,6 +859,23 @@
 			NO_MATCH, NO_MATCH,
 			} },
 
+	/*      
+	 * Several HP Proliant (and maybe other OSB4/ProFusion) systems
+	 * can't use i8042 in mux mode, or they crash or reboot.
+	 */                     
+
+	{ set_8042_noloop, "Compaq Proliant 8500", {
+			MATCH(DMI_SYS_VENDOR, "Compaq"),
+			MATCH(DMI_PRODUCT_NAME , "ProLiant"),
+			MATCH(DMI_PRODUCT_VERSION, "8500"),
+			NO_MATCH }},
+
+	{ set_8042_noloop, "Compaq Proliant DL760", {
+			MATCH(DMI_SYS_VENDOR, "Compaq"),
+			MATCH(DMI_PRODUCT_NAME , "ProLiant"),
+			MATCH(DMI_PRODUCT_VERSION, "DL760"),
+			NO_MATCH }},
+
 #ifdef	CONFIG_ACPI_BOOT
 	/*
 	 * If your system is blacklisted here, but you find that acpi=force
@@ -1034,6 +1034,13 @@
 			MATCH(DMI_BOARD_NAME, "PR-DLS"),
 			MATCH(DMI_BIOS_VERSION, "ASUS PR-DLS ACPI BIOS Revision 1010"),
 			MATCH(DMI_BIOS_DATE, "03/21/2003") }},
+
+ 	{ disable_acpi_pci, "Acer TravelMate 36x Laptop", {
+ 			MATCH(DMI_SYS_VENDOR, "Acer"),
+ 			MATCH(DMI_PRODUCT_NAME, "TravelMate 360"),
+ 			NO_MATCH, NO_MATCH
+ 			} },
+
 #endif
 
 	{ NULL, }
@@ -1048,9 +1055,6 @@
 
 static __init void dmi_check_blacklist(void)
 {
-	struct dmi_blacklist *d;
-	int i;
-		
 #ifdef	CONFIG_ACPI_BOOT
 #define	ACPI_BLACKLIST_CUTOFF_YEAR	2001
 
@@ -1072,25 +1076,7 @@
 		}
 	}
 #endif
-
-	d=&dmi_blacklist[0];
-	while(d->callback)
-	{
-		for(i=0;i<4;i++)
-		{
-			int s = d->matches[i].slot;
-			if(s==NONE)
-				continue;
-			if(dmi_ident[s] && strstr(dmi_ident[s], d->matches[i].substr))
-				continue;
-			/* No match */
-			goto fail;
-		}
-		if(d->callback(d))
-			return;
-fail:			
-		d++;
-	}
+ 	dmi_check_system(dmi_blacklist);
 }
 
 	
@@ -1157,3 +1143,52 @@
 }
 
 EXPORT_SYMBOL(is_unsafe_smbus);
+
+
+/**
+ *	dmi_check_system - check system DMI data
+ *	@list: array of dmi_system_id structures to match against
+ *
+ *	Walk the blacklist table running matching functions until someone
+ *	returns non zero or we hit the end. Callback function is called for
+ *	each successfull match. Returns the number of matches.
+ */
+int dmi_check_system(struct dmi_system_id *list)
+{
+	int i, count = 0;
+	struct dmi_system_id *d = list;
+
+	while (d->ident) {
+		for (i = 0; i < ARRAY_SIZE(d->matches); i++) {
+			int s = d->matches[i].slot;
+			if (s == DMI_NONE)
+				continue;
+			if (dmi_ident[s] && strstr(dmi_ident[s], d->matches[i].substr))
+				continue;
+			/* No match */
+			goto fail;
+		}
+		if (d->callback && d->callback(d))
+			break;
+		count++;
+fail:		d++;
+	}
+
+	return count;
+}
+
+EXPORT_SYMBOL(dmi_check_system);
+
+/**
+ *	dmi_get_system_info - return DMI data value
+ *	@field: data index (see enum dmi_filed)
+ *
+ *	Returns one DMI data value, can be used to perform
+ *	complex DMI data checks.
+ */
+char * dmi_get_system_info(int field)
+{
+	return dmi_ident[field];
+}
+
+EXPORT_SYMBOL(dmi_get_system_info);
--- diff/arch/i386/kernel/efi.c	2004-05-19 22:11:00.000000000 +0100
+++ source/arch/i386/kernel/efi.c	2004-06-11 19:21:56.000000000 +0100
@@ -37,7 +37,6 @@
 #include <asm/pgtable.h>
 #include <asm/processor.h>
 #include <asm/desc.h>
-#include <asm/pgalloc.h>
 #include <asm/tlbflush.h>
 
 #define EFI_DEBUG	0
--- diff/arch/i386/kernel/entry.S	2004-06-11 19:17:22.000000000 +0100
+++ source/arch/i386/kernel/entry.S	2004-06-11 19:21:56.000000000 +0100
@@ -48,6 +48,18 @@
 #include <asm/smp.h>
 #include <asm/page.h>
 #include "irq_vectors.h"
+        /* We do not recover from a stack overflow, but at least
+         * we know it happened and should be able to track it down.
+         */
+#ifdef CONFIG_STACK_OVERFLOW_TEST
+#define STACK_OVERFLOW_TEST \
+        testl $(THREAD_SIZE - 512),%esp;    \
+        jnz   10f;            \
+        call  stack_overflow; \
+10:
+#else
+#define STACK_OVERFLOW_TEST
+#endif
 
 #define nr_syscalls ((syscall_table_size)/4)
 
@@ -94,7 +106,8 @@
 	pushl %ebx; \
 	movl $(__USER_DS), %edx; \
 	movl %edx, %ds; \
-	movl %edx, %es;
+	movl %edx, %es; \
+        STACK_OVERFLOW_TEST
 
 #define RESTORE_INT_REGS \
 	popl %ebx;	\
@@ -294,6 +307,19 @@
 	testw $_TIF_ALLWORK_MASK, %cx	# current->work
 	jne syscall_exit_work
 restore_all:
+#ifdef CONFIG_TRAP_BAD_SYSCALL_EXITS
+	movl EFLAGS(%esp), %eax		# mix EFLAGS and CS
+	movb CS(%esp), %al
+	testl $(VM_MASK | 3), %eax
+	jz resume_kernelX		# returning to kernel or vm86-space
+
+	cmpl $0,TI_PRE_COUNT(%ebx)	# non-zero preempt_count ?
+	jz resume_kernelX
+
+        int $3
+
+resume_kernelX:
+#endif
 	RESTORE_ALL
 
 	# perform work that needs to be done immediately before resumption
@@ -348,7 +374,7 @@
 	# perform syscall exit tracing
 	ALIGN
 syscall_exit_work:
-	testb $(_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT), %cl
+	testb $(_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT|_TIF_SINGLESTEP), %cl
 	jz work_pending
 	sti				# could let do_syscall_trace() call
 					# schedule() instead
@@ -406,6 +432,16 @@
 /* The include is where all of the SMP etc. interrupts come from */
 #include "entry_arch.h"
 
+#if defined(CONFIG_X86_LOCAL_APIC) && defined(CONFIG_PERFCTR)
+ENTRY(perfctr_interrupt)
+	pushl $LOCAL_PERFCTR_VECTOR-256
+	SAVE_ALL
+	pushl %esp
+	call smp_perfctr_interrupt
+	addl $4, %esp
+	jmp ret_from_intr
+#endif
+
 ENTRY(divide_error)
 	pushl $0			# no error code
 	pushl $do_divide_error
@@ -886,5 +922,11 @@
 	.long sys_mq_notify
 	.long sys_mq_getsetattr
 	.long sys_ni_syscall		/* reserved for kexec */
+	.long sys_perfctr_info
+	.long sys_vperfctr_open
+	.long sys_vperfctr_control
+	.long sys_vperfctr_unlink
+	.long sys_vperfctr_iresume
+	.long sys_vperfctr_read
 
 syscall_table_size=(.-sys_call_table)
--- diff/arch/i386/kernel/head.S	2004-06-11 19:17:22.000000000 +0100
+++ source/arch/i386/kernel/head.S	2004-06-11 19:21:56.000000000 +0100
@@ -153,6 +153,32 @@
 	orl %edx,%eax
 	movl %eax,%cr4
 
+	btl $5, %eax		# check if PAE is enabled
+	jnc 6f
+
+	/* Check if extended functions are implemented */
+	movl $0x80000000, %eax
+	cpuid
+	cmpl $0x80000000, %eax
+	jbe 6f
+	mov $0x80000001, %eax
+	cpuid
+	/* Execute Disable bit supported? */
+	btl $20, %edx
+	jnc 6f
+
+	/* Setup EFER (Extended Feature Enable Register) */
+	movl $0xc0000080, %ecx
+	rdmsr
+
+	btsl $11, %eax
+	/* Make changes effective */
+	wrmsr
+
+6:
+	/* cpuid clobbered ebx, set it up again: */
+	xorl %ebx,%ebx
+	incl %ebx
 3:
 #endif /* CONFIG_SMP */
 
--- diff/arch/i386/kernel/i386_ksyms.c	2004-05-19 22:11:00.000000000 +0100
+++ source/arch/i386/kernel/i386_ksyms.c	2004-06-11 19:21:56.000000000 +0100
@@ -29,7 +29,6 @@
 #include <asm/mmx.h>
 #include <asm/desc.h>
 #include <asm/pgtable.h>
-#include <asm/pgalloc.h>
 #include <asm/tlbflush.h>
 #include <asm/nmi.h>
 #include <asm/ist.h>
--- diff/arch/i386/kernel/i8259.c	2004-05-19 22:11:00.000000000 +0100
+++ source/arch/i386/kernel/i8259.c	2004-06-11 19:21:57.000000000 +0100
@@ -23,6 +23,7 @@
 #include <asm/apic.h>
 #include <asm/arch_hooks.h>
 #include <asm/i8259.h>
+#include <asm/perfctr.h>
 
 #include <linux/irq.h>
 
@@ -317,16 +318,11 @@
  * be shot.
  */
  
-/*
- * =PC9800NOTE= In NEC PC-9800, we use irq8 instead of irq13!
- */
 
 static irqreturn_t math_error_irq(int cpl, void *dev_id, struct pt_regs *regs)
 {
 	extern void math_error(void *);
-#ifndef CONFIG_X86_PC9800
 	outb(0,0xF0);
-#endif
 	if (ignore_fpu_irq || !boot_cpu_data.hard_math)
 		return IRQ_NONE;
 	math_error((void *)regs->eip);
@@ -432,6 +428,8 @@
 	 */
 	intr_init_hook();
 
+	perfctr_vector_init();
+
 	/*
 	 * Set the clock to HZ Hz, we already have a valid
 	 * vector now:
--- diff/arch/i386/kernel/init_task.c	2004-05-19 22:11:00.000000000 +0100
+++ source/arch/i386/kernel/init_task.c	2004-06-11 19:21:57.000000000 +0100
@@ -4,6 +4,7 @@
 #include <linux/init.h>
 #include <linux/init_task.h>
 #include <linux/fs.h>
+#include <linux/mqueue.h>
 
 #include <asm/uaccess.h>
 #include <asm/pgtable.h>
--- diff/arch/i386/kernel/io_apic.c	2004-06-11 19:17:22.000000000 +0100
+++ source/arch/i386/kernel/io_apic.c	2004-06-11 19:21:57.000000000 +0100
@@ -41,10 +41,6 @@
 
 #include "io_ports.h"
 
-#undef APIC_LOCKUP_DEBUG
-
-#define APIC_LOCKUP_DEBUG
-
 static spinlock_t ioapic_lock = SPIN_LOCK_UNLOCKED;
 
 /*
@@ -127,83 +123,47 @@
 	}
 }
 
-/* mask = 1 */
-static void __mask_IO_APIC_irq (unsigned int irq)
+static void __modify_IO_APIC_irq (unsigned int irq, unsigned long enable, unsigned long disable)
 {
-	int pin;
 	struct irq_pin_list *entry = irq_2_pin + irq;
+	unsigned int pin, reg;
 
 	for (;;) {
-		unsigned int reg;
 		pin = entry->pin;
 		if (pin == -1)
 			break;
 		reg = io_apic_read(entry->apic, 0x10 + pin*2);
-		io_apic_modify(entry->apic, 0x10 + pin*2, reg |= 0x00010000);
+		reg &= ~disable;
+		reg |= enable;
+		io_apic_modify(entry->apic, 0x10 + pin*2, reg);
 		if (!entry->next)
 			break;
 		entry = irq_2_pin + entry->next;
 	}
-	io_apic_sync(entry->apic);
+}
+
+/* mask = 1 */
+static void __mask_IO_APIC_irq (unsigned int irq)
+{
+	__modify_IO_APIC_irq(irq, 0x00010000, 0);
 }
 
 /* mask = 0 */
 static void __unmask_IO_APIC_irq (unsigned int irq)
 {
-	int pin;
-	struct irq_pin_list *entry = irq_2_pin + irq;
-
-	for (;;) {
-		unsigned int reg;
-		pin = entry->pin;
-		if (pin == -1)
-			break;
-		reg = io_apic_read(entry->apic, 0x10 + pin*2);
-		io_apic_modify(entry->apic, 0x10 + pin*2, reg &= 0xfffeffff);
-		if (!entry->next)
-			break;
-		entry = irq_2_pin + entry->next;
-	}
+	__modify_IO_APIC_irq(irq, 0, 0x00010000);
 }
 
 /* mask = 1, trigger = 0 */
 static void __mask_and_edge_IO_APIC_irq (unsigned int irq)
 {
-	int pin;
-	struct irq_pin_list *entry = irq_2_pin + irq;
-
-	for (;;) {
-		unsigned int reg;
-		pin = entry->pin;
-		if (pin == -1)
-			break;
-		reg = io_apic_read(entry->apic, 0x10 + pin*2);
-		reg = (reg & 0xffff7fff) | 0x00010000;
-		io_apic_modify(entry->apic, 0x10 + pin*2, reg);
-		if (!entry->next)
-			break;
-		entry = irq_2_pin + entry->next;
-	}
+	__modify_IO_APIC_irq(irq, 0x00010000, 0x00008000);
 }
 
 /* mask = 0, trigger = 1 */
 static void __unmask_and_level_IO_APIC_irq (unsigned int irq)
 {
-	int pin;
-	struct irq_pin_list *entry = irq_2_pin + irq;
-
-	for (;;) {
-		unsigned int reg;
-		pin = entry->pin;
-		if (pin == -1)
-			break;
-		reg = io_apic_read(entry->apic, 0x10 + pin*2);
-		reg = (reg & 0xfffeffff) | 0x00008000;
-		io_apic_modify(entry->apic, 0x10 + pin*2, reg);
-		if (!entry->next)
-			break;
-		entry = irq_2_pin + entry->next;
-	}
+	__modify_IO_APIC_irq(irq, 0x00008000, 0x00010000);
 }
 
 static void mask_IO_APIC_irq (unsigned int irq)
@@ -264,7 +224,7 @@
 	struct irq_pin_list *entry = irq_2_pin + irq;
 	unsigned int apicid_value;
 	
-	apicid_value = cpu_mask_to_apicid(mk_cpumask_const(cpumask));
+	apicid_value = cpu_mask_to_apicid(cpumask);
 	/* Prepare to do the io_apic_write */
 	apicid_value = apicid_value << 24;
 	spin_lock_irqsave(&ioapic_lock, flags);
@@ -762,6 +722,17 @@
 
 __setup("pirq=", ioapic_pirq_setup);
 
+static int get_physical_broadcast(void)
+{
+	unsigned int lvr, version;
+	lvr = apic_read(APIC_LVR);
+	version = GET_APIC_VERSION(lvr);
+	if (version >= 0x14)
+		return 0xff;
+	else
+		return 0xf;
+}
+
 /*
  * Find the IRQ entry number of a certain pin.
  */
@@ -1366,7 +1337,7 @@
 	printk(KERN_DEBUG ".......    : physical APIC id: %02X\n", reg_00.bits.ID);
 	printk(KERN_DEBUG ".......    : Delivery Type: %X\n", reg_00.bits.delivery_type);
 	printk(KERN_DEBUG ".......    : LTS          : %X\n", reg_00.bits.LTS);
-	if (reg_00.bits.ID >= APIC_BROADCAST_ID)
+	if (reg_00.bits.ID >= get_physical_broadcast())
 		UNEXPECTED_IO_APIC();
 	if (reg_00.bits.__reserved_1 || reg_00.bits.__reserved_2)
 		UNEXPECTED_IO_APIC();
@@ -1451,12 +1422,17 @@
 		);
 	}
 	}
+	if (use_pci_vector())
+		printk(KERN_INFO "Using vector-based indexing\n");
 	printk(KERN_DEBUG "IRQ to pin mappings:\n");
 	for (i = 0; i < NR_IRQS; i++) {
 		struct irq_pin_list *entry = irq_2_pin + i;
 		if (entry->pin < 0)
 			continue;
-		printk(KERN_DEBUG "IRQ%d ", i);
+ 		if (use_pci_vector() && !platform_legacy_irq(i))
+			printk(KERN_DEBUG "IRQ%d ", IO_APIC_VECTOR(i));
+		else
+			printk(KERN_DEBUG "IRQ%d ", i);
 		for (;;) {
 			printk("-> %d:%d", entry->apic, entry->pin);
 			if (!entry->next)
@@ -1682,7 +1658,7 @@
 		
 		old_id = mp_ioapics[apic].mpc_apicid;
 
-		if (mp_ioapics[apic].mpc_apicid >= APIC_BROADCAST_ID) {
+		if (mp_ioapics[apic].mpc_apicid >= get_physical_broadcast()) {
 			printk(KERN_ERR "BIOS bug, IO-APIC#%d ID is %d in the MPC table!...\n",
 				apic, mp_ioapics[apic].mpc_apicid);
 			printk(KERN_ERR "... fixing up to %d. (tell your hw vendor)\n",
@@ -1703,10 +1679,10 @@
 					mp_ioapics[apic].mpc_apicid)) {
 			printk(KERN_ERR "BIOS bug, IO-APIC#%d ID %d is already used!...\n",
 				apic, mp_ioapics[apic].mpc_apicid);
-			for (i = 0; i < APIC_BROADCAST_ID; i++)
+			for (i = 0; i < get_physical_broadcast(); i++)
 				if (!physid_isset(i, phys_id_present_map))
 					break;
-			if (i >= APIC_BROADCAST_ID)
+			if (i >= get_physical_broadcast())
 				panic("Max APIC ID exceeded!\n");
 			printk(KERN_ERR "... fixing up to %d. (tell your hw vendor)\n",
 				i);
@@ -1893,30 +1869,11 @@
 	ack_APIC_irq();
 
 	if (!(v & (1 << (i & 0x1f)))) {
-#ifdef APIC_LOCKUP_DEBUG
-		struct irq_pin_list *entry;
-#endif
-
 #ifdef APIC_MISMATCH_DEBUG
 		atomic_inc(&irq_mis_count);
 #endif
 		spin_lock(&ioapic_lock);
 		__mask_and_edge_IO_APIC_irq(irq);
-#ifdef APIC_LOCKUP_DEBUG
-		for (entry = irq_2_pin + irq;;) {
-			unsigned int reg;
-
-			if (entry->pin == -1)
-				break;
-			reg = io_apic_read(entry->apic, 0x10 + entry->pin * 2);
-			if (reg & 0x00004000)
-				printk(KERN_CRIT "Aieee!!!  Remote IRR"
-					" still set after unlock!\n");
-			if (!entry->next)
-				break;
-			entry = irq_2_pin + entry->next;
-		}
-#endif
 		__unmask_and_level_IO_APIC_irq(irq);
 		spin_unlock(&ioapic_lock);
 	}
@@ -2322,8 +2279,6 @@
 
 #ifdef CONFIG_ACPI_BOOT
 
-#define IO_APIC_MAX_ID APIC_BROADCAST_ID
-
 int __init io_apic_get_unique_id (int ioapic, int apic_id)
 {
 	union IO_APIC_reg_00 reg_00;
@@ -2348,7 +2303,7 @@
 	reg_00.raw = io_apic_read(ioapic, 0);
 	spin_unlock_irqrestore(&ioapic_lock, flags);
 
-	if (apic_id >= IO_APIC_MAX_ID) {
+	if (apic_id >= get_physical_broadcast()) {
 		printk(KERN_WARNING "IOAPIC[%d]: Invalid apic_id %d, trying "
 			"%d\n", ioapic, apic_id, reg_00.bits.ID);
 		apic_id = reg_00.bits.ID;
@@ -2360,12 +2315,12 @@
 	 */
 	if (check_apicid_used(apic_id_map, apic_id)) {
 
-		for (i = 0; i < IO_APIC_MAX_ID; i++) {
+		for (i = 0; i < get_physical_broadcast(); i++) {
 			if (!check_apicid_used(apic_id_map, i))
 				break;
 		}
 
-		if (i == IO_APIC_MAX_ID)
+		if (i == get_physical_broadcast())
 			panic("Max apic_id exceeded!\n");
 
 		printk(KERN_WARNING "IOAPIC[%d]: apic_id %d already used, "
--- diff/arch/i386/kernel/irq.c	2004-06-11 19:17:22.000000000 +0100
+++ source/arch/i386/kernel/irq.c	2004-06-11 19:21:57.000000000 +0100
@@ -41,7 +41,6 @@
 #include <asm/system.h>
 #include <asm/bitops.h>
 #include <asm/uaccess.h>
-#include <asm/pgalloc.h>
 #include <asm/delay.h>
 #include <asm/desc.h>
 #include <asm/irq.h>
@@ -570,6 +569,8 @@
 
 	irq_exit();
 
+	kgdb_process_breakpoint();
+
 	return 1;
 }
 
--- diff/arch/i386/kernel/module.c	2004-05-19 22:11:00.000000000 +0100
+++ source/arch/i386/kernel/module.c	2004-06-11 19:21:57.000000000 +0100
@@ -32,7 +32,7 @@
 {
 	if (size == 0)
 		return NULL;
-	return vmalloc(size);
+	return vmalloc_exec(size);
 }
 
 
--- diff/arch/i386/kernel/mpparse.c	2004-06-11 19:17:22.000000000 +0100
+++ source/arch/i386/kernel/mpparse.c	2004-06-11 19:21:57.000000000 +0100
@@ -23,12 +23,12 @@
 #include <linux/smp_lock.h>
 #include <linux/kernel_stat.h>
 #include <linux/mc146818rtc.h>
+#include <linux/bitops.h>
 
 #include <asm/smp.h>
 #include <asm/acpi.h>
 #include <asm/mtrr.h>
 #include <asm/mpspec.h>
-#include <asm/pgalloc.h>
 #include <asm/io_apic.h>
 
 #include <mach_apic.h>
@@ -104,6 +104,31 @@
 static int mpc_record; 
 static struct mpc_config_translation *translation_table[MAX_MPC_ENTRY] __initdata;
 
+#ifdef CONFIG_X86_NUMAQ
+static int MP_valid_apicid(int apicid, int version)
+{
+	return hweight_long(i & 0xf) == 1 && (i >> 4) != 0xf;
+}
+#else
+static int MP_valid_apicid(int apicid, int version)
+{
+	if (version >= 0x14)
+		return apicid < 0xff;
+	else
+		return apicid < 0xf;
+}
+#endif
+
+static void MP_mark_version_physids(int version)
+{
+	int i;
+
+	for (i = 0; i < MAX_APICS; ++i) {
+		if (!MP_valid_apicid(i, version))
+			physid_set(i, phys_cpu_present_map);
+	}
+}
+
 void __init MP_processor_info (struct mpc_config_processor *m)
 {
  	int ver, apicid;
@@ -180,14 +205,16 @@
 		return;
 	}
 	num_processors++;
+	ver = m->mpc_apicver;
 
-	if (MAX_APICS - m->mpc_apicid <= 0) {
+	if (MP_valid_apicid(m->mpc_apicid, ver))
+		MP_mark_version_physids(ver);
+	else {
 		printk(KERN_WARNING "Processor #%d INVALID. (Max ID: %d).\n",
 			m->mpc_apicid, MAX_APICS);
 		--num_processors;
 		return;
 	}
-	ver = m->mpc_apicver;
 
 	tmp = apicid_to_cpu_present(apicid);
 	physids_or(phys_cpu_present_map, phys_cpu_present_map, tmp);
@@ -857,7 +884,7 @@
 } mp_ioapic_routing[MAX_IO_APICS];
 
 
-static int __init mp_find_ioapic (
+static int mp_find_ioapic (
 	int			gsi)
 {
 	int			i = 0;
@@ -1025,96 +1052,56 @@
 	}
 }
 
-extern FADT_DESCRIPTOR acpi_fadt;
-
-#ifdef CONFIG_ACPI_PCI
-
 int (*platform_rename_gsi)(int ioapic, int gsi);
 
-void __init mp_parse_prt (void)
+void mp_register_gsi (u32 gsi, int edge_level, int active_high_low)
 {
-	struct list_head	*node = NULL;
-	struct acpi_prt_entry	*entry = NULL;
 	int			ioapic = -1;
 	int			ioapic_pin = 0;
-	int			gsi = 0;
 	int			idx, bit = 0;
-	int			edge_level = 0;
-	int			active_high_low = 0;
 
-	/*
-	 * Parsing through the PCI Interrupt Routing Table (PRT) and program
-	 * routing for all entries.
-	 */
-	list_for_each(node, &acpi_prt.entries) {
-		entry = list_entry(node, struct acpi_prt_entry, node);
+#ifdef CONFIG_ACPI_BUS
+	/* Don't set up the ACPI SCI because it's already set up */
+	if (acpi_fadt.sci_int == gsi)
+		return;
+#endif
 
-		/* Need to get gsi for dynamic entry */
-		if (entry->link.handle) {
-			gsi = acpi_pci_link_get_irq(entry->link.handle, entry->link.index, &edge_level, &active_high_low);
-			if (!gsi)
-				continue;
-		}
-		else {
-			/* Hardwired GSI. Assume PCI standard settings */
-			gsi = entry->link.index;
-			edge_level = 1;
-			active_high_low = 1;
-		}
+	ioapic = mp_find_ioapic(gsi);
+	if (ioapic < 0) {
+		printk(KERN_WARNING "No IOAPIC for GSI %u\n", gsi);
+		return;
+	}
 
-		/* Don't set up the ACPI SCI because it's already set up */
-                if (acpi_fadt.sci_int == gsi) {
-			/* we still need to set entry's irq */
-			acpi_gsi_to_irq(gsi, &entry->irq);
-			continue;
-                }
-	
-		ioapic = mp_find_ioapic(gsi);
-		if (ioapic < 0)
-			continue;
-		ioapic_pin = gsi - mp_ioapic_routing[ioapic].gsi_base;
-
-		if (platform_rename_gsi)
-			gsi = platform_rename_gsi(ioapic, gsi);
-
-		/* 
-		 * Avoid pin reprogramming.  PRTs typically include entries  
-		 * with redundant pin->gsi mappings (but unique PCI devices);
-		 * we only only program the IOAPIC on the first.
-		 */
-		bit = ioapic_pin % 32;
-		idx = (ioapic_pin < 32) ? 0 : (ioapic_pin / 32);
-		if (idx > 3) {
-			printk(KERN_ERR "Invalid reference to IOAPIC pin "
-				"%d-%d\n", mp_ioapic_routing[ioapic].apic_id, 
-				ioapic_pin);
-			continue;
-		}
-		if ((1<<bit) & mp_ioapic_routing[ioapic].pin_programmed[idx]) {
-			Dprintk(KERN_DEBUG "Pin %d-%d already programmed\n",
-				mp_ioapic_routing[ioapic].apic_id, ioapic_pin);
-			acpi_gsi_to_irq(gsi, &entry->irq);
-			continue;
-		}
+	ioapic_pin = gsi - mp_ioapic_routing[ioapic].gsi_base;
 
-		mp_ioapic_routing[ioapic].pin_programmed[idx] |= (1<<bit);
+	if (platform_rename_gsi)
+		gsi = platform_rename_gsi(ioapic, gsi);
 
-		if (!io_apic_set_pci_routing(ioapic, ioapic_pin, gsi, edge_level, active_high_low)) {
-			acpi_gsi_to_irq(gsi, &entry->irq);
-		}
-		printk(KERN_DEBUG "%02x:%02x:%02x[%c] -> %d-%d -> IRQ %d %s %s\n",
-			entry->id.segment, entry->id.bus,
-			entry->id.device, ('A' + entry->pin),
-			mp_ioapic_routing[ioapic].apic_id, ioapic_pin,
-			entry->irq, edge_level ? "level" : "edge",
-			active_high_low ? "low" : "high");
+	/* 
+	 * Avoid pin reprogramming.  PRTs typically include entries  
+	 * with redundant pin->gsi mappings (but unique PCI devices);
+	 * we only program the IOAPIC on the first.
+	 */
+	bit = ioapic_pin % 32;
+	idx = (ioapic_pin < 32) ? 0 : (ioapic_pin / 32);
+	if (idx > 3) {
+		printk(KERN_ERR "Invalid reference to IOAPIC pin "
+			"%d-%d\n", mp_ioapic_routing[ioapic].apic_id, 
+			ioapic_pin);
+		return;
+	}
+	if ((1<<bit) & mp_ioapic_routing[ioapic].pin_programmed[idx]) {
+		Dprintk(KERN_DEBUG "Pin %d-%d already programmed\n",
+			mp_ioapic_routing[ioapic].apic_id, ioapic_pin);
+		return;
 	}
 
-	print_IO_APIC();
+	mp_ioapic_routing[ioapic].pin_programmed[idx] |= (1<<bit);
 
-	return;
+	io_apic_set_pci_routing(ioapic, ioapic_pin, gsi,
+		    edge_level == ACPI_EDGE_SENSITIVE ? 0 : 1,
+		    active_high_low == ACPI_ACTIVE_HIGH ? 0 : 1);
 }
 
-#endif /*CONFIG_ACPI_PCI*/
 #endif /*CONFIG_X86_IO_APIC && CONFIG_ACPI_INTERPRETER*/
 #endif /*CONFIG_ACPI_BOOT*/
--- diff/arch/i386/kernel/nmi.c	2004-06-11 19:17:22.000000000 +0100
+++ source/arch/i386/kernel/nmi.c	2004-06-11 19:21:57.000000000 +0100
@@ -31,7 +31,17 @@
 #include <asm/mpspec.h>
 #include <asm/nmi.h>
 
+#ifdef CONFIG_KGDB
+#include <asm/kgdb.h>
+#ifdef CONFIG_SMP
+unsigned int nmi_watchdog = NMI_IO_APIC;
+#else
+unsigned int nmi_watchdog = NMI_LOCAL_APIC;
+#endif
+#else
 unsigned int nmi_watchdog = NMI_NONE;
+#endif
+
 static unsigned int nmi_hz = HZ;
 static unsigned int nmi_perfctr_msr;	/* the MSR to reset in NMI handler */
 static unsigned int nmi_p4_cccr_val;
@@ -458,6 +468,9 @@
 	for (i = 0; i < NR_CPUS; i++)
 		alert_counter[i] = 0;
 }
+#ifdef CONFIG_KGDB
+int tune_watchdog = 5*HZ;
+#endif
 
 void nmi_watchdog_tick (struct pt_regs * regs)
 {
@@ -471,12 +484,24 @@
 
 	sum = irq_stat[cpu].apic_timer_irqs;
 
+#ifdef CONFIG_KGDB
+ 	if (! in_kgdb(regs) && last_irq_sums[cpu] == sum ) {
+
+#else
 	if (last_irq_sums[cpu] == sum) {
+#endif
 		/*
 		 * Ayiee, looks like this CPU is stuck ...
 		 * wait a few IRQs (5 seconds) before doing the oops ...
 		 */
 		alert_counter[cpu]++;
+#ifdef CONFIG_KGDB
+		if (alert_counter[cpu] == tune_watchdog) {
+			kgdb_handle_exception(2, SIGPWR, 0, regs);
+			last_irq_sums[cpu] = sum;
+			alert_counter[cpu] = 0;
+		}
+#endif
 		if (alert_counter[cpu] == 5*nmi_hz) {
 			spin_lock(&nmi_print_lock);
 			/*
--- diff/arch/i386/kernel/process.c	2004-06-11 19:17:22.000000000 +0100
+++ source/arch/i386/kernel/process.c	2004-06-11 19:21:57.000000000 +0100
@@ -32,6 +32,7 @@
 #include <linux/delay.h>
 #include <linux/reboot.h>
 #include <linux/init.h>
+#include <linux/perfctr.h>
 #include <linux/mc146818rtc.h>
 #include <linux/module.h>
 #include <linux/kallsyms.h>
@@ -304,6 +305,7 @@
 		tss->io_bitmap_base = INVALID_IO_BITMAP_OFFSET;
 		put_cpu();
 	}
+	perfctr_exit_thread(&tsk->thread);
 }
 
 void flush_thread(void)
@@ -366,6 +368,8 @@
 	savesegment(fs,p->thread.fs);
 	savesegment(gs,p->thread.gs);
 
+	perfctr_copy_thread(&p->thread);
+
 	tsk = current;
 	if (unlikely(NULL != tsk->thread.io_bitmap_ptr)) {
 		p->thread.io_bitmap_ptr = kmalloc(IO_BITMAP_BYTES, GFP_KERNEL);
@@ -511,6 +515,8 @@
 
 	/* never put a printk in __switch_to... printk() calls wake_up*() indirectly */
 
+	perfctr_suspend_thread(prev);
+
 	__unlazy_fpu(prev_p);
 
 	/*
@@ -573,6 +579,9 @@
 			 */
 			tss->io_bitmap_base = INVALID_IO_BITMAP_OFFSET;
 	}
+
+	perfctr_resume_thread(next);
+
 	return prev_p;
 }
 
--- diff/arch/i386/kernel/ptrace.c	2004-06-11 19:17:22.000000000 +0100
+++ source/arch/i386/kernel/ptrace.c	2004-06-11 19:21:57.000000000 +0100
@@ -147,6 +147,7 @@
 { 
 	long tmp;
 
+	clear_tsk_thread_flag(child, TIF_SINGLESTEP);
 	tmp = get_stack_long(child, EFL_OFFSET) & ~TRAP_FLAG;
 	put_stack_long(child, EFL_OFFSET, tmp);
 }
@@ -370,6 +371,7 @@
 		else {
 			clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
 		}
+		clear_tsk_thread_flag(child, TIF_SINGLESTEP);
 		child->exit_code = data;
 	/* make sure the single step bit is not set. */
 		tmp = get_stack_long(child, EFL_OFFSET) & ~TRAP_FLAG;
@@ -391,6 +393,7 @@
 		if (child->state == TASK_ZOMBIE)	/* already dead */
 			break;
 		child->exit_code = SIGKILL;
+		clear_tsk_thread_flag(child, TIF_SINGLESTEP);
 		/* make sure the single step bit is not set. */
 		tmp = get_stack_long(child, EFL_OFFSET) & ~TRAP_FLAG;
 		put_stack_long(child, EFL_OFFSET, tmp);
@@ -411,6 +414,7 @@
 		}
 		tmp = get_stack_long(child, EFL_OFFSET) | TRAP_FLAG;
 		put_stack_long(child, EFL_OFFSET, tmp);
+		set_tsk_thread_flag(child, TIF_SINGLESTEP);
 		child->exit_code = data;
 		/* give it a chance to run. */
 		wake_up_process(child);
@@ -535,7 +539,8 @@
 			audit_syscall_exit(current, regs->eax);
 	}
 
-	if (!test_thread_flag(TIF_SYSCALL_TRACE))
+	if (!test_thread_flag(TIF_SYSCALL_TRACE) &&
+	    !test_thread_flag(TIF_SINGLESTEP))
 		return;
 	if (!(current->ptrace & PT_PTRACED))
 		return;
--- diff/arch/i386/kernel/setup.c	2004-06-11 19:17:22.000000000 +0100
+++ source/arch/i386/kernel/setup.c	2004-06-11 19:21:57.000000000 +0100
@@ -47,7 +47,7 @@
 #include <asm/sections.h>
 #include <asm/io_apic.h>
 #include <asm/ist.h>
-#include <asm/std_resources.h>
+#include <asm/io.h>
 #include "setup_arch_pre.h"
 
 /* This value is set up by the early boot code to point to the value
@@ -129,12 +129,206 @@
 #define RAMDISK_LOAD_FLAG		0x4000	
 
 static char command_line[COMMAND_LINE_SIZE];
-       char saved_command_line[COMMAND_LINE_SIZE];
 
 unsigned char __initdata boot_params[PARAM_SIZE];
 
-static struct resource code_resource = { "Kernel code", 0x100000, 0 };
-static struct resource data_resource = { "Kernel data", 0, 0 };
+static struct resource data_resource = {
+	.name	= "Kernel data",
+	.start	= 0,
+	.end	= 0,
+	.flags	= IORESOURCE_BUSY | IORESOURCE_MEM
+};
+
+static struct resource code_resource = {
+	.name	= "Kernel code",
+	.start	= 0,
+	.end	= 0,
+	.flags	= IORESOURCE_BUSY | IORESOURCE_MEM
+};
+
+static struct resource system_rom_resource = {
+	.name	= "System ROM",
+	.start	= 0xf0000,
+	.end	= 0xfffff,
+	.flags	= IORESOURCE_BUSY | IORESOURCE_READONLY | IORESOURCE_MEM
+};
+
+static struct resource extension_rom_resource = {
+	.name	= "Extension ROM",
+	.start	= 0xe0000,
+	.end	= 0xeffff,
+	.flags	= IORESOURCE_BUSY | IORESOURCE_READONLY | IORESOURCE_MEM
+};
+
+static struct resource adapter_rom_resources[] = { {
+	.name 	= "Adapter ROM",
+	.start	= 0xc8000,
+	.end	= 0,
+	.flags	= IORESOURCE_BUSY | IORESOURCE_READONLY | IORESOURCE_MEM
+}, {
+	.name 	= "Adapter ROM",
+	.start	= 0,
+	.end	= 0,
+	.flags	= IORESOURCE_BUSY | IORESOURCE_READONLY | IORESOURCE_MEM
+}, {
+	.name 	= "Adapter ROM",
+	.start	= 0,
+	.end	= 0,
+	.flags	= IORESOURCE_BUSY | IORESOURCE_READONLY | IORESOURCE_MEM
+}, {
+	.name 	= "Adapter ROM",
+	.start	= 0,
+	.end	= 0,
+	.flags	= IORESOURCE_BUSY | IORESOURCE_READONLY | IORESOURCE_MEM
+}, {
+	.name 	= "Adapter ROM",
+	.start	= 0,
+	.end	= 0,
+	.flags	= IORESOURCE_BUSY | IORESOURCE_READONLY | IORESOURCE_MEM
+}, {
+	.name 	= "Adapter ROM",
+	.start	= 0,
+	.end	= 0,
+	.flags	= IORESOURCE_BUSY | IORESOURCE_READONLY | IORESOURCE_MEM
+} };
+
+#define ADAPTER_ROM_RESOURCES \
+	(sizeof adapter_rom_resources / sizeof adapter_rom_resources[0])
+
+static struct resource video_rom_resource = {
+	.name 	= "Video ROM",
+	.start	= 0xc0000,
+	.end	= 0xc7fff,
+	.flags	= IORESOURCE_BUSY | IORESOURCE_READONLY | IORESOURCE_MEM
+};
+
+static struct resource video_ram_resource = {
+	.name	= "Video RAM area",
+	.start	= 0xa0000,
+	.end	= 0xbffff,
+	.flags	= IORESOURCE_BUSY | IORESOURCE_MEM
+};
+
+static struct resource standard_io_resources[] = { {
+	.name	= "dma1",
+	.start	= 0x0000,
+	.end	= 0x001f,
+	.flags	= IORESOURCE_BUSY | IORESOURCE_IO
+}, {
+	.name	= "pic1",
+	.start	= 0x0020,
+	.end	= 0x0021,
+	.flags	= IORESOURCE_BUSY | IORESOURCE_IO
+}, {
+	.name	= "timer",
+	.start	= 0x0040,
+	.end	= 0x005f,
+	.flags	= IORESOURCE_BUSY | IORESOURCE_IO
+}, {
+	.name	= "keyboard",
+	.start	= 0x0060,
+	.end	= 0x006f,
+	.flags	= IORESOURCE_BUSY | IORESOURCE_IO
+}, {
+	.name	= "dma page reg",
+	.start	= 0x0080,
+	.end	= 0x008f,
+	.flags	= IORESOURCE_BUSY | IORESOURCE_IO
+}, {
+	.name	= "pic2",
+	.start	= 0x00a0,
+	.end	= 0x00a1,
+	.flags	= IORESOURCE_BUSY | IORESOURCE_IO
+}, {
+	.name	= "dma2",
+	.start	= 0x00c0,
+	.end	= 0x00df,
+	.flags	= IORESOURCE_BUSY | IORESOURCE_IO
+}, {
+	.name	= "fpu",
+	.start	= 0x00f0,
+	.end	= 0x00ff,
+	.flags	= IORESOURCE_BUSY | IORESOURCE_IO
+} };
+
+#define STANDARD_IO_RESOURCES \
+	(sizeof standard_io_resources / sizeof standard_io_resources[0])
+
+#define romsignature(x) (*(unsigned short *)(x) == 0xaa55)
+
+static int __init romchecksum(unsigned char *rom, unsigned long length)
+{
+	unsigned char *p, sum = 0;
+
+	for (p = rom; p < rom + length; p++)
+		sum += *p;
+	return sum == 0;
+}
+
+static void __init probe_roms(void)
+{
+	unsigned long start, length, upper;
+	unsigned char *rom;
+	int	      i;
+
+	/* video rom */
+	upper = adapter_rom_resources[0].start;
+	for (start = video_rom_resource.start; start < upper; start += 2048) {
+		rom = isa_bus_to_virt(start);
+		if (!romsignature(rom))
+			continue;
+
+		video_rom_resource.start = start;
+
+		/* 0 < length <= 0x7f * 512, historically */
+		length = rom[2] * 512;
+
+		/* if checksum okay, trust length byte */
+		if (length && romchecksum(rom, length))
+			video_rom_resource.end = start + length - 1;
+
+		request_resource(&iomem_resource, &video_rom_resource);
+		break;
+	}
+
+	start = (video_rom_resource.end + 1 + 2047) & ~2047UL;
+	if (start < upper)
+		start = upper;
+
+	/* system rom */
+	request_resource(&iomem_resource, &system_rom_resource);
+	upper = system_rom_resource.start;
+
+	/* check for extension rom (ignore length byte!) */
+	rom = isa_bus_to_virt(extension_rom_resource.start);
+	if (romsignature(rom)) {
+		length = extension_rom_resource.end - extension_rom_resource.start + 1;
+		if (romchecksum(rom, length)) {
+			request_resource(&iomem_resource, &extension_rom_resource);
+			upper = extension_rom_resource.start;
+		}
+	}
+
+	/* check for adapter roms on 2k boundaries */
+	for (i = 0; i < ADAPTER_ROM_RESOURCES && start < upper; start += 2048) {
+		rom = isa_bus_to_virt(start);
+		if (!romsignature(rom))
+			continue;
+
+		/* 0 < length <= 0x7f * 512, historically */
+		length = rom[2] * 512;
+
+		/* but accept any length that fits if checksum okay */
+		if (!length || start + length > upper || !romchecksum(rom, length))
+			continue;
+
+		adapter_rom_resources[i].start = start;
+		adapter_rom_resources[i].end = start + length - 1;
+		request_resource(&iomem_resource, &adapter_rom_resources[i]);
+
+		start = adapter_rom_resources[i++].end & ~2047UL;
+	}
+}
 
 static void __init limit_regions(unsigned long long size)
 {
@@ -948,6 +1142,7 @@
 static void __init register_memory(unsigned long max_low_pfn)
 {
 	unsigned long low_mem_size;
+	int	      i;
 
 	if (efi_enabled)
 		efi_initialize_iomem_resources(&code_resource, &data_resource);
@@ -955,10 +1150,11 @@
 		legacy_init_iomem_resources(&code_resource, &data_resource);
 
 	/* EFI systems may still have VGA */
-	request_graphics_resource();
+	request_resource(&iomem_resource, &video_ram_resource);
 
 	/* request I/O space for devices used on all i[345]86 PCs */
-	request_standard_io_resources();
+	for (i = 0; i < STANDARD_IO_RESOURCES; i++)
+		request_resource(&ioport_resource, &standard_io_resources[i]);
 
 	/* Tell the PCI layer not to allocate too close to the RAM area.. */
 	low_mem_size = ((max_low_pfn << PAGE_SHIFT) + 0xfffff) & ~0xfffff;
--- diff/arch/i386/kernel/smp.c	2004-06-11 19:17:22.000000000 +0100
+++ source/arch/i386/kernel/smp.c	2004-06-11 19:21:57.000000000 +0100
@@ -21,7 +21,6 @@
 #include <linux/interrupt.h>
 
 #include <asm/mtrr.h>
-#include <asm/pgalloc.h>
 #include <asm/tlbflush.h>
 #include <mach_ipi.h>
 #include <mach_apic.h>
@@ -160,7 +159,7 @@
  */
 inline void send_IPI_mask_bitmask(cpumask_t cpumask, int vector)
 {
-	unsigned long mask = cpus_coerce(cpumask);
+	unsigned long mask = cpus_addr(cpumask)[0];
 	unsigned long cfg;
 	unsigned long flags;
 
@@ -466,7 +465,17 @@
 {
 	on_each_cpu(do_flush_tlb_all, 0, 1, 1);
 }
-
+#ifdef CONFIG_KGDB
+/*
+ * By using the NMI code instead of a vector we just sneak thru the
+ * word generator coming out with just what we want.  AND it does
+ * not matter if clustered_apic_mode is set or not.
+ */
+void smp_send_nmi_allbutself(void)
+{
+	send_IPI_allbutself(APIC_DM_NMI);
+}
+#endif
 /*
  * this function sends a 'reschedule' IPI to another CPU.
  * it goes straight through and wastes no time serializing
--- diff/arch/i386/kernel/smpboot.c	2004-06-11 19:17:22.000000000 +0100
+++ source/arch/i386/kernel/smpboot.c	2004-06-11 19:21:57.000000000 +0100
@@ -47,7 +47,6 @@
 
 #include <linux/delay.h>
 #include <linux/mc146818rtc.h>
-#include <asm/pgalloc.h>
 #include <asm/tlbflush.h>
 #include <asm/desc.h>
 #include <asm/arch_hooks.h>
--- diff/arch/i386/kernel/sysenter.c	2004-05-19 22:11:00.000000000 +0100
+++ source/arch/i386/kernel/sysenter.c	2004-06-11 19:21:57.000000000 +0100
@@ -45,7 +45,7 @@
 {
 	unsigned long page = get_zeroed_page(GFP_ATOMIC);
 
-	__set_fixmap(FIX_VSYSCALL, __pa(page), PAGE_READONLY);
+	__set_fixmap(FIX_VSYSCALL, __pa(page), PAGE_READONLY_EXEC);
 
 	if (!boot_cpu_has(X86_FEATURE_SEP)) {
 		memcpy((void *) page,
--- diff/arch/i386/kernel/time_hpet.c	2004-05-19 22:11:00.000000000 +0100
+++ source/arch/i386/kernel/time_hpet.c	2004-06-11 19:21:57.000000000 +0100
@@ -21,6 +21,7 @@
 #include <linux/config.h>
 
 #include <asm/hpet.h>
+#include <linux/hpet.h>
 
 unsigned long hpet_period;	/* fsecs / HPET clock */
 unsigned long hpet_tick;	/* hpet clks count per tick */
@@ -135,6 +136,51 @@
 	hpet_writel(cfg, HPET_CFG);
 
 	use_hpet = 1;
+
+#ifdef	CONFIG_HPET
+	{
+		struct hpet_data	hd;
+		unsigned int 		ntimer;
+
+		memset(&hd, 0, sizeof (hd));
+
+		ntimer = hpet_readl(HPET_ID);
+		ntimer = (ntimer & HPET_ID_NUMBER) >> HPET_ID_NUMBER_SHIFT;
+		ntimer++;
+
+		/*
+		 * Register with driver.
+		 * Timer0 and Timer1 is used by platform.
+		 */
+		hd.hd_address = hpet_virt_address;
+		hd.hd_nirqs = ntimer;
+		hd.hd_flags = HPET_DATA_PLATFORM;
+#ifndef	CONFIG_HPET_EMULATE_RTC
+		hd.hd_state = 0x1;
+#else
+		hd.hd_state = 0x3;
+#endif
+		hd.hd_irq[0] = HPET_LEGACY_8254;
+		hd.hd_irq[1] = HPET_LEGACY_RTC;
+		if (ntimer > 2) {
+			struct hpet		*hpet;
+			struct hpet_timer	*timer;
+			int			i;
+
+			hpet = (struct hpet *) hpet_virt_address;
+
+			for (i = 2, timer = &hpet->hpet_timers[2]; i < ntimer;
+				timer++, i++)
+				hd.hd_irq[i] = (timer->hpet_config &
+					Tn_INT_ROUTE_CNF_MASK) >>
+					Tn_INT_ROUTE_CNF_SHIFT;
+
+		}
+
+		hpet_alloc(&hd);
+	}
+#endif
+
 #ifdef CONFIG_X86_LOCAL_APIC
 	wait_timer_tick = wait_hpet_tick;
 #endif
--- diff/arch/i386/kernel/timers/timer_cyclone.c	2004-05-19 22:11:01.000000000 +0100
+++ source/arch/i386/kernel/timers/timer_cyclone.c	2004-06-11 19:21:57.000000000 +0100
@@ -17,6 +17,7 @@
 #include <asm/io.h>
 #include <asm/pgtable.h>
 #include <asm/fixmap.h>
+#include "io_ports.h"
 
 extern spinlock_t i8253_lock;
 
@@ -62,6 +63,17 @@
 
 	count = inb_p(0x40);    /* read the latched count */
 	count |= inb(0x40) << 8;
+
+	/*
+	 * VIA686a test code... reset the latch if count > max + 1
+	 * from timer_pit.c - cjb
+	 */
+	if (count > LATCH) {
+		outb_p(0x34, PIT_MODE);
+		outb_p(LATCH & 0xff, PIT_CH0);
+		outb(LATCH >> 8, PIT_CH0);
+		count = LATCH - 1;
+	}
 	spin_unlock(&i8253_lock);
 
 	/* lost tick compensation */
--- diff/arch/i386/kernel/timers/timer_pm.c	2004-05-19 22:11:01.000000000 +0100
+++ source/arch/i386/kernel/timers/timer_pm.c	2004-06-11 19:21:57.000000000 +0100
@@ -21,6 +21,14 @@
 #include <asm/io.h>
 #include <asm/arch_hooks.h>
 
+#include <linux/timex.h>
+#include "mach_timer.h"
+
+/* Number of PMTMR ticks expected during calibration run */
+#define PMTMR_TICKS_PER_SEC 3579545
+#define PMTMR_EXPECTED_RATE \
+  ((CALIBRATE_LATCH * (PMTMR_TICKS_PER_SEC >> 10)) / (CLOCK_TICK_RATE>>10))
+
 
 /* The I/O port the PMTMR resides at.
  * The location is detected during setup_arch(),
@@ -57,6 +65,33 @@
 	return v2 & ACPI_PM_MASK;
 }
 
+
+/*
+ * Some boards have the PMTMR running way too fast. We check
+ * the PMTMR rate against PIT channel 2 to catch these cases.
+ */
+static int verify_pmtmr_rate(void)
+{
+	u32 value1, value2;
+	unsigned long count, delta;
+
+	mach_prepare_counter();
+	value1 = read_pmtmr();
+	mach_countup(&count);
+	value2 = read_pmtmr();
+	delta = (value2 - value1) & ACPI_PM_MASK;
+
+	/* Check that the PMTMR delta is within 5% of what we expect */
+	if (delta < (PMTMR_EXPECTED_RATE * 19) / 20 ||
+	    delta > (PMTMR_EXPECTED_RATE * 21) / 20) {
+		printk(KERN_INFO "PM-Timer running at invalid rate: %lu%% of normal - aborting.\n", 100UL * delta / PMTMR_EXPECTED_RATE);
+		return -1;
+	}
+
+	return 0;
+}
+
+
 static int init_pmtmr(char* override)
 {
 	u32 value1, value2;
@@ -89,6 +124,9 @@
 	return -ENODEV;
 
 pm_good:
+	if (verify_pmtmr_rate() != 0)
+		return -ENODEV;
+
 	init_cpu_khz();
 	return 0;
 }
--- diff/arch/i386/kernel/traps.c	2004-06-11 19:17:22.000000000 +0100
+++ source/arch/i386/kernel/traps.c	2004-06-11 19:21:57.000000000 +0100
@@ -47,7 +47,6 @@
 #include <asm/nmi.h>
 
 #include <asm/smp.h>
-#include <asm/pgalloc.h>
 #include <asm/arch_hooks.h>
 
 #include <linux/irq.h>
@@ -103,8 +102,42 @@
 	return 1;
 }
 
+#ifdef CONFIG_KGDB
+extern void sysenter_entry(void);
+#include <asm/kgdb.h>
+#include <linux/init.h>
+void set_intr_gate(unsigned int n, void *addr);
+static void set_intr_usr_gate(unsigned int n, void *addr);
+/*
+ * Should be able to call this breakpoint() very early in
+ * bring up.  Just hard code the call where needed.
+ * The breakpoint() code is here because set_?_gate() functions
+ * are local (static) to trap.c.  They need be done only once,
+ * but it does not hurt to do them over.
+ */
+void breakpoint(void)
+{
+        set_intr_usr_gate(3,&int3); /* disable ints on trap */
+	set_intr_gate(1,&debug);
+	set_intr_gate(14,&page_fault);
+
+        BREAKPOINT;
+}
+#define	CHK_REMOTE_DEBUG(trapnr,signr,error_code,regs,after)		\
+    {									\
+	if (!user_mode(regs)  ) \
+	{								\
+		kgdb_handle_exception(trapnr, signr, error_code, regs);	\
+		after;							\
+	} else if ((trapnr == 3) && (regs->eflags &0x200)) local_irq_enable(); \
+    }
+#else
+#define	CHK_REMOTE_DEBUG(trapnr,signr,error_code,regs,after)
+#endif
+
+
 #ifdef CONFIG_FRAME_POINTER
-void print_context_stack(struct task_struct *task, unsigned long *stack,
+static void print_context_stack(struct task_struct *task, unsigned long *stack,
 			 unsigned long ebp)
 {
 	unsigned long addr;
@@ -118,7 +151,7 @@
 	}
 }
 #else
-void print_context_stack(struct task_struct *task, unsigned long *stack,
+static void print_context_stack(struct task_struct *task, unsigned long *stack,
 			 unsigned long ebp)
 {
 	unsigned long addr;
@@ -126,8 +159,9 @@
 	while (!kstack_end(stack)) {
 		addr = *stack++;
 		if (kernel_text_address(addr)) {
-			printk(" [<%08lx>] ", addr);
-			print_symbol("%s\n", addr);
+			printk(" [<%08lx>]", addr);
+			print_symbol(" %s", addr);
+			printk("\n");
 		}
 	}
 }
@@ -217,7 +251,7 @@
 		ss = regs->xss & 0xffff;
 	}
 	print_modules();
-	printk("CPU:    %d\nEIP:    %04x:[<%08lx>]    %s\nEFLAGS: %08lx"
+	printk("CPU:    %d\nEIP:    %04x:[<%08lx>]    %s VLI\nEFLAGS: %08lx"
 			"   (%s) \n",
 		smp_processor_id(), 0xffff & regs->xcs, regs->eip,
 		print_tainted(), regs->eflags, UTS_RELEASE);
@@ -235,23 +269,25 @@
 	 * time of the fault..
 	 */
 	if (in_kernel) {
+		u8 *eip;
 
 		printk("\nStack: ");
 		show_stack(NULL, (unsigned long*)esp);
 
 		printk("Code: ");
-		if(regs->eip < PAGE_OFFSET)
-			goto bad;
 
-		for(i=0;i<20;i++)
-		{
+		eip = (u8 *)regs->eip - 43;
+		for (i = 0; i < 64; i++, eip++) {
 			unsigned char c;
-			if(__get_user(c, &((unsigned char*)regs->eip)[i])) {
-bad:
+
+			if (eip < (u8 *)PAGE_OFFSET || __get_user(c, eip)) {
 				printk(" Bad EIP value.");
 				break;
 			}
-			printk("%02x ", c);
+			if (eip == (u8 *)regs->eip)
+				printk("<%02x> ", c);
+			else
+				printk("%02x ", c);
 		}
 	}
 	printk("\n");
@@ -319,6 +355,15 @@
 #endif
 	if (nl)
 		printk("\n");
+#ifdef CONFIG_KGDB
+	/* This is about the only place we want to go to kgdb even if in
+	 * user mode.  But we must go in via a trap so within kgdb we will
+	 * always be in kernel mode.
+	 */
+	if (user_mode(regs))
+		BREAKPOINT;
+#endif
+ 	CHK_REMOTE_DEBUG(0,SIGTRAP,err,regs,)
 	show_registers(regs);
 	bust_spinlocks(0);
 	spin_unlock_irq(&die_lock);
@@ -388,6 +433,7 @@
 #define DO_ERROR(trapnr, signr, str, name) \
 asmlinkage void do_##name(struct pt_regs * regs, long error_code) \
 { \
+	CHK_REMOTE_DEBUG(trapnr,signr,error_code,regs,)\
 	do_trap(trapnr, signr, str, 0, regs, error_code, NULL); \
 }
 
@@ -405,7 +451,9 @@
 #define DO_VM86_ERROR(trapnr, signr, str, name) \
 asmlinkage void do_##name(struct pt_regs * regs, long error_code) \
 { \
+	CHK_REMOTE_DEBUG(trapnr, signr, error_code,regs, return)\
 	do_trap(trapnr, signr, str, 1, regs, error_code, NULL); \
+	return; \
 }
 
 #define DO_VM86_ERROR_INFO(trapnr, signr, str, name, sicode, siaddr) \
@@ -452,8 +500,10 @@
 	return;
 
 gp_in_kernel:
-	if (!fixup_exception(regs))
+	if (!fixup_exception(regs)){
+ 		CHK_REMOTE_DEBUG(13,SIGSEGV,error_code,regs,)
 		die("general protection fault", regs, error_code);
+	}
 }
 
 static void mem_parity_error(unsigned char reason, struct pt_regs * regs)
@@ -615,8 +665,18 @@
 		 * allowing programs to debug themselves without the ptrace()
 		 * interface.
 		 */
+#ifdef CONFIG_KGDB
+		/*
+		 * I think this is the only "real" case of a TF in the kernel
+		 * that really belongs to user space.  Others are
+		 * "Ours all ours!"
+		 */
+		if (((regs->xcs & 3) == 0) && ((void *)regs->eip == sysenter_entry))
+			goto clear_TF_reenable;
+#else
 		if ((regs->xcs & 3) == 0)
 			goto clear_TF_reenable;
+#endif
 		if ((tsk->ptrace & (PT_DTRACE|PT_PTRACED)) == PT_DTRACE)
 			goto clear_TF;
 	}
@@ -628,6 +688,17 @@
 	info.si_errno = 0;
 	info.si_code = TRAP_BRKPT;
 	
+#ifdef CONFIG_KGDB
+        /*
+	 * If this is a kernel mode trap, we need to reset db7 to allow us
+	 * to continue sanely ALSO skip the signal delivery
+         */
+	if ((regs->xcs & 3) == 0)
+		goto clear_dr7;
+
+        /* if not kernel, allow ints but only if they were on */
+       if ( regs->eflags & 0x200) local_irq_enable();
+#endif
 	/* If this is a kernel mode trap, save the user PC on entry to 
 	 * the kernel, that's what the debugger can make sense of.
 	 */
@@ -642,6 +713,7 @@
 	__asm__("movl %0,%%db7"
 		: /* no output */
 		: "r" (0));
+	CHK_REMOTE_DEBUG(1,SIGTRAP,error_code,regs,)
 	return;
 
 debug_vm86:
@@ -890,6 +962,12 @@
 {
 	_set_gate(a,12,3,addr,__KERNEL_CS);
 }
+#ifdef CONFIG_KGDB
+void set_intr_usr_gate(unsigned int n, void *addr)
+{
+	_set_gate(idt_table+n,14,3,addr,__KERNEL_CS);
+}
+#endif
 
 static void __init set_task_gate(unsigned int n, unsigned int gdt_entry)
 {
@@ -912,7 +990,11 @@
 	set_trap_gate(0,&divide_error);
 	set_intr_gate(1,&debug);
 	set_intr_gate(2,&nmi);
+#ifndef CONFIG_KGDB
 	set_system_gate(3,&int3);	/* int3-5 can be called from all */
+#else
+	set_intr_usr_gate(3,&int3);	/* int3-5 can be called from all */
+#endif
 	set_system_gate(4,&overflow);
 	set_system_gate(5,&bounds);
 	set_trap_gate(6,&invalid_op);
--- diff/arch/i386/kernel/vm86.c	2004-05-19 22:11:00.000000000 +0100
+++ source/arch/i386/kernel/vm86.c	2004-06-11 19:21:57.000000000 +0100
@@ -44,7 +44,6 @@
 #include <linux/ptrace.h>
 
 #include <asm/uaccess.h>
-#include <asm/pgalloc.h>
 #include <asm/io.h>
 #include <asm/tlbflush.h>
 #include <asm/irq.h>
--- diff/arch/i386/lib/Makefile	2004-05-19 22:11:01.000000000 +0100
+++ source/arch/i386/lib/Makefile	2004-06-11 19:21:57.000000000 +0100
@@ -3,9 +3,9 @@
 #
 
 
-lib-y = checksum.o delay.o \
-	usercopy.o getuser.o \
-	memcpy.o strstr.o
+lib-y = checksum.o delay.o usercopy.o getuser.o memcpy.o strstr.o \
+	bitops.o
 
 lib-$(CONFIG_X86_USE_3DNOW) += mmx.o
 lib-$(CONFIG_HAVE_DEC_LOCK) += dec_and_lock.o
+lib-$(CONFIG_KGDB) += kgdb_serial.o
--- diff/arch/i386/lib/dec_and_lock.c	2004-05-19 22:11:01.000000000 +0100
+++ source/arch/i386/lib/dec_and_lock.c	2004-06-11 19:21:57.000000000 +0100
@@ -10,6 +10,7 @@
 #include <linux/spinlock.h>
 #include <asm/atomic.h>
 
+#ifndef ATOMIC_DEC_AND_LOCK
 int atomic_dec_and_lock(atomic_t *atomic, spinlock_t *lock)
 {
 	int counter;
@@ -38,3 +39,5 @@
 	spin_unlock(lock);
 	return 0;
 }
+#endif
+
--- diff/arch/i386/mach-es7000/es7000plat.c	2004-06-11 19:17:22.000000000 +0100
+++ source/arch/i386/mach-es7000/es7000plat.c	2004-06-11 19:21:57.000000000 +0100
@@ -134,7 +134,6 @@
 	}
 
 	if (success < 2) {
-		printk("\nNo ES7000 found.\n");
 		es7000_plat = 0;
 	} else {
 		printk("\nEnabling ES7000 specific features...\n");
--- diff/arch/i386/mach-visws/mpparse.c	2004-05-19 22:11:01.000000000 +0100
+++ source/arch/i386/mach-visws/mpparse.c	2004-06-11 19:21:57.000000000 +0100
@@ -57,12 +57,12 @@
 		boot_cpu_logical_apicid = logical_apicid;
 	}
 
-	if (m->mpc_apicid > MAX_APICS) {
+	ver = m->mpc_apicver;
+	if ((ver >= 0x14 && m->mpc_apicid >= 0xff) || m->mpc_apicid >= 0xf) {
 		printk(KERN_ERR "Processor #%d INVALID. (Max ID: %d).\n",
 			m->mpc_apicid, MAX_APICS);
 		return;
 	}
-	ver = m->mpc_apicver;
 
 	apic_cpus = apicid_to_cpu_present(m->mpc_apicid);
 	physids_or(phys_cpu_present_map, phys_cpu_present_map, apic_cpus);
@@ -75,6 +75,14 @@
 			m->mpc_apicid);
 		ver = 0x10;
 	}
+	if (ver >= 0x14)
+		physid_set(0xff, phys_cpu_present_map);
+	else {
+		int i;
+
+		for (i = 0xf; i < MAX_APICS; ++i)
+			physid_set(i, phys_cpu_present_map);
+	}
 	apic_version[m->mpc_apicid] = ver;
 }
 
--- diff/arch/i386/mach-visws/traps.c	2004-05-19 22:11:01.000000000 +0100
+++ source/arch/i386/mach-visws/traps.c	2004-06-11 19:21:57.000000000 +0100
@@ -8,7 +8,6 @@
 #include <linux/pci_ids.h>
 
 #include <asm/io.h>
-#include <asm/pgalloc.h>
 #include <asm/arch_hooks.h>
 #include <asm/apic.h>
 #include "cobalt.h"
--- diff/arch/i386/mach-voyager/voyager_basic.c	2004-05-19 22:11:01.000000000 +0100
+++ source/arch/i386/mach-voyager/voyager_basic.c	2004-06-11 19:21:57.000000000 +0100
@@ -24,7 +24,6 @@
 #include <linux/reboot.h>
 #include <linux/sysrq.h>
 #include <asm/io.h>
-#include <asm/pgalloc.h>
 #include <asm/voyager.h>
 #include <asm/vic.h>
 #include <linux/pm.h>
--- diff/arch/i386/mach-voyager/voyager_smp.c	2004-06-11 19:17:22.000000000 +0100
+++ source/arch/i386/mach-voyager/voyager_smp.c	2004-06-11 19:21:57.000000000 +0100
@@ -24,7 +24,6 @@
 #include <asm/desc.h>
 #include <asm/voyager.h>
 #include <asm/vic.h>
-#include <asm/pgalloc.h>
 #include <asm/mtrr.h>
 #include <asm/pgalloc.h>
 #include <asm/tlbflush.h>
@@ -154,7 +153,7 @@
 send_CPI_allbutself(__u8 cpi)
 {
 	__u8 cpu = smp_processor_id();
-	__u32 mask = cpus_coerce(cpu_online_map) & ~(1 << cpu);
+	__u32 mask = cpus_addr(cpu_online_map)[0] & ~(1 << cpu);
 	send_CPI(mask, cpi);
 }
 
@@ -403,11 +402,11 @@
 	/* set up everything for just this CPU, we can alter
 	 * this as we start the other CPUs later */
 	/* now get the CPU disposition from the extended CMOS */
-	phys_cpu_present_map = cpus_promote(voyager_extended_cmos_read(VOYAGER_PROCESSOR_PRESENT_MASK));
-	cpus_coerce(phys_cpu_present_map) |= voyager_extended_cmos_read(VOYAGER_PROCESSOR_PRESENT_MASK + 1) << 8;
-	cpus_coerce(phys_cpu_present_map) |= voyager_extended_cmos_read(VOYAGER_PROCESSOR_PRESENT_MASK + 2) << 16;
-	cpus_coerce(phys_cpu_present_map) |= voyager_extended_cmos_read(VOYAGER_PROCESSOR_PRESENT_MASK + 3) << 24;
-	printk("VOYAGER SMP: phys_cpu_present_map = 0x%lx\n", cpus_coerce(phys_cpu_present_map));
+	cpus_addr(phys_cpu_present_map)[0] = voyager_extended_cmos_read(VOYAGER_PROCESSOR_PRESENT_MASK);
+	cpus_addr(phys_cpu_present_map)[0] |= voyager_extended_cmos_read(VOYAGER_PROCESSOR_PRESENT_MASK + 1) << 8;
+	cpus_addr(phys_cpu_present_map)[0] |= voyager_extended_cmos_read(VOYAGER_PROCESSOR_PRESENT_MASK + 2) << 16;
+	cpus_addr(phys_cpu_present_map)[0] |= voyager_extended_cmos_read(VOYAGER_PROCESSOR_PRESENT_MASK + 3) << 24;
+	printk("VOYAGER SMP: phys_cpu_present_map = 0x%lx\n", cpus_addr(phys_cpu_present_map)[0]);
 	/* Here we set up the VIC to enable SMP */
 	/* enable the CPIs by writing the base vector to their register */
 	outb(VIC_DEFAULT_CPI_BASE, VIC_CPI_BASE_REGISTER);
@@ -707,12 +706,12 @@
 		/* now that the cat has probed the Voyager System Bus, sanity
 		 * check the cpu map */
 		if( ((voyager_quad_processors | voyager_extended_vic_processors)
-		     & cpus_coerce(phys_cpu_present_map)) != cpus_coerce(phys_cpu_present_map)) {
+		     & cpus_addr(phys_cpu_present_map)[0]) != cpus_addr(phys_cpu_present_map)[0]) {
 			/* should panic */
 			printk("\n\n***WARNING*** Sanity check of CPU present map FAILED\n");
 		}
 	} else if(voyager_level == 4)
-		voyager_extended_vic_processors = cpus_coerce(phys_cpu_present_map);
+		voyager_extended_vic_processors = cpus_addr(phys_cpu_present_map)[0];
 
 	/* this sets up the idle task to run on the current cpu */
 	voyager_extended_cpus = 1;
@@ -910,7 +909,7 @@
 
 	if (!cpumask)
 		BUG();
-	if ((cpumask & cpus_coerce(cpu_online_map)) != cpumask)
+	if ((cpumask & cpus_addr(cpu_online_map)[0]) != cpumask)
 		BUG();
 	if (cpumask & (1 << smp_processor_id()))
 		BUG();
@@ -953,7 +952,7 @@
 
 	preempt_disable();
 
-	cpu_mask = cpus_coerce(mm->cpu_vm_mask) & ~(1 << smp_processor_id());
+	cpu_mask = cpus_addr(mm->cpu_vm_mask)[0] & ~(1 << smp_processor_id());
 	local_flush_tlb();
 	if (cpu_mask)
 		flush_tlb_others(cpu_mask, mm, FLUSH_ALL);
@@ -969,7 +968,7 @@
 
 	preempt_disable();
 
-	cpu_mask = cpus_coerce(mm->cpu_vm_mask) & ~(1 << smp_processor_id());
+	cpu_mask = cpus_addr(mm->cpu_vm_mask)[0] & ~(1 << smp_processor_id());
 
 	if (current->active_mm == mm) {
 		if (current->mm)
@@ -990,7 +989,7 @@
 
 	preempt_disable();
 
-	cpu_mask = cpus_coerce(mm->cpu_vm_mask) & ~(1 << smp_processor_id());
+	cpu_mask = cpus_addr(mm->cpu_vm_mask)[0] & ~(1 << smp_processor_id());
 	if (current->active_mm == mm) {
 		if(current->mm)
 			__flush_tlb_one(va);
@@ -1099,7 +1098,7 @@
 		   int wait)
 {
 	struct call_data_struct data;
-	__u32 mask = cpus_coerce(cpu_online_map);
+	__u32 mask = cpus_addr(cpu_online_map)[0];
 
 	mask &= ~(1<<smp_processor_id());
 
@@ -1790,9 +1789,9 @@
 	unsigned long irq_mask = 1 << irq;
 	int cpu;
 
-	real_mask = cpus_coerce(mask) & voyager_extended_vic_processors;
+	real_mask = cpus_addr(mask)[0] & voyager_extended_vic_processors;
 	
-	if(cpus_coerce(mask) == 0)
+	if(cpus_addr(mask)[0] == 0)
 		/* can't have no cpu's to accept the interrupt -- extremely
 		 * bad things will happen */
 		return;
--- diff/arch/i386/mach-voyager/voyager_thread.c	2004-05-19 22:11:01.000000000 +0100
+++ source/arch/i386/mach-voyager/voyager_thread.c	2004-06-11 19:21:57.000000000 +0100
@@ -28,7 +28,6 @@
 #include <asm/desc.h>
 #include <asm/voyager.h>
 #include <asm/vic.h>
-#include <asm/pgalloc.h>
 #include <asm/mtrr.h>
 #include <asm/msr.h>
 
--- diff/arch/i386/mm/fault.c	2004-06-11 19:17:22.000000000 +0100
+++ source/arch/i386/mm/fault.c	2004-06-11 19:21:57.000000000 +0100
@@ -24,7 +24,6 @@
 
 #include <asm/system.h>
 #include <asm/uaccess.h>
-#include <asm/pgalloc.h>
 #include <asm/hardirq.h>
 #include <asm/desc.h>
 
@@ -262,7 +261,27 @@
 	if (in_atomic() || !mm)
 		goto bad_area_nosemaphore;
 
-	down_read(&mm->mmap_sem);
+	/* When running in the kernel we expect faults to occur only to
+	 * addresses in user space.  All other faults represent errors in the
+	 * kernel and should generate an OOPS.  Unfortunatly, in the case of an
+	 * erroneous fault occuring in a code path which already holds mmap_sem
+	 * we will deadlock attempting to validate the fault against the
+	 * address space.  Luckily the kernel only validly references user
+	 * space from well defined areas of code, which are listed in the
+	 * exceptions table.
+	 *
+	 * As the vast majority of faults will be valid we will only perform
+	 * the source reference check when there is a possibilty of a deadlock.
+	 * Attempt to lock the address space, if we cannot we then validate the
+	 * source.  If this is invalid we can skip the address space check,
+	 * thus avoiding the deadlock.
+	 */
+	if (!down_read_trylock(&mm->mmap_sem)) {
+		if ((error_code & 4) == 0 &&
+		    !search_exception_tables(regs->eip))
+			goto bad_area_nosemaphore;
+		down_read(&mm->mmap_sem);
+	}
 
 	vma = find_vma(mm, address);
 	if (!vma)
@@ -403,9 +422,30 @@
  * Oops. The kernel tried to access some bad page. We'll have to
  * terminate things with extreme prejudice.
  */
+#ifdef CONFIG_KGDB
+        if (!user_mode(regs)){
+                kgdb_handle_exception(14,SIGBUS, error_code, regs);
+                return;
+        }
+#endif
 
 	bust_spinlocks(1);
 
+#ifdef CONFIG_X86_PAE
+	{
+		pgd_t *pgd;
+		pmd_t *pmd;
+
+
+
+		pgd = init_mm.pgd + pgd_index(address);
+		if (pgd_present(*pgd)) {
+			pmd = pmd_offset(pgd, address);
+			if (pmd_val(*pmd) & _PAGE_NX)
+				printk(KERN_CRIT "kernel tried to access NX-protected page - exploit attempt? (uid: %d)\n", current->uid);
+		}
+	}
+#endif
 	if (address < PAGE_SIZE)
 		printk(KERN_ALERT "Unable to handle kernel NULL pointer dereference");
 	else
--- diff/arch/i386/mm/hugetlbpage.c	2004-06-11 19:17:22.000000000 +0100
+++ source/arch/i386/mm/hugetlbpage.c	2004-06-11 19:21:57.000000000 +0100
@@ -15,7 +15,6 @@
 #include <linux/err.h>
 #include <linux/sysctl.h>
 #include <asm/mman.h>
-#include <asm/pgalloc.h>
 #include <asm/tlb.h>
 #include <asm/tlbflush.h>
 
--- diff/arch/i386/mm/init.c	2004-06-11 19:17:22.000000000 +0100
+++ source/arch/i386/mm/init.c	2004-06-11 19:21:57.000000000 +0100
@@ -32,7 +32,6 @@
 #include <asm/system.h>
 #include <asm/uaccess.h>
 #include <asm/pgtable.h>
-#include <asm/pgalloc.h>
 #include <asm/dma.h>
 #include <asm/fixmap.h>
 #include <asm/e820.h>
@@ -123,6 +122,13 @@
 	}
 }
 
+static inline int is_kernel_text(unsigned long addr)
+{
+	if (addr >= (unsigned long)_stext && addr <= (unsigned long)__init_end)
+		return 1;
+	return 0;
+}
+
 /*
  * This maps the physical memory to kernel virtual address space, a total 
  * of max_low_pfn pages, by creating page tables starting from address 
@@ -145,18 +151,29 @@
 		if (pfn >= max_low_pfn)
 			continue;
 		for (pmd_idx = 0; pmd_idx < PTRS_PER_PMD && pfn < max_low_pfn; pmd++, pmd_idx++) {
+			unsigned int address = pfn * PAGE_SIZE + PAGE_OFFSET;
+
 			/* Map with big pages if possible, otherwise create normal page tables. */
 			if (cpu_has_pse) {
-				set_pmd(pmd, pfn_pmd(pfn, PAGE_KERNEL_LARGE));
+				unsigned int address2 = (pfn + PTRS_PER_PTE - 1) * PAGE_SIZE + PAGE_OFFSET + PAGE_SIZE-1;
+
+				if (is_kernel_text(address) || is_kernel_text(address2))
+					set_pmd(pmd, pfn_pmd(pfn, PAGE_KERNEL_LARGE_EXEC));
+				else
+					set_pmd(pmd, pfn_pmd(pfn, PAGE_KERNEL_LARGE));
 				pfn += PTRS_PER_PTE;
 			} else {
 				pte = one_page_table_init(pmd);
 
-				for (pte_ofs = 0; pte_ofs < PTRS_PER_PTE && pfn < max_low_pfn; pte++, pfn++, pte_ofs++)
-					set_pte(pte, pfn_pte(pfn, PAGE_KERNEL));
+				for (pte_ofs = 0; pte_ofs < PTRS_PER_PTE && pfn < max_low_pfn; pte++, pfn++, pte_ofs++) {
+						if (is_kernel_text(address))
+							set_pte(pte, pfn_pte(pfn, PAGE_KERNEL_EXEC));
+						else
+							set_pte(pte, pfn_pte(pfn, PAGE_KERNEL));
+				}
 			}
 		}
-	}	
+	}
 }
 
 static inline int page_kills_ppro(unsigned long pagenr)
@@ -273,7 +290,8 @@
 #define set_highmem_pages_init(bad_ppro) do { } while (0)
 #endif /* CONFIG_HIGHMEM */
 
-unsigned long __PAGE_KERNEL = _PAGE_KERNEL;
+unsigned long long __PAGE_KERNEL = _PAGE_KERNEL;
+unsigned long long __PAGE_KERNEL_EXEC = _PAGE_KERNEL_EXEC;
 
 #ifndef CONFIG_DISCONTIGMEM
 #define remap_numa_kva() do {} while (0)
@@ -302,6 +320,7 @@
 	if (cpu_has_pge) {
 		set_in_cr4(X86_CR4_PGE);
 		__PAGE_KERNEL |= _PAGE_GLOBAL;
+		__PAGE_KERNEL_EXEC |= _PAGE_GLOBAL;
 	}
 
 	kernel_physical_mapping_init(pgd_base);
@@ -392,6 +411,52 @@
 extern void zone_sizes_init(void);
 #endif /* !CONFIG_DISCONTIGMEM */
 
+static int disable_nx __initdata = 0;
+u64 __supported_pte_mask = ~_PAGE_NX;
+
+/*
+ * noexec = on|off
+ *
+ * Control non executable mappings.
+ *
+ * on      Enable
+ * off     Disable
+ */
+static int __init noexec_setup(char *str)
+{
+	if (!strncmp(str, "on",2) && cpu_has_nx) {
+		__supported_pte_mask |= _PAGE_NX;
+		disable_nx = 0;
+	} else if (!strncmp(str,"off",3)) {
+		disable_nx = 1;
+		__supported_pte_mask &= ~_PAGE_NX;
+	}
+	return 1;
+}
+
+__setup("noexec=", noexec_setup);
+
+#ifdef CONFIG_X86_PAE
+static int use_nx = 0;
+
+static void __init set_nx(void)
+{
+	unsigned int v[4], l, h;
+
+	if (cpu_has_pae && (cpuid_eax(0x80000000) > 0x80000001)) {
+		cpuid(0x80000001, &v[0], &v[1], &v[2], &v[3]);
+		if ((v[3] & (1 << 20)) && !disable_nx) {
+			rdmsr(MSR_EFER, l, h);
+			l |= EFER_NX;
+			wrmsr(MSR_EFER, l, h);
+			use_nx = 1;
+			__supported_pte_mask |= _PAGE_NX;
+		}
+	}
+}
+
+#endif
+
 /*
  * paging_init() sets up the page tables - note that the first 8MB are
  * already mapped by head.S.
@@ -401,6 +466,14 @@
  */
 void __init paging_init(void)
 {
+#ifdef CONFIG_X86_PAE
+	set_nx();
+	if (use_nx)
+		printk("NX (Execute Disable) protection: active\n");
+	else
+		printk("NX (Execute Disable) protection: not present!\n");
+#endif
+
 	pagetable_init();
 
 	load_cr3(swapper_pg_dir);
--- diff/arch/i386/mm/ioremap.c	2004-05-19 22:11:02.000000000 +0100
+++ source/arch/i386/mm/ioremap.c	2004-06-11 19:21:57.000000000 +0100
@@ -12,7 +12,6 @@
 #include <linux/init.h>
 #include <linux/slab.h>
 #include <asm/io.h>
-#include <asm/pgalloc.h>
 #include <asm/fixmap.h>
 #include <asm/cacheflush.h>
 #include <asm/tlbflush.h>
--- diff/arch/i386/pci/acpi.c	2004-05-19 22:11:02.000000000 +0100
+++ source/arch/i386/pci/acpi.c	2004-06-11 19:21:57.000000000 +0100
@@ -1,6 +1,8 @@
 #include <linux/pci.h>
 #include <linux/acpi.h>
 #include <linux/init.h>
+#include <linux/irq.h>
+#include <asm/hw_irq.h>
 #include "pci.h"
 
 struct pci_bus * __devinit pci_acpi_scan_root(struct acpi_device *device, int domain, int busnum)
@@ -15,18 +17,31 @@
 
 static int __init pci_acpi_init(void)
 {
+	struct pci_dev *dev = NULL;
+
 	if (pcibios_scanned)
 		return 0;
 
-	if (!acpi_noirq) {
-		if (!acpi_pci_irq_init()) {
-			printk(KERN_INFO "PCI: Using ACPI for IRQ routing\n");
-			pcibios_scanned++;
-			pcibios_enable_irq = acpi_pci_irq_enable;
-		} else
-			printk(KERN_WARNING "PCI: Invalid ACPI-PCI IRQ routing table\n");
+	if (acpi_noirq)
+		return 0;
 
-	}
+	printk(KERN_INFO "PCI: Using ACPI for IRQ routing\n");
+	acpi_irq_penalty_init();
+	pcibios_scanned++;
+	pcibios_enable_irq = acpi_pci_irq_enable;
+
+	/*
+	 * PCI IRQ routing is set up by pci_enable_device(), but we
+	 * also do it here in case there are still broken drivers that
+	 * don't use pci_enable_device().
+	 */
+	while ((dev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL)
+		acpi_pci_irq_enable(dev);
+
+#ifdef CONFIG_X86_IO_APIC
+	if (acpi_ioapic)
+		print_IO_APIC();
+#endif
 
 	return 0;
 }
--- diff/arch/i386/pci/irq.c	2004-06-11 19:17:22.000000000 +0100
+++ source/arch/i386/pci/irq.c	2004-06-11 19:21:57.000000000 +0100
@@ -12,6 +12,7 @@
 #include <linux/slab.h>
 #include <linux/interrupt.h>
 #include <linux/irq.h>
+#include <linux/dmi.h>
 #include <asm/io.h>
 #include <asm/smp.h>
 #include <asm/io_apic.h>
@@ -22,7 +23,8 @@
 #define PIRQ_SIGNATURE	(('$' << 0) + ('P' << 8) + ('I' << 16) + ('R' << 24))
 #define PIRQ_VERSION 0x0100
 
-int broken_hp_bios_irq9;
+static int broken_hp_bios_irq9;
+int acer_tm360_irqrouting;
 
 static struct irq_routing_table *pirq_table;
 
@@ -745,6 +747,14 @@
 		r->set(pirq_router_dev, dev, pirq, 11);
 	}
 
+	/* same for Acer Travelmate 360, but with CB and irq 11 -> 10 */
+	if (acer_tm360_irqrouting && dev->irq == 11 && dev->vendor == PCI_VENDOR_ID_O2) {
+		pirq = 0x68;
+		mask = 0x400;
+		dev->irq = r->get(pirq_router_dev, dev, pirq);
+		pci_write_config_byte(dev, PCI_INTERRUPT_LINE, dev->irq);
+	}
+
 	/*
 	 * Find the best IRQ to assign: use the one
 	 * reported by the device if possible.
@@ -893,6 +903,33 @@
 	}
 }
 
+/*
+ * Work around broken HP Pavilion Notebooks which assign USB to
+ * IRQ 9 even though it is actually wired to IRQ 11
+ */
+static int __init fix_broken_hp_bios_irq9(struct dmi_system_id *d)
+{
+	if (!broken_hp_bios_irq9) {
+		broken_hp_bios_irq9 = 1;
+		printk(KERN_INFO "%s detected - fixing broken IRQ routing\n", d->ident);
+	}
+	return 0;
+}
+
+static struct dmi_system_id __initdata pciirq_dmi_table[] = {
+	{
+		.callback = fix_broken_hp_bios_irq9,
+		.ident = "HP Pavilion N5400 Series Laptop",
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"),
+			DMI_MATCH(DMI_BIOS_VERSION, "GE.M1.03"),
+			DMI_MATCH(DMI_PRODUCT_VERSION, "HP Pavilion Notebook Model GE"),
+			DMI_MATCH(DMI_BOARD_VERSION, "OmniBook N32N-736"),
+		},
+	},
+	{ }
+};
+
 static int __init pcibios_irq_init(void)
 {
 	DBG("PCI: IRQ init\n");
@@ -900,6 +937,8 @@
 	if (pcibios_enable_irq || raw_pci_ops == NULL)
 		return 0;
 
+	dmi_check_system(pciirq_dmi_table);
+
 	pirq_table = pirq_find_routing_table();
 
 #ifdef CONFIG_PCI_BIOS
--- diff/arch/i386/pci/visws.c	2004-05-19 22:11:02.000000000 +0100
+++ source/arch/i386/pci/visws.c	2004-06-11 19:21:57.000000000 +0100
@@ -15,8 +15,6 @@
 #include "pci.h"
 
 
-int broken_hp_bios_irq9;
-
 extern struct pci_raw_ops pci_direct_conf1;
 
 static int pci_visws_enable_irq(struct pci_dev *dev) { return 0; }
--- diff/arch/ia64/Kconfig	2004-06-11 19:17:22.000000000 +0100
+++ source/arch/ia64/Kconfig	2004-06-11 19:21:57.000000000 +0100
@@ -192,6 +192,184 @@
 	  or have huge holes in the physical address space for other reasons.
 	  See <file:Documentation/vm/numa> for more.
 
+config KGDB
+	bool "Include kgdb kernel debugger"
+	depends on DEBUG_KERNEL
+	help
+	  If you say Y here, the system will be compiled with the debug
+	  option (-g) and a debugging stub will be included in the
+	  kernel.  This stub communicates with gdb on another (host)
+	  computer via a serial port.  The host computer should have
+	  access to the kernel binary file (vmlinux) and a serial port
+	  that is connected to the target machine.  Gdb can be made to
+	  configure the serial port or you can use stty and setserial to
+	  do this. See the 'target' command in gdb. This option also
+	  configures in the ability to request a breakpoint early in the
+	  boot process.  To request the breakpoint just include 'kgdb'
+	  as a boot option when booting the target machine.  The system
+	  will then break as soon as it looks at the boot options.  This
+	  option also installs a breakpoint in panic and sends any
+	  kernel faults to the debugger. For more information see the
+	  Documentation/i386/kgdb/kgdb.txt file.
+
+config	KGDB_EARLY
+	bool
+	depends on KGDB
+	default n
+	prompt "KGDB Early"
+	help
+	  Kgdb debugging in kernel can start shortly before/after setup_arch routine exits.
+
+choice
+	depends on KGDB
+    	prompt "Debug serial port BAUD"
+	default KGDB_115200BAUD
+	help
+	  Gdb and the kernel stub need to agree on the baud rate to be
+	  used.  Some systems (x86 family at this writing) allow this to
+	  be configured.
+
+config KGDB_9600BAUD
+	bool "9600"
+
+config KGDB_19200BAUD
+	bool "19200"
+
+config KGDB_38400BAUD
+	bool "38400"
+
+config KGDB_57600BAUD
+	bool "57600"
+
+config KGDB_115200BAUD
+	bool "115200"
+endchoice
+
+config KGDB_IOMEM
+	hex "hex I/O port IOMEM address"
+	depends on KGDB
+	default	0xc0000000ff5e0000
+	help
+	  Some systems use IOMEM address for the port.  This value is from
+	  the rx2600 chassis console port.
+
+config KGDB_IOMEM_REG_SHIFT
+	hex "hex I/O port IOMEM reg shift"
+	depends on KGDB
+	default 0x0
+	help
+	  This is the memory shift for IOMEM.
+
+config KGDB_IRQ
+	int "IRQ of the debug serial port"
+	depends on KGDB
+	default 59
+	help
+	  This is the irq for the debug port.  If everything is working
+	  correctly and the kernel has interrupts on a control C to the
+	  port should cause a break into the kernel debug stub. This value
+	  is the rx2600 chassis's console port.
+
+config DEBUG_INFO
+	bool
+	depends on KGDB
+	default y
+
+config KGDB_MORE
+	bool "Add any additional compile options"
+	depends on KGDB
+	default n
+	help
+	  Saying yes here turns on the ability to enter additional
+	  compile options.
+
+
+config KGDB_OPTIONS
+	depends on KGDB_MORE
+	string "Additional compile arguments"
+	default "-O1"
+	help
+	  This option allows you enter additional compile options for
+	  the whole kernel compile.  Each platform will have a default
+	  that seems right for it.  For example on PPC "-ggdb -O1", and
+	  for i386 "-O1".  Note that by configuring KGDB "-g" is already
+	  turned on.  In addition, on i386 platforms
+	  "-fomit-frame-pointer" is deleted from the standard compile
+	  options.
+
+config NO_KGDB_CPUS
+	int "Number of CPUs"
+	depends on KGDB && SMP
+	default NR_CPUS
+	help
+
+	  This option sets the number of cpus for kgdb ONLY.  It is used
+	  to prune some internal structures so they look "nice" when
+	  displayed with gdb.  This is to overcome possibly larger
+	  numbers that may have been entered above.  Enter the real
+	  number to get nice clean kgdb_info displays.
+
+config KGDB_TS
+	bool "Enable kgdb time stamp macros?"
+	depends on KGDB
+	default n
+	help
+	  Kgdb event macros allow you to instrument your code with calls
+	  to the kgdb event recording function.  The event log may be
+	  examined with gdb at a break point.  Turning on this
+	  capability also allows you to choose how many events to
+	  keep. Kgdb always keeps the lastest events.
+
+choice
+	depends on KGDB_TS
+	prompt "Max number of time stamps to save?"
+	default KGDB_TS_128
+
+config KGDB_TS_64
+	bool "64"
+
+config KGDB_TS_128
+	bool "128"
+
+config KGDB_TS_256
+	bool "256"
+
+config KGDB_TS_512
+	bool "512"
+
+config KGDB_TS_1024
+	bool "1024"
+
+endchoice
+
+config KGDB_CONSOLE
+	bool "Enable serial console thru kgdb port"
+	depends on KGDB
+	default n
+	help
+	  This option enables the command line "console=kgdb" option.
+	  When the system is booted with this option in the command line
+	  all kernel printk output is sent to gdb (as well as to other
+	  consoles).  For this to work gdb must be connected.  For this
+	  reason, this command line option will generate a breakpoint if
+	  gdb has not yet connected.  After the gdb continue command is
+	  given all pent up console output will be printed by gdb on the
+	  host machine.  Neither this option, nor KGDB require the
+	  serial driver to be configured.
+
+config KGDB_SYSRQ
+	bool "Turn on SysRq 'G' command to do a break?"
+	depends on KGDB
+	default y
+	help
+	  This option includes an option in the SysRq code that allows
+	  you to enter SysRq G which generates a breakpoint to the KGDB
+	  stub.  This will work if the keyboard is alive and can
+	  interrupt the system.  Because of constraints on when the
+	  serial port interrupt can be enabled, this code may allow you
+	  to interrupt the system before the serial port control C is
+	  available.  Just say yes here.
+
 config IA64_CYCLONE
 	bool "Support Cyclone(EXA) Time Source"
 	help
@@ -445,6 +623,19 @@
 	  keys are documented in <file:Documentation/sysrq.txt>. Don't say Y
 	  unless you really know what this hack does.
 
+config SCHEDSTATS
+	bool "Collect scheduler statistics"
+	depends on PROC_FS
+	default n
+	help
+	  If you say Y here, additional code will be inserted into the
+	  scheduler and related routines to collect statistics about
+	  scheduler behavior and provide them in /proc/schedstat.  These
+	  stats may be useful for both tuning and debugging the scheduler
+	  If you aren't debugging the scheduler or trying to tune a specific
+	  application, you can say N to avoid the very slight overhead
+	  this adds.
+
 config DEBUG_SLAB
 	bool "Debug memory allocations"
 	depends on DEBUG_KERNEL
@@ -494,6 +685,13 @@
 	  Say Y here only if you plan to use gdb to debug the kernel.
 	  If you don't debug the kernel, you can say N.
 
+config LOCKMETER
+       bool "Kernel lock metering"
+       depends on SMP
+       help
+         Say Y to enable kernel lock metering, which adds overhead to SMP locks,
+         but allows you to see various statistics using the lockstat command.
+
 config SYSVIPC_COMPAT
 	bool
 	depends on COMPAT && SYSVIPC
--- diff/arch/ia64/ia32/ia32_entry.S	2004-06-11 19:17:22.000000000 +0100
+++ source/arch/ia64/ia32/ia32_entry.S	2004-06-11 19:21:57.000000000 +0100
@@ -349,7 +349,7 @@
 	data8 sys_setfsuid	/* 16-bit version */
 	data8 sys_setfsgid	/* 16-bit version */
 	data8 sys_llseek	  /* 140 */
-	data8 sys32_getdents
+	data8 compat_sys_getdents
 	data8 compat_sys_select
 	data8 sys_flock
 	data8 sys32_msync
@@ -428,7 +428,7 @@
 	data8 sys_pivot_root
 	data8 sys_mincore
 	data8 sys_madvise
-	data8 sys_getdents64	  /* 220 */
+	data8 compat_sys_getdents64	  /* 220 */
 	data8 compat_sys_fcntl64
 	data8 sys_ni_syscall		/* reserved for TUX */
 	data8 sys_ni_syscall		/* reserved for Security */
--- diff/arch/ia64/kernel/Makefile	2004-06-11 19:17:22.000000000 +0100
+++ source/arch/ia64/kernel/Makefile	2004-06-11 19:21:58.000000000 +0100
@@ -17,6 +17,7 @@
 obj-$(CONFIG_SMP)		+= smp.o smpboot.o
 obj-$(CONFIG_PERFMON)		+= perfmon_default_smpl.o
 obj-$(CONFIG_IA64_CYCLONE)	+= cyclone.o
+obj-$(CONFIG_KGDB)		+= kgdb_stub.o
 
 # The gate DSO image is built using a special linker script.
 targets += gate.so gate-syms.o
--- diff/arch/ia64/kernel/acpi.c	2004-06-11 19:17:22.000000000 +0100
+++ source/arch/ia64/kernel/acpi.c	2004-06-11 19:21:57.000000000 +0100
@@ -521,9 +521,14 @@
 #endif /* CONFIG_ACPI_NUMA */
 
 unsigned int
-acpi_register_gsi (u32 gsi, int polarity, int trigger)
+acpi_register_gsi (u32 gsi, int edge_level, int active_high_low)
 {
-	return acpi_register_irq(gsi, polarity, trigger);
+	if (has_8259 && gsi < 16)
+		return isa_irq_to_vector(gsi);
+
+	return iosapic_register_intr(gsi,
+			(active_high_low == ACPI_ACTIVE_HIGH) ? IOSAPIC_POL_HIGH : IOSAPIC_POL_LOW,
+			(edge_level == ACPI_EDGE_SENSITIVE) ? IOSAPIC_EDGE : IOSAPIC_LEVEL);
 }
 EXPORT_SYMBOL(acpi_register_gsi);
 
@@ -548,7 +553,7 @@
 	if (fadt->iapc_boot_arch & BAF_LEGACY_DEVICES)
 		acpi_legacy_devices = 1;
 
-	acpi_register_gsi(fadt->sci_int, ACPI_ACTIVE_LOW, ACPI_LEVEL_SENSITIVE);
+	acpi_register_gsi(fadt->sci_int, ACPI_LEVEL_SENSITIVE, ACPI_ACTIVE_LOW);
 	return 0;
 }
 
@@ -662,16 +667,4 @@
 	return 0;
 }
 
-int
-acpi_register_irq (u32 gsi, u32 polarity, u32 trigger)
-{
-	if (has_8259 && gsi < 16)
-		return isa_irq_to_vector(gsi);
-
-	return iosapic_register_intr(gsi,
-			(polarity == ACPI_ACTIVE_HIGH) ? IOSAPIC_POL_HIGH : IOSAPIC_POL_LOW,
-			(trigger == ACPI_EDGE_SENSITIVE) ? IOSAPIC_EDGE : IOSAPIC_LEVEL);
-}
-EXPORT_SYMBOL(acpi_register_irq);
-
 #endif /* CONFIG_ACPI_BOOT */
--- diff/arch/ia64/kernel/init_task.c	2004-05-19 22:11:03.000000000 +0100
+++ source/arch/ia64/kernel/init_task.c	2004-06-11 19:21:57.000000000 +0100
@@ -11,6 +11,7 @@
 #include <linux/module.h>
 #include <linux/sched.h>
 #include <linux/init_task.h>
+#include <linux/mqueue.h>
 
 #include <asm/uaccess.h>
 #include <asm/pgtable.h>
--- diff/arch/ia64/kernel/iosapic.c	2004-06-11 19:17:23.000000000 +0100
+++ source/arch/ia64/kernel/iosapic.c	2004-06-11 19:21:57.000000000 +0100
@@ -483,7 +483,7 @@
 
 	index = find_iosapic(gsi);
 	if (index < 0) {
-		printk(KERN_WARNING "%s: No IOSAPIC for GSI 0x%x\n", __FUNCTION__, gsi);
+		printk(KERN_WARNING "%s: No IOSAPIC for GSI %u\n", __FUNCTION__, gsi);
 		return;
 	}
 
@@ -512,6 +512,42 @@
 	}
 }
 
+static unsigned int
+get_target_cpu (void)
+{
+#ifdef CONFIG_SMP
+	static int cpu = -1;
+
+	/*
+	 * If the platform supports redirection via XTP, let it
+	 * distribute interrupts.
+	 */
+	if (smp_int_redirect & SMP_IRQ_REDIRECTION)
+		return hard_smp_processor_id();
+
+	/*
+	 * Some interrupts (ACPI SCI, for instance) are registered
+	 * before the BSP is marked as online.
+	 */
+	if (!cpu_online(smp_processor_id()))
+		return hard_smp_processor_id();
+
+	/*
+	 * Otherwise, round-robin interrupt vectors across all the
+	 * processors.  (It'd be nice if we could be smarter in the
+	 * case of NUMA.)
+	 */
+	do {
+		if (++cpu >= NR_CPUS)
+			cpu = 0;
+	} while (!cpu_online(cpu));
+
+	return cpu_physical_id(cpu);
+#else
+	return hard_smp_processor_id();
+#endif
+}
+
 /*
  * ACPI can describe IOSAPIC interrupts via static tables and namespace
  * methods.  This provides an interface to register those interrupts and
@@ -522,21 +558,35 @@
 		       unsigned long polarity, unsigned long trigger)
 {
 	int vector;
-	unsigned int dest = (ia64_getreg(_IA64_REG_CR_LID) >> 16) & 0xffff;
-
-	vector = gsi_to_vector(gsi);
-	if (vector < 0)
-		vector = assign_irq_vector(AUTO_ASSIGN);
+	unsigned int dest;
+	unsigned long flags;
 
-	register_intr(gsi, vector, IOSAPIC_LOWEST_PRIORITY,
-		      polarity, trigger);
+	/*
+	 * If this GSI has already been registered (i.e., it's a
+	 * shared interrupt, or we lost a race to register it),
+	 * don't touch the RTE.
+	 */
+	spin_lock_irqsave(&iosapic_lock, flags);
+	{
+		vector = gsi_to_vector(gsi);
+		if (vector > 0) {
+			spin_unlock_irqrestore(&iosapic_lock, flags);
+			return vector;
+		}
 
-	printk(KERN_INFO "GSI 0x%x(%s,%s) -> CPU 0x%04x vector %d\n",
-	       gsi, (polarity == IOSAPIC_POL_HIGH ? "high" : "low"),
-	       (trigger == IOSAPIC_EDGE ? "edge" : "level"), dest, vector);
+		vector = assign_irq_vector(AUTO_ASSIGN);
+		dest = get_target_cpu();
+		register_intr(gsi, vector, IOSAPIC_LOWEST_PRIORITY,
+			polarity, trigger);
+	}
+	spin_unlock_irqrestore(&iosapic_lock, flags);
+
+	printk(KERN_INFO "GSI %u (%s, %s) -> CPU %d (0x%04x) vector %d\n",
+	       gsi, (trigger == IOSAPIC_EDGE ? "edge" : "level"),
+	       (polarity == IOSAPIC_POL_HIGH ? "high" : "low"),
+	       cpu_logical_id(dest), dest, vector);
 
-	/* program the IOSAPIC routing table */
-	set_rte(vector, dest, 0);
+	set_rte(vector, dest, 1);
 	return vector;
 }
 
@@ -549,8 +599,9 @@
 				int iosapic_vector, u16 eid, u16 id,
 				unsigned long polarity, unsigned long trigger)
 {
+	static const char * const name[] = {"unknown", "PMI", "INIT", "CPEI"};
 	unsigned char delivery;
-	int vector;
+	int vector, mask = 0;
 	unsigned int dest = ((id << 8) | eid) & 0xffff;
 
 	switch (int_type) {
@@ -570,21 +621,22 @@
 	      case ACPI_INTERRUPT_CPEI:
 		vector = IA64_CPE_VECTOR;
 		delivery = IOSAPIC_LOWEST_PRIORITY;
+		mask = 1;
 		break;
 	      default:
-		printk(KERN_ERR "iosapic_register_platform_irq(): invalid int type\n");
+		printk(KERN_ERR "iosapic_register_platform_irq(): invalid int type 0x%x\n", int_type);
 		return -1;
 	}
 
-	register_intr(gsi, vector, delivery, polarity,
-		      trigger);
+	register_intr(gsi, vector, delivery, polarity, trigger);
 
-	printk(KERN_INFO "PLATFORM int 0x%x: GSI 0x%x(%s,%s) -> CPU 0x%04x vector %d\n",
-	       int_type, gsi, (polarity == IOSAPIC_POL_HIGH ? "high" : "low"),
-	       (trigger == IOSAPIC_EDGE ? "edge" : "level"), dest, vector);
+	printk(KERN_INFO "PLATFORM int %s (0x%x): GSI %u (%s, %s) -> CPU %d (0x%04x) vector %d\n",
+	       int_type < ARRAY_SIZE(name) ? name[int_type] : "unknown",
+	       int_type, gsi, (trigger == IOSAPIC_EDGE ? "edge" : "level"),
+	       (polarity == IOSAPIC_POL_HIGH ? "high" : "low"),
+	       cpu_logical_id(dest), dest, vector);
 
-	/* program the IOSAPIC routing table */
-	set_rte(vector, dest, 0);
+	set_rte(vector, dest, mask);
 	return vector;
 }
 
@@ -599,18 +651,18 @@
 			  unsigned long trigger)
 {
 	int vector;
-	unsigned int dest = (ia64_getreg(_IA64_REG_CR_LID) >> 16) & 0xffff;
+	unsigned int dest = hard_smp_processor_id();
 
 	vector = isa_irq_to_vector(isa_irq);
 
 	register_intr(gsi, vector, IOSAPIC_LOWEST_PRIORITY, polarity, trigger);
 
-	DBG("ISA: IRQ %u -> GSI 0x%x (%s,%s) -> CPU 0x%04x vector %d\n",
-	    isa_irq, gsi, polarity == IOSAPIC_POL_HIGH ? "high" : "low",
-	    trigger == IOSAPIC_EDGE ? "edge" : "level", dest, vector);
+	DBG("ISA: IRQ %u -> GSI %u (%s,%s) -> CPU %d (0x%04x) vector %d\n",
+	    isa_irq, gsi, trigger == IOSAPIC_EDGE ? "edge" : "level",
+	    polarity == IOSAPIC_POL_HIGH ? "high" : "low",
+	    cpu_logical_id(dest), dest, vector);
 
-	/* program the IOSAPIC routing table */
-	set_rte(vector, dest, 0);
+	set_rte(vector, dest, 1);
 }
 
 void __init
@@ -665,104 +717,3 @@
 			iosapic_override_isa_irq(isa_irq, isa_irq, IOSAPIC_POL_HIGH, IOSAPIC_EDGE);
 	}
 }
-
-void
-iosapic_enable_intr (unsigned int vector)
-{
-	unsigned int dest;
-	irq_desc_t *desc;
-
-	/*
-	 * In the case of a shared interrupt, do not re-route the vector, and
-	 * especially do not mask a running interrupt (startup will not get
-	 * called for a shared interrupt).
-	 */
-	desc = irq_descp(vector);
-	if (desc->action)
-		return;
-
-#ifdef CONFIG_SMP
-	/*
-	 * For platforms that do not support interrupt redirect via the XTP interface, we
-	 * can round-robin the PCI device interrupts to the processors
-	 */
-	if (!(smp_int_redirect & SMP_IRQ_REDIRECTION)) {
-		static int cpu_index = -1;
-
-		do
-			if (++cpu_index >= NR_CPUS)
-				cpu_index = 0;
-		while (!cpu_online(cpu_index));
-
-		dest = cpu_physical_id(cpu_index) & 0xffff;
-	} else {
-		/*
-		 * Direct the interrupt vector to the current cpu, platform redirection
-		 * will distribute them.
-		 */
-		dest = (ia64_getreg(_IA64_REG_CR_LID) >> 16) & 0xffff;
-	}
-#else
-	/* direct the interrupt vector to the running cpu id */
-	dest = (ia64_getreg(_IA64_REG_CR_LID) >> 16) & 0xffff;
-#endif
-	set_rte(vector, dest, 1);
-
-	printk(KERN_INFO "IOSAPIC: vector %d -> CPU 0x%04x, enabled\n",
-	       vector, dest);
-}
-
-#ifdef CONFIG_ACPI_PCI
-
-void __init
-iosapic_parse_prt (void)
-{
-	struct acpi_prt_entry *entry;
-	struct list_head *node;
-	unsigned int gsi;
-	int vector;
-	char pci_id[16];
-	struct hw_interrupt_type *irq_type = &irq_type_iosapic_level;
-	irq_desc_t *idesc;
-
-	list_for_each(node, &acpi_prt.entries) {
-		entry = list_entry(node, struct acpi_prt_entry, node);
-
-		/* We're only interested in static (non-link) entries.  */
-		if (entry->link.handle)
-			continue;
-
-		gsi = entry->link.index;
-
-		vector = gsi_to_vector(gsi);
-		if (vector < 0) {
-			if (find_iosapic(gsi) < 0)
-				continue;
-
-			/* allocate a vector for this interrupt line */
-			if (pcat_compat && (gsi < 16))
-				vector = isa_irq_to_vector(gsi);
-			else
-				/* new GSI; allocate a vector for it */
-				vector = assign_irq_vector(AUTO_ASSIGN);
-
-			register_intr(gsi, vector, IOSAPIC_LOWEST_PRIORITY, IOSAPIC_POL_LOW,
-				      IOSAPIC_LEVEL);
-		}
-		entry->irq = vector;
-		snprintf(pci_id, sizeof(pci_id), "%02x:%02x:%02x[%c]",
-			 entry->id.segment, entry->id.bus, entry->id.device, 'A' + entry->pin);
-
-		/*
-		 * If vector was previously initialized to a different
-		 * handler, re-initialize.
-		 */
-		idesc = irq_descp(vector);
-		if (idesc->handler != irq_type)
-			register_intr(gsi, vector, IOSAPIC_LOWEST_PRIORITY, IOSAPIC_POL_LOW,
-				      IOSAPIC_LEVEL);
-
-	}
-}
-
-#endif /* CONFIG_ACPI */
--- diff/arch/ia64/kernel/irq.c	2004-06-11 19:17:23.000000000 +0100
+++ source/arch/ia64/kernel/irq.c	2004-06-11 19:21:57.000000000 +0100
@@ -538,6 +538,11 @@
 		desc->handler->end(irq);
 		spin_unlock(&desc->lock);
 	}
+
+#ifdef	CONFIG_KGDB
+	kgdb_process_breakpoint();
+#endif
+
 	return 1;
 }
 
--- diff/arch/ia64/kernel/ivt.S	2004-06-11 19:17:23.000000000 +0100
+++ source/arch/ia64/kernel/ivt.S	2004-06-11 19:21:58.000000000 +0100
@@ -68,6 +68,13 @@
 # define DBG_FAULT(i)
 #endif
 
+#ifdef	CONFIG_KGDB
+#define	KGDB_ENABLE_PSR_DB mov r31=psr;; movl r30=IA64_PSR_DB;; or r31=r31,r30;; \
+		mov psr.l=r31;; srlz.i;;
+#else
+#define	KGDB_ENABLE_PSR_DB
+#endif
+
 #define MINSTATE_VIRT	/* needed by minstate.h */
 #include "minstate.h"
 
@@ -473,6 +480,7 @@
 	movl r14=ia64_leave_kernel
 	;;
 	SAVE_REST
+	KGDB_ENABLE_PSR_DB
 	mov rp=r14
 	;;
 	adds out2=16,r12			// out2 = pointer to pt_regs
@@ -733,6 +741,8 @@
 	;;
 	srlz.i					// guarantee that interruption collection is on
 	;;
+	KGDB_ENABLE_PSR_DB
+	;;
 (p15)	ssm psr.i				// restore psr.i
 	;;
 	mov r3=NR_syscalls - 1
@@ -774,6 +784,7 @@
 	srlz.i			// ensure everybody knows psr.ic is back on
 	;;
 	SAVE_REST
+	KGDB_ENABLE_PSR_DB
 	;;
 	alloc r14=ar.pfs,0,0,2,0 // must be first in an insn group
 	mov out0=cr.ivr		// pass cr.ivr as first arg
@@ -1001,6 +1012,7 @@
 	movl r15=ia64_leave_kernel
 	;;
 	SAVE_REST
+	KGDB_ENABLE_PSR_DB
 	mov rp=r15
 	;;
 	br.call.sptk.many b6=ia64_bad_break	// avoid WAW on CFM and ignore return addr
@@ -1034,6 +1046,7 @@
 	adds r3=8,r2				// set up second base pointer
 	;;
 	SAVE_REST
+	KGDB_ENABLE_PSR_DB
 	movl r14=ia64_leave_kernel
 	;;
 	mov rp=r14
@@ -1076,6 +1089,7 @@
 	adds r3=8,r2				// set up second base pointer for SAVE_REST
 	;;
 	SAVE_REST
+	KGDB_ENABLE_PSR_DB
 	movl r14=ia64_leave_kernel
 	;;
 	mov rp=r14
--- diff/arch/ia64/kernel/machvec.c	2004-06-11 19:17:23.000000000 +0100
+++ source/arch/ia64/kernel/machvec.c	2004-06-11 19:21:58.000000000 +0100
@@ -62,6 +62,12 @@
 EXPORT_SYMBOL(machvec_timer_interrupt);
 
 void
+machvec_tlb_migrate_finish (struct mm_struct *mm)
+{
+}
+EXPORT_SYMBOL(machvec_tlb_migrate_finish);
+
+void
 machvec_dma_sync_single (struct device *hwdev, dma_addr_t dma_handle, size_t size, int dir)
 {
 	mb();
--- diff/arch/ia64/kernel/process.c	2004-06-11 19:17:23.000000000 +0100
+++ source/arch/ia64/kernel/process.c	2004-06-11 19:21:58.000000000 +0100
@@ -407,6 +407,9 @@
 	 */
 	child_ptregs->cr_ipsr = ((child_ptregs->cr_ipsr | IA64_PSR_BITS_TO_SET)
 				 & ~(IA64_PSR_BITS_TO_CLEAR | IA64_PSR_PP | IA64_PSR_UP));
+#ifdef	CONFIG_KGDB
+	child_ptregs->cr_ipsr |= IA64_PSR_DB;
+#endif
 
 	/*
 	 * NOTE: The calling convention considers all floating point
@@ -639,6 +642,9 @@
 	regs.pt.r11 = (unsigned long) arg;	/* 2nd argument */
 	/* Preserve PSR bits, except for bits 32-34 and 37-45, which we can't read.  */
 	regs.pt.cr_ipsr = ia64_getreg(_IA64_REG_PSR) | IA64_PSR_BN;
+#ifdef	CONFIG_KGDB
+	regs.pt.cr_ipsr |= IA64_PSR_DB;
+#endif
 	regs.pt.cr_ifs = 1UL << 63;		/* mark as valid, empty frame */
 	regs.sw.ar_fpsr = regs.pt.ar_fpsr = ia64_getreg(_IA64_REG_AR_FPSR);
 	regs.sw.ar_bspstore = (unsigned long) current + IA64_RBS_OFFSET;
--- diff/arch/ia64/kernel/setup.c	2004-06-11 19:17:23.000000000 +0100
+++ source/arch/ia64/kernel/setup.c	2004-06-11 19:21:58.000000000 +0100
@@ -50,6 +50,7 @@
 #include <asm/smp.h>
 #include <asm/system.h>
 #include <asm/unistd.h>
+#include <asm/kgdb.h>
 
 #if defined(CONFIG_SMP) && (IA64_CPU_SIZE > PAGE_SIZE)
 # error "struct cpuinfo_ia64 too big!"
@@ -88,10 +89,6 @@
 unsigned long ia64_max_iommu_merge_mask = ~0UL;
 EXPORT_SYMBOL(ia64_max_iommu_merge_mask);
 
-#define COMMAND_LINE_SIZE	512
-
-char saved_command_line[COMMAND_LINE_SIZE]; /* used in proc filesystem */
-
 /*
  * We use a special marker for the end of memory and it uses the extra (+1) slot
  */
@@ -349,11 +346,36 @@
 		conswitchp = &vga_con;
 # endif
 #endif
+#ifndef	CONFIG_IA64_HP_SIM
+#ifdef	CONFIG_KGDB
+	{
+		unsigned long total_ibr, total_dbr;
+		long status;
+		int dbr;
+
+		status = ia64_pal_debug_info(&total_ibr, &total_dbr);
+
+		if (!status) {
+			printk(KERN_INFO "kgdb has DBR = %d IBR = %d\n",
+				(int) total_dbr, (int) total_ibr);
+
+			for (dbr = 0; dbr < total_dbr; dbr++)
+				ia64_set_dbr((dbr << 1) + 1, 0);
+			for (dbr = 0; dbr < total_ibr; dbr++)
+				ia64_set_ibr((dbr << 1) + 1, 0);
+		}
+	}
+#endif
+#endif
+
 
 	/* enable IA-64 Machine Check Abort Handling */
 	ia64_mca_init();
 
 	platform_setup(cmdline_p);
+#ifdef	CONFIG_KGDB_EARLY
+	kgdb_serial_init();
+#endif
 	paging_init();
 }
 
--- diff/arch/ia64/kernel/smp.c	2004-06-11 19:17:23.000000000 +0100
+++ source/arch/ia64/kernel/smp.c	2004-06-11 19:21:58.000000000 +0100
@@ -47,6 +47,7 @@
 #include <asm/tlbflush.h>
 #include <asm/unistd.h>
 #include <asm/mca.h>
+#include <asm/kgdb.h>
 
 /*
  * Structure and data for smp_call_function(). This is designed to minimise static memory
@@ -66,6 +67,9 @@
 
 #define IPI_CALL_FUNC		0
 #define IPI_CPU_STOP		1
+#ifdef	CONFIG_KGDB
+#define	IPI_KGDB_INTERRUPT	2
+#endif
 
 /* This needs to be cacheline aligned because it is written to by *other* CPUs.  */
 static DEFINE_PER_CPU(u64, ipi_operation) ____cacheline_aligned;
@@ -156,6 +160,12 @@
 				stop_this_cpu();
 				break;
 
+#ifdef	CONFIG_KGDB
+			      case IPI_KGDB_INTERRUPT:
+				(void) in_kgdb(regs, NULL);
+				break;
+#endif
+
 			      default:
 				printk(KERN_CRIT "Unknown IPI on CPU %d: %lu\n", this_cpu, which);
 				break;
@@ -361,6 +371,14 @@
 }
 EXPORT_SYMBOL(smp_call_function);
 
+#ifdef	CONFIG_KGDB
+void
+smp_send_nmi_allbutself(void)
+{
+	send_IPI_allbutself(IPI_KGDB_INTERRUPT);
+}
+#endif
+
 /*
  * this function calls the 'stop' function on all other CPUs in the system.
  */
--- diff/arch/ia64/kernel/traps.c	2004-06-11 19:17:23.000000000 +0100
+++ source/arch/ia64/kernel/traps.c	2004-06-11 19:21:58.000000000 +0100
@@ -35,6 +35,19 @@
 		fpswa_interface = __va(ia64_boot_param->fpswa);
 }
 
+#ifdef	CONFIG_KGDB
+extern int kgdb_handle_exception(int, int, int, struct pt_regs *);
+#define	CHK_REMOTE_DEBUG(trapnr, signr, error_code, regs, after)		\
+	{									\
+		if (!user_mode(regs)) {						\
+			kgdb_handle_exception(trapnr, signr, error_code, regs);	\
+			after;							\
+		}								\
+	}
+#else
+#define	CHK_REMOTE_DEBUG(trapnr, signr, error_code, regs, after)
+#endif
+
 /*
  * Unlock any spinlocks which will prevent us from getting the message out (timerlist_lock
  * is acquired through the console unblank code)
@@ -85,6 +98,8 @@
 		bust_spinlocks(1);
 	}
 
+	CHK_REMOTE_DEBUG(-1, SIGTRAP, err, regs,)
+
 	if (++die.lock_owner_depth < 3) {
 		printk("%s[%d]: %s %ld [%d]\n",
 			current->comm, current->pid, str, err, ++die_counter);
@@ -117,9 +132,13 @@
 	siginfo.si_flags = 0;		/* clear __ISR_VALID */
 	siginfo.si_isr = 0;
 
+
+
 	switch (break_num) {
 	      case 0: /* unknown error (used by GCC for __builtin_abort()) */
+#ifndef	CONFIG_KGDB
 		die_if_kernel("bugcheck!", regs, break_num);
+#endif
 		sig = SIGILL; code = ILL_ILLOPC;
 		break;
 
@@ -172,8 +191,10 @@
 		break;
 
 	      default:
+#ifndef	CONFIG_KGDB
 		if (break_num < 0x40000 || break_num > 0x100000)
 			die_if_kernel("Bad break", regs, break_num);
+#endif
 
 		if (break_num < 0x80000) {
 			sig = SIGILL; code = __ILL_BREAK;
@@ -181,6 +202,13 @@
 			sig = SIGTRAP; code = TRAP_BRKPT;
 		}
 	}
+#ifdef	CONFIG_KGDB
+	/*
+	 * We don't want to trap simulator system calls.
+	 */
+	if (break_num != 0x80001)
+		CHK_REMOTE_DEBUG(11, sig, break_num, regs, return)
+#endif
 	siginfo.si_signo = sig;
 	siginfo.si_errno = 0;
 	siginfo.si_code = code;
@@ -488,8 +516,9 @@
 		break;
 
 	      case 29: /* Debug */
-	      case 35: /* Taken Branch Trap */
 	      case 36: /* Single Step Trap */
+		CHK_REMOTE_DEBUG(vector, SIGTRAP, isr, regs, return)
+	      case 35: /* Taken Branch Trap */
 		if (fsys_mode(current, regs)) {
 			extern char __kernel_syscall_via_break[];
 			/*
@@ -603,6 +632,7 @@
 		sprintf(buf, "Fault %lu", vector);
 		break;
 	}
+	CHK_REMOTE_DEBUG(vector, SIGTRAP, isr, regs,)
 	die_if_kernel(buf, regs, error);
 	force_sig(SIGILL, current);
 }
--- diff/arch/ia64/kernel/unwind.c	2004-06-11 19:17:23.000000000 +0100
+++ source/arch/ia64/kernel/unwind.c	2004-06-11 19:21:58.000000000 +0100
@@ -75,10 +75,69 @@
 # define STAT(x...)
 #endif
 
+
+#ifdef	CONFIG_KGDB_EARLY
+#define	KGDB_EARLY_SIZE	100
+static struct unw_reg_state __initdata kgdb_reg_state[KGDB_EARLY_SIZE];
+static struct unw_labeled_state __initdata kgdb_labeled_state[KGDB_EARLY_SIZE];
+void __initdata *kgdb_reg_state_free, __initdata *kgdb_labeled_state_free;
+
+static void __init
+kgdb_malloc_init(void)
+{
+	int i;
+
+	kgdb_reg_state_free = kgdb_reg_state;
+	for (i = 1; i < KGDB_EARLY_SIZE; i++) {
+		*((unsigned long *) &kgdb_reg_state[i]) = (unsigned long) kgdb_reg_state_free;
+		kgdb_reg_state_free = &kgdb_reg_state[i];
+	}
+
+	kgdb_labeled_state_free = kgdb_labeled_state;
+	for (i = 1; i < KGDB_EARLY_SIZE; i++) {
+		*((unsigned long *) &kgdb_labeled_state[i]) =
+			(unsigned long) kgdb_labeled_state_free;
+		kgdb_labeled_state_free = &kgdb_labeled_state[i];
+	}
+
+}
+
+static void * __init
+kgdb_malloc(void **mem)
+{
+	void *p;
+
+	p = *mem;
+	*mem = *((void **) p);
+	return p;
+}
+
+static void __init
+kgdb_free(void **mem, void *p)
+{
+	*((void **)p) = *mem;
+	*mem = p;
+}
+
+#define alloc_reg_state()	(!malloc_sizes[0].cs_cachep ? 		\
+		kgdb_malloc(&kgdb_reg_state_free) : 			\
+		kmalloc(sizeof(struct unw_reg_state), GFP_ATOMIC))
+#define free_reg_state(usr)	(!malloc_sizes[0].cs_cachep ?		\
+		kgdb_free(&kgdb_reg_state_free, usr) :			\
+		kfree(usr))
+#define alloc_labeled_state()	(!malloc_sizes[0].cs_cachep ?		\
+		kgdb_malloc(&kgdb_labeled_state_free) :			\
+		kmalloc(sizeof(struct unw_labeled_state), GFP_ATOMIC))
+#define free_labeled_state(usr)	(!malloc_sizes[0].cs_cachep ?		\
+		kgdb_free(&kgdb_labeled_state_free, usr) :		\
+		kfree(usr))
+
+#else
 #define alloc_reg_state()	kmalloc(sizeof(struct unw_reg_state), GFP_ATOMIC)
 #define free_reg_state(usr)	kfree(usr)
 #define alloc_labeled_state()	kmalloc(sizeof(struct unw_labeled_state), GFP_ATOMIC)
 #define free_labeled_state(usr)	kfree(usr)
+#endif
 
 typedef unsigned long unw_word;
 typedef unsigned char unw_hash_index_t;
@@ -2262,6 +2321,10 @@
 
 	init_unwind_table(&unw.kernel_table, "kernel", KERNEL_START, (unsigned long) __gp,
 			  __start_unwind, __end_unwind);
+
+#ifdef	CONFIG_KGDB_EARLY
+	kgdb_malloc_init();
+#endif
 }
 
 /*
--- diff/arch/ia64/lib/Makefile	2004-06-11 19:17:23.000000000 +0100
+++ source/arch/ia64/lib/Makefile	2004-06-11 19:21:58.000000000 +0100
@@ -16,6 +16,7 @@
 lib-$(CONFIG_PERFMON)	+= carta_random.o
 lib-$(CONFIG_MD_RAID5)	+= xor.o
 lib-$(CONFIG_HAVE_DEC_LOCK) += dec_and_lock.o
+lib-$(CONFIG_KGDB)	+= kgdb_serial.o
 
 AFLAGS___divdi3.o	=
 AFLAGS___udivdi3.o	= -DUNSIGNED
--- diff/arch/ia64/lib/dec_and_lock.c	2004-05-19 22:11:04.000000000 +0100
+++ source/arch/ia64/lib/dec_and_lock.c	2004-06-11 19:21:58.000000000 +0100
@@ -13,6 +13,7 @@
 #include <linux/spinlock.h>
 #include <asm/atomic.h>
 
+#ifndef CONFIG_LOCKMETER
 /*
  * Decrement REFCOUNT and if the count reaches zero, acquire the spinlock.  Both of these
  * operations have to be done atomically, so that the count doesn't drop to zero without
@@ -40,3 +41,4 @@
 }
 
 EXPORT_SYMBOL(atomic_dec_and_lock);
+#endif
--- diff/arch/ia64/mm/fault.c	2004-05-19 22:11:04.000000000 +0100
+++ source/arch/ia64/mm/fault.c	2004-06-11 19:21:58.000000000 +0100
@@ -15,6 +15,7 @@
 #include <asm/system.h>
 #include <asm/uaccess.h>
 #include <asm/hardirq.h>
+#include <asm/kgdb.h>
 
 extern void die (char *, struct pt_regs *, long);
 
@@ -232,6 +233,11 @@
 	 */
 	bust_spinlocks(1);
 
+#ifdef	CONFIG_KGDB
+	kgdb_handle_exception(5, SIGBUS, isr, regs);
+	return;
+#endif
+
 	if (address < PAGE_SIZE)
 		printk(KERN_ALERT "Unable to handle kernel NULL pointer dereference (address %016lx)\n", address);
 	else
--- diff/arch/ia64/pci/pci.c	2004-06-11 19:17:23.000000000 +0100
+++ source/arch/ia64/pci/pci.c	2004-06-11 19:21:58.000000000 +0100
@@ -134,10 +134,18 @@
 static int __init
 pci_acpi_init (void)
 {
-	if (!acpi_pci_irq_init())
-		printk(KERN_INFO "PCI: Using ACPI for IRQ routing\n");
-	else
-		printk(KERN_WARNING "PCI: Invalid ACPI-PCI IRQ routing table\n");
+	struct pci_dev *dev = NULL;
+
+	printk(KERN_INFO "PCI: Using ACPI for IRQ routing\n");
+
+	/*
+	 * PCI IRQ routing is set up by pci_enable_device(), but we
+	 * also do it here in case there are still broken drivers that
+	 * don't use pci_enable_device().
+	 */
+	while ((dev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL)
+		acpi_pci_irq_enable(dev);
+
 	return 0;
 }
 
--- diff/arch/ia64/sn/kernel/sn2/sn2_smp.c	2004-05-19 22:11:05.000000000 +0100
+++ source/arch/ia64/sn/kernel/sn2/sn2_smp.c	2004-06-11 19:21:58.000000000 +0100
@@ -27,6 +27,7 @@
 #include <asm/delay.h>
 #include <asm/io.h>
 #include <asm/smp.h>
+#include <asm/tlb.h>
 #include <asm/numa.h>
 #include <asm/bitops.h>
 #include <asm/hw_irq.h>
@@ -60,6 +61,13 @@
 }
 
 
+void
+sn_tlb_migrate_finish(struct mm_struct *mm)
+{
+	if (mm == current->mm)
+		flush_tlb_mm(mm);
+}
+
 
 /**
  * sn2_global_tlb_purge - globally purge translation cache of virtual address range
@@ -114,6 +122,13 @@
 		return;
 	}
 
+	if (atomic_read(&mm->mm_users) == 1) {
+		flush_tlb_mm(mm);
+		preempt_enable();
+		return;
+	}
+
+
 	nix = 0;
 	for (cnode=find_first_bit(&nodes_flushed, NR_NODES); cnode < NR_NODES; 
 			cnode=find_next_bit(&nodes_flushed, NR_NODES, ++cnode))
--- diff/arch/m68k/kernel/process.c	2004-06-11 19:17:24.000000000 +0100
+++ source/arch/m68k/kernel/process.c	2004-06-11 19:21:58.000000000 +0100
@@ -26,6 +26,7 @@
 #include <linux/a.out.h>
 #include <linux/reboot.h>
 #include <linux/init_task.h>
+#include <linux/mqueue.h>
 
 #include <asm/uaccess.h>
 #include <asm/system.h>
--- diff/arch/m68k/kernel/setup.c	2004-06-11 19:17:24.000000000 +0100
+++ source/arch/m68k/kernel/setup.c	2004-06-11 19:21:58.000000000 +0100
@@ -62,7 +62,6 @@
 static struct mem_info m68k_ramdisk;
 
 static char m68k_command_line[CL_SIZE];
-char saved_command_line[CL_SIZE];
 
 char m68k_debug_device[6] = "";
 
--- diff/arch/m68k/q40/config.c	2004-06-11 19:17:24.000000000 +0100
+++ source/arch/m68k/q40/config.c	2004-06-11 19:21:58.000000000 +0100
@@ -64,7 +64,6 @@
 
 extern void q40_mksound(unsigned int /*freq*/, unsigned int /*ticks*/ );
 
-extern char *saved_command_line;
 extern char m68k_debug_device[];
 static void q40_mem_console_write(struct console *co, const char *b,
 				    unsigned int count);
--- diff/arch/m68knommu/kernel/init_task.c	2004-05-19 22:11:07.000000000 +0100
+++ source/arch/m68knommu/kernel/init_task.c	2004-06-11 19:21:58.000000000 +0100
@@ -7,6 +7,7 @@
 #include <linux/init.h>
 #include <linux/init_task.h>
 #include <linux/fs.h>
+#include <linux/mqueue.h>
 
 #include <asm/uaccess.h>
 #include <asm/pgtable.h>
--- diff/arch/m68knommu/kernel/setup.c	2004-05-19 22:11:07.000000000 +0100
+++ source/arch/m68knommu/kernel/setup.c	2004-06-11 19:21:58.000000000 +0100
@@ -31,6 +31,7 @@
 #include <linux/bootmem.h>
 #include <linux/seq_file.h>
 #include <linux/root_dev.h>
+#include <linux/init.h>
 
 #include <asm/setup.h>
 #include <asm/irq.h>
@@ -44,8 +45,7 @@
 unsigned long memory_start;
 unsigned long memory_end;
 
-char command_line[512];
-char saved_command_line[512];
+char command_line[COMMAND_LINE_SIZE];
 
 /* setup some dummy routines */
 static void dummy_waitbut(void)
--- diff/arch/mips/kernel/init_task.c	2004-05-19 22:11:09.000000000 +0100
+++ source/arch/mips/kernel/init_task.c	2004-06-11 19:21:58.000000000 +0100
@@ -3,6 +3,7 @@
 #include <linux/sched.h>
 #include <linux/init_task.h>
 #include <linux/fs.h>
+#include <linux/mqueue.h>
 
 #include <asm/thread_info.h>
 #include <asm/uaccess.h>
--- diff/arch/mips/kernel/setup.c	2004-05-19 22:11:10.000000000 +0100
+++ source/arch/mips/kernel/setup.c	2004-06-11 19:21:58.000000000 +0100
@@ -71,7 +71,6 @@
 struct boot_mem_map boot_mem_map;
 
 static char command_line[CL_SIZE];
-       char saved_command_line[CL_SIZE];
        char arcs_cmdline[CL_SIZE]=CONFIG_CMDLINE;
 
 /*
--- diff/arch/parisc/kernel/init_task.c	2004-06-11 19:17:24.000000000 +0100
+++ source/arch/parisc/kernel/init_task.c	2004-06-11 19:21:58.000000000 +0100
@@ -27,6 +27,7 @@
 #include <linux/sched.h>
 #include <linux/init.h>
 #include <linux/init_task.h>
+#include <linux/mqueue.h>
 
 #include <asm/uaccess.h>
 #include <asm/pgtable.h>
--- diff/arch/parisc/kernel/setup.c	2004-06-11 19:17:24.000000000 +0100
+++ source/arch/parisc/kernel/setup.c	2004-06-11 19:21:58.000000000 +0100
@@ -45,8 +45,6 @@
 #include <asm/pdc_chassis.h>
 #include <asm/io.h>
 
-#define COMMAND_LINE_SIZE 1024
-char	saved_command_line[COMMAND_LINE_SIZE];
 char	command_line[COMMAND_LINE_SIZE];
 
 /* Intended for ccio/sba/cpu statistics under /proc/bus/{runway|gsc} */
--- diff/arch/ppc/8260_io/fcc_enet.c	2004-05-19 22:11:13.000000000 +0100
+++ source/arch/ppc/8260_io/fcc_enet.c	2004-06-11 19:21:59.000000000 +0100
@@ -158,12 +158,21 @@
 #define PA1_DIRA0	(PA1_RXDAT | PA1_CRS | PA1_COL | PA1_RXER | PA1_RXDV)
 #define PA1_DIRA1	(PA1_TXDAT | PA1_TXEN | PA1_TXER)
 
+#ifdef CONFIG_SBC82xx
+/* rx is clk9, tx is clk10
+ */
+#define PC_F1RXCLK     ((uint)0x00000100)
+#define PC_F1TXCLK     ((uint)0x00000200)
+#define CMX1_CLK_ROUTE ((uint)0x25000000)
+#define CMX1_CLK_MASK  ((uint)0xff000000)
+#else
 /* CLK12 is receive, CLK11 is transmit.  These are board specific.
 */
 #define PC_F1RXCLK	((uint)0x00000800)
 #define PC_F1TXCLK	((uint)0x00000400)
 #define CMX1_CLK_ROUTE	((uint)0x3e000000)
 #define CMX1_CLK_MASK	((uint)0xff000000)
+#endif /* !CONFIG_SBC82xx */
 
 /* I/O Pin assignment for FCC2.  I don't yet know the best way to do this,
  * but there is little variation among the choices.
@@ -288,6 +297,8 @@
 	ushort	skb_cur;
 	ushort	skb_dirty;
 
+	atomic_t n_pkts;  /* Number of packets in tx ring */
+
 	/* CPM dual port RAM relative addresses.
 	*/
 	cbd_t	*rx_bd_base;		/* Address of Rx and Tx buffers. */
@@ -347,6 +358,7 @@
 {
 	struct fcc_enet_private *cep = (struct fcc_enet_private *)dev->priv;
 	volatile cbd_t	*bdp;
+	int idx;
 
 	if (!cep->link) {
 		/* Link is down or autonegotiation is in progress. */
@@ -379,13 +391,24 @@
 	bdp->cbd_datlen = skb->len;
 	bdp->cbd_bufaddr = __pa(skb->data);
 
+	spin_lock_irq(&cep->lock);
+
 	/* Save skb pointer. */
-	cep->tx_skbuff[cep->skb_cur] = skb;
+	idx = cep->skb_cur & TX_RING_MOD_MASK;
+	if (cep->tx_skbuff[idx]) {
+		/* This should never happen (any more).
+		   Leave the sanity check in for now... */
+		printk(KERN_ERR "EEP. cep->tx_skbuff[%d] is %p not NULL in %s\n", 
+		       idx, cep->tx_skbuff[idx], __func__);
+		printk(KERN_ERR "Expect to lose %d bytes of sock space", 
+		       cep->tx_skbuff[idx]->truesize);
+	}
+	cep->tx_skbuff[idx] = skb;
 
 	cep->stats.tx_bytes += skb->len;
-	cep->skb_cur = (cep->skb_cur+1) & TX_RING_MOD_MASK;
+	cep->skb_cur++;
 
-	spin_lock_irq(&cep->lock);
+	atomic_inc(&cep->n_pkts);
 
 	/* Send it on its way.  Tell CPM its ready, interrupt when done,
 	 * its the last BD of the frame, and to put the CRC on the end.
@@ -404,9 +427,13 @@
 	else
 		bdp++;
 
-	if (bdp->cbd_sc & BD_ENET_TX_READY) {
-		netif_stop_queue(dev);
+
+	/* If the tx_ring is full, stop the queue */
+	if (atomic_read(&cep->n_pkts) >= (TX_RING_SIZE-1)) {
+	  if (!netif_queue_stopped(dev)) {
+		netif_stop_queue(dev);	  
 		cep->tx_full = 1;
+	  }
 	}
 
 	cep->cur_tx = (cbd_t *)bdp;
@@ -460,6 +487,7 @@
 	volatile cbd_t	*bdp;
 	ushort	int_events;
 	int	must_restart;
+	int idx;
 
 	cep = (struct fcc_enet_private *)dev->priv;
 
@@ -522,8 +550,12 @@
 			cep->stats.collisions++;
 
 		/* Free the sk buffer associated with this last transmit. */
-		dev_kfree_skb_irq(cep->tx_skbuff[cep->skb_dirty]);
-		cep->skb_dirty = (cep->skb_dirty + 1) & TX_RING_MOD_MASK;
+		idx = cep->skb_dirty & TX_RING_MOD_MASK;
+		dev_kfree_skb_irq(cep->tx_skbuff[idx]);
+		cep->tx_skbuff[idx] = NULL;
+		cep->skb_dirty++;
+
+		atomic_dec(&cep->n_pkts);
 
 		/* Update pointer to next buffer descriptor to be transmitted. */
 		if (bdp->cbd_sc & BD_ENET_TX_WRAP)
@@ -1594,11 +1626,21 @@
 	 */
 	eap = (unsigned char *)&(ep->fen_paddrh);
 	for (i=5; i>=0; i--) {
+#ifdef CONFIG_SBC82xx
+		if (i == 5) {
+			/* bd->bi_enetaddr holds the SCC0 address; the FCC
+			   devices count up from there */
+			dev->dev_addr[i] = bd->bi_enetaddr[i] & ~3;
+			dev->dev_addr[i] += 1 + fip->fc_fccnum;
+			*eap++ = dev->dev_addr[i];
+		}
+#else
 		if (i == 3) {
 			dev->dev_addr[i] = bd->bi_enetaddr[i];
 			dev->dev_addr[i] |= (1 << (7 - fip->fc_fccnum));
 			*eap++ = dev->dev_addr[i];
 		}
+#endif
 		else {
 			*eap++ = dev->dev_addr[i] = bd->bi_enetaddr[i];
 		}
@@ -1683,6 +1725,7 @@
 	while (cp->cp_cpcr & CPM_CR_FLG);
 
 	cep->skb_cur = cep->skb_dirty = 0;
+	atomic_set(&cep->n_pkts, 0);
 }
 
 /* Let 'er rip.
--- diff/arch/ppc/8260_io/uart.c	2004-06-11 19:17:24.000000000 +0100
+++ source/arch/ppc/8260_io/uart.c	2004-06-11 19:21:59.000000000 +0100
@@ -161,7 +161,7 @@
 #ifndef CONFIG_SCC1_ENET
 	{ 0,     0, PROFF_SCC1, SIU_INT_SCC1,   0, SCC_NUM_BASE},    /* SCC1 ttyS2 */
 #endif
-#ifndef CONFIG_SCC2_ENET
+#if !defined(CONFIG_SBC82xx) && !defined(CONFIG_SCC2_ENET)
 	{ 0,     0, PROFF_SCC2, SIU_INT_SCC2,   0, SCC_NUM_BASE + 1},    /* SCC2 ttyS3 */
 #endif
 };
@@ -475,7 +475,7 @@
 			if (break_pressed && info->line == sercons.index) {
 				if (ch != 0 && time_before(jiffies,
 							break_pressed + HZ*5)) {
-					handle_sysrq(ch, regs, NULL, NULL);
+					handle_sysrq(ch, regs, NULL);
 					break_pressed = 0;
 					goto ignore_char;
 				} else
--- diff/arch/ppc/Kconfig	2004-06-11 19:17:24.000000000 +0100
+++ source/arch/ppc/Kconfig	2004-06-11 19:21:59.000000000 +0100
@@ -72,8 +72,21 @@
 config 8xx
 	bool "8xx"
 
+config E500
+	bool "e500"
+
 endchoice
 
+config BOOKE
+	bool
+	depends on E500
+	default y
+
+config FSL_BOOKE
+	bool
+	depends on E500
+	default y
+
 config PTE_64BIT
 	bool
 	depends on 44x
@@ -96,6 +109,21 @@
 
 	  If in doubt, say Y here.
 
+config SPE
+	bool "SPE Support"
+	depends on E500
+	---help---
+	  This option enables kernel support for the Signal Processing
+	  Extensions (SPE) to the PowerPC processor. The kernel currently
+	  supports saving and restoring SPE registers, and turning on the
+	  'spe enable' bit so user processes can execute SPE instructions.
+
+	  This option is only usefully if you have a processor that supports
+	  SPE (e500, otherwise known as 85xx series), but does not have any
+	  affect on a non-spe cpu (it does, however add code to the kernel).
+
+	  If in doubt, say Y here.
+
 config TAU
 	bool "Thermal Management Support"
 	depends on 6xx && !8260
@@ -142,7 +170,7 @@
 
 config MATH_EMULATION
 	bool "Math emulation"
-	depends on 4xx || 8xx
+	depends on 4xx || 8xx || E500
 	---help---
 	  Some PowerPC chips designed for embedded applications do not have
 	  a floating-point unit and therefore do not implement the
@@ -198,6 +226,7 @@
 	  If in doubt, say Y here.
 
 source arch/ppc/platforms/4xx/Kconfig
+source arch/ppc/platforms/85xx/Kconfig
 
 config PPC64BRIDGE
 	bool
@@ -214,6 +243,8 @@
 	depends on 4xx || 8xx
 	default y
 
+source "drivers/perfctr/Kconfig"
+
 endmenu
 
 menu "Platform options"
@@ -542,6 +573,15 @@
 	  <http://www.windriver.com/>, but the EST8260 cannot be found on it
 	  and has probably been discontinued or rebadged.
 
+config SBC82xx
+	bool "SBC82xx"
+	---help---
+	  SBC PowerQUICC II, single-board computer with MPC82xx CPU
+	  Manufacturer: Wind River Systems, Inc.
+	  Date of Release: May 2003
+	  End of Life: -
+	  URL: <http://www.windriver.com/>
+
 config SBS8260
 	bool "SBS8260"
 
@@ -575,7 +615,7 @@
 config 8260
 	bool "MPC8260 CPM Support" if WILLOW
 	depends on 6xx
-	default y if TQM8260 || RPXSUPER || EST8260 || SBS8260
+	default y if TQM8260 || RPXSUPER || EST8260 || SBS8260 || SBC82xx
 	help
 	  The MPC8260 CPM (Communications Processor Module) is a typical
 	  embedded CPU made by Motorola.  Selecting this option means that
@@ -965,8 +1005,8 @@
 	bool
 
 config PCI
-	bool "PCI support" if 40x || 8260
-	default y if !40x && !8260 && !8xx && !APUS
+	bool "PCI support" if 40x || 8260 || 85xx
+	default y if !40x && !8260 && !8xx && !APUS && !85xx
 	default PCI_PERMEDIA if !4xx && !8260 && !8xx && APUS
 	default PCI_QSPAN if !4xx && !8260 && 8xx
 	help
@@ -1251,6 +1291,19 @@
 	  debug the kernel.
 	  If you don't debug the kernel, you can say N.
 
+config SCHEDSTATS
+	bool "Collect scheduler statistics"
+	depends on PROC_FS
+	default n
+	help
+	  If you say Y here, additional code will be inserted into the
+	  scheduler and related routines to collect statistics about
+	  scheduler behavior and provide them in /proc/schedstat.  These
+	  stats may be useful for both tuning and debugging the scheduler
+	  If you aren't debugging the scheduler or trying to tune a specific
+	  application, you can say N to avoid the very slight overhead
+	  this adds.
+
 config BOOTX_TEXT
 	bool "Support for early boot text console (BootX or OpenFirmware only)"
 	depends PPC_OF
@@ -1264,7 +1317,7 @@
 
 config PPC_OCP
 	bool
-	depends on IBM_OCP
+	depends on IBM_OCP || FSL_OCP
 	default y
 
 endmenu
--- diff/arch/ppc/Makefile	2004-06-11 19:17:24.000000000 +0100
+++ source/arch/ppc/Makefile	2004-06-11 19:21:59.000000000 +0100
@@ -17,19 +17,24 @@
 CPPFLAGS	+= -Iarch/$(ARCH)
 AFLAGS		+= -Iarch/$(ARCH)
 cflags-y	+= -Iarch/$(ARCH) -msoft-float -pipe \
-		-ffixed-r2 -Wno-uninitialized -mmultiple -mstring
+		-ffixed-r2 -Wno-uninitialized -mmultiple
 CPP		= $(CC) -E $(CFLAGS)
 
+ifndef CONFIG_E500
+cflags-y	+= -mstring
+endif
+
 cflags-$(CONFIG_4xx)		+= -Wa,-m405
+cflags-$(CONFIG_E500)		+= -Wa,-me500
 cflags-$(CONFIG_PPC64BRIDGE)	+= -Wa,-mppc64bridge
 
 CFLAGS += $(cflags-y)
 
-
 head-y				:= arch/ppc/kernel/head.o
 head-$(CONFIG_8xx)		:= arch/ppc/kernel/head_8xx.o
 head-$(CONFIG_4xx)		:= arch/ppc/kernel/head_4xx.o
 head-$(CONFIG_44x)		:= arch/ppc/kernel/head_44x.o
+head-$(CONFIG_E500)		:= arch/ppc/kernel/head_e500.o
 
 head-$(CONFIG_6xx)		+= arch/ppc/kernel/idle_6xx.o
 head-$(CONFIG_POWER4)		+= arch/ppc/kernel/idle_power4.o
@@ -37,6 +42,7 @@
 core-y				+= arch/ppc/kernel/ arch/ppc/platforms/ \
 				   arch/ppc/mm/ arch/ppc/lib/ arch/ppc/syslib/
 core-$(CONFIG_4xx)		+= arch/ppc/platforms/4xx/
+core-$(CONFIG_85xx)		+= arch/ppc/platforms/85xx/
 core-$(CONFIG_MATH_EMULATION)	+= arch/ppc/math-emu/
 core-$(CONFIG_XMON)		+= arch/ppc/xmon/
 core-$(CONFIG_APUS)		+= arch/ppc/amiga/
@@ -86,7 +92,7 @@
 
 ifdef CONFIG_6xx
 # Ensure this is binutils 2.12.1 (or 2.12.90.0.7) or later
-NEW_AS	:= $(shell echo dssall | $(AS) -o /dev/null >/dev/null 2>&1 ; echo $$?)
+NEW_AS	:= $(shell echo dssall | $(AS) -many -o /dev/null >/dev/null 2>&1 ; echo $$?)
 GOODVER	:= 2.12.1
 else
 NEW_AS	:= 0
@@ -94,7 +100,7 @@
 
 ifneq ($(NEW_AS),0)
 checkbin:
-	@echo -n '*** ${VERSION}.${PATCHLEVEL} kernels no longer build'
+	@echo -n '*** ${VERSION}.${PATCHLEVEL} kernels no longer build '
 	@echo 'correctly with old versions of binutils.'
 	@echo '*** Please upgrade your binutils to ${GOODVER} or newer'
 	@false
--- diff/arch/ppc/boot/simple/embed_config.c	2004-06-11 19:17:24.000000000 +0100
+++ source/arch/ppc/boot/simple/embed_config.c	2004-06-11 19:21:59.000000000 +0100
@@ -10,6 +10,7 @@
 #include <linux/types.h>
 #include <linux/config.h>
 #include <linux/string.h>
+#include <asm/reg.h>
 #ifdef CONFIG_8xx
 #include <asm/mpc8xx.h>
 #endif
@@ -402,14 +403,18 @@
 
 #ifdef CONFIG_8260
 /* Compute 8260 clock values if the rom doesn't provide them.
- * We can't compute the internal core frequency (I don't know how to
- * do that).
  */
+static unsigned char bus2core_8260[] = {
+/*      0   1   2   3   4   5   6   7   8   9   a   b   c   d   e   f */
+	3,  2,  2,  2,  4,  4,  5,  9,  6, 11,  8, 10,  3, 12,  7,  2,
+	6,  5, 13,  2, 14,  4, 15,  2,  3, 11,  8, 10, 16, 12,  7,  2,
+};
+
 static void
 clk_8260(bd_t *bd)
 {
 	uint	scmr, vco_out, clkin;
-	uint	plldf, pllmf, busdf, brgdf, cpmdf;
+	uint	plldf, pllmf, corecnf;
 	volatile immap_t	*ip;
 
 	ip = (immap_t *)IMAP_ADDR;
@@ -423,8 +428,7 @@
 	*/
 	plldf = (scmr >> 12) & 1;
 	pllmf = scmr & 0xfff;
-	cpmdf = (scmr >> 16) & 0x0f;
-	busdf = (scmr >> 20) & 0x0f;
+	corecnf = (scmr >> 24) &0x1f;
 
 	/* This is arithmetic from the 8260 manual.
 	*/
@@ -433,6 +437,7 @@
 	bd->bi_vco = vco_out;		/* Save for later */
 
 	bd->bi_cpmfreq = vco_out / 2;	/* CPM Freq, in MHz */
+	bd->bi_intfreq = bd->bi_busfreq * bus2core_8260[corecnf] / 2;
 
 	/* Set Baud rate divisor.  The power up default is divide by 16,
 	 * but we set it again here in case it was changed.
@@ -440,8 +445,79 @@
 	ip->im_clkrst.car_sccr = 1;	/* DIV 16 BRG */
 	bd->bi_brgfreq = vco_out / 16;
 }
+
+static unsigned char bus2core_8280[] = {
+/*      0   1   2   3   4   5   6   7   8   9   a   b   c   d   e   f */
+	3,  2,  2,  2,  4,  4,  5,  9,  6, 11,  8, 10,  3, 12,  7,  2,
+	6,  5, 13,  2, 14,  2, 15,  2,  3,  2,  2,  2, 16,  2,  2,  2,
+};
+
+static void
+clk_8280(bd_t *bd)
+{
+	uint	scmr, main_clk, clkin;
+	uint	pllmf, corecnf;
+	volatile immap_t	*ip;
+
+	ip = (immap_t *)IMAP_ADDR;
+	scmr = ip->im_clkrst.car_scmr;
+
+	/* The clkin is always bus frequency.
+	*/
+	clkin = bd->bi_busfreq;
+
+	/* Collect the bits from the scmr.
+	*/
+	pllmf = scmr & 0xf;
+	corecnf = (scmr >> 24) & 0x1f;
+
+	/* This is arithmetic from the 8280 manual.
+	*/
+	main_clk = clkin * (pllmf + 1);
+
+	bd->bi_cpmfreq = main_clk / 2;	/* CPM Freq, in MHz */
+	bd->bi_intfreq = bd->bi_busfreq * bus2core_8280[corecnf] / 2;
+
+	/* Set Baud rate divisor.  The power up default is divide by 16,
+	 * but we set it again here in case it was changed.
+	 */
+	ip->im_clkrst.car_sccr = (ip->im_clkrst.car_sccr & 0x3) | 0x1;
+	bd->bi_brgfreq = main_clk / 16;
+}
 #endif
 
+#ifdef CONFIG_SBC82xx
+void
+embed_config(bd_t **bdp)
+{
+	u_char	*cp;
+	int	i;
+	bd_t	*bd;
+	unsigned long pvr;
+
+	bd = *bdp;
+
+	bd = &bdinfo;
+	*bdp = bd;
+	bd->bi_baudrate = 9600;
+	bd->bi_memsize = 256 * 1024 * 1024;	/* just a guess */
+
+	cp = (void*)SBC82xx_MACADDR_NVRAM_SCC1;
+	memcpy(bd->bi_enetaddr, cp, 6);
+
+	/* can busfreq be calculated? */
+	pvr = mfspr(PVR);
+	if ((pvr & 0xffff0000) == 0x80820000) {
+		bd->bi_busfreq = 100000000;
+		clk_8280(bd);
+	} else {
+		bd->bi_busfreq = 66000000;
+		clk_8260(bd);
+	}
+
+}
+#endif /* SBC82xx */
+
 #if defined(CONFIG_EST8260) || defined(CONFIG_TQM8260)
 void
 embed_config(bd_t **bdp)
--- diff/arch/ppc/kernel/Makefile	2004-06-11 19:17:24.000000000 +0100
+++ source/arch/ppc/kernel/Makefile	2004-06-11 19:21:59.000000000 +0100
@@ -8,10 +8,14 @@
 ifdef CONFIG_4xx
 EXTRA_AFLAGS		:= -Wa,-m405
 endif
+ifdef CONFIG_E500
+EXTRA_AFLAGS		:= -Wa,-me500
+endif
 
 extra-$(CONFIG_PPC_STD_MMU)	:= head.o
 extra-$(CONFIG_40x)		:= head_4xx.o
 extra-$(CONFIG_44x)		:= head_44x.o
+extra-$(CONFIG_E500)		:= head_e500.o
 extra-$(CONFIG_8xx)		:= head_8xx.o
 extra-$(CONFIG_6xx)		+= idle_6xx.o
 extra-$(CONFIG_POWER4)		+= idle_power4.o
--- diff/arch/ppc/kernel/align.c	2004-05-19 22:11:15.000000000 +0100
+++ source/arch/ppc/kernel/align.c	2004-06-11 19:21:59.000000000 +0100
@@ -21,7 +21,7 @@
 	unsigned char flags;
 };
 
-#if defined(CONFIG_4xx) || defined(CONFIG_POWER4)
+#if defined(CONFIG_4xx) || defined(CONFIG_POWER4) || defined(CONFIG_BOOKE)
 #define	OPCD(inst)	(((inst) & 0xFC000000) >> 26)
 #define	RS(inst)	(((inst) & 0x03E00000) >> 21)
 #define	RA(inst)	(((inst) & 0x001F0000) >> 16)
@@ -184,7 +184,7 @@
 fix_alignment(struct pt_regs *regs)
 {
 	int instr, nb, flags;
-#if defined(CONFIG_4xx) || defined(CONFIG_POWER4)
+#if defined(CONFIG_4xx) || defined(CONFIG_POWER4) || defined(CONFIG_BOOKE)
 	int opcode, f1, f2, f3;
 #endif
 	int i, t;
@@ -199,8 +199,8 @@
 
 	CHECK_FULL_REGS(regs);
 
-#if defined(CONFIG_4xx) || defined(CONFIG_POWER4)
-	/* The 4xx-family processors have no DSISR register,
+#if defined(CONFIG_4xx) || defined(CONFIG_POWER4) || defined(CONFIG_BOOKE)
+	/* The 4xx-family & Book-E processors have no DSISR register,
 	 * so we emulate it.
 	 * The POWER4 has a DSISR register but doesn't set it on
 	 * an alignment fault.  -- paulus
@@ -250,7 +250,7 @@
 
 	flags = aligninfo[instr].flags;
 
-	/* For the 4xx-family processors, the 'dar' field of the
+	/* For the 4xx-family & Book-E processors, the 'dar' field of the
 	 * pt_regs structure is overloaded and is really from the DEAR.
 	 */
 
--- diff/arch/ppc/kernel/asm-offsets.c	2004-05-19 22:11:15.000000000 +0100
+++ source/arch/ppc/kernel/asm-offsets.c	2004-06-11 19:21:59.000000000 +0100
@@ -44,7 +44,7 @@
 	DEFINE(THREAD_FPEXC_MODE, offsetof(struct thread_struct, fpexc_mode));
 	DEFINE(THREAD_FPR0, offsetof(struct thread_struct, fpr[0]));
 	DEFINE(THREAD_FPSCR, offsetof(struct thread_struct, fpscr));
-#ifdef CONFIG_4xx
+#if defined(CONFIG_4xx) || defined(CONFIG_BOOKE)
 	DEFINE(THREAD_DBCR0, offsetof(struct thread_struct, dbcr0));
 	DEFINE(PT_PTRACED, PT_PTRACED);
 #endif
@@ -54,6 +54,12 @@
 	DEFINE(THREAD_VSCR, offsetof(struct thread_struct, vscr));
 	DEFINE(THREAD_USED_VR, offsetof(struct thread_struct, used_vr));
 #endif /* CONFIG_ALTIVEC */
+#ifdef CONFIG_SPE
+	DEFINE(THREAD_EVR0, offsetof(struct thread_struct, evr[0]));
+	DEFINE(THREAD_ACC, offsetof(struct thread_struct, acc));
+	DEFINE(THREAD_SPEFSCR, offsetof(struct thread_struct, spefscr));
+	DEFINE(THREAD_USED_SPE, offsetof(struct thread_struct, used_spe));
+#endif /* CONFIG_SPE */
 	/* Interrupt register frame */
 	DEFINE(STACK_FRAME_OVERHEAD, STACK_FRAME_OVERHEAD);
 	DEFINE(INT_FRAME_SIZE, STACK_FRAME_OVERHEAD + sizeof(struct pt_regs));
--- diff/arch/ppc/kernel/cputable.c	2004-06-11 19:17:24.000000000 +0100
+++ source/arch/ppc/kernel/cputable.c	2004-06-11 19:21:59.000000000 +0100
@@ -34,7 +34,8 @@
 extern void __setup_cpu_generic(unsigned long offset, int cpu_nr, struct cpu_spec* spec);
 
 #define CLASSIC_PPC (!defined(CONFIG_8xx) && !defined(CONFIG_4xx) && \
-		     !defined(CONFIG_POWER3) && !defined(CONFIG_POWER4))
+		     !defined(CONFIG_POWER3) && !defined(CONFIG_POWER4) && \
+		     !defined(CONFIG_BOOKE))
 
 /* This table only contains "desktop" CPUs, it need to be filled with embedded
  * ones as well...
@@ -350,6 +351,14 @@
 	32, 32,
 	__setup_cpu_603
     },
+    {	/* 8280 is a G2_LE (603e core, plus some) */
+	0x7fff0000, 0x00820000, "8280",
+	CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_CAN_DOZE | CPU_FTR_USE_TB |
+	CPU_FTR_CAN_NAP | CPU_FTR_HAS_HIGH_BATS,
+	COMMON_PPC,
+	32, 32,
+	__setup_cpu_603
+    },
     {	/* default match, we assume split I/D cache & TB (non-601)... */
     	0x00000000, 0x00000000, "(generic PPC)",
 	CPU_FTR_COMMON |
@@ -553,6 +562,16 @@
         0, /*__setup_cpu_440 */
     },
 #endif /* CONFIG_44x */
+#ifdef CONFIG_E500
+    { /* e500 */
+        0xffff0000, 0x80200000, "e500",
+	/* xxx - galak: add CPU_FTR_CAN_DOZE */
+        CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_USE_TB,
+        PPC_FEATURE_32 | PPC_FEATURE_HAS_MMU,
+        32, 32,
+        0, /*__setup_cpu_e500 */
+    },
+#endif
 #if !CLASSIC_PPC
     {	/* default match */
     	0x00000000, 0x00000000, "(generic PPC)",
--- diff/arch/ppc/kernel/entry.S	2004-06-11 19:17:24.000000000 +0100
+++ source/arch/ppc/kernel/entry.S	2004-06-11 19:21:59.000000000 +0100
@@ -36,7 +36,7 @@
 #undef SHOW_SYSCALLS_TASK
 
 /*
- * MSR_KERNEL is > 0x10000 on 4xx since it include MSR_CE.
+ * MSR_KERNEL is > 0x10000 on 4xx/Book-E since it include MSR_CE.
  */
 #if MSR_KERNEL >= 0x10000
 #define LOAD_MSR_KERNEL(r, x)	lis r,(x)@h; ori r,r,(x)@l
@@ -45,7 +45,7 @@
 #endif
 
 #ifdef CONFIG_BOOKE
-#define	COR	r8
+#define	COR	r8	/* Critical Offset Register (COR) */
 #define BOOKE_LOAD_COR	lis COR,crit_save@ha
 #define BOOKE_REST_COR	mfspr COR,SPRG2
 #define BOOKE_SAVE_COR	mtspr SPRG2,COR
@@ -241,11 +241,11 @@
 	andi.	r0,r9,(_TIF_SYSCALL_TRACE|_TIF_SIGPENDING|_TIF_NEED_RESCHED)
 	bne-	syscall_exit_work
 syscall_exit_cont:
-#ifdef CONFIG_4xx
+#if defined(CONFIG_4xx) || defined(CONFIG_BOOKE)
 	/* If the process has its own DBCR0 value, load it up */
 	lwz	r0,PTRACE(r2)
 	andi.	r0,r0,PT_PTRACED
-	bnel-	load_4xx_dbcr0
+	bnel-	load_dbcr0
 #endif
 	stwcx.	r0,0,r1			/* to clear the reservation */
 	lwz	r4,_LINK(r1)
@@ -510,7 +510,12 @@
 	stw	r12,THREAD+THREAD_VRSAVE(r2)
 END_FTR_SECTION_IFSET(CPU_FTR_ALTIVEC)
 #endif /* CONFIG_ALTIVEC */
-	and.	r0,r0,r11	/* FP or altivec enabled? */
+#ifdef CONFIG_SPE
+	oris	r0,r0,MSR_SPE@h	 /* Disable SPE */
+	mfspr	r12,SPRN_SPEFSCR /* save spefscr register value */
+	stw	r12,THREAD+THREAD_SPEFSCR(r2)
+#endif /* CONFIG_SPE */
+	and.	r0,r0,r11	/* FP or altivec or SPE enabled? */
 	beq+	1f
 	andc	r11,r11,r0
 	MTMSRD(r11)
@@ -543,6 +548,10 @@
 	mtspr	SPRN_VRSAVE,r0		/* if G4, restore VRSAVE reg */
 END_FTR_SECTION_IFSET(CPU_FTR_ALTIVEC)
 #endif /* CONFIG_ALTIVEC */
+#ifdef CONFIG_SPE
+	lwz	r0,THREAD+THREAD_SPEFSCR(r2)
+	mtspr	SPRN_SPEFSCR,r0		/* restore SPEFSCR reg */
+#endif /* CONFIG_SPE */
 
 	lwz	r0,_CCR(r1)
 	mtcrf	0xFF,r0
@@ -589,11 +598,11 @@
 	bne	do_work
 
 restore_user:
-#ifdef CONFIG_4xx
+#if defined(CONFIG_4xx) || defined(CONFIG_BOOKE)
 	/* Check whether this process has its own DBCR0 value */
 	lwz	r0,PTRACE(r2)
 	andi.	r0,r0,PT_PTRACED
-	bnel-	load_4xx_dbcr0
+	bnel-	load_dbcr0
 #endif
 
 #ifdef CONFIG_PREEMPT
@@ -645,7 +654,7 @@
 	PPC405_ERR77(0,r1)
 	stwcx.	r0,0,r1			/* to clear the reservation */
 
-#ifndef CONFIG_4xx
+#if !(defined(CONFIG_4xx) || defined(CONFIG_BOOKE))
 	lwz	r9,_MSR(r1)
 	andi.	r10,r9,MSR_RI		/* check if this exception occurred */
 	beql	nonrecoverable		/* at a bad place (MSR:RI = 0) */
@@ -681,9 +690,9 @@
 	SYNC
 	RFI
 
-#else /* CONFIG_4xx */
+#else /* !(CONFIG_4xx || CONFIG_BOOKE) */
 	/*
-	 * This is a bit different on 4xx because 4xx doesn't have
+	 * This is a bit different on 4xx/Book-E because it doesn't have
 	 * the RI bit in the MSR.
 	 * The TLB miss handler checks if we have interrupted
 	 * the exception exit path and restarts it if so
@@ -720,6 +729,9 @@
  * give the wrong answer).
  * We have to restore various SPRs that may have been in use at the
  * time of the critical interrupt.
+ *
+ * Note that SPRG6 is used for machine check on CONFIG_BOOKE parts and
+ * thus not saved in the critical handler
  */
 	.globl	ret_from_crit_exc
 ret_from_crit_exc:
@@ -866,7 +878,7 @@
  * Load the DBCR0 value for a task that is being ptraced,
  * having first saved away the global DBCR0.
  */
-load_4xx_dbcr0:
+load_dbcr0:
 	mfmsr	r0		/* first disable debug exceptions */
 	rlwinm	r0,r0,0,~MSR_DE
 	mtmsr	r0
@@ -885,7 +897,7 @@
 	blr
 
 	.comm	global_dbcr0,8
-#endif /* CONFIG_4xx */
+#endif /* !(CONFIG_4xx || CONFIG_BOOKE) */
 
 do_work:			/* r10 contains MSR_KERNEL here */
 	andi.	r0,r9,_TIF_NEED_RESCHED
--- diff/arch/ppc/kernel/misc.S	2004-06-11 19:17:24.000000000 +0100
+++ source/arch/ppc/kernel/misc.S	2004-06-11 19:21:59.000000000 +0100
@@ -419,7 +419,24 @@
 	ble	1b
 
 	isync
-#else /* !(CONFIG_40x || CONFIG_44x) */
+#elif defined(CONFIG_FSL_BOOKE)
+	/* Invalidate all entries in TLB0 */
+	li	r3, 0x04
+	tlbivax	0,3
+	/* Invalidate all entries in TLB1 */
+	li	r3, 0x0c
+	tlbivax	0,3
+	/* Invalidate all entries in TLB2 */
+	li	r3, 0x14
+	tlbivax	0,3
+	/* Invalidate all entries in TLB3 */
+	li	r3, 0x1c
+	tlbivax	0,3
+	msync
+#ifdef CONFIG_SMP
+	tlbsync
+#endif /* CONFIG_SMP */
+#else /* !(CONFIG_40x || CONFIG_44x || CONFIG_FSL_BOOKE) */
 #if defined(CONFIG_SMP)
 	rlwinm	r8,r1,0,0,18
 	lwz	r8,TI_CPU(r8)
@@ -487,7 +504,20 @@
 	tlbwe	r3, r3, PPC44x_TLB_PAGEID
 	isync
 10:
-#else /* !(CONFIG_40x || CONFIG_44x) */
+#elif defined(CONFIG_FSL_BOOKE)
+	rlwinm	r4, r3, 0, 0, 19
+	ori	r5, r4, 0x08	/* TLBSEL = 1 */
+	ori	r6, r4, 0x10	/* TLBSEL = 2 */
+	ori	r7, r4, 0x18	/* TLBSEL = 3 */
+	tlbivax	0, r4
+	tlbivax	0, r5
+	tlbivax	0, r6
+	tlbivax	0, r7
+	msync
+#if defined(CONFIG_SMP)
+	tlbsync
+#endif /* CONFIG_SMP */
+#else /* !(CONFIG_40x || CONFIG_44x || CONFIG_FSL_BOOKE) */
 #if defined(CONFIG_SMP)
 	rlwinm	r8,r1,0,0,18
 	lwz	r8,TI_CPU(r8)
@@ -544,6 +574,10 @@
 	lis	r3, KERNELBASE@h
 	iccci	0,r3
 #endif
+#elif CONFIG_FSL_BOOKE
+	mfspr	r3,SPRN_L1CSR1
+	ori	r3,r3,L1CSR1_ICFI|L1CSR1_ICLFR
+	mtspr	SPRN_L1CSR1,r3
 #else
 	mfspr	r3,PVR
 	rlwinm	r3,r3,16,16,31
@@ -1047,7 +1081,7 @@
  * and exceptions as if the cpu had performed the load or store.
  */
 
-#if defined(CONFIG_4xx)
+#if defined(CONFIG_4xx) || defined(CONFIG_E500)
 _GLOBAL(cvt_fd)
 	lfs	0,0(r3)
 	stfd	0,0(r4)
@@ -1398,3 +1432,9 @@
 	.long sys_mq_notify
 	.long sys_mq_getsetattr
 	.long sys_ni_syscall		/* 268 reserved for sys_kexec_load */
+	.long sys_perfctr_info
+	.long sys_vperfctr_open		/* 270 */
+	.long sys_vperfctr_control
+	.long sys_vperfctr_unlink
+	.long sys_vperfctr_iresume
+	.long sys_vperfctr_read
--- diff/arch/ppc/kernel/ppc_ksyms.c	2004-06-11 19:17:24.000000000 +0100
+++ source/arch/ppc/kernel/ppc_ksyms.c	2004-06-11 19:21:59.000000000 +0100
@@ -199,6 +199,10 @@
 EXPORT_SYMBOL(last_task_used_altivec);
 EXPORT_SYMBOL(giveup_altivec);
 #endif /* CONFIG_ALTIVEC */
+#ifdef CONFIG_SPE
+EXPORT_SYMBOL(last_task_used_spe);
+EXPORT_SYMBOL(giveup_spe);
+#endif /* CONFIG_SPE */
 #ifdef CONFIG_SMP
 EXPORT_SYMBOL(smp_call_function);
 EXPORT_SYMBOL(smp_hw_index);
@@ -324,7 +328,7 @@
 EXPORT_SYMBOL(cpm_install_handler);
 EXPORT_SYMBOL(cpm_free_handler);
 #endif /* CONFIG_8xx */
-#if defined(CONFIG_8xx) || defined(CONFIG_40x)
+#if defined(CONFIG_8xx) || defined(CONFIG_40x) || defined(CONFIG_85xx)
 EXPORT_SYMBOL(__res);
 #endif
 #if defined(CONFIG_8xx)
--- diff/arch/ppc/kernel/process.c	2004-06-11 19:17:24.000000000 +0100
+++ source/arch/ppc/kernel/process.c	2004-06-11 19:21:59.000000000 +0100
@@ -35,6 +35,8 @@
 #include <linux/init_task.h>
 #include <linux/module.h>
 #include <linux/kallsyms.h>
+#include <linux/perfctr.h>
+#include <linux/mqueue.h>
 
 #include <asm/pgtable.h>
 #include <asm/uaccess.h>
@@ -49,6 +51,7 @@
 
 struct task_struct *last_task_used_math = NULL;
 struct task_struct *last_task_used_altivec = NULL;
+struct task_struct *last_task_used_spe = NULL;
 
 static struct fs_struct init_fs = INIT_FS;
 static struct files_struct init_files = INIT_FILES;
@@ -177,6 +180,34 @@
 EXPORT_SYMBOL(enable_kernel_altivec);
 #endif /* CONFIG_ALTIVEC */
 
+#ifdef CONFIG_SPE
+int
+dump_spe(struct pt_regs *regs, elf_vrregset_t *evrregs)
+{
+	if (regs->msr & MSR_SPE)
+		giveup_spe(current);
+	/* We copy u32 evr[32] + u64 acc + u32 spefscr -> 35 */
+	memcpy(evrregs, &current->thread.evr[0], sizeof(u32) * 35);
+	return 1;
+}
+
+void
+enable_kernel_spe(void)
+{
+	WARN_ON(preemptible());
+
+#ifdef CONFIG_SMP
+	if (current->thread.regs && (current->thread.regs->msr & MSR_SPE))
+		giveup_spe(current);
+	else
+		giveup_spe(NULL);	/* just enable SPE for kernel - force */
+#else
+	giveup_spe(last_task_used_spe);
+#endif /* __SMP __ */
+}
+EXPORT_SYMBOL(enable_kernel_spe);
+#endif /* CONFIG_SPE */
+
 void
 enable_kernel_fp(void)
 {
@@ -244,6 +275,17 @@
 	if ((prev->thread.regs && (prev->thread.regs->msr & MSR_VEC)))
 		giveup_altivec(prev);
 #endif /* CONFIG_ALTIVEC */
+#ifdef CONFIG_SPE
+	/*
+	 * If the previous thread used spe in the last quantum
+	 * (thus changing spe regs) then save them.
+	 *
+	 * On SMP we always save/restore spe regs just to avoid the
+	 * complexity of changing processors.
+	 */
+	if ((prev->thread.regs && (prev->thread.regs->msr & MSR_SPE)))
+		giveup_spe(prev);
+#endif /* CONFIG_SPE */
 #endif /* CONFIG_SMP */
 
 	/* Avoid the trap.  On smp this this never happens since
@@ -251,9 +293,18 @@
 	 */
 	if (new->thread.regs && last_task_used_altivec == new)
 		new->thread.regs->msr |= MSR_VEC;
+#ifdef CONFIG_SPE
+	/* Avoid the trap.  On smp this this never happens since
+	 * we don't set last_task_used_spe
+	 */
+	if (new->thread.regs && last_task_used_spe == new)
+		new->thread.regs->msr |= MSR_SPE;
+#endif /* CONFIG_SPE */
 	new_thread = &new->thread;
 	old_thread = &current->thread;
+	perfctr_suspend_thread(&prev->thread);
 	last = _switch(old_thread, new_thread);
+	perfctr_resume_thread(&current->thread);
 	local_irq_restore(s);
 	return last;
 }
@@ -322,6 +373,7 @@
 		last_task_used_math = NULL;
 	if (last_task_used_altivec == current)
 		last_task_used_altivec = NULL;
+	perfctr_exit_thread(&current->thread);
 }
 
 void flush_thread(void)
@@ -354,6 +406,10 @@
 	if (regs->msr & MSR_VEC)
 		giveup_altivec(current);
 #endif /* CONFIG_ALTIVEC */
+#ifdef CONFIG_SPE
+	if (regs->msr & MSR_SPE)
+		giveup_spe(current);
+#endif /* CONFIG_SPE */
 	preempt_enable();
 }
 
@@ -408,6 +464,8 @@
 
 	p->thread.last_syscall = -1;
 
+	perfctr_copy_thread(&p->thread);
+
 	return 0;
 }
 
@@ -438,18 +496,45 @@
 	current->thread.vrsave = 0;
 	current->thread.used_vr = 0;
 #endif /* CONFIG_ALTIVEC */
+#ifdef CONFIG_SPE
+	memset(current->thread.evr, 0, sizeof(current->thread.evr));
+	current->thread.acc = 0;
+	current->thread.spefscr = 0;
+	current->thread.used_spe = 0;
+#endif /* CONFIG_SPE */
 }
 
+#define PR_FP_ALL_EXCEPT (PR_FP_EXC_DIV | PR_FP_EXC_OVF | PR_FP_EXC_UND \
+		| PR_FP_EXC_RES | PR_FP_EXC_INV)
+
 int set_fpexc_mode(struct task_struct *tsk, unsigned int val)
 {
 	struct pt_regs *regs = tsk->thread.regs;
 
-	if (val > PR_FP_EXC_PRECISE)
+	/* This is a bit hairy.  If we are an SPE enabled  processor
+	 * (have embedded fp) we store the IEEE exception enable flags in
+	 * fpexc_mode.  fpexc_mode is also used for setting FP exception
+	 * mode (asyn, precise, disabled) for 'Classic' FP. */
+	if (val & PR_FP_EXC_SW_ENABLE) {
+#ifdef CONFIG_SPE
+		tsk->thread.fpexc_mode = val &
+			(PR_FP_EXC_SW_ENABLE | PR_FP_ALL_EXCEPT);
+#else
 		return -EINVAL;
-	tsk->thread.fpexc_mode = __pack_fe01(val);
-	if (regs != NULL && (regs->msr & MSR_FP) != 0)
-		regs->msr = (regs->msr & ~(MSR_FE0|MSR_FE1))
-			| tsk->thread.fpexc_mode;
+#endif
+	} else {
+		/* on a CONFIG_SPE this does not hurt us.  The bits that
+		 * __pack_fe01 use do not overlap with bits used for
+		 * PR_FP_EXC_SW_ENABLE.  Additionally, the MSR[FE0,FE1] bits
+		 * on CONFIG_SPE implementations are reserved so writing to
+		 * them does not change anything */
+		if (val > PR_FP_EXC_PRECISE)
+			return -EINVAL;
+		tsk->thread.fpexc_mode = __pack_fe01(val);
+		if (regs != NULL && (regs->msr & MSR_FP) != 0)
+			regs->msr = (regs->msr & ~(MSR_FE0|MSR_FE1))
+				| tsk->thread.fpexc_mode;
+	}
 	return 0;
 }
 
@@ -457,7 +542,14 @@
 {
 	unsigned int val;
 
-	val = __unpack_fe01(tsk->thread.fpexc_mode);
+	if (tsk->thread.fpexc_mode & PR_FP_EXC_SW_ENABLE)
+#ifdef CONFIG_SPE
+		val = tsk->thread.fpexc_mode;
+#else
+		return -EINVAL;
+#endif
+	else
+		val = __unpack_fe01(tsk->thread.fpexc_mode);
 	return put_user(val, (unsigned int *) adr);
 }
 
@@ -506,6 +598,10 @@
 	if (regs->msr & MSR_VEC)
 		giveup_altivec(current);
 #endif /* CONFIG_ALTIVEC */
+#ifdef CONFIG_SPE
+	if (regs->msr & MSR_SPE)
+		giveup_spe(current);
+#endif /* CONFIG_SPE */
 	preempt_enable();
 	error = do_execve(filename, (char __user *__user *) a1,
 			  (char __user *__user *) a2, regs);
--- diff/arch/ppc/kernel/ptrace.c	2004-05-19 22:11:15.000000000 +0100
+++ source/arch/ppc/kernel/ptrace.c	2004-06-11 19:21:59.000000000 +0100
@@ -35,7 +35,7 @@
 /*
  * Set of msr bits that gdb can change on behalf of a process.
  */
-#ifdef CONFIG_4xx
+#if defined(CONFIG_4xx) || defined(CONFIG_BOOKE)
 #define MSR_DEBUGCHANGE	0
 #else
 #define MSR_DEBUGCHANGE	(MSR_SE | MSR_BE)
@@ -131,13 +131,77 @@
 }
 #endif
 
+#ifdef CONFIG_SPE
+
+/*
+ * For get_evrregs/set_evrregs functions 'data' has the following layout:
+ *
+ * struct {
+ *   u32 evr[32];
+ *   u64 acc;
+ *   u32 spefscr;
+ * }
+ */
+
+/*
+ * Get contents of SPE register state in task TASK.
+ */
+static inline int get_evrregs(unsigned long *data, struct task_struct *task)
+{
+	int i;
+
+	if (!access_ok(VERIFY_WRITE, data, 35 * sizeof(unsigned long)))
+		return -EFAULT;
+
+	/* copy SPEFSCR */
+	if (__put_user(task->thread.spefscr, &data[34]))
+		return -EFAULT;
+
+	/* copy SPE registers EVR[0] .. EVR[31] */
+	for (i = 0; i < 32; i++, data++)
+		if (__put_user(task->thread.evr[i], data))
+			return -EFAULT;
+
+	/* copy ACC */
+	if (__put_user64(task->thread.acc, (unsigned long long *)data))
+		return -EFAULT;
+
+	return 0;
+}
+
+/*
+ * Write contents of SPE register state into task TASK.
+ */
+static inline int set_evrregs(struct task_struct *task, unsigned long *data)
+{
+	int i;
+
+	if (!access_ok(VERIFY_READ, data, 35 * sizeof(unsigned long)))
+		return -EFAULT;
+
+	/* copy SPEFSCR */
+	if (__get_user(task->thread.spefscr, &data[34]))
+		return -EFAULT;
+
+	/* copy SPE registers EVR[0] .. EVR[31] */
+	for (i = 0; i < 32; i++, data++)
+		if (__get_user(task->thread.evr[i], data))
+			return -EFAULT;
+	/* copy ACC */
+	if (__get_user64(task->thread.acc, (unsigned long long*)data))
+		return -EFAULT;
+
+	return 0;
+}
+#endif /* CONFIG_SPE */
+
 static inline void
 set_single_step(struct task_struct *task)
 {
 	struct pt_regs *regs = task->thread.regs;
 
 	if (regs != NULL) {
-#ifdef CONFIG_4xx
+#if defined(CONFIG_4xx) || defined(CONFIG_BOOKE)
 		task->thread.dbcr0 = DBCR0_IDM | DBCR0_IC;
 		/* MSR.DE should already be set */
 #else
@@ -152,7 +216,7 @@
 	struct pt_regs *regs = task->thread.regs;
 
 	if (regs != NULL) {
-#ifdef CONFIG_4xx
+#if defined(CONFIG_4xx) || defined(CONFIG_BOOKE)
 		task->thread.dbcr0 = 0;
 #else
 		regs->msr &= ~MSR_SE;
@@ -360,6 +424,23 @@
 		ret = set_vrregs(child, (unsigned long *)data);
 		break;
 #endif
+#ifdef CONFIG_SPE
+	case PTRACE_GETEVRREGS:
+		/* Get the child spe register state. */
+		if (child->thread.regs->msr & MSR_SPE)
+			giveup_spe(child);
+		ret = get_evrregs((unsigned long *)data, child);
+		break;
+
+	case PTRACE_SETEVRREGS:
+		/* Set the child spe register state. */
+		/* this is to clear the MSR_SPE bit to force a reload
+		 * of register state from memory */
+		if (child->thread.regs->msr & MSR_SPE)
+			giveup_spe(child);
+		ret = set_evrregs(child, (unsigned long *)data);
+		break;
+#endif
 
 	default:
 		ret = ptrace_request(child, request, addr, data);
--- diff/arch/ppc/kernel/setup.c	2004-06-11 19:17:24.000000000 +0100
+++ source/arch/ppc/kernel/setup.c	2004-06-11 19:21:59.000000000 +0100
@@ -54,7 +54,6 @@
 extern void power4_idle(void);
 
 extern boot_infos_t *boot_infos;
-char saved_command_line[COMMAND_LINE_SIZE];
 unsigned char aux_device_present;
 struct ide_machdep_calls ppc_ide_md;
 char *sysmap;
--- diff/arch/ppc/kernel/signal.c	2004-05-19 22:11:15.000000000 +0100
+++ source/arch/ppc/kernel/signal.c	2004-06-11 19:21:59.000000000 +0100
@@ -183,8 +183,8 @@
 
 /*
  * Save the current user registers on the user stack.
- * We only save the altivec registers if the process has used
- * altivec instructions at some point.
+ * We only save the altivec/spe registers if the process has used
+ * altivec/spe instructions at some point.
  */
 static int
 save_user_regs(struct pt_regs *regs, struct mcontext *frame, int sigret)
@@ -198,6 +198,10 @@
 	if (current->thread.used_vr && (regs->msr & MSR_VEC))
 		giveup_altivec(current);
 #endif /* CONFIG_ALTIVEC */
+#ifdef CONFIG_SPE
+	if (current->thread.used_spe && (regs->msr & MSR_SPE))
+		giveup_spe(current);
+#endif /* CONFIG_ALTIVEC */
 	preempt_enable();
 
 	if (__copy_to_user(&frame->mc_gregs, regs, GP_REGS_SIZE)
@@ -229,6 +233,24 @@
 		return 1;
 #endif /* CONFIG_ALTIVEC */
 
+#ifdef CONFIG_SPE
+	/* save spe registers */
+	if (current->thread.used_spe) {
+		if (__copy_to_user(&frame->mc_vregs, current->thread.evr,
+				   ELF_NEVRREG * sizeof(u32)))
+			return 1;
+		/* set MSR_SPE in the saved MSR value to indicate that
+		   frame->mc_vregs contains valid data */
+		if (__put_user(regs->msr | MSR_SPE, &frame->mc_gregs[PT_MSR]))
+			return 1;
+	}
+	/* else assert((regs->msr & MSR_SPE) == 0) */
+
+	/* We always copy to/from spefscr */
+	if (__put_user(current->thread.spefscr, (u32 *)&frame->mc_vregs + ELF_NEVRREG))
+		return 1;
+#endif /* CONFIG_SPE */
+
 	if (sigret) {
 		/* Set up the sigreturn trampoline: li r0,sigret; sc */
 		if (__put_user(0x38000000UL + sigret, &frame->tramp[0])
@@ -249,7 +271,7 @@
 restore_user_regs(struct pt_regs *regs, struct mcontext __user *sr, int sig)
 {
 	unsigned long save_r2;
-#ifdef CONFIG_ALTIVEC
+#if defined(CONFIG_ALTIVEC) || defined(CONFIG_SPE)
 	unsigned long msr;
 #endif
 
@@ -290,6 +312,23 @@
 		return 1;
 #endif /* CONFIG_ALTIVEC */
 
+#ifdef CONFIG_SPE
+	/* force the process to reload the spe registers from
+	   current->thread when it next does spe instructions */
+	regs->msr &= ~MSR_SPE;
+	if (!__get_user(msr, &sr->mc_gregs[PT_MSR]) && (msr & MSR_SPE) != 0) {
+		/* restore spe registers from the stack */
+		if (__copy_from_user(current->thread.evr, &sr->mc_vregs,
+				     sizeof(sr->mc_vregs)))
+			return 1;
+	} else if (current->thread.used_spe)
+		memset(&current->thread.evr, 0, ELF_NEVRREG * sizeof(u32));
+
+	/* Always get SPEFSCR back */
+	if (__get_user(current->thread.spefscr, (u32 *)&sr->mc_vregs + ELF_NEVRREG))
+		return 1;
+#endif /* CONFIG_SPE */
+
 	return 0;
 }
 
--- diff/arch/ppc/kernel/traps.c	2004-06-11 19:17:24.000000000 +0100
+++ source/arch/ppc/kernel/traps.c	2004-06-11 19:21:59.000000000 +0100
@@ -30,6 +30,7 @@
 #include <linux/config.h>
 #include <linux/init.h>
 #include <linux/module.h>
+#include <linux/prctl.h>
 
 #include <asm/pgtable.h>
 #include <asm/uaccess.h>
@@ -171,6 +172,11 @@
 /* On 4xx, the reason for the machine check or program exception
    is in the ESR. */
 #define get_reason(regs)	((regs)->dsisr)
+#ifndef CONFIG_E500
+#define get_mc_reason(regs)	((regs)->dsisr)
+#else
+#define get_mc_reason(regs)	(mfspr(SPRN_MCSR))
+#endif
 #define REASON_FP		0
 #define REASON_ILLEGAL		ESR_PIL
 #define REASON_PRIVILEGED	ESR_PPR
@@ -184,6 +190,7 @@
 /* On non-4xx, the reason for the machine check or program
    exception is in the MSR. */
 #define get_reason(regs)	((regs)->msr)
+#define get_mc_reason(regs)	((regs)->msr)
 #define REASON_FP		0x100000
 #define REASON_ILLEGAL		0x80000
 #define REASON_PRIVILEGED	0x40000
@@ -196,7 +203,7 @@
 void
 MachineCheckException(struct pt_regs *regs)
 {
-	unsigned long reason = get_reason(regs);
+	unsigned long reason = get_mc_reason(regs);
 
 	if (user_mode(regs)) {
 		regs->msr |= MSR_RI;
@@ -256,7 +263,37 @@
 		/* Clear MCSR */
 		mtspr(SPRN_MCSR, mcsr);
 	}
-#else /* !CONFIG_4xx */
+#elif defined (CONFIG_E500)
+	printk("Machine check in kernel mode.\n");
+	printk("Caused by (from MCSR=%lx): ", reason);
+
+	if (reason & MCSR_MCP)
+		printk("Machine Check Signal\n");
+	if (reason & MCSR_ICPERR)
+		printk("Instruction Cache Parity Error\n");
+	if (reason & MCSR_DCP_PERR)
+		printk("Data Cache Push Parity Error\n");
+	if (reason & MCSR_DCPERR)
+		printk("Data Cache Parity Error\n");
+	if (reason & MCSR_GL_CI)
+		printk("Guarded Load or Cache-Inhibited stwcx.\n");
+	if (reason & MCSR_BUS_IAERR)
+		printk("Bus - Instruction Address Error\n");
+	if (reason & MCSR_BUS_RAERR)
+		printk("Bus - Read Address Error\n");
+	if (reason & MCSR_BUS_WAERR)
+		printk("Bus - Write Address Error\n");
+	if (reason & MCSR_BUS_IBERR)
+		printk("Bus - Instruction Data Error\n");
+	if (reason & MCSR_BUS_RBERR)
+		printk("Bus - Read Data Bus Error\n");
+	if (reason & MCSR_BUS_WBERR)
+		printk("Bus - Read Data Bus Error\n");
+	if (reason & MCSR_BUS_IPERR)
+		printk("Bus - Instruction Parity Error\n");
+	if (reason & MCSR_BUS_RPERR)
+		printk("Bus - Read Parity Error\n");
+#else /* !CONFIG_4xx && !CONFIG_E500 */
 	printk("Machine check in kernel mode.\n");
 	printk("Caused by (from SRR1=%lx): ", reason);
 	switch (reason & 0x601F0000) {
@@ -682,6 +719,56 @@
 }
 #endif /* CONFIG_ALTIVEC */
 
+#ifdef CONFIG_FSL_BOOKE
+void CacheLockingException(struct pt_regs *regs, unsigned long address,
+			   unsigned long error_code)
+{
+	/* We treat cache locking instructions from the user
+	 * as priv ops, in the future we could try to do
+	 * something smarter
+	 */
+	if (error_code & (ESR_DLK|ESR_ILK))
+		_exception(SIGILL, regs, ILL_PRVOPC, regs->nip);
+	return;
+}
+#endif /* CONFIG_FSL_BOOKE */
+
+#ifdef CONFIG_SPE
+void
+SPEFloatingPointException(struct pt_regs *regs)
+{
+	unsigned long spefscr;
+	int fpexc_mode;
+	int code = 0;
+
+	spefscr = current->thread.spefscr;
+	fpexc_mode = current->thread.fpexc_mode;
+
+	/* Hardware does not neccessarily set sticky
+	 * underflow/overflow/invalid flags */
+	if ((spefscr & SPEFSCR_FOVF) && (fpexc_mode & PR_FP_EXC_OVF)) {
+		code = FPE_FLTOVF;
+		spefscr |= SPEFSCR_FOVFS;
+	}
+	else if ((spefscr & SPEFSCR_FUNF) && (fpexc_mode & PR_FP_EXC_UND)) {
+		code = FPE_FLTUND;
+		spefscr |= SPEFSCR_FUNFS;
+	}
+	else if ((spefscr & SPEFSCR_FDBZ) && (fpexc_mode & PR_FP_EXC_DIV))
+		code = FPE_FLTDIV;
+	else if ((spefscr & SPEFSCR_FINV) && (fpexc_mode & PR_FP_EXC_INV)) {
+		code = FPE_FLTINV;
+		spefscr |= SPEFSCR_FINVS;
+	}
+	else if ((spefscr & (SPEFSCR_FG | SPEFSCR_FX)) && (fpexc_mode & PR_FP_EXC_RES))
+		code = FPE_FLTRES;
+
+	current->thread.spefscr = spefscr;
+
+	_exception(SIGFPE, regs, code, regs->nip);
+	return;
+}
+#endif
 
 void __init trap_init(void)
 {
--- diff/arch/ppc/mm/Makefile	2004-06-11 19:17:24.000000000 +0100
+++ source/arch/ppc/mm/Makefile	2004-06-11 19:21:59.000000000 +0100
@@ -12,3 +12,4 @@
 obj-$(CONFIG_PPC_STD_MMU)	+= hashtable.o ppc_mmu.o tlb.o
 obj-$(CONFIG_40x)		+= 4xx_mmu.o
 obj-$(CONFIG_44x)		+= 44x_mmu.o
+obj-$(CONFIG_FSL_BOOKE)		+= fsl_booke_mmu.o
--- diff/arch/ppc/mm/fault.c	2004-06-11 19:17:24.000000000 +0100
+++ source/arch/ppc/mm/fault.c	2004-06-11 19:21:59.000000000 +0100
@@ -99,7 +99,7 @@
 	struct mm_struct *mm = current->mm;
 	siginfo_t info;
 	int code = SEGV_MAPERR;
-#if defined(CONFIG_4xx)
+#if defined(CONFIG_4xx) || defined (CONFIG_BOOKE)
 	int is_write = error_code & ESR_DST;
 #else
 	int is_write = 0;
@@ -114,20 +114,20 @@
 		error_code &= 0x48200000;
 	else
 		is_write = error_code & 0x02000000;
-#endif /* CONFIG_4xx */
+#endif /* CONFIG_4xx || CONFIG_BOOKE */
 
 #if defined(CONFIG_XMON) || defined(CONFIG_KGDB)
 	if (debugger_fault_handler && TRAP(regs) == 0x300) {
 		debugger_fault_handler(regs);
 		return 0;
 	}
-#if !defined(CONFIG_4xx)
+#if !(defined(CONFIG_4xx) || defined(CONFIG_BOOKE))
 	if (error_code & 0x00400000) {
 		/* DABR match */
 		if (debugger_dabr_match(regs))
 			return 0;
 	}
-#endif /* !CONFIG_4xx */
+#endif /* !(CONFIG_4xx || CONFIG_BOOKE)*/
 #endif /* CONFIG_XMON || CONFIG_KGDB */
 
 	if (in_atomic() || mm == NULL)
@@ -200,8 +200,8 @@
 	if (is_write) {
 		if (!(vma->vm_flags & VM_WRITE))
 			goto bad_area;
-#if defined(CONFIG_4xx)
-	/* an exec  - 4xx allows for per-page execute permission */
+#if defined(CONFIG_4xx) || defined(CONFIG_BOOKE)
+	/* an exec  - 4xx/Book-E allows for per-page execute permission */
 	} else if (TRAP(regs) == 0x400) {
 		pte_t *ptep;
 
@@ -214,7 +214,7 @@
 			goto bad_area;
 #endif
 
-		/* Since 4xx supports per-page execute permission,
+		/* Since 4xx/Book-E supports per-page execute permission,
 		 * we lazily flush dcache to icache. */
 		ptep = NULL;
 		if (get_pteptr(mm, address, &ptep) && pte_present(*ptep)) {
--- diff/arch/ppc/mm/init.c	2004-06-11 19:17:24.000000000 +0100
+++ source/arch/ppc/mm/init.c	2004-06-11 19:21:59.000000000 +0100
@@ -253,6 +253,12 @@
 	if (__max_memory && total_memory > __max_memory)
 		total_memory = __max_memory;
 	total_lowmem = total_memory;
+#ifdef CONFIG_FSL_BOOKE
+	/* Freescale Book-E parts expect lowmem to be mapped by fixed TLB
+	 * entries, so we need to adjust lowmem to match the amount we can map
+	 * in the fixed entries */
+	adjust_total_lowmem();
+#endif /* CONFIG_FSL_BOOKE */
 	if (total_lowmem > __max_low_memory) {
 		total_lowmem = __max_low_memory;
 #ifndef CONFIG_HIGHMEM
--- diff/arch/ppc/mm/mmu_decl.h	2004-05-19 22:11:15.000000000 +0100
+++ source/arch/ppc/mm/mmu_decl.h	2004-06-11 19:21:59.000000000 +0100
@@ -27,6 +27,9 @@
 extern void setbat(int index, unsigned long virt, unsigned long phys,
 		   unsigned int size, int flags);
 extern void reserve_phys_mem(unsigned long start, unsigned long size);
+extern void settlbcam(int index, unsigned long virt, phys_addr_t phys,
+		      unsigned int size, int flags, unsigned int pid);
+extern void invalidate_tlbcam_entry(int index);
 
 extern int __map_without_bats;
 extern unsigned long ioremap_base;
@@ -53,6 +56,12 @@
 extern void MMU_init_hw(void);
 extern unsigned long mmu_mapin_ram(void);
 
+#elif defined(CONFIG_FSL_BOOKE)
+#define flush_HPTE(X, va, pg)	_tlbie(va)
+extern void MMU_init_hw(void);
+extern unsigned long mmu_mapin_ram(void);
+extern void adjust_total_lowmem(void);
+
 #else
 /* anything except 4xx or 8xx */
 extern void MMU_init_hw(void);
--- diff/arch/ppc/mm/pgtable.c	2004-06-11 19:17:24.000000000 +0100
+++ source/arch/ppc/mm/pgtable.c	2004-06-11 19:21:59.000000000 +0100
@@ -42,6 +42,10 @@
 #define HAVE_BATS	1
 #endif
 
+#if defined(CONFIG_FSL_BOOKE)
+#define HAVE_TLBCAM	1
+#endif
+
 extern char etext[], _stext[];
 
 #ifdef CONFIG_SMP
@@ -59,6 +63,16 @@
 #define p_mapped_by_bats(x)	(0UL)
 #endif /* HAVE_BATS */
 
+#ifdef HAVE_TLBCAM
+extern unsigned int tlbcam_index;
+extern unsigned int num_tlbcam_entries;
+extern unsigned long v_mapped_by_tlbcam(unsigned long va);
+extern unsigned long p_mapped_by_tlbcam(unsigned long pa);
+#else /* !HAVE_TLBCAM */
+#define v_mapped_by_tlbcam(x)	(0UL)
+#define p_mapped_by_tlbcam(x)	(0UL)
+#endif /* HAVE_TLBCAM */
+
 #ifdef CONFIG_44x
 /* 44x uses an 8kB pgdir because it has 8-byte Linux PTEs. */
 #define PGDIR_ORDER	1
@@ -210,6 +224,9 @@
 	if ((v = p_mapped_by_bats(p)) /*&& p_mapped_by_bats(p+size-1)*/ )
 		goto out;
 
+	if ((v = p_mapped_by_tlbcam(p)))
+		goto out;
+
 	if (mem_init_done) {
 		struct vm_struct *area;
 		area = get_vm_area(size, VM_IOREMAP);
@@ -300,6 +317,9 @@
 /* is x a power of 2? */
 #define is_power_of_2(x)	((x) != 0 && (((x) & ((x) - 1)) == 0))
 
+/* is x a power of 4? */
+#define is_power_of_4(x)	((x) != 0 && (((x) & (x-1)) == 0) && (ffs(x) & 1))
+
 /*
  * Set up a mapping for a block of I/O.
  * virt, phys, size must all be page-aligned.
@@ -325,6 +345,18 @@
 	}
 #endif /* HAVE_BATS */
 
+#ifdef HAVE_TLBCAM
+	/*
+	 * Use a CAM for this if possible...
+	 */
+	if (tlbcam_index < num_tlbcam_entries && is_power_of_4(size)
+	    && (virt & (size - 1)) == 0 && (phys & (size - 1)) == 0) {
+		settlbcam(tlbcam_index, virt, phys, size, flags, 0);
+		++tlbcam_index;
+		return;
+	}
+#endif /* HAVE_TLBCAM */
+
 	/* No BATs available, put it in the page tables. */
 	for (i = 0; i < size; i += PAGE_SIZE)
 		map_page(virt + i, phys + i, flags);
--- diff/arch/ppc/platforms/Makefile	2004-05-19 22:11:16.000000000 +0100
+++ source/arch/ppc/platforms/Makefile	2004-06-11 19:21:59.000000000 +0100
@@ -45,6 +45,7 @@
 obj-$(CONFIG_PRPMC750)		+= prpmc750.o
 obj-$(CONFIG_PRPMC800)		+= prpmc800.o
 obj-$(CONFIG_SANDPOINT)		+= sandpoint.o
+obj-$(CONFIG_SBC82xx)		+= sbc82xx.o
 obj-$(CONFIG_SPRUCE)		+= spruce.o
 
 ifeq ($(CONFIG_SMP),y)
--- diff/arch/ppc/platforms/lopec_setup.c	2004-05-19 22:11:16.000000000 +0100
+++ source/arch/ppc/platforms/lopec_setup.c	2004-06-11 19:21:59.000000000 +0100
@@ -33,7 +33,6 @@
 #include <asm/hw_irq.h>
 #include <asm/prep_nvram.h>
 
-extern char saved_command_line[];
 extern void lopec_find_bridges(void);
 
 /*
--- diff/arch/ppc/platforms/pmac_setup.c	2004-06-11 19:17:25.000000000 +0100
+++ source/arch/ppc/platforms/pmac_setup.c	2004-06-11 19:21:59.000000000 +0100
@@ -103,8 +103,6 @@
 
 static int current_root_goodness = -1;
 
-extern char saved_command_line[];
-
 extern int pmac_newworld;
 
 #define DEFAULT_ROOT_DEVICE Root_SDA1	/* sda1 - slightly silly choice */
--- diff/arch/ppc/platforms/pplus.c	2004-05-19 22:11:16.000000000 +0100
+++ source/arch/ppc/platforms/pplus.c	2004-06-11 19:21:59.000000000 +0100
@@ -48,8 +48,6 @@
 
 TODC_ALLOC();
 
-extern char saved_command_line[];
-
 extern void pplus_setup_hose(void);
 extern void pplus_set_VIA_IDE_native(void);
 
--- diff/arch/ppc/platforms/prep_setup.c	2004-05-19 22:11:16.000000000 +0100
+++ source/arch/ppc/platforms/prep_setup.c	2004-06-11 19:21:59.000000000 +0100
@@ -76,7 +76,6 @@
 extern void ibm_prep_init(void);
 
 extern void prep_find_bridges(void);
-extern char saved_command_line[];
 
 int _prep_type;
 
--- diff/arch/ppc/syslib/Makefile	2004-06-11 19:17:25.000000000 +0100
+++ source/arch/ppc/syslib/Makefile	2004-06-11 19:21:59.000000000 +0100
@@ -8,6 +8,9 @@
 ifdef CONFIG_4xx
 EXTRA_AFLAGS		:= -Wa,-m405
 endif
+ifdef CONFIG_E500
+EXTRA_AFLAGS		:= -Wa,-me500
+endif
 
 CFLAGS_prom_init.o      += -fPIC
 CFLAGS_btext.o          += -fPIC
@@ -63,6 +66,7 @@
 obj-$(CONFIG_HARRIER)		+= harrier.o
 obj-$(CONFIG_PRPMC800)		+= open_pic.o indirect_pci.o pci_auto.o
 obj-$(CONFIG_SANDPOINT)		+= i8259.o open_pic.o pci_auto.o todc_time.o
+obj-$(CONFIG_SBC82xx)		+= todc_time.o
 obj-$(CONFIG_SPRUCE)		+= cpc700_pic.o indirect_pci.o pci_auto.o \
 				   todc_time.o
 obj-$(CONFIG_8260)		+= m8260_setup.o ppc8260_pic.o
@@ -74,3 +78,7 @@
 obj-$(CONFIG_MPC10X_BRIDGE)     += mpc10x_common.o indirect_pci.o
 obj-$(CONFIG_40x)		+= dcr.o
 obj-$(CONFIG_BOOKE)		+= dcr.o
+obj-$(CONFIG_85xx)		+= open_pic.o ppc85xx_common.o ppc85xx_setup.o
+ifeq ($(CONFIG_85xx),y)
+obj-$(CONFIG_PCI)		+= indirect_pci.o pci_auto.o
+endif
--- diff/arch/ppc/syslib/open_pic.c	2004-05-19 22:11:17.000000000 +0100
+++ source/arch/ppc/syslib/open_pic.c	2004-06-11 19:21:59.000000000 +0100
@@ -28,7 +28,7 @@
 
 #include "open_pic_defs.h"
 
-#ifdef CONFIG_PRPMC800
+#if defined(CONFIG_PRPMC800) || defined(CONFIG_85xx)
 #define OPENPIC_BIG_ENDIAN
 #endif
 
--- diff/arch/ppc64/Kconfig	2004-06-11 19:17:25.000000000 +0100
+++ source/arch/ppc64/Kconfig	2004-06-11 19:21:58.000000000 +0100
@@ -427,6 +427,19 @@
 	  
 endmenu
 
+config SCHEDSTATS
+	bool "Collect scheduler statistics"
+	depends on PROC_FS
+	default n
+	help
+	  If you say Y here, additional code will be inserted into the
+	  scheduler and related routines to collect statistics about
+	  scheduler behavior and provide them in /proc/schedstat.  These
+	  stats may be useful for both tuning and debugging the scheduler
+	  If you aren't debugging the scheduler or trying to tune a specific
+	  application, you can say N to avoid the very slight overhead
+	  this adds.
+
 config SPINLINE
 	bool "Inline spinlock code at each call site"
 	depends on SMP && !PPC_SPLPAR && !PPC_ISERIES
--- diff/arch/ppc64/kernel/head.S	2004-06-11 19:17:25.000000000 +0100
+++ source/arch/ppc64/kernel/head.S	2004-06-11 19:21:58.000000000 +0100
@@ -35,6 +35,7 @@
 #include <asm/offsets.h>
 #include <asm/bug.h>
 #include <asm/cputable.h>
+#include <asm/setup.h>
 
 #ifdef CONFIG_PPC_ISERIES
 #define DO_SOFT_DISABLE
@@ -2275,4 +2276,4 @@
  */
 	.globl	cmd_line
 cmd_line:
-	.space	512	/* COMMAND_LINE_SIZE */
+	.space	COMMAND_LINE_SIZE
--- diff/arch/ppc64/kernel/init_task.c	2004-05-19 22:11:18.000000000 +0100
+++ source/arch/ppc64/kernel/init_task.c	2004-06-11 19:21:58.000000000 +0100
@@ -4,6 +4,7 @@
 #include <linux/init.h>
 #include <linux/init_task.h>
 #include <linux/fs.h>
+#include <linux/mqueue.h>
 #include <asm/uaccess.h>
 
 static struct fs_struct init_fs = INIT_FS;
--- diff/arch/ppc64/kernel/irq.c	2004-06-11 19:17:25.000000000 +0100
+++ source/arch/ppc64/kernel/irq.c	2004-06-11 19:21:58.000000000 +0100
@@ -738,7 +738,6 @@
 	irq_desc_t *desc = get_irq_desc(irq);
 	int ret;
 	cpumask_t new_value, tmp;
-	cpumask_t allcpus = CPU_MASK_ALL;
 
 	if (!desc->handler->set_affinity)
 		return -EIO;
@@ -753,7 +752,7 @@
 	 * NR_CPUS == 32 and cpumask is a long), so we mask it here to
 	 * be consistent.
 	 */
-	cpus_and(new_value, new_value, allcpus);
+	cpus_and(new_value, new_value, CPU_MASK_ALL);
 
 	/*
 	 * Grab lock here so cpu_online_map can't change, and also
--- diff/arch/ppc64/kernel/open_pic.c	2004-05-19 22:11:18.000000000 +0100
+++ source/arch/ppc64/kernel/open_pic.c	2004-06-11 19:21:58.000000000 +0100
@@ -591,7 +591,7 @@
 void openpic_init_processor(u_int cpumask)
 {
 	openpic_write(&OpenPIC->Global.Processor_Initialization,
-		      physmask(cpumask & cpus_coerce(cpu_online_map)));
+		      physmask(cpumask & cpus_addr(cpu_online_map)[0]));
 }
 
 #ifdef CONFIG_SMP
@@ -625,7 +625,7 @@
 	CHECK_THIS_CPU;
 	check_arg_ipi(ipi);
 	openpic_write(&OpenPIC->THIS_CPU.IPI_Dispatch(ipi),
-		      physmask(cpumask & cpus_coerce(cpu_online_map)));
+		      physmask(cpumask & cpus_addr(cpu_online_map)[0]));
 }
 
 void openpic_request_IPIs(void)
@@ -711,7 +711,7 @@
 {
 	check_arg_timer(timer);
 	openpic_write(&OpenPIC->Global.Timer[timer].Destination,
-		      physmask(cpumask & cpus_coerce(cpu_online_map)));
+		      physmask(cpumask & cpus_addr(cpu_online_map)[0]));
 }
 
 
@@ -844,7 +844,7 @@
 	cpumask_t tmp;
 
 	cpus_and(tmp, cpumask, cpu_online_map);
-	openpic_mapirq(irq_nr - open_pic_irq_offset, physmask(cpus_coerce(tmp)));
+	openpic_mapirq(irq_nr - open_pic_irq_offset, physmask(cpus_addr(tmp)[0]));
 }
 
 #ifdef CONFIG_SMP
--- diff/arch/ppc64/kernel/rtasd.c	2004-06-11 19:17:25.000000000 +0100
+++ source/arch/ppc64/kernel/rtasd.c	2004-06-11 19:21:58.000000000 +0100
@@ -364,7 +364,6 @@
 	unsigned int err_type;
 	int cpu = 0;
 	int event_scan = rtas_token("event-scan");
-	cpumask_t all = CPU_MASK_ALL;
 	int rc;
 
 	daemonize("rtasd");
@@ -415,11 +414,11 @@
 	}
 
 	lock_cpu_hotplug();
-	cpu = first_cpu_const(mk_cpumask_const(cpu_online_map));
+	cpu = first_cpu(cpu_online_map);
 	for (;;) {
 		set_cpus_allowed(current, cpumask_of_cpu(cpu));
 		do_event_scan(event_scan);
-		set_cpus_allowed(current, all);
+		set_cpus_allowed(current, CPU_MASK_ALL);
 
 		/* Drop hotplug lock, and sleep for a bit (at least
 		 * one second since some machines have problems if we
@@ -429,9 +428,9 @@
 		schedule_timeout((HZ*60/rtas_event_scan_rate) / 2);
 		lock_cpu_hotplug();
 
-		cpu = next_cpu_const(cpu, mk_cpumask_const(cpu_online_map));
+		cpu = next_cpu(cpu, cpu_online_map);
 		if (cpu == NR_CPUS)
-			cpu = first_cpu_const(mk_cpumask_const(cpu_online_map));
+			cpu = first_cpu(cpu_online_map);
 	}
 
 error:
--- diff/arch/ppc64/kernel/setup.c	2004-06-11 19:17:25.000000000 +0100
+++ source/arch/ppc64/kernel/setup.c	2004-06-11 19:21:58.000000000 +0100
@@ -82,7 +82,6 @@
 
 int powersave_nap;
 
-char saved_command_line[COMMAND_LINE_SIZE];
 unsigned char aux_device_present;
 
 void parse_cmd_line(unsigned long r3, unsigned long r4, unsigned long r5,
--- diff/arch/ppc64/kernel/smp.c	2004-06-11 19:17:25.000000000 +0100
+++ source/arch/ppc64/kernel/smp.c	2004-06-11 19:21:58.000000000 +0100
@@ -390,8 +390,7 @@
 	}
 
 	/* Fixup atomic count: it exited inside IRQ handler. */
-	((struct task_struct *)paca[lcpu].xCurrent)->thread_info->preempt_count
-		= 0;
+	paca[lcpu].xCurrent->thread_info->preempt_count	= 0;
 	/* Fixup SLB round-robin so next segment (kernel) goes in segment 0 */
 	paca[lcpu].xStab_data.next_round_robin = 0;
 
@@ -817,7 +816,7 @@
 	init_idle(p, cpu);
 	unhash_process(p);
 
-	paca[cpu].xCurrent = (u64)p;
+	paca[cpu].xCurrent = p;
 	current_set[cpu] = p->thread_info;
 }
 
@@ -869,7 +868,7 @@
 	/* cpu_possible is set up in prom.c */
 	cpu_set(boot_cpuid, cpu_online_map);
 
-	paca[boot_cpuid].xCurrent = (u64)current;
+	paca[boot_cpuid].xCurrent = current;
 	current_set[boot_cpuid] = current->thread_info;
 }
 
--- diff/arch/ppc64/kernel/traps.c	2004-06-11 19:17:25.000000000 +0100
+++ source/arch/ppc64/kernel/traps.c	2004-06-11 19:21:58.000000000 +0100
@@ -466,6 +466,18 @@
 	_exception(SIGTRAP, &info, regs);	
 }
 
+/*
+ * After we have successfully emulated an instruction, we have to
+ * check if the instruction was being single-stepped, and if so,
+ * pretend we got a single-step exception.  This was pointed out
+ * by Kumar Gala.  -- paulus
+ */
+static inline void emulate_single_step(struct pt_regs *regs)
+{
+	if (regs->msr & MSR_SE)
+		SingleStepException(regs);
+}
+
 static void dummy_perf(struct pt_regs *regs)
 {
 }
@@ -487,10 +499,8 @@
 	fixed = fix_alignment(regs);
 
 	if (fixed == 1) {
-		if (!user_mode(regs))
-			PPCDBG(PPCDBG_ALIGNFIXUP, "fix alignment at %lx\n",
-			       regs->nip);
 		regs->nip += 4;	/* skip over emulated instruction */
+		emulate_single_step(regs);
 		return;
 	}
 
--- diff/arch/ppc64/kernel/vio.c	2004-06-11 19:17:25.000000000 +0100
+++ source/arch/ppc64/kernel/vio.c	2004-06-11 19:21:58.000000000 +0100
@@ -32,7 +32,9 @@
 
 extern struct subsystem devices_subsys; /* needed for vio_find_name() */
 
-struct iommu_table *vio_build_iommu_table(struct vio_dev *dev);
+static struct iommu_table *vio_build_iommu_table(struct vio_dev *);
+static const struct vio_device_id *vio_match_device(
+		const struct vio_device_id *, const struct vio_dev *);
 
 #ifdef CONFIG_PPC_PSERIES
 static int vio_num_address_cells;
@@ -136,15 +138,15 @@
  * system is in its list of supported devices. Returns the matching
  * vio_device_id structure or NULL if there is no match.
  */
-const struct vio_device_id * vio_match_device(const struct vio_device_id *ids,
+static const struct vio_device_id * vio_match_device(const struct vio_device_id *ids,
 	const struct vio_dev *dev)
 {
 	DBGENTER();
 
 #ifdef CONFIG_PPC_PSERIES
 	while (ids->type) {
-		if ((strncmp(dev->archdata->type, ids->type, strlen(ids->type)) == 0) &&
-			device_is_compatible((struct device_node*)dev->archdata, ids->compat))
+		if ((strncmp(((struct device_node *)dev->dev.platform_data)->type, ids->type, strlen(ids->type)) == 0) &&
+			device_is_compatible(dev->dev.platform_data, ids->compat))
 			return ids;
 		ids++;
 	}
@@ -263,14 +265,13 @@
 	DBGENTER();
 
 	/* XXX free TCE table */
-	of_node_put(viodev->archdata);
+	of_node_put(viodev->dev.platform_data);
 	kfree(viodev);
 }
 
 static ssize_t viodev_show_devspec(struct device *dev, char *buf)
 {
-	struct vio_dev *viodev = to_vio_dev(dev);
-	struct device_node *of_node = viodev->archdata;
+	struct device_node *of_node = dev->platform_data;
 
 	return sprintf(buf, "%s\n", of_node->full_name);
 }
@@ -278,8 +279,7 @@
 
 static ssize_t viodev_show_name(struct device *dev, char *buf)
 {
-	struct vio_dev *viodev = to_vio_dev(dev);
-	struct device_node *of_node = viodev->archdata;
+	struct device_node *of_node = dev->platform_data;
 
 	return sprintf(buf, "%s\n", of_node->name);
 }
@@ -290,7 +290,7 @@
  * @of_node:	The OF node for this device.
  *
  * Creates and initializes a vio_dev structure from the data in
- * of_node (archdata) and adds it to the list of virtual devices.
+ * of_node (dev.platform_data) and adds it to the list of virtual devices.
  * Returns a pointer to the created vio_dev or NULL if node has
  * NULL device_type or compatible fields.
  */
@@ -324,7 +324,7 @@
 	}
 	memset(viodev, 0, sizeof(struct vio_dev));
 
-	viodev->archdata = (void *)of_node_get(of_node);
+	viodev->dev.platform_data = of_node_get(of_node);
 	viodev->unit_address = *unit_address;
 	viodev->iommu_table = vio_build_iommu_table(viodev);
 
@@ -380,7 +380,7 @@
 */
 const void * vio_get_attribute(struct vio_dev *vdev, void* which, int* length)
 {
-	return get_property((struct device_node *)vdev->archdata, (char*)which, length);
+	return get_property(vdev->dev.platform_data, (char*)which, length);
 }
 EXPORT_SYMBOL(vio_get_attribute);
 
@@ -427,7 +427,7 @@
  * Returns a pointer to the built tce tree, or NULL if it can't
  * find property.
 */
-struct iommu_table * vio_build_iommu_table(struct vio_dev *dev)
+static struct iommu_table * vio_build_iommu_table(struct vio_dev *dev)
 {
 	unsigned int *dma_window;
 	struct iommu_table *newTceTable;
@@ -435,7 +435,7 @@
 	unsigned long size;
 	int dma_window_property_size;
 
-	dma_window = (unsigned int *) get_property((struct device_node *)dev->archdata, "ibm,my-dma-window", &dma_window_property_size);
+	dma_window = (unsigned int *) get_property(dev->dev.platform_data, "ibm,my-dma-window", &dma_window_property_size);
 	if(!dma_window) {
 		return NULL;
 	}
--- diff/arch/ppc64/kernel/xics.c	2004-06-11 19:17:26.000000000 +0100
+++ source/arch/ppc64/kernel/xics.c	2004-06-11 19:21:59.000000000 +0100
@@ -240,14 +240,13 @@
 static int get_irq_server(unsigned int irq)
 {
 	cpumask_t cpumask = irq_affinity[irq];
-	cpumask_t allcpus = CPU_MASK_ALL;
 	cpumask_t tmp = CPU_MASK_NONE;
 	unsigned int server;
 
 #ifdef CONFIG_IRQ_ALL_CPUS
 	/* For the moment only implement delivery to all cpus or one cpu */
 	if (smp_threads_ready) {
-		if (cpus_equal(cpumask, allcpus)) {
+		if (cpus_equal(cpumask, CPU_MASK_ALL)) {
 			server = default_distrib_server;
 		} else {
 			cpus_and(tmp, cpu_online_map, cpumask);
@@ -616,7 +615,6 @@
 	long status;
 	unsigned long xics_status[2];
 	unsigned long newmask;
-	cpumask_t allcpus = CPU_MASK_ALL;
 	cpumask_t tmp = CPU_MASK_NONE;
 
 	irq = virt_irq_to_real(irq_offset_down(virq));
@@ -632,7 +630,7 @@
 	}
 
 	/* For the moment only implement delivery to all cpus or one cpu */
-	if (cpus_equal(cpumask, allcpus)) {
+	if (cpus_equal(cpumask, CPU_MASK_ALL)) {
 		newmask = default_distrib_server;
 	} else {
 		cpus_and(tmp, cpu_online_map, cpumask);
--- diff/arch/ppc64/mm/fault.c	2004-06-11 19:17:26.000000000 +0100
+++ source/arch/ppc64/mm/fault.c	2004-06-11 19:21:59.000000000 +0100
@@ -110,7 +110,29 @@
 		bad_page_fault(regs, address, SIGSEGV);
 		return;
 	}
-	down_read(&mm->mmap_sem);
+
+	/* When running in the kernel we expect faults to occur only to
+	 * addresses in user space.  All other faults represent errors in the
+	 * kernel and should generate an OOPS.  Unfortunatly, in the case of an
+	 * erroneous fault occuring in a code path which already holds mmap_sem
+	 * we will deadlock attempting to validate the fault against the
+	 * address space.  Luckily the kernel only validly references user
+	 * space from well defined areas of code, which are listed in the
+	 * exceptions table.
+	 *
+	 * As the vast majority of faults will be valid we will only perform
+	 * the source reference check when there is a possibilty of a deadlock.
+	 * Attempt to lock the address space, if we cannot we then validate the
+	 * source.  If this is invalid we can skip the address space check,
+	 * thus avoiding the deadlock.
+	 */
+	if (!down_read_trylock(&mm->mmap_sem)) {
+		if (!user_mode(regs) && !search_exception_tables(regs->nip))
+			goto bad_area_nosemaphore;
+
+		down_read(&mm->mmap_sem);
+	}
+
 	vma = find_vma(mm, address);
 	if (!vma)
 		goto bad_area;
@@ -200,6 +222,7 @@
 bad_area:
 	up_read(&mm->mmap_sem);
 
+bad_area_nosemaphore:
 	/* User mode accesses cause a SIGSEGV */
 	if (user_mode(regs)) {
 		info.si_signo = SIGSEGV;
--- diff/arch/ppc64/mm/tlb.c	2004-06-11 19:17:26.000000000 +0100
+++ source/arch/ppc64/mm/tlb.c	2004-06-11 19:21:59.000000000 +0100
@@ -41,6 +41,33 @@
 DEFINE_PER_CPU(struct pte_freelist_batch *, pte_freelist_cur);
 unsigned long pte_freelist_forced_free;
 
+void __pte_free_tlb(struct mmu_gather *tlb, struct page *ptepage)
+{
+	/* This is safe as we are holding page_table_lock */
+        cpumask_t local_cpumask = cpumask_of_cpu(smp_processor_id());
+	struct pte_freelist_batch **batchp = &__get_cpu_var(pte_freelist_cur);
+
+	if (atomic_read(&tlb->mm->mm_users) < 2 ||
+	    cpus_equal(tlb->mm->cpu_vm_mask, local_cpumask)) {
+		pte_free(ptepage);
+		return;
+	}
+
+	if (*batchp == NULL) {
+		*batchp = (struct pte_freelist_batch *)__get_free_page(GFP_ATOMIC);
+		if (*batchp == NULL) {
+			pte_free_now(ptepage);
+			return;
+		}
+		(*batchp)->index = 0;
+	}
+	(*batchp)->pages[(*batchp)->index++] = ptepage;
+	if ((*batchp)->index == PTE_FREELIST_SIZE) {
+		pte_free_submit(*batchp);
+		*batchp = NULL;
+	}
+}
+
 /*
  * Update the MMU hash table to correspond with a change to
  * a Linux PTE.  If wrprot is true, it is permissible to
--- diff/arch/s390/kernel/asm-offsets.c	2004-05-19 22:11:20.000000000 +0100
+++ source/arch/s390/kernel/asm-offsets.c	2004-06-11 19:21:59.000000000 +0100
@@ -32,6 +32,7 @@
 	DEFINE(__TI_cpu, offsetof(struct thread_info, cpu),);
 	DEFINE(__TI_precount, offsetof(struct thread_info, preempt_count),);
 	BLANK();
+	DEFINE(__PT_ARGS, offsetof(struct pt_regs, args),);
 	DEFINE(__PT_PSW, offsetof(struct pt_regs, psw),);
 	DEFINE(__PT_GPRS, offsetof(struct pt_regs, gprs),);
 	DEFINE(__PT_ORIG_GPR2, offsetof(struct pt_regs, orig_gpr2),);
--- diff/arch/s390/kernel/compat_wrapper.S	2004-06-11 19:17:26.000000000 +0100
+++ source/arch/s390/kernel/compat_wrapper.S	2004-06-11 19:22:00.000000000 +0100
@@ -1097,6 +1097,8 @@
 	lgfr	%r4,%r4			# int
 	llgtr	%r5,%r5			# struct compat_timespec *
 	llgtr	%r6,%r6			# u32 *
+	lgf	%r0,164(%r15)		# int
+	stg	%r0,160(%r15)
 	jg	compat_sys_futex	# branch to system call
 
 	.globl	sys32_setxattr_wrapper
--- diff/arch/s390/kernel/entry.S	2004-06-11 19:17:26.000000000 +0100
+++ source/arch/s390/kernel/entry.S	2004-06-11 19:22:00.000000000 +0100
@@ -24,7 +24,8 @@
  * Stack layout for the system_call stack entry.
  * The first few entries are identical to the user_regs_struct.
  */
-SP_PTREGS    =  STACK_FRAME_OVERHEAD 
+SP_PTREGS    =  STACK_FRAME_OVERHEAD
+SP_ARGS      =  STACK_FRAME_OVERHEAD + __PT_ARGS
 SP_PSW       =  STACK_FRAME_OVERHEAD + __PT_PSW
 SP_R0        =  STACK_FRAME_OVERHEAD + __PT_GPRS
 SP_R1        =  STACK_FRAME_OVERHEAD + __PT_GPRS + 4
@@ -230,12 +231,14 @@
 sysc_enter:
         GET_THREAD_INFO           # load pointer to task_struct to R9
 	sla	%r7,2             # *4 and test for svc 0
-	bnz	BASED(sysc_do_restart)  # svc number > 0
+	bnz	BASED(sysc_nr_ok) # svc number > 0
 	# svc 0: system call number in %r1
 	cl	%r1,BASED(.Lnr_syscalls)
-	bnl	BASED(sysc_do_restart)
+	bnl	BASED(sysc_nr_ok)
 	lr	%r7,%r1           # copy svc number to %r7
 	sla	%r7,2             # *4
+sysc_nr_ok:
+	mvc	SP_ARGS(4,%r15),SP_R7(%r15)
 sysc_do_restart:
 	tm	__TI_flags+3(%r9),(_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT)
         l       %r8,sys_call_table-system_call(%r7,%r13) # get system call addr.
@@ -510,6 +513,7 @@
 	lr	%r7,%r1           # copy svc number to %r7
 	sla	%r7,2             # *4
 pgm_svcstd:
+	mvc	SP_ARGS(4,%r15),SP_R7(%r15)
 	tm	__TI_flags+3(%r9),(_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT)
         l       %r8,sys_call_table-system_call(%r7,%r13) # get system call addr.
         bnz     BASED(pgm_tracesys)
--- diff/arch/s390/kernel/entry64.S	2004-06-11 19:17:26.000000000 +0100
+++ source/arch/s390/kernel/entry64.S	2004-06-11 19:22:00.000000000 +0100
@@ -24,7 +24,8 @@
  * Stack layout for the system_call stack entry.
  * The first few entries are identical to the user_regs_struct.
  */
-SP_PTREGS    =  STACK_FRAME_OVERHEAD 
+SP_PTREGS    =  STACK_FRAME_OVERHEAD
+SP_ARGS      =  STACK_FRAME_OVERHEAD + __PT_ARGS
 SP_PSW       =  STACK_FRAME_OVERHEAD + __PT_PSW
 SP_R0        =  STACK_FRAME_OVERHEAD + __PT_GPRS
 SP_R1        =  STACK_FRAME_OVERHEAD + __PT_GPRS + 8
@@ -214,13 +215,15 @@
 sysc_enter:
         GET_THREAD_INFO           # load pointer to task_struct to R9
         slag    %r7,%r7,2         # *4 and test for svc 0
-	jnz	sysc_do_restart
+	jnz	sysc_nr_ok
 	# svc 0: system call number in %r1
 	lghi	%r0,NR_syscalls
 	clr	%r1,%r0
-	jnl	sysc_do_restart
+	jnl	sysc_nr_ok
 	lgfr	%r7,%r1           # clear high word in r1
 	slag    %r7,%r7,2         # svc 0: system call number in %r1
+sysc_nr_ok:
+	mvc	SP_ARGS(8,%r15),SP_R7(%r15)
 sysc_do_restart:
 	larl    %r10,sys_call_table
 #ifdef CONFIG_S390_SUPPORT
@@ -542,6 +545,7 @@
 	clr	%r1,%r0
 	slag	%r7,%r1,2
 pgm_svcstd:
+	mvc	SP_ARGS(8,%r15),SP_R7(%r15)
 	larl    %r10,sys_call_table
 #ifdef CONFIG_S390_SUPPORT
         tm      SP_PSW+3(%r15),0x01  # are we running in 31 bit mode ?
--- diff/arch/s390/kernel/init_task.c	2004-05-19 22:11:20.000000000 +0100
+++ source/arch/s390/kernel/init_task.c	2004-06-11 19:22:00.000000000 +0100
@@ -10,6 +10,7 @@
 #include <linux/module.h>
 #include <linux/sched.h>
 #include <linux/init_task.h>
+#include <linux/mqueue.h>
 
 #include <asm/uaccess.h>
 #include <asm/pgtable.h>
--- diff/arch/s390/kernel/ptrace.c	2004-05-19 22:11:20.000000000 +0100
+++ source/arch/s390/kernel/ptrace.c	2004-06-11 19:22:00.000000000 +0100
@@ -141,7 +141,7 @@
 		/*
 		 * psw and gprs are stored on the stack
 		 */
-		tmp = *(addr_t *)((addr_t) __KSTK_PTREGS(child) + addr);
+		tmp = *(addr_t *)((addr_t) &__KSTK_PTREGS(child)->psw + addr);
 		if (addr == (addr_t) &dummy->regs.psw.mask)
 			/* Remove per bit from user psw. */
 			tmp &= ~PSW_MASK_PER;
@@ -215,7 +215,7 @@
 			   high order bit but older gdb's rely on it */
 			data |= PSW_ADDR_AMODE;
 #endif
-		*(addr_t *)((addr_t) __KSTK_PTREGS(child) + addr) = data;
+		*(addr_t *)((addr_t) &__KSTK_PTREGS(child)->psw + addr) = data;
 
 	} else if (addr < (addr_t) (&dummy->regs.orig_gpr2)) {
 		/*
@@ -360,7 +360,7 @@
 				PSW32_ADDR_AMODE31;
 		} else {
 			/* gpr 0-15 */
-			tmp = *(__u32 *)((addr_t) __KSTK_PTREGS(child) + 
+			tmp = *(__u32 *)((addr_t) &__KSTK_PTREGS(child)->psw +
 					 addr*2 + 4);
 		}
 	} else if (addr < (addr_t) (&dummy32->regs.orig_gpr2)) {
@@ -439,8 +439,8 @@
 				(__u64) tmp & PSW32_ADDR_INSN;
 		} else {
 			/* gpr 0-15 */
-			*(__u32*)((addr_t) __KSTK_PTREGS(child) + addr*2 + 4) =
-				tmp;
+			*(__u32*)((addr_t) &__KSTK_PTREGS(child)->psw
+				  + addr*2 + 4) = tmp;
 		}
 	} else if (addr < (addr_t) (&dummy32->regs.orig_gpr2)) {
 		/*
--- diff/arch/s390/kernel/setup.c	2004-05-19 22:11:20.000000000 +0100
+++ source/arch/s390/kernel/setup.c	2004-06-11 19:22:00.000000000 +0100
@@ -74,7 +74,6 @@
 #include <asm/setup.h>
 
 static char command_line[COMMAND_LINE_SIZE] = { 0, };
-       char saved_command_line[COMMAND_LINE_SIZE];
 
 static struct resource code_resource = { "Kernel code", 0x100000, 0 };
 static struct resource data_resource = { "Kernel data", 0, 0 };
--- diff/arch/sh/kernel/init_task.c	2004-05-19 22:11:22.000000000 +0100
+++ source/arch/sh/kernel/init_task.c	2004-06-11 19:22:00.000000000 +0100
@@ -2,6 +2,7 @@
 #include <linux/module.h>
 #include <linux/sched.h>
 #include <linux/init_task.h>
+#include <linux/mqueue.h>
 
 #include <asm/uaccess.h>
 #include <asm/pgtable.h>
--- diff/arch/sh/kernel/setup.c	2004-05-19 22:11:22.000000000 +0100
+++ source/arch/sh/kernel/setup.c	2004-06-11 19:22:00.000000000 +0100
@@ -85,14 +85,12 @@
 #define INITRD_SIZE (*(unsigned long *) (PARAM+0x014))
 /* ... */
 #define COMMAND_LINE ((char *) (PARAM+0x100))
-#define COMMAND_LINE_SIZE 256
 
 #define RAMDISK_IMAGE_START_MASK  	0x07FF
 #define RAMDISK_PROMPT_FLAG		0x8000
 #define RAMDISK_LOAD_FLAG		0x4000	
 
 static char command_line[COMMAND_LINE_SIZE] = { 0, };
-       char saved_command_line[COMMAND_LINE_SIZE];
 
 struct resource standard_io_resources[] = {
 	{ "dma1", 0x00, 0x1f },
--- diff/arch/sparc/kernel/init_task.c	2004-05-19 22:11:22.000000000 +0100
+++ source/arch/sparc/kernel/init_task.c	2004-06-11 19:22:00.000000000 +0100
@@ -2,6 +2,7 @@
 #include <linux/module.h>
 #include <linux/sched.h>
 #include <linux/init_task.h>
+#include <linux/mqueue.h>
 
 #include <asm/pgtable.h>
 #include <asm/uaccess.h>
--- diff/arch/sparc/kernel/setup.c	2004-05-19 22:11:23.000000000 +0100
+++ source/arch/sparc/kernel/setup.c	2004-06-11 19:22:00.000000000 +0100
@@ -244,8 +244,7 @@
 
 extern int root_mountflags;
 
-char saved_command_line[256];
-char reboot_command[256];
+char reboot_command[COMMAND_LINE_SIZE];
 enum sparc_cpu sparc_cpu_model;
 
 struct tt_entry *sparc_ttable;
--- diff/arch/sparc/kernel/sparc_ksyms.c	2004-05-19 22:11:23.000000000 +0100
+++ source/arch/sparc/kernel/sparc_ksyms.c	2004-06-11 19:22:00.000000000 +0100
@@ -11,6 +11,7 @@
 
 #include <linux/config.h>
 #include <linux/module.h>
+#include <linux/init.h>
 #include <linux/smp.h>
 #include <linux/types.h>
 #include <linux/string.h>
@@ -74,7 +75,6 @@
 extern void *__memscan_generic(void *, int, size_t);
 extern int __memcmp(const void *, const void *, __kernel_size_t);
 extern int __strncmp(const char *, const char *, __kernel_size_t);
-extern char saved_command_line[];
 
 extern void bcopy (const char *, char *, int);
 extern int __ashrdi3(int, int);
--- diff/arch/sparc64/Kconfig	2004-06-11 19:17:27.000000000 +0100
+++ source/arch/sparc64/Kconfig	2004-06-11 19:22:00.000000000 +0100
@@ -687,12 +687,19 @@
 	depends on DEBUG_KERNEL
 	bool "Debug BOOTMEM initialization"
 
+config LOCKMETER
+	bool "Kernel lock metering"
+	depends on SMP && !PREEMPT
+	help
+	  Say Y to enable kernel lock metering, which adds overhead to SMP locks,
+	  but allows you to see various statistics using the lockstat command.
+
 # We have a custom atomic_dec_and_lock() implementation but it's not
 # compatible with spinlock debugging so we need to fall back on
 # the generic version in that case.
 config HAVE_DEC_LOCK
 	bool
-	depends on SMP && !DEBUG_SPINLOCK
+	depends on SMP && !DEBUG_SPINLOCK && !LOCKMETER
 	default y
 
 config MCOUNT
--- diff/arch/sparc64/kernel/init_task.c	2004-05-19 22:11:24.000000000 +0100
+++ source/arch/sparc64/kernel/init_task.c	2004-06-11 19:22:00.000000000 +0100
@@ -2,6 +2,7 @@
 #include <linux/module.h>
 #include <linux/sched.h>
 #include <linux/init_task.h>
+#include <linux/mqueue.h>
 
 #include <asm/pgtable.h>
 #include <asm/uaccess.h>
--- diff/arch/sparc64/kernel/irq.c	2004-06-11 19:17:27.000000000 +0100
+++ source/arch/sparc64/kernel/irq.c	2004-06-11 19:22:00.000000000 +0100
@@ -687,9 +687,10 @@
 	 *    Just Do It.
 	 */
 	struct irqaction *ap = bp->irq_info;
-	cpumask_t cpu_mask = get_smpaff_in_irqaction(ap);
+	cpumask_t cpu_mask;
 	unsigned int buddy, ticks;
 
+	cpus_addr(cpu_mask)[0] = get_smpaff_in_irqaction(ap);
 	cpus_and(cpu_mask, cpu_mask, cpu_online_map);
 	if (cpus_empty(cpu_mask))
 		cpu_mask = cpu_online_map;
@@ -1206,9 +1207,10 @@
 {
 	struct ino_bucket *bp = ivector_table + (long)data;
 	struct irqaction *ap = bp->irq_info;
-	cpumask_t mask = get_smpaff_in_irqaction(ap);
+	cpumask_t mask;
 	int len;
 
+	cpus_addr(mask)[0] = get_smpaff_in_irqaction(ap);
 	if (cpus_empty(mask))
 		mask = cpu_online_map;
 
--- diff/arch/sparc64/kernel/setup.c	2004-06-11 19:17:27.000000000 +0100
+++ source/arch/sparc64/kernel/setup.c	2004-06-11 19:22:00.000000000 +0100
@@ -451,8 +451,7 @@
 
 extern int root_mountflags;
 
-char saved_command_line[256];
-char reboot_command[256];
+char reboot_command[COMMAND_LINE_SIZE];
 
 static struct pt_regs fake_swapper_regs = { { 0, }, 0, 0, 0, 0 };
 
--- diff/arch/sparc64/kernel/smp.c	2004-06-11 19:17:27.000000000 +0100
+++ source/arch/sparc64/kernel/smp.c	2004-06-11 19:22:00.000000000 +0100
@@ -406,14 +406,8 @@
 	int i;
 
 	__asm__ __volatile__("rdpr %%pstate, %0" : "=r" (pstate));
-	for (i = 0; i < NR_CPUS; i++) {
-		if (cpu_isset(i, mask)) {
-			spitfire_xcall_helper(data0, data1, data2, pstate, i);
-			cpu_clear(i, mask);
-			if (cpus_empty(mask))
-				break;
-		}
-	}
+	for_each_cpu_mask(i, mask)
+		spitfire_xcall_helper(data0, data1, data2, pstate, i);
 }
 
 /* Cheetah now allows to send the whole 64-bytes of data in the interrupt
@@ -456,25 +450,19 @@
 
 	nack_busy_id = 0;
 	{
-		cpumask_t work_mask = mask;
 		int i;
 
-		for (i = 0; i < NR_CPUS; i++) {
-			if (cpu_isset(i, work_mask)) {
-				u64 target = (i << 14) | 0x70;
-
-				if (!is_jalapeno)
-					target |= (nack_busy_id << 24);
-				__asm__ __volatile__(
-					"stxa	%%g0, [%0] %1\n\t"
-					"membar	#Sync\n\t"
-					: /* no outputs */
-					: "r" (target), "i" (ASI_INTR_W));
-				nack_busy_id++;
- 				cpu_clear(i, work_mask);
-				if (cpus_empty(work_mask))
-					break;
-			}
+		for_each_cpu_mask(i, mask) {
+			u64 target = (i << 14) | 0x70;
+
+			if (!is_jalapeno)
+				target |= (nack_busy_id << 24);
+			__asm__ __volatile__(
+				"stxa	%%g0, [%0] %1\n\t"
+				"membar	#Sync\n\t"
+				: /* no outputs */
+				: "r" (target), "i" (ASI_INTR_W));
+			nack_busy_id++;
 		}
 	}
 
@@ -507,7 +495,6 @@
 			printk("CPU[%d]: mondo stuckage result[%016lx]\n",
 			       smp_processor_id(), dispatch_stat);
 		} else {
-			cpumask_t work_mask = mask;
 			int i, this_busy_nack = 0;
 
 			/* Delay some random time with interrupts enabled
@@ -518,22 +505,17 @@
 			/* Clear out the mask bits for cpus which did not
 			 * NACK us.
 			 */
-			for (i = 0; i < NR_CPUS; i++) {
-				if (cpu_isset(i, work_mask)) {
-					u64 check_mask;
-
-					if (is_jalapeno)
-						check_mask = (0x2UL << (2*i));
-					else
-						check_mask = (0x2UL <<
-							      this_busy_nack);
-					if ((dispatch_stat & check_mask) == 0)
-						cpu_clear(i, mask);
-					this_busy_nack += 2;
-					cpu_clear(i, work_mask);
-					if (cpus_empty(work_mask))
-						break;
-				}
+			for_each_cpu_mask(i, mask) {
+				u64 check_mask;
+
+				if (is_jalapeno)
+					check_mask = (0x2UL << (2*i));
+				else
+					check_mask = (0x2UL <<
+						      this_busy_nack);
+				if ((dispatch_stat & check_mask) == 0)
+					cpu_clear(i, mask);
+				this_busy_nack += 2;
 			}
 
 			goto retry;
--- diff/arch/sparc64/kernel/sparc64_ksyms.c	2004-06-11 19:17:27.000000000 +0100
+++ source/arch/sparc64/kernel/sparc64_ksyms.c	2004-06-11 19:22:00.000000000 +0100
@@ -24,6 +24,7 @@
 #include <linux/socket.h>
 #include <linux/syscalls.h>
 #include <linux/percpu.h>
+#include <linux/init.h>
 #include <net/compat.h>
 
 #include <asm/oplib.h>
@@ -76,7 +77,6 @@
 extern int __strncmp(const char *, const char *, __kernel_size_t);
 extern __kernel_size_t __strlen(const char *);
 extern __kernel_size_t strlen(const char *);
-extern char saved_command_line[];
 extern void linux_sparc_syscall(void);
 extern void rtrap(void);
 extern void show_regs(struct pt_regs *);
--- diff/arch/sparc64/lib/rwlock.S	2004-05-19 22:11:25.000000000 +0100
+++ source/arch/sparc64/lib/rwlock.S	2004-06-11 19:22:00.000000000 +0100
@@ -85,5 +85,20 @@
 __write_trylock_fail:
 	retl
 	 mov		0, %o0
+
+	.globl	__read_trylock
+__read_trylock: /* %o0 = lock_ptr */
+	ldsw		[%o0], %g5
+	brlz,pn		%g5, 100f
+	add		%g5, 1, %g7
+	cas		[%o0], %g5, %g7
+	cmp		%g5, %g7
+	bne,pn		%icc, __read_trylock
+	 membar		#StoreLoad | #StoreStore
+	retl
+	mov		1, %o0
+100:	retl
+	mov		0, %o0
+
 rwlock_impl_end:
 
--- diff/arch/um/kernel/init_task.c	2004-05-19 22:11:27.000000000 +0100
+++ source/arch/um/kernel/init_task.c	2004-06-11 19:22:00.000000000 +0100
@@ -9,6 +9,7 @@
 #include "linux/sched.h"
 #include "linux/init_task.h"
 #include "linux/version.h"
+#include "linux/mqueue.h"
 #include "asm/uaccess.h"
 #include "asm/pgtable.h"
 #include "user_util.h"
--- diff/arch/um/kernel/user_util.c	2004-05-19 22:11:27.000000000 +0100
+++ source/arch/um/kernel/user_util.c	2004-06-11 19:22:00.000000000 +0100
@@ -34,7 +34,6 @@
 #define COMMAND_LINE_SIZE _POSIX_ARG_MAX
 
 /* Changed in linux_main and setup_arch, which run before SMP is started */
-char saved_command_line[COMMAND_LINE_SIZE] = { 0 };
 char command_line[COMMAND_LINE_SIZE] = { 0 };
 
 void add_arg(char *cmd_line, char *arg)
--- diff/arch/v850/kernel/init_task.c	2004-05-19 22:11:28.000000000 +0100
+++ source/arch/v850/kernel/init_task.c	2004-06-11 19:22:00.000000000 +0100
@@ -15,6 +15,7 @@
 #include <linux/init.h>
 #include <linux/init_task.h>
 #include <linux/fs.h>
+#include <linux/mqueue.h>
 
 #include <asm/uaccess.h>
 #include <asm/pgtable.h>
--- diff/arch/v850/kernel/setup.c	2004-05-19 22:11:28.000000000 +0100
+++ source/arch/v850/kernel/setup.c	2004-06-11 19:22:00.000000000 +0100
@@ -20,6 +20,7 @@
 #include <linux/major.h>
 #include <linux/root_dev.h>
 #include <linux/mtd/mtd.h>
+#include <linux/init.h>
 
 #include <asm/irq.h>
 
@@ -40,8 +41,7 @@
 extern char _root_fs_image_end __attribute__ ((__weak__));
 
 
-char command_line[512];
-char saved_command_line[512];
+char command_line[COMMAND_LINE_SIZE];
 
 /* Memory not used by the kernel.  */
 static unsigned long total_ram_pages;
--- diff/arch/x86_64/Kconfig	2004-06-11 19:17:27.000000000 +0100
+++ source/arch/x86_64/Kconfig	2004-06-11 19:22:00.000000000 +0100
@@ -318,6 +318,8 @@
 	bool
 	default y
 
+source "drivers/perfctr/Kconfig"
+
 endmenu
 
 
@@ -455,12 +457,26 @@
 config DEBUG_INFO
 	bool "Compile the kernel with debug info"
 	depends on DEBUG_KERNEL
+	default n
 	help
           If you say Y here the resulting kernel image will include
 	  debugging info resulting in a larger kernel image.
 	  Say Y here only if you plan to use gdb to debug the kernel.
 	  Please note that this option requires new binutils.
 	  If you don't debug the kernel, you can say N.
+
+config SCHEDSTATS
+	bool "Collect scheduler statistics"
+	depends on PROC_FS
+	default n
+	help
+	  If you say Y here, additional code will be inserted into the
+	  scheduler and related routines to collect statistics about
+	  scheduler behavior and provide them in /proc/schedstat.  These
+	  stats may be useful for both tuning and debugging the scheduler
+	  If you aren't debugging the scheduler or trying to tune a specific
+	  application, you can say N to avoid the very slight overhead
+	  this adds.
 	  
 config FRAME_POINTER
        bool "Compile the kernel with frame pointers"
@@ -493,9 +509,8 @@
        help
          Add a simple leak tracer to the IOMMU code. This is useful when you
 	 are debugging a buggy device driver that leaks IOMMU mappings.
-       
-#config X86_REMOTE_DEBUG
-#       bool "kgdb debugging stub"
+
+source "arch/x86_64/Kconfig.kgdb"
 
 endmenu
 
--- diff/arch/x86_64/ia32/ia32entry.S	2004-06-11 19:17:27.000000000 +0100
+++ source/arch/x86_64/ia32/ia32entry.S	2004-06-11 19:22:00.000000000 +0100
@@ -589,6 +589,12 @@
 	.quad compat_sys_mq_notify
 	.quad compat_sys_mq_getsetattr
 	.quad quiet_ni_syscall		/* reserved for kexec */
+	.quad sys_perfctr_info
+	.quad sys_vperfctr_open
+	.quad sys_vperfctr_control
+	.quad sys_vperfctr_unlink
+	.quad sys_vperfctr_iresume
+	.quad sys_vperfctr_read
 	/* don't forget to change IA32_NR_syscalls */
 ia32_syscall_end:		
 	.rept IA32_NR_syscalls-(ia32_syscall_end-ia32_sys_call_table)/8
--- diff/arch/x86_64/kernel/Makefile	2004-06-11 19:17:27.000000000 +0100
+++ source/arch/x86_64/kernel/Makefile	2004-06-11 19:22:00.000000000 +0100
@@ -28,6 +28,7 @@
 obj-$(CONFIG_SCHED_SMT)		+= domain.o
 
 obj-$(CONFIG_MODULES)		+= module.o
+obj-$(CONFIG_KGDB)		+= kgdb_stub.o
 
 obj-y				+= topology.o
 
--- diff/arch/x86_64/kernel/e820.c	2004-05-19 22:11:28.000000000 +0100
+++ source/arch/x86_64/kernel/e820.c	2004-06-11 19:22:00.000000000 +0100
@@ -34,7 +34,7 @@
  */
 unsigned long end_user_pfn = MAXMEM>>PAGE_SHIFT;  
 
-extern struct resource code_resource, data_resource, vram_resource;
+extern struct resource code_resource, data_resource;
 
 /* Check for some hardcoded bad areas that early boot is not allowed to touch */ 
 static inline int bad_addr(unsigned long *addrp, unsigned long size)
--- diff/arch/x86_64/kernel/entry.S	2004-05-19 22:11:28.000000000 +0100
+++ source/arch/x86_64/kernel/entry.S	2004-06-11 19:22:00.000000000 +0100
@@ -557,6 +557,11 @@
 	apicinterrupt SPURIOUS_APIC_VECTOR,smp_spurious_interrupt
 #endif
 				
+#if defined(CONFIG_X86_LOCAL_APIC) && defined(CONFIG_PERFCTR)
+ENTRY(perfctr_interrupt)
+	apicinterrupt LOCAL_PERFCTR_VECTOR,smp_perfctr_interrupt
+#endif
+
 /*
  * Exception entry points.
  */ 		
--- diff/arch/x86_64/kernel/i8259.c	2004-05-19 22:11:28.000000000 +0100
+++ source/arch/x86_64/kernel/i8259.c	2004-06-11 19:22:00.000000000 +0100
@@ -24,6 +24,7 @@
 #include <asm/delay.h>
 #include <asm/desc.h>
 #include <asm/apic.h>
+#include <asm/perfctr.h>
 
 #include <linux/irq.h>
 
@@ -47,6 +48,12 @@
 	BI(x,8) BI(x,9) BI(x,a) BI(x,b) \
 	BI(x,c) BI(x,d) BI(x,e) BI(x,f)
 
+#define BUILD_14_IRQS(x) \
+	BI(x,0) BI(x,1) BI(x,2) BI(x,3) \
+	BI(x,4) BI(x,5) BI(x,6) BI(x,7) \
+	BI(x,8) BI(x,9) BI(x,a) BI(x,b) \
+	BI(x,c) BI(x,d)
+
 /*
  * ISA PIC or low IO-APIC triggered (INTA-cycle or APIC) interrupts:
  * (these are usually mapped to vectors 0x20-0x2f)
@@ -68,9 +75,15 @@
 BUILD_16_IRQS(0x4) BUILD_16_IRQS(0x5) BUILD_16_IRQS(0x6) BUILD_16_IRQS(0x7)
 BUILD_16_IRQS(0x8) BUILD_16_IRQS(0x9) BUILD_16_IRQS(0xa) BUILD_16_IRQS(0xb)
 BUILD_16_IRQS(0xc) BUILD_16_IRQS(0xd)
+
+#ifdef CONFIG_PCI_USE_VECTOR
+	BUILD_14_IRQS(0xe)
+#endif
+
 #endif
 
 #undef BUILD_16_IRQS
+#undef BUILD_14_IRQS
 #undef BI
 
 
@@ -83,6 +96,12 @@
 	IRQ(x,8), IRQ(x,9), IRQ(x,a), IRQ(x,b), \
 	IRQ(x,c), IRQ(x,d), IRQ(x,e), IRQ(x,f)
 
+#define IRQLIST_14(x) \
+	IRQ(x,0), IRQ(x,1), IRQ(x,2), IRQ(x,3), \
+	IRQ(x,4), IRQ(x,5), IRQ(x,6), IRQ(x,7), \
+	IRQ(x,8), IRQ(x,9), IRQ(x,a), IRQ(x,b), \
+	IRQ(x,c), IRQ(x,d)
+
 void (*interrupt[NR_IRQS])(void) = {
 	IRQLIST_16(0x0),
 
@@ -91,11 +110,17 @@
 	IRQLIST_16(0x4), IRQLIST_16(0x5), IRQLIST_16(0x6), IRQLIST_16(0x7),
 	IRQLIST_16(0x8), IRQLIST_16(0x9), IRQLIST_16(0xa), IRQLIST_16(0xb),
 	IRQLIST_16(0xc), IRQLIST_16(0xd)
+
+#ifdef CONFIG_PCI_USE_VECTOR
+	, IRQLIST_14(0xe)
+#endif
+
 #endif
 };
 
 #undef IRQ
 #undef IRQLIST_16
+#undef IRQLIST_14
 
 /*
  * This is the 'legacy' 8259A Programmable Interrupt Controller,
@@ -485,6 +510,8 @@
 	set_intr_gate(ERROR_APIC_VECTOR, error_interrupt);
 #endif
 
+	perfctr_vector_init();
+
 	/*
 	 * Set the clock to HZ Hz, we already have a valid
 	 * vector now:
--- diff/arch/x86_64/kernel/init_task.c	2004-05-19 22:11:28.000000000 +0100
+++ source/arch/x86_64/kernel/init_task.c	2004-06-11 19:22:00.000000000 +0100
@@ -4,6 +4,7 @@
 #include <linux/init.h>
 #include <linux/init_task.h>
 #include <linux/fs.h>
+#include <linux/mqueue.h>
 
 #include <asm/uaccess.h>
 #include <asm/pgtable.h>
--- diff/arch/x86_64/kernel/io_apic.c	2004-06-11 19:17:27.000000000 +0100
+++ source/arch/x86_64/kernel/io_apic.c	2004-06-11 19:22:00.000000000 +0100
@@ -67,8 +67,8 @@
 	short apic, pin, next;
 } irq_2_pin[PIN_MAP_SIZE];
 
+int vector_irq[NR_VECTORS] = { [0 ... NR_VECTORS - 1] = -1};
 #ifdef CONFIG_PCI_USE_VECTOR
-int vector_irq[NR_IRQS] = { [0 ... NR_IRQS -1] = -1};
 #define vector_to_irq(vector) 	\
 	(platform_legacy_irq(vector) ? vector : vector_irq[vector])
 #else
@@ -655,10 +655,14 @@
 /* irq_vectors is indexed by the sum of all RTEs in all I/O APICs. */
 u8 irq_vector[NR_IRQ_VECTORS] = { FIRST_DEVICE_VECTOR , 0 };
 
-#ifndef CONFIG_PCI_USE_VECTOR
+#ifdef CONFIG_PCI_USE_VECTOR
+int assign_irq_vector(int irq)
+#else
 int __init assign_irq_vector(int irq)
+#endif
 {
 	static int current_vector = FIRST_DEVICE_VECTOR, offset = 0;
+
 	BUG_ON(irq >= NR_IRQ_VECTORS);
 	if (IO_APIC_VECTOR(irq) > 0)
 		return IO_APIC_VECTOR(irq);
@@ -667,18 +671,19 @@
 	if (current_vector == IA32_SYSCALL_VECTOR)
 		goto next;
 
-	if (current_vector > FIRST_SYSTEM_VECTOR) {
+	if (current_vector >= FIRST_SYSTEM_VECTOR) {
 		offset++;
+		if (!(offset%8))
+			return -ENOSPC;
 		current_vector = FIRST_DEVICE_VECTOR + offset;
 	}
 
-	if (current_vector == FIRST_SYSTEM_VECTOR)
-		panic("ran out of interrupt sources!");
+	vector_irq[current_vector] = irq;
+	if (irq != AUTO_ASSIGN)
+		IO_APIC_VECTOR(irq) = current_vector;
 
-	IO_APIC_VECTOR(irq) = current_vector;
 	return current_vector;
 }
-#endif
 
 extern void (*interrupt[NR_IRQS])(void);
 static struct hw_interrupt_type ioapic_level_type;
@@ -924,12 +929,17 @@
 		);
 	}
 	}
+	if (use_pci_vector())
+		printk(KERN_INFO "Using vector-based indexing\n");
 	printk(KERN_DEBUG "IRQ to pin mappings:\n");
 	for (i = 0; i < NR_IRQS; i++) {
 		struct irq_pin_list *entry = irq_2_pin + i;
 		if (entry->pin < 0)
 			continue;
-		printk(KERN_DEBUG "IRQ%d ", i);
+ 		if (use_pci_vector() && !platform_legacy_irq(i))
+			printk(KERN_DEBUG "IRQ%d ", IO_APIC_VECTOR(i));
+		else
+			printk(KERN_DEBUG "IRQ%d ", i);
 		for (;;) {
 			printk("-> %d:%d", entry->apic, entry->pin);
 			if (!entry->next)
@@ -1383,7 +1393,7 @@
 	unsigned long flags;
 	unsigned int dest;
 
-	dest = cpu_mask_to_apicid(mk_cpumask_const(mask));
+	dest = cpu_mask_to_apicid(mask);
 
 	/*
 	 * Only the first 8 bits are valid.
--- diff/arch/x86_64/kernel/irq.c	2004-06-11 19:17:27.000000000 +0100
+++ source/arch/x86_64/kernel/irq.c	2004-06-11 19:22:00.000000000 +0100
@@ -405,6 +405,9 @@
 	spin_unlock(&desc->lock);
 
 	irq_exit();
+
+	kgdb_process_breakpoint();
+
 	return 1;
 }
 
--- diff/arch/x86_64/kernel/module.c	2004-05-19 22:11:28.000000000 +0100
+++ source/arch/x86_64/kernel/module.c	2004-06-11 19:22:00.000000000 +0100
@@ -121,7 +121,7 @@
 			goto fail;
 	}
 	
-	if (map_vm_area(area, PAGE_KERNEL_EXECUTABLE, &pages))
+	if (map_vm_area(area, PAGE_KERNEL_EXEC, &pages))
 		goto fail;
 	
 	memset(addr, 0, size);
--- diff/arch/x86_64/kernel/mpparse.c	2004-06-11 19:17:27.000000000 +0100
+++ source/arch/x86_64/kernel/mpparse.c	2004-06-11 19:22:00.000000000 +0100
@@ -888,91 +888,54 @@
 	return;
 }
 
-
-extern FADT_DESCRIPTOR acpi_fadt;
-
-#ifdef CONFIG_ACPI_PCI
-
-void __init mp_parse_prt (void)
+void mp_register_gsi (u32 gsi, int edge_level, int active_high_low)
 {
-	struct list_head	*node = NULL;
-	struct acpi_prt_entry	*entry = NULL;
 	int			ioapic = -1;
 	int			ioapic_pin = 0;
-	int			gsi = 0;
 	int			idx, bit = 0;
-	int			edge_level = 0;
-	int			active_high_low = 0;
 
-	/*
-	 * Parsing through the PCI Interrupt Routing Table (PRT) and program
-	 * routing for all static (IOAPIC-direct) entries.
-	 */
-	list_for_each(node, &acpi_prt.entries) {
-		entry = list_entry(node, struct acpi_prt_entry, node);
+	if (acpi_irq_model != ACPI_IRQ_MODEL_IOAPIC)
+		return;
 
-		/* Need to get gsi for dynamic entry */
-		if (entry->link.handle) {
-			gsi = acpi_pci_link_get_irq(entry->link.handle, entry->link.index, &edge_level, &active_high_low);
-			if (!gsi)
-				continue;
-		} else {
-			/* Hardwired GSI. Assume PCI standard settings */
-			gsi = entry->link.index;
-			edge_level = 1;
-			active_high_low = 1;
-		}
-
-		/* Don't set up the ACPI SCI because it's already set up */
-		if (acpi_fadt.sci_int == gsi) {
-			/* we still need to set up the entry's irq */
-			acpi_gsi_to_irq(gsi, &entry->irq);
-			continue;
-		}
-
-		ioapic = mp_find_ioapic(gsi);
-		if (ioapic < 0)
-			continue;
-		ioapic_pin = gsi - mp_ioapic_routing[ioapic].gsi_start;
-
-		/* 
-		 * Avoid pin reprogramming.  PRTs typically include entries  
-		 * with redundant pin->gsi mappings (but unique PCI devices);
-		 * we only only program the IOAPIC on the first.
-		 */
-		bit = ioapic_pin % 32;
-		idx = (ioapic_pin < 32) ? 0 : (ioapic_pin / 32);
-		if (idx > 3) {
-			printk(KERN_ERR "Invalid reference to IOAPIC pin "
-				"%d-%d\n", mp_ioapic_routing[ioapic].apic_id, 
-				ioapic_pin);
-			continue;
-		}
-		if ((1<<bit) & mp_ioapic_routing[ioapic].pin_programmed[idx]) {
-			Dprintk(KERN_DEBUG "Pin %d-%d already programmed\n",
-				mp_ioapic_routing[ioapic].apic_id, ioapic_pin);
-			acpi_gsi_to_irq(gsi, &entry->irq);
-			continue;
-		}
-
-		mp_ioapic_routing[ioapic].pin_programmed[idx] |= (1<<bit);
-		if (!io_apic_set_pci_routing(ioapic, ioapic_pin, gsi, edge_level, active_high_low)) {
-			acpi_gsi_to_irq(gsi, &entry->irq);
- 		}
-		printk(KERN_DEBUG "%02x:%02x:%02x[%c] -> %d-%d -> IRQ %d\n",
-			entry->id.segment, entry->id.bus,
-			entry->id.device, ('A' + entry->pin), 
-			mp_ioapic_routing[ioapic].apic_id, ioapic_pin,
-			entry->irq);
+#ifdef CONFIG_ACPI_BUS
+	/* Don't set up the ACPI SCI because it's already set up */
+	if (acpi_fadt.sci_int == gsi)
+		return;
+#endif
+
+	ioapic = mp_find_ioapic(gsi);
+	if (ioapic < 0) {
+		printk(KERN_WARNING "No IOAPIC for GSI %u\n", gsi);
+		return;
 	}
-	
-	print_IO_APIC();
 
-	return;
-}
+	ioapic_pin = gsi - mp_ioapic_routing[ioapic].gsi_start;
 
-#endif /*CONFIG_ACPI_PCI*/
+	/* 
+	 * Avoid pin reprogramming.  PRTs typically include entries  
+	 * with redundant pin->gsi mappings (but unique PCI devices);
+	 * we only program the IOAPIC on the first.
+	 */
+	bit = ioapic_pin % 32;
+	idx = (ioapic_pin < 32) ? 0 : (ioapic_pin / 32);
+	if (idx > 3) {
+		printk(KERN_ERR "Invalid reference to IOAPIC pin "
+			"%d-%d\n", mp_ioapic_routing[ioapic].apic_id, 
+			ioapic_pin);
+		return;
+	}
+	if ((1<<bit) & mp_ioapic_routing[ioapic].pin_programmed[idx]) {
+		Dprintk(KERN_DEBUG "Pin %d-%d already programmed\n",
+			mp_ioapic_routing[ioapic].apic_id, ioapic_pin);
+		return;
+	}
 
-#endif /*CONFIG_X86_IO_APIC*/
+	mp_ioapic_routing[ioapic].pin_programmed[idx] |= (1<<bit);
 
+	io_apic_set_pci_routing(ioapic, ioapic_pin, gsi,
+		edge_level == ACPI_EDGE_SENSITIVE ? 0 : 1,
+		active_high_low == ACPI_ACTIVE_HIGH ? 0 : 1);
+}
+
+#endif /*CONFIG_X86_IO_APIC*/
 #endif /*CONFIG_ACPI_BOOT*/
--- diff/arch/x86_64/kernel/pci-gart.c	2004-06-11 19:17:27.000000000 +0100
+++ source/arch/x86_64/kernel/pci-gart.c	2004-06-11 19:22:00.000000000 +0100
@@ -148,7 +148,7 @@
 { 
 	unsigned long flags;
 	int bus = dev ? dev->bus->number : -1;
-	cpumask_const_t bus_cpumask = pcibus_to_cpumask(bus);
+	cpumask_t bus_cpumask = pcibus_to_cpumask(bus);
 	int flushed = 0;
 	int i;
 
@@ -158,7 +158,7 @@
 			u32 w;
 			if (!northbridges[i]) 
 				continue;
-			if (bus >= 0 && !(cpu_isset_const(i, bus_cpumask)))
+			if (bus >= 0 && !(cpu_isset(i, bus_cpumask)))
 				continue;
 			pci_write_config_dword(northbridges[i], 0x9c, 
 					       northbridge_flush_word[i] | 1); 
--- diff/arch/x86_64/kernel/process.c	2004-06-11 19:17:27.000000000 +0100
+++ source/arch/x86_64/kernel/process.c	2004-06-11 19:22:00.000000000 +0100
@@ -32,6 +32,7 @@
 #include <linux/delay.h>
 #include <linux/irq.h>
 #include <linux/ptrace.h>
+#include <linux/perfctr.h>
 #include <linux/version.h>
 
 #include <asm/uaccess.h>
@@ -262,6 +263,7 @@
 		tss->io_bitmap_base = INVALID_IO_BITMAP_OFFSET;
 		put_cpu();
 	}
+	perfctr_exit_thread(&me->thread);
 }
 
 void flush_thread(void)
@@ -365,6 +367,8 @@
 	asm("movl %%es,%0" : "=m" (p->thread.es));
 	asm("movl %%ds,%0" : "=m" (p->thread.ds));
 
+	perfctr_copy_thread(&p->thread);
+
 	if (unlikely(me->thread.io_bitmap_ptr != NULL)) { 
 		p->thread.io_bitmap_ptr = kmalloc(IO_BITMAP_BYTES, GFP_KERNEL);
 		if (!p->thread.io_bitmap_ptr) 
@@ -411,6 +415,8 @@
 	int cpu = smp_processor_id();  
 	struct tss_struct *tss = init_tss + cpu;
 
+	perfctr_suspend_thread(prev);
+
 	unlazy_fpu(prev_p);
 
 	/*
@@ -514,6 +520,8 @@
 		}
 	}
 
+	perfctr_resume_thread(next);
+
 	return prev_p;
 }
 
--- diff/arch/x86_64/kernel/setup.c	2004-06-11 19:17:27.000000000 +0100
+++ source/arch/x86_64/kernel/setup.c	2004-06-11 19:22:00.000000000 +0100
@@ -100,7 +100,6 @@
 extern char _text, _etext, _edata, _end;
 
 char command_line[COMMAND_LINE_SIZE];
-char saved_command_line[COMMAND_LINE_SIZE];
 
 struct resource standard_io_resources[] = {
 	{ "dma1", 0x00, 0x1f, IORESOURCE_BUSY | IORESOURCE_IO },
@@ -116,9 +115,10 @@
 #define STANDARD_IO_RESOURCES \
 	(sizeof standard_io_resources / sizeof standard_io_resources[0])
 
-struct resource code_resource = { "Kernel code", 0x100000, 0, IORESOURCE_MEM };
-struct resource data_resource = { "Kernel data", 0, 0, IORESOURCE_MEM };
-struct resource vram_resource = { "Video RAM area", 0xa0000, 0xbffff, IORESOURCE_BUSY | IORESOURCE_MEM };
+#define IORESOURCE_RAM (IORESOURCE_BUSY | IORESOURCE_MEM)
+
+struct resource data_resource = { "Kernel data", 0, 0, IORESOURCE_RAM };
+struct resource code_resource = { "Kernel code", 0, 0, IORESOURCE_RAM };
 
 #define IORESOURCE_ROM (IORESOURCE_BUSY | IORESOURCE_READONLY | IORESOURCE_MEM)
 
@@ -138,10 +138,11 @@
 	(sizeof adapter_rom_resources / sizeof adapter_rom_resources[0])
 
 static struct resource video_rom_resource = { "Video ROM", 0xc0000, 0xc7fff, IORESOURCE_ROM };
+static struct resource video_ram_resource = { "Video RAM area", 0xa0000, 0xbffff, IORESOURCE_RAM };
 
 #define romsignature(x) (*(unsigned short *)(x) == 0xaa55)
 
-static int __init checksum(unsigned char *rom, unsigned long length)
+static int __init romchecksum(unsigned char *rom, unsigned long length)
 {
 	unsigned char *p, sum = 0;
 
@@ -169,7 +170,7 @@
 		length = rom[2] * 512;
 
 		/* if checksum okay, trust length byte */
-		if (length && checksum(rom, length))
+		if (length && romchecksum(rom, length))
 			video_rom_resource.end = start + length - 1;
 
 		request_resource(&iomem_resource, &video_rom_resource);
@@ -188,7 +189,7 @@
 	rom = isa_bus_to_virt(extension_rom_resource.start);
 	if (romsignature(rom)) {
 		length = extension_rom_resource.end - extension_rom_resource.start + 1;
-		if (checksum(rom, length)) {
+		if (romchecksum(rom, length)) {
 			request_resource(&iomem_resource, &extension_rom_resource);
 			upper = extension_rom_resource.start;
 		}
@@ -204,7 +205,7 @@
 		length = rom[2] * 512;
 
 		/* but accept any length that fits if checksum okay */
-		if (!length || start + length > upper || !checksum(rom, length))
+		if (!length || start + length > upper || !romchecksum(rom, length))
 			continue;
 
 		adapter_rom_resources[i].start = start;
@@ -555,13 +556,13 @@
 	probe_roms();
 	e820_reserve_resources(); 
 
-	request_resource(&iomem_resource, &vram_resource);
+	request_resource(&iomem_resource, &video_ram_resource);
 
 	{
 	unsigned i;
 	/* request I/O space for devices used on all i[345]86 PCs */
 	for (i = 0; i < STANDARD_IO_RESOURCES; i++)
-		request_resource(&ioport_resource, standard_io_resources+i);
+		request_resource(&ioport_resource, &standard_io_resources[i]);
 	}
 
 	/* Will likely break when you have unassigned resources with more
--- diff/arch/x86_64/kernel/smp.c	2004-06-11 19:17:27.000000000 +0100
+++ source/arch/x86_64/kernel/smp.c	2004-06-11 19:22:00.000000000 +0100
@@ -94,7 +94,7 @@
 
 static inline void send_IPI_mask(cpumask_t cpumask, int vector)
 {
-	unsigned long mask = cpus_coerce(cpumask);
+	unsigned long mask = cpus_addr(cpumask)[0];
 	unsigned long cfg;
 	unsigned long flags;
 
@@ -362,6 +362,18 @@
 	send_IPI_mask(cpumask_of_cpu(cpu), RESCHEDULE_VECTOR);
 }
 
+#ifdef CONFIG_KGDB
+/*
+ * By using the NMI code instead of a vector we just sneak thru the
+ * word generator coming out with just what we want.  AND it does
+ * not matter if clustered_apic_mode is set or not.
+ */
+void smp_send_nmi_allbutself(void)
+{
+	send_IPI_allbutself(APIC_DM_NMI);
+}
+#endif
+
 /*
  * Structure and data for smp_call_function(). This is designed to minimise
  * static memory requirements. It also looks cleaner.
--- diff/arch/x86_64/kernel/smpboot.c	2004-06-11 19:17:27.000000000 +0100
+++ source/arch/x86_64/kernel/smpboot.c	2004-06-11 19:22:00.000000000 +0100
@@ -827,7 +827,7 @@
 		if (apicid == boot_cpu_id || (apicid == BAD_APICID))
 			continue;
 
-		if (!cpu_isset(apicid, phys_cpu_present_map))
+		if (!physid_isset(apicid, phys_cpu_present_map))
 			continue;
 		if ((max_cpus >= 0) && (max_cpus <= cpucount+1))
 			continue;
--- diff/arch/x86_64/kernel/traps.c	2004-06-11 19:17:27.000000000 +0100
+++ source/arch/x86_64/kernel/traps.c	2004-06-11 19:22:00.000000000 +0100
@@ -45,6 +45,9 @@
 #include <asm/proto.h>
 
 #include <linux/irq.h>
+#ifdef CONFIG_KGDB
+#include <asm/kgdb.h>
+#endif
 
 extern struct gate_struct idt_table[256]; 
 
--- diff/arch/x86_64/lib/Makefile	2004-06-11 19:17:27.000000000 +0100
+++ source/arch/x86_64/lib/Makefile	2004-06-11 19:22:00.000000000 +0100
@@ -12,3 +12,4 @@
 lib-y += memcpy.o memmove.o memset.o copy_user.o
 
 lib-$(CONFIG_HAVE_DEC_LOCK) += dec_and_lock.o
+lib-$(CONFIG_KGDB) += kgdb_serial.o
--- diff/arch/x86_64/mm/pageattr.c	2004-06-11 19:17:27.000000000 +0100
+++ source/arch/x86_64/mm/pageattr.c	2004-06-11 19:22:00.000000000 +0100
@@ -180,7 +180,7 @@
 			unsigned long addr2;
 			addr2 = __START_KERNEL_map + page_to_phys(page);
 			err = __change_page_attr(addr2, page, prot, 
-						 PAGE_KERNEL_EXECUTABLE);
+						 PAGE_KERNEL_EXEC);
 		} 
 	} 	
 	up_write(&init_mm.mmap_sem); 
--- diff/drivers/Makefile	2004-05-19 22:11:29.000000000 +0100
+++ source/drivers/Makefile	2004-06-11 19:22:01.000000000 +0100
@@ -49,4 +49,5 @@
 obj-$(CONFIG_MCA)		+= mca/
 obj-$(CONFIG_EISA)		+= eisa/
 obj-$(CONFIG_CPU_FREQ)		+= cpufreq/
+obj-$(CONFIG_PERFCTR)		+= perfctr/
 obj-y				+= firmware/
--- diff/drivers/acpi/Kconfig	2004-05-19 22:11:29.000000000 +0100
+++ source/drivers/acpi/Kconfig	2004-06-11 19:22:01.000000000 +0100
@@ -267,7 +267,7 @@
 	  (TSC) timing source.
 
 	  So, if you see messages like 'Losing too many ticks!' in the
-	  kernel logs, and/or you are using a this on a notebook which
+	  kernel logs, and/or you are using this on a notebook which
 	  does not yet have an HPET, you should say "Y" here.
 
 endmenu
--- diff/drivers/acpi/pci_irq.c	2004-05-19 22:11:29.000000000 +0100
+++ source/drivers/acpi/pci_irq.c	2004-06-11 19:22:01.000000000 +0100
@@ -35,12 +35,6 @@
 #include <linux/pm.h>
 #include <linux/pci.h>
 #include <linux/acpi.h>
-#ifdef CONFIG_X86_IO_APIC
-#include <asm/mpspec.h>
-#endif
-#ifdef CONFIG_IOSAPIC
-# include <asm/iosapic.h>
-#endif
 #include <acpi/acpi_bus.h>
 #include <acpi/acpi_drivers.h>
 
@@ -50,10 +44,6 @@
 
 struct acpi_prt_list		acpi_prt;
 
-#ifdef CONFIG_X86
-extern void eisa_set_level_irq(unsigned int irq);
-#endif
-
 
 /* --------------------------------------------------------------------------
                          PCI IRQ Routing Table (PRT) Support
@@ -237,12 +227,18 @@
                           PCI Interrupt Routing Support
    -------------------------------------------------------------------------- */
 
-int
-acpi_pci_irq_lookup (struct pci_bus *bus, int device, int pin)
+static int
+acpi_pci_irq_lookup (
+	struct pci_bus		*bus,
+	int			device,
+	int			pin,
+	int			*edge_level,
+	int			*active_high_low)
 {
 	struct acpi_prt_entry	*entry = NULL;
 	int segment = pci_domain_nr(bus);
 	int bus_nr = bus->number;
+	int irq;
 
 	ACPI_FUNCTION_TRACE("acpi_pci_irq_lookup");
 
@@ -255,28 +251,30 @@
 		ACPI_DEBUG_PRINT((ACPI_DB_INFO, "PRT entry not found\n"));
 		return_VALUE(0);
 	}
-
-	if (!entry->irq && entry->link.handle) {
-		entry->irq = acpi_pci_link_get_irq(entry->link.handle, entry->link.index, NULL, NULL);
-		if (!entry->irq) {
+	
+	if (entry->link.handle) {
+		irq = acpi_pci_link_get_irq(entry->link.handle, entry->link.index, edge_level, active_high_low);
+		if (!irq) {
 			ACPI_DEBUG_PRINT((ACPI_DB_WARN, "Invalid IRQ link routing entry\n"));
 			return_VALUE(0);
 		}
-	}
-	else if (!entry->irq) {
-		ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Invalid static routing entry (IRQ 0)\n"));
-		return_VALUE(0);
+	} else {
+		irq = entry->link.index;
+		*edge_level = ACPI_LEVEL_SENSITIVE;
+		*active_high_low = ACPI_ACTIVE_LOW;
 	}
 
-	ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Found IRQ %d\n", entry->irq));
+	ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Found IRQ %d\n", irq));
 
-	return_VALUE(entry->irq);
+	return_VALUE(irq);
 }
 
 static int
 acpi_pci_irq_derive (
 	struct pci_dev		*dev,
-	int			pin)
+	int			pin,
+	int			*edge_level,
+	int			*active_high_low)
 {
 	struct pci_dev		*bridge = dev;
 	int			irq = 0;
@@ -308,8 +306,8 @@
 			pin = bridge_pin;
 		}
 
-		irq = acpi_pci_irq_lookup(bridge->bus,
-				PCI_SLOT(bridge->devfn), pin);
+		irq = acpi_pci_irq_lookup(bridge->bus, PCI_SLOT(bridge->devfn),
+			pin, edge_level, active_high_low);
 	}
 
 	if (!irq) {
@@ -330,6 +328,8 @@
 {
 	int			irq = 0;
 	u8			pin = 0;
+	int			edge_level = ACPI_LEVEL_SENSITIVE;
+	int			active_high_low = ACPI_ACTIVE_LOW;
 
 	ACPI_FUNCTION_TRACE("acpi_pci_irq_enable");
 
@@ -352,21 +352,22 @@
 	 * First we check the PCI IRQ routing table (PRT) for an IRQ.  PRT
 	 * values override any BIOS-assigned IRQs set during boot.
 	 */
- 	irq = acpi_pci_irq_lookup(dev->bus, PCI_SLOT(dev->devfn), pin);
+ 	irq = acpi_pci_irq_lookup(dev->bus, PCI_SLOT(dev->devfn), pin, &edge_level, &active_high_low);
 
 	/*
 	 * If no PRT entry was found, we'll try to derive an IRQ from the
 	 * device's parent bridge.
 	 */
 	if (!irq)
- 		irq = acpi_pci_irq_derive(dev, pin);
+ 		irq = acpi_pci_irq_derive(dev, pin, &edge_level, &active_high_low);
  
 	/*
 	 * No IRQ known to the ACPI subsystem - maybe the BIOS / 
 	 * driver reported one, then use it. Exit in any case.
 	 */
 	if (!irq) {
-		printk(KERN_WARNING PREFIX "No IRQ known for interrupt pin %c of device %s", ('A' + pin), pci_name(dev));
+		printk(KERN_WARNING PREFIX "PCI interrupt %s[%c]: no GSI",
+			pci_name(dev), ('A' + pin));
 		/* Interrupt Line values above 0xF are forbidden */
 		if (dev->irq && (dev->irq <= 0xF)) {
 			printk(" - using IRQ %d\n", dev->irq);
@@ -378,62 +379,14 @@
 		}
  	}
 
-	dev->irq = irq;
+	dev->irq = acpi_register_gsi(irq, edge_level, active_high_low);
 
-	ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Device %s using IRQ %d\n", pci_name(dev), dev->irq));
-
-	/* 
-	 * Make sure all (legacy) PCI IRQs are set as level-triggered.
-	 */
-#ifdef CONFIG_X86
-	{
-		static u16 irq_mask;
-		if ((dev->irq < 16) &&  !((1 << dev->irq) & irq_mask)) {
-			ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Setting IRQ %d as level-triggered\n", dev->irq));
-			irq_mask |= (1 << dev->irq);
-			eisa_set_level_irq(dev->irq);
-		}
-	}
-#endif
-#ifdef CONFIG_IOSAPIC
-	if (acpi_irq_model == ACPI_IRQ_MODEL_IOSAPIC)
-		iosapic_enable_intr(dev->irq);
-#endif
+	printk(KERN_INFO PREFIX "PCI interrupt %s[%c] -> GSI %u "
+		"(%s, %s) -> IRQ %d\n",
+		pci_name(dev), 'A' + pin, irq,
+		(edge_level == ACPI_LEVEL_SENSITIVE) ? "level" : "edge",
+		(active_high_low == ACPI_ACTIVE_LOW) ? "low" : "high",
+		dev->irq);
 
 	return_VALUE(dev->irq);
 }
-
-
-int __init
-acpi_pci_irq_init (void)
-{
-	struct pci_dev          *dev = NULL;
-
-	ACPI_FUNCTION_TRACE("acpi_pci_irq_init");
-
-	if (!acpi_prt.count) {
-		printk(KERN_WARNING PREFIX "ACPI tables contain no PCI IRQ "
-			"routing entries\n");
-		return_VALUE(-ENODEV);
-	}
-
-	/* Make sure all link devices have a valid IRQ. */
-	if (acpi_pci_link_check()) {
-		return_VALUE(-ENODEV);
-	}
-
-#ifdef CONFIG_X86_IO_APIC
-	/* Program IOAPICs using data from PRT entries. */
-	if (acpi_irq_model == ACPI_IRQ_MODEL_IOAPIC)
-		mp_parse_prt();
-#endif
-#ifdef CONFIG_IOSAPIC
-	if (acpi_irq_model == ACPI_IRQ_MODEL_IOSAPIC)
-		iosapic_parse_prt();
-#endif
-
-	while ((dev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL)
-		acpi_pci_irq_enable(dev);
-
-	return_VALUE(0);
-}
--- diff/drivers/acpi/pci_link.c	2004-06-11 19:17:27.000000000 +0100
+++ source/drivers/acpi/pci_link.c	2004-06-11 19:22:01.000000000 +0100
@@ -487,13 +487,13 @@
 };
 
 int
-acpi_pci_link_check (void)
+acpi_irq_penalty_init(void)
 {
 	struct list_head	*node = NULL;
 	struct acpi_pci_link    *link = NULL;
 	int			i = 0;
 
-	ACPI_FUNCTION_TRACE("acpi_pci_link_check");
+	ACPI_FUNCTION_TRACE("acpi_irq_penalty_init");
 
 	/*
 	 * Update penalties to facilitate IRQ balancing.
--- diff/drivers/acpi/tables.c	2004-06-11 19:17:27.000000000 +0100
+++ source/drivers/acpi/tables.c	2004-06-11 19:22:01.000000000 +0100
@@ -131,7 +131,7 @@
 	{
 		struct acpi_table_ioapic *p =
 			(struct acpi_table_ioapic*) header;
-		printk(KERN_INFO PREFIX "IOAPIC (id[0x%02x] address[0x%08x] global_irq_base[0x%x])\n",
+		printk(KERN_INFO PREFIX "IOAPIC (id[0x%02x] address[0x%08x] gsi_base[%d])\n",
 			p->id, p->address, p->global_irq_base);
 	}
 		break;
@@ -185,8 +185,8 @@
 	{
 		struct acpi_table_iosapic *p =
 			(struct acpi_table_iosapic*) header;
-		printk(KERN_INFO PREFIX "IOSAPIC (id[0x%x] global_irq_base[0x%x] address[%p])\n",
-			p->id, p->global_irq_base, (void *) (unsigned long) p->address);
+		printk(KERN_INFO PREFIX "IOSAPIC (id[0x%x] address[%p] gsi_base[%d])\n",
+			p->id, (void *) (unsigned long) p->address, p->global_irq_base);
 	}
 		break;
 
--- diff/drivers/atm/ambassador.c	2004-06-11 19:17:27.000000000 +0100
+++ source/drivers/atm/ambassador.c	2004-06-11 19:22:01.000000000 +0100
@@ -2215,7 +2215,7 @@
     
   } /* amb_reset */
   
-  return -1;
+  return -EINVAL;
 }
 
 static void setup_dev(amb_dev *dev, struct pci_dev *pci_dev) 
@@ -2257,27 +2257,31 @@
 	spin_lock_init (&dev->rxq[pool].lock);
 }
 
-static void setup_pci_dev(struct pci_dev *pci_dev)
+static int setup_pci_dev(struct pci_dev *pci_dev)
 {
-      unsigned char lat;
+	unsigned char lat;
+	int ret;
       
-      /* XXX check return value */
-      pci_enable_device(pci_dev);
-
-      // enable bus master accesses
-      pci_set_master(pci_dev);
+	// enable bus master accesses
+	pci_set_master(pci_dev);
       
-      // frobnicate latency (upwards, usually)
-      pci_read_config_byte (pci_dev, PCI_LATENCY_TIMER, &lat);
-      if (pci_lat) {
-	PRINTD (DBG_INIT, "%s PCI latency timer from %hu to %hu",
-		"changing", lat, pci_lat);
-	pci_write_config_byte (pci_dev, PCI_LATENCY_TIMER, pci_lat);
-      } else if (lat < MIN_PCI_LATENCY) {
-	PRINTK (KERN_INFO, "%s PCI latency timer from %hu to %hu",
-		"increasing", lat, MIN_PCI_LATENCY);
-	pci_write_config_byte (pci_dev, PCI_LATENCY_TIMER, MIN_PCI_LATENCY);
-      }
+	ret = pci_enable_device(pci_dev);
+	if (ret < 0)
+		goto out;
+
+	// frobnicate latency (upwards, usually)
+	pci_read_config_byte (pci_dev, PCI_LATENCY_TIMER, &lat);
+
+	if (!pci_lat)
+		pci_lat = (lat < MIN_PCI_LATENCY) ? MIN_PCI_LATENCY : lat;
+
+	if (lat != pci_lat) {
+		PRINTK (KERN_INFO, "Changing PCI latency timer from %hu to %hu",
+			lat, pci_lat);
+		pci_write_config_byte(pci_dev, PCI_LATENCY_TIMER, pci_lat);
+	}
+out:
+	return ret;
 }
 
 static int __init do_pci_device(struct pci_dev *pci_dev)
@@ -2294,40 +2298,43 @@
 		" IO %x, IRQ %u, MEM %p", iobase, irq, membase);
 
 	// check IO region
-	if (!request_region (iobase, AMB_EXTENT, DEV_LABEL)) {
+	err = pci_request_region(pci_dev, 1, DEV_LABEL);
+	if (err < 0) {
 		PRINTK (KERN_ERR, "IO range already in use!");
-		return -EBUSY;
+		goto out;
 	}
 
 	dev = kmalloc (sizeof(amb_dev), GFP_KERNEL);
 	if (!dev) {
 		PRINTK (KERN_ERR, "out of memory!");
 		err = -ENOMEM;
-		goto out;
+		goto out_release;
 	}
 
 	setup_dev(dev, pci_dev);
 
-	if (amb_init (dev)) {
+	err = amb_init(dev);
+	if (err < 0) {
 		PRINTK (KERN_ERR, "adapter initialisation failure");
-		err = -EINVAL;
-		goto out1;
+		goto out_free;
 	}
 
-	setup_pci_dev(pci_dev);
+	err = setup_pci_dev(pci_dev);
+	if (err < 0)
+		goto out_reset;
 
 	// grab (but share) IRQ and install handler
-	if (request_irq (irq, interrupt_handler, SA_SHIRQ, DEV_LABEL, dev)) {
+	err = request_irq(irq, interrupt_handler, SA_SHIRQ, DEV_LABEL, dev);
+	if (err < 0) {
 		PRINTK (KERN_ERR, "request IRQ failed!");
-		err = -EBUSY;
-		goto out2;
+		goto out_disable;
 	}
 
 	dev->atm_dev = atm_dev_register (DEV_LABEL, &amb_ops, -1, NULL);
 	if (!dev->atm_dev) {
 		PRINTD (DBG_ERR, "failed to register Madge ATM adapter");
 		err = -EINVAL;
-		goto out3;
+		goto out_free_irq;
 	}
 
 	PRINTD (DBG_INFO, "registered Madge ATM adapter (no. %d) (%p) at %p",
@@ -2348,17 +2355,20 @@
 	// enable host interrupts
 	interrupts_on (dev);
 
-	return 0;
-
-out3:
-	free_irq (irq, dev);
-out2:
-	amb_reset (dev, 0);
-out1:
-	kfree (dev);
 out:
-	release_region (iobase, AMB_EXTENT);
 	return err;
+
+out_free_irq:
+	free_irq(irq, dev);
+out_disable:
+	pci_disable_device(pci_dev);
+out_reset:
+	amb_reset(dev, 0);
+out_free:
+	kfree(dev);
+out_release:
+	pci_release_region(pci_dev, 1);
+	goto out;
 }
 
 static int __init amb_probe (void) {
@@ -2488,7 +2498,10 @@
   del_timer_sync(&housekeeping);
   
   while (amb_devs) {
+    struct pci_dev *pdev;
+
     dev = amb_devs;
+    pdev = dev->pci_dev;
     amb_devs = dev->prev;
     
     PRINTD (DBG_INFO|DBG_INIT, "closing %p (atm_dev = %p)", dev, dev->atm_dev);
@@ -2496,11 +2509,12 @@
     drain_rx_pools (dev);
     interrupts_off (dev);
     amb_reset (dev, 0);
+    free_irq (dev->irq, dev);
+    pci_disable_device (pdev);
     destroy_queues (dev);
     atm_dev_deregister (dev->atm_dev);
-    free_irq (dev->irq, dev);
-    release_region (dev->iobase, AMB_EXTENT);
     kfree (dev);
+    pci_release_region (pdev, 1);
   }
   
   return;
--- diff/drivers/atm/firestream.c	2004-06-11 19:17:27.000000000 +0100
+++ source/drivers/atm/firestream.c	2004-06-11 19:22:01.000000000 +0100
@@ -576,7 +576,7 @@
 }
 
 
-static inline u32  read_fs (struct fs_dev *dev, int offset)
+static inline u32 read_fs (struct fs_dev *dev, int offset)
 {
 	return readl (dev->base + offset);
 }
@@ -1380,7 +1380,7 @@
 
 	if (alignment <= 0x10) {
 		t = kmalloc (size, flags);
-		if ((unsigned int)t & (alignment-1)) {
+		if ((unsigned long)t & (alignment-1)) {
 			printk ("Kmalloc doesn't align things correctly! %p\n", t);
 			kfree (t);
 			return aligned_kmalloc (size, flags, alignment * 4);
@@ -1496,7 +1496,7 @@
 		ne->skb = skb;
 		ne->fp = fp;
 
-		qe = (struct FS_BPENTRY *) (read_fs (dev, FP_EA(fp->offset)));
+		qe = (struct FS_BPENTRY *)(long)(read_fs (dev, FP_EA(fp->offset)));
 		fs_dprintk (FS_DEBUG_QUEUE, "link at %p\n", qe);
 		if (qe) {
 			qe = bus_to_virt ((long) qe);
--- diff/drivers/base/bus.c	2004-06-11 19:17:27.000000000 +0100
+++ source/drivers/base/bus.c	2004-06-11 19:22:01.000000000 +0100
@@ -392,6 +392,38 @@
 	
 }
 
+static int device_add_attrs(struct bus_type * bus, struct device * dev)
+{
+	int error = 0;
+	int i;
+
+	if (bus->dev_attrs) {
+		for (i = 0; attr_name(bus->dev_attrs[i]); i++) {
+			error = device_create_file(dev,&bus->dev_attrs[i]);
+			if (error)
+				goto Err;
+		}
+	}
+ Done:
+	return error;
+ Err:
+	while (--i >= 0)
+		device_remove_file(dev,&bus->dev_attrs[i]);
+	goto Done;
+}
+
+
+static void device_remove_attrs(struct bus_type * bus, struct device * dev)
+{
+	int i;
+	
+	if (bus->dev_attrs) {
+		for (i = 0; attr_name(bus->dev_attrs[i]); i++)
+			device_remove_file(dev,&bus->dev_attrs[i]);
+	}
+}
+
+
 /**
  *	bus_add_device - add device to bus
  *	@dev:	device being added
@@ -411,6 +443,7 @@
 		list_add_tail(&dev->bus_list,&dev->bus->devices.list);
 		device_attach(dev);
 		up_write(&dev->bus->subsys.rwsem);
+		device_add_attrs(bus,dev);
 		sysfs_create_link(&bus->devices.kobj,&dev->kobj,dev->bus_id);
 	}
 	return error;
@@ -429,6 +462,7 @@
 {
 	if (dev->bus) {
 		sysfs_remove_link(&dev->bus->devices.kobj,dev->bus_id);
+		device_remove_attrs(dev->bus,dev);
 		down_write(&dev->bus->subsys.rwsem);
 		pr_debug("bus %s: remove device %s\n",dev->bus->name,dev->bus_id);
 		device_release_driver(dev);
@@ -549,6 +583,41 @@
 	return k ? to_bus(k) : NULL;
 }
 
+
+/**
+ *	bus_add_attrs - Add default attributes for this bus.
+ *	@bus:	Bus that has just been registered.
+ */
+
+static int bus_add_attrs(struct bus_type * bus)
+{
+	int error = 0;
+	int i;
+
+	if (bus->bus_attrs) {
+		for (i = 0; attr_name(bus->bus_attrs[i]); i++) {
+			if ((error = bus_create_file(bus,&bus->bus_attrs[i])))
+				goto Err;
+		}
+	}
+ Done:
+	return error;
+ Err:
+	while (--i >= 0)
+		bus_remove_file(bus,&bus->bus_attrs[i]);
+	goto Done;
+}
+
+static void bus_remove_attrs(struct bus_type * bus)
+{
+	int i;
+	
+	if (bus->bus_attrs) {
+		for (i = 0; attr_name(bus->bus_attrs[i]); i++)
+			bus_remove_file(bus,&bus->bus_attrs[i]);
+	}
+}
+
 /**
  *	bus_register - register a bus with the system.
  *	@bus:	bus.
@@ -582,6 +651,7 @@
 	retval = kset_register(&bus->drivers);
 	if (retval)
 		goto bus_drivers_fail;
+	bus_add_attrs(bus);
 
 	pr_debug("bus type '%s' registered\n",bus->name);
 	return 0;
@@ -605,6 +675,7 @@
 void bus_unregister(struct bus_type * bus)
 {
 	pr_debug("bus %s: unregistering\n",bus->name);
+	bus_remove_attrs(bus);
 	kset_unregister(&bus->drivers);
 	kset_unregister(&bus->devices);
 	subsystem_unregister(&bus->subsys);
--- diff/drivers/base/class.c	2004-06-11 19:17:27.000000000 +0100
+++ source/drivers/base/class.c	2004-06-11 19:22:01.000000000 +0100
@@ -100,6 +100,37 @@
 	subsys_put(&cls->subsys);
 }
 
+
+static int add_class_attrs(struct class * cls)
+{
+	int i;
+	int error = 0;
+
+	if (cls->class_attrs) {
+		for (i = 0; attr_name(cls->class_attrs[i]); i++) {
+			error = class_create_file(cls,&cls->class_attrs[i]);
+			if (error)
+				goto Err;
+		}
+	}
+ Done:
+	return error;
+ Err:
+	while (--i >= 0)
+		class_remove_file(cls,&cls->class_attrs[i]);
+	goto Done;
+}
+
+static void remove_class_attrs(struct class * cls)
+{
+	int i;
+
+	if (cls->class_attrs) {
+		for (i = 0; attr_name(cls->class_attrs[i]); i++)
+			class_remove_file(cls,&cls->class_attrs[i]);
+	}
+}
+
 int class_register(struct class * cls)
 {
 	int error;
@@ -115,18 +146,21 @@
 	subsys_set_kset(cls,class_subsys);
 
 	error = subsystem_register(&cls->subsys);
-	if (error)
-		return error;
-
-	return 0;
+	if (!error) {
+		error = add_class_attrs(class_get(cls));
+		class_put(cls);
+	}
+	return error;
 }
 
 void class_unregister(struct class * cls)
 {
 	pr_debug("device class '%s': unregistering\n",cls->name);
+	remove_class_attrs(cls);
 	subsystem_unregister(&cls->subsys);
 }
 
+
 /* Class Device Stuff */
 
 int class_device_create_file(struct class_device * class_dev,
@@ -272,6 +306,40 @@
 
 static decl_subsys(class_obj, &ktype_class_device, &class_hotplug_ops);
 
+
+static int class_device_add_attrs(struct class_device * cd)
+{
+	int i;
+	int error = 0;
+	struct class * cls = cd->class;
+
+	if (cls->class_dev_attrs) {
+		for (i = 0; attr_name(cls->class_dev_attrs[i]); i++) {
+			error = class_device_create_file(cd,
+							 &cls->class_dev_attrs[i]);
+			if (error)
+				goto Err;
+		}
+	}
+ Done:
+	return error;
+ Err:
+	while (--i >= 0)
+		class_device_remove_file(cd,&cls->class_dev_attrs[i]);
+	goto Done;
+}
+
+static void class_device_remove_attrs(struct class_device * cd)
+{
+	int i;
+	struct class * cls = cd->class;
+
+	if (cls->class_dev_attrs) {
+		for (i = 0; attr_name(cls->class_dev_attrs[i]); i++)
+			class_device_remove_file(cd,&cls->class_dev_attrs[i]);
+	}
+}
+
 void class_device_initialize(struct class_device *class_dev)
 {
 	kobj_set_kset_s(class_dev, class_obj_subsys);
@@ -311,7 +379,7 @@
 				class_intf->add(class_dev);
 		up_write(&parent->subsys.rwsem);
 	}
-
+	class_device_add_attrs(class_dev);
 	class_device_dev_link(class_dev);
 	class_device_driver_link(class_dev);
 
@@ -344,7 +412,8 @@
 
 	class_device_dev_unlink(class_dev);
 	class_device_driver_unlink(class_dev);
-	
+	class_device_remove_attrs(class_dev);
+
 	kobject_del(&class_dev->kobj);
 
 	if (parent)
--- diff/drivers/base/core.c	2004-05-19 22:11:32.000000000 +0100
+++ source/drivers/base/core.c	2004-06-11 19:22:01.000000000 +0100
@@ -245,7 +245,7 @@
  BusError:
 	device_pm_remove(dev);
  PMError:
-	kobject_unregister(&dev->kobj);
+	kobject_del(&dev->kobj);
  Error:
 	if (parent)
 		put_device(parent);
--- diff/drivers/base/platform.c	2004-06-11 19:17:27.000000000 +0100
+++ source/drivers/base/platform.c	2004-06-11 19:22:01.000000000 +0100
@@ -19,6 +19,90 @@
 };
 
 /**
+ *	platform_get_resource - get a resource for a device
+ *	@dev: platform device
+ *	@type: resource type
+ *	@num: resource index
+ */
+struct resource *
+platform_get_resource(struct platform_device *dev, unsigned int type,
+		      unsigned int num)
+{
+	int i;
+
+	for (i = 0; i < dev->num_resources; i++) {
+		struct resource *r = &dev->resource[i];
+
+		if ((r->flags & (IORESOURCE_IO|IORESOURCE_MEM|
+				 IORESOURCE_IRQ|IORESOURCE_DMA))
+		    == type)
+			if (num-- == 0)
+				return r;
+	}
+	return NULL;
+}
+
+/**
+ *	platform_get_irq - get an IRQ for a device
+ *	@dev: platform device
+ *	@num: IRQ number index
+ */
+int platform_get_irq(struct platform_device *dev, unsigned int num)
+{
+	struct resource *r = platform_get_resource(dev, IORESOURCE_IRQ, num);
+
+	return r ? r->start : 0;
+}
+
+/**
+ *	platform_add_device - add one platform device
+ *	@dev: platform device
+ *
+ *	Adds one platform device, claiming the memory resources
+ */
+int platform_add_device(struct platform_device *dev)
+{
+	int i;
+
+	for (i = 0; i < dev->num_resources; i++) {
+		struct resource *p, *r = &dev->resource[i];
+
+		r->name = dev->dev.bus_id;
+
+		p = NULL;
+		if (r->flags & IORESOURCE_MEM)
+			p = &iomem_resource;
+		else if (r->flags & IORESOURCE_IO)
+			p = &ioport_resource;
+
+		if (p && request_resource(p, r)) {
+			printk(KERN_ERR
+			       "%s%d: failed to claim resource %d\n",
+			       dev->name, dev->id, i);
+			break;
+		}
+	}
+	if (i == dev->num_resources)
+		platform_device_register(dev);
+	return 0;
+}
+
+/**
+ *	platform_add_devices - add a numbers of platform devices
+ *	@devs: array of platform devices to add
+ *	@num: number of platform devices in array
+ */
+int platform_add_devices(struct platform_device **devs, int num)
+{
+	int i;
+
+	for (i = 0; i < num; i++)
+		platform_add_device(devs[i]);
+
+	return 0;
+}
+
+/**
  *	platform_device_register - add a platform-level device
  *	@dev:	platform device we're adding
  *
@@ -114,3 +198,5 @@
 EXPORT_SYMBOL(platform_bus_type);
 EXPORT_SYMBOL(platform_device_register);
 EXPORT_SYMBOL(platform_device_unregister);
+EXPORT_SYMBOL(platform_get_irq);
+EXPORT_SYMBOL(platform_get_resource);
--- diff/drivers/block/Kconfig	2004-06-11 19:17:27.000000000 +0100
+++ source/drivers/block/Kconfig	2004-06-11 19:22:01.000000000 +0100
@@ -6,7 +6,7 @@
 
 config BLK_DEV_FD
 	tristate "Normal floppy disk support"
-	depends on (!X86_PC9800 && !ARCH_S390 && !M68K && !IA64) || Q40 || (SUN3X && BROKEN)
+	depends on (!ARCH_S390 && !M68K && !IA64) || Q40 || (SUN3X && BROKEN)
 	---help---
 	  If you want to use the floppy disk drive(s) of your PC under Linux,
 	  say Y. Information about this driver, especially important for IBM
@@ -26,13 +26,6 @@
 	tristate "Atari floppy support"
 	depends on ATARI
 
-config BLK_DEV_FD98
-	tristate "NEC PC-9800 floppy disk support"
-	depends on X86_PC9800
-	---help---
-	  If you want to use the floppy disk drive(s) of NEC PC-9801/PC-9821,
-	  say Y.
-
 config BLK_DEV_SWIM_IOP
 	bool "Macintosh IIfx/Quadra 900/Quadra 950 floppy support (EXPERIMENTAL)"
 	depends on MAC && EXPERIMENTAL && BROKEN
--- diff/drivers/block/cciss.c	2004-06-11 19:17:27.000000000 +0100
+++ source/drivers/block/cciss.c	2004-06-11 19:22:01.000000000 +0100
@@ -479,6 +479,148 @@
 	return 0;
 }
 
+#ifdef CONFIG_COMPAT
+/* for AMD 64 bit kernel compatibility with 32-bit userland ioctls */
+extern long sys_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg);
+extern int
+register_ioctl32_conversion(unsigned int cmd, int (*handler)(unsigned int,
+      unsigned int, unsigned long, struct file *));
+extern int unregister_ioctl32_conversion(unsigned int cmd);
+
+static int cciss_ioctl32_passthru(unsigned int fd, unsigned cmd, unsigned long arg, struct file *file);
+static int cciss_ioctl32_big_passthru(unsigned int fd, unsigned cmd, unsigned long arg,
+	struct file *file);
+
+typedef int (*handler_type) (unsigned int, unsigned int, unsigned long, struct file *);
+
+static struct ioctl32_map {
+	unsigned int cmd;
+	handler_type handler;
+	int registered;
+} cciss_ioctl32_map[] = {
+	{ CCISS_GETPCIINFO,	(handler_type) sys_ioctl, 0 },
+	{ CCISS_GETINTINFO,	(handler_type) sys_ioctl, 0 },
+	{ CCISS_SETINTINFO,	(handler_type) sys_ioctl, 0 },
+	{ CCISS_GETNODENAME,	(handler_type) sys_ioctl, 0 },
+	{ CCISS_SETNODENAME,	(handler_type) sys_ioctl, 0 },
+	{ CCISS_GETHEARTBEAT,	(handler_type) sys_ioctl, 0 },
+	{ CCISS_GETBUSTYPES,	(handler_type) sys_ioctl, 0 },
+	{ CCISS_GETFIRMVER,	(handler_type) sys_ioctl, 0 },
+	{ CCISS_GETDRIVVER,	(handler_type) sys_ioctl, 0 },
+	{ CCISS_REVALIDVOLS,	(handler_type) sys_ioctl, 0 },
+	{ CCISS_PASSTHRU32,	cciss_ioctl32_passthru, 0 },
+	{ CCISS_DEREGDISK,	(handler_type) sys_ioctl, 0 },
+	{ CCISS_REGNEWDISK,	(handler_type) sys_ioctl, 0 },
+	{ CCISS_REGNEWD,	(handler_type) sys_ioctl, 0 },
+	{ CCISS_RESCANDISK,	(handler_type) sys_ioctl, 0 },
+	{ CCISS_GETLUNINFO,	(handler_type) sys_ioctl, 0 },
+	{ CCISS_BIG_PASSTHRU32,	cciss_ioctl32_big_passthru, 0 },
+};
+#define NCCISS_IOCTL32_ENTRIES (sizeof(cciss_ioctl32_map) / sizeof(cciss_ioctl32_map[0]))
+static void register_cciss_ioctl32(void)
+{
+	int i, rc;
+
+	for (i=0; i < NCCISS_IOCTL32_ENTRIES; i++) {
+		rc = register_ioctl32_conversion(
+			cciss_ioctl32_map[i].cmd,
+			cciss_ioctl32_map[i].handler);
+		if (rc != 0) {
+			printk(KERN_WARNING "cciss: failed to register "
+				"32 bit compatible ioctl 0x%08x\n",
+				cciss_ioctl32_map[i].cmd);
+			cciss_ioctl32_map[i].registered = 0;
+		} else
+			cciss_ioctl32_map[i].registered = 1;
+	}
+}
+static void unregister_cciss_ioctl32(void)
+{
+	int i, rc;
+
+	for (i=0; i < NCCISS_IOCTL32_ENTRIES; i++) {
+		if (!cciss_ioctl32_map[i].registered)
+			continue;
+		rc = unregister_ioctl32_conversion(
+			cciss_ioctl32_map[i].cmd);
+		if (rc == 0) {
+			cciss_ioctl32_map[i].registered = 0;
+			continue;
+		}
+		printk(KERN_WARNING "cciss: failed to unregister "
+			"32 bit compatible ioctl 0x%08x\n",
+			cciss_ioctl32_map[i].cmd);
+	}
+}
+int cciss_ioctl32_passthru(unsigned int fd, unsigned cmd, unsigned long arg,
+	struct file *file)
+{
+	IOCTL32_Command_struct *arg32 =
+		(IOCTL32_Command_struct *) arg;
+	IOCTL_Command_struct arg64;
+	mm_segment_t old_fs;
+	int err;
+	unsigned long cp;
+
+	err = 0;
+	err |= copy_from_user(&arg64.LUN_info, &arg32->LUN_info, sizeof(arg64.LUN_info));
+	err |= copy_from_user(&arg64.Request, &arg32->Request, sizeof(arg64.Request));
+	err |= copy_from_user(&arg64.error_info, &arg32->error_info, sizeof(arg64.error_info));
+	err |= get_user(arg64.buf_size, &arg32->buf_size);
+	err |= get_user(cp, &arg32->buf);
+	arg64.buf = (BYTE *)cp;
+
+	if (err)
+		return -EFAULT;
+
+	old_fs = get_fs();
+	set_fs(KERNEL_DS);
+	err = sys_ioctl(fd, CCISS_PASSTHRU, (unsigned long) &arg64);
+	set_fs(old_fs);
+	if (err)
+		return err;
+	err |= copy_to_user(&arg32->error_info, &arg64.error_info, sizeof(&arg32->error_info));
+	if (err)
+		return -EFAULT;
+	return err;
+}
+int cciss_ioctl32_big_passthru(unsigned int fd, unsigned cmd, unsigned long arg,
+	struct file *file)
+{
+	BIG_IOCTL32_Command_struct *arg32 =
+		(BIG_IOCTL32_Command_struct *) arg;
+	BIG_IOCTL_Command_struct arg64;
+	mm_segment_t old_fs;
+	int err;
+	unsigned long cp;
+
+	err = 0;
+	err |= copy_from_user(&arg64.LUN_info, &arg32->LUN_info, sizeof(arg64.LUN_info));
+	err |= copy_from_user(&arg64.Request, &arg32->Request, sizeof(arg64.Request));
+	err |= copy_from_user(&arg64.error_info, &arg32->error_info, sizeof(arg64.error_info));
+	err |= get_user(arg64.buf_size, &arg32->buf_size);
+	err |= get_user(arg64.malloc_size, &arg32->malloc_size);
+	err |= get_user(cp, &arg32->buf);
+	arg64.buf = (BYTE *)cp;
+
+	if (err)
+		 return -EFAULT;
+
+	old_fs = get_fs();
+	set_fs(KERNEL_DS);
+	err = sys_ioctl(fd, CCISS_BIG_PASSTHRU, (unsigned long) &arg64);
+	set_fs(old_fs);
+	if (err)
+		return err;
+	err |= copy_to_user(&arg32->error_info, &arg64.error_info, sizeof(&arg32->error_info));
+	if (err)
+		return -EFAULT;
+	return err;
+}
+#else
+static inline void register_cciss_ioctl32(void) {}
+static inline void unregister_cciss_ioctl32(void) {}
+#endif
 /*
  * ioctl 
  */
@@ -2728,6 +2870,7 @@
 
 static int __init init_cciss_module(void)
 {
+	register_cciss_ioctl32();
 	return ( cciss_init());
 }
 
@@ -2735,6 +2878,7 @@
 {
 	int i;
 
+	unregister_cciss_ioctl32();
 	pci_unregister_driver(&cciss_pci_driver);
 	/* double check that all controller entrys have been removed */
 	for (i=0; i< MAX_CTLR; i++) 
--- diff/drivers/block/ll_rw_blk.c	2004-06-11 19:17:27.000000000 +0100
+++ source/drivers/block/ll_rw_blk.c	2004-06-11 19:22:01.000000000 +0100
@@ -263,6 +263,45 @@
 EXPORT_SYMBOL(blk_queue_make_request);
 
 /**
+ * blk_queue_ordered - does this queue support ordered writes
+ * @q:     the request queue
+ * @flag:  see below
+ *
+ * Description:
+ *   For journalled file systems, doing ordered writes on a commit
+ *   block instead of explicitly doing wait_on_buffer (which is bad
+ *   for performance) can be a big win. Block drivers supporting this
+ *   feature should call this function and indicate so.
+ *
+ **/
+void blk_queue_ordered(request_queue_t *q, int flag)
+{
+	if (flag)
+		set_bit(QUEUE_FLAG_ORDERED, &q->queue_flags);
+	else
+		clear_bit(QUEUE_FLAG_ORDERED, &q->queue_flags);
+}
+
+EXPORT_SYMBOL(blk_queue_ordered);
+
+/**
+ * blk_queue_issue_flush_fn - set function for issuing a flush
+ * @q:     the request queue
+ * @iff:   the function to be called issuing the flush
+ *
+ * Description:
+ *   If a driver supports issuing a flush command, the support is notified
+ *   to the block layer by defining it through this call.
+ *
+ **/
+void blk_queue_issue_flush_fn(request_queue_t *q, issue_flush_fn *iff)
+{
+	q->issue_flush_fn = iff;
+}
+
+EXPORT_SYMBOL(blk_queue_issue_flush_fn);
+
+/**
  * blk_queue_bounce_limit - set bounce buffer limit for queue
  * @q:  the request queue for the device
  * @dma_addr:   bus address limit
@@ -1151,6 +1190,7 @@
  **/
 void generic_unplug_device(request_queue_t *q)
 {
+	might_sleep();
 	spin_lock_irq(q->queue_lock);
 	__generic_unplug_device(q);
 	spin_unlock_irq(q->queue_lock);
@@ -1872,10 +1912,11 @@
 	}
 
 	rq->flags |= REQ_NOMERGE;
-	rq->waiting = &wait;
+	if (!rq->waiting)
+		rq->waiting = &wait;
 	elv_add_request(q, rq, ELEVATOR_INSERT_BACK, 1);
 	generic_unplug_device(q);
-	wait_for_completion(&wait);
+	wait_for_completion(rq->waiting);
 	rq->waiting = NULL;
 
 	if (rq->errors)
@@ -1886,6 +1927,72 @@
 
 EXPORT_SYMBOL(blk_execute_rq);
 
+/**
+ * blkdev_issue_flush - queue a flush
+ * @bdev:	blockdev to issue flush for
+ * @error_sector:	error sector
+ *
+ * Description:
+ *    Issue a flush for the block device in question. Caller can supply
+ *    room for storing the error offset in case of a flush error, if they
+ *    wish to.  Caller must run wait_for_completion() on its own.
+ */
+int blkdev_issue_flush(struct block_device *bdev, sector_t *error_sector)
+{
+	request_queue_t *q;
+
+	if (bdev->bd_disk == NULL)
+		return -ENXIO;
+
+	q = bdev_get_queue(bdev);
+	if (!q)
+		return -ENXIO;
+	if (!q->issue_flush_fn)
+		return -EOPNOTSUPP;
+
+	return q->issue_flush_fn(q, bdev->bd_disk, error_sector);
+}
+
+EXPORT_SYMBOL(blkdev_issue_flush);
+
+/**
+ * blkdev_scsi_issue_flush_fn - issue flush for SCSI devices
+ * @q:		device queue
+ * @disk:	gendisk
+ * @error_sector:	error offset
+ *
+ * Description:
+ *    Devices understanding the SCSI command set, can use this function as
+ *    a helper for issuing a cache flush. Note: driver is required to store
+ *    the error offset (in case of error flushing) in ->sector of struct
+ *    request.
+ */
+int blkdev_scsi_issue_flush_fn(request_queue_t *q, struct gendisk *disk,
+			       sector_t *error_sector)
+{
+	struct request *rq = blk_get_request(q, WRITE, __GFP_WAIT);
+	int ret;
+
+	rq->flags |= REQ_BLOCK_PC | REQ_SOFTBARRIER;
+	rq->sector = 0;
+	memset(rq->cmd, 0, sizeof(rq->cmd));
+	rq->cmd[0] = 0x35;
+	rq->cmd_len = 12;
+	rq->data = NULL;
+	rq->data_len = 0;
+	rq->timeout = 60 * HZ;
+
+	ret = blk_execute_rq(q, disk, rq);
+
+	if (ret && error_sector)
+		*error_sector = rq->sector;
+
+	blk_put_request(rq);
+	return ret;
+}
+
+EXPORT_SYMBOL(blkdev_scsi_issue_flush_fn);
+
 void drive_stat_acct(struct request *rq, int nr_sectors, int new_io)
 {
 	int rw = rq_data_dir(rq);
@@ -2139,7 +2246,7 @@
 static int __make_request(request_queue_t *q, struct bio *bio)
 {
 	struct request *req, *freereq = NULL;
-	int el_ret, rw, nr_sectors, cur_nr_sectors, barrier, ra;
+	int el_ret, rw, nr_sectors, cur_nr_sectors, barrier, err;
 	sector_t sector;
 
 	sector = bio->bi_sector;
@@ -2157,9 +2264,11 @@
 
 	spin_lock_prefetch(q->queue_lock);
 
-	barrier = test_bit(BIO_RW_BARRIER, &bio->bi_rw);
-
-	ra = bio->bi_rw & (1 << BIO_RW_AHEAD);
+	barrier = bio_barrier(bio);
+	if (barrier && !(q->queue_flags & (1 << QUEUE_FLAG_ORDERED))) {
+		err = -EOPNOTSUPP;
+		goto end_io;
+	}
 
 again:
 	spin_lock_irq(q->queue_lock);
@@ -2239,7 +2348,8 @@
 			/*
 			 * READA bit set
 			 */
-			if (ra)
+			err = -EWOULDBLOCK;
+			if (bio_rw_ahead(bio))
 				goto end_io;
 	
 			freereq = get_request_wait(q, rw);
@@ -2250,10 +2360,9 @@
 	req->flags |= REQ_CMD;
 
 	/*
-	 * inherit FAILFAST from bio and don't stack up
-	 * retries for read ahead
+	 * inherit FAILFAST from bio (for read-ahead, and explicit FAILFAST)
 	 */
-	if (ra || test_bit(BIO_RW_FAILFAST, &bio->bi_rw))	
+	if (bio_rw_ahead(bio) || bio_failfast(bio))
 		req->flags |= REQ_FAILFAST;
 
 	/*
@@ -2291,7 +2400,7 @@
 	return 0;
 
 end_io:
-	bio_endio(bio, nr_sectors << 9, -EWOULDBLOCK);
+	bio_endio(bio, nr_sectors << 9, err);
 	return 0;
 }
 
@@ -2591,10 +2700,17 @@
 static int __end_that_request_first(struct request *req, int uptodate,
 				    int nr_bytes)
 {
-	int total_bytes, bio_nbytes, error = 0, next_idx = 0;
+	int total_bytes, bio_nbytes, error, next_idx = 0;
 	struct bio *bio;
 
 	/*
+	 * extend uptodate bool to allow < 0 value to be direct io error
+	 */
+	error = 0;
+	if (end_io_error(uptodate))
+		error = !uptodate ? -EIO : uptodate;
+
+	/*
 	 * for a REQ_BLOCK_PC request, we want to carry any eventual
 	 * sense key with us all the way through
 	 */
@@ -2602,7 +2718,6 @@
 		req->errors = 0;
 
 	if (!uptodate) {
-		error = -EIO;
 		if (blk_fs_request(req) && !(req->flags & REQ_QUIET))
 			printk("end_request: I/O error, dev %s, sector %llu\n",
 				req->rq_disk ? req->rq_disk->disk_name : "?",
@@ -2685,7 +2800,7 @@
 /**
  * end_that_request_first - end I/O on a request
  * @req:      the request being processed
- * @uptodate: 0 for I/O error
+ * @uptodate: 1 for success, 0 for I/O error, < 0 for specific error
  * @nr_sectors: number of sectors to end I/O on
  *
  * Description:
@@ -2706,7 +2821,7 @@
 /**
  * end_that_request_chunk - end I/O on a request
  * @req:      the request being processed
- * @uptodate: 0 for I/O error
+ * @uptodate: 1 for success, 0 for I/O error, < 0 for specific error
  * @nr_bytes: number of bytes to complete
  *
  * Description:
--- diff/drivers/block/paride/epat.c	2004-05-19 22:11:33.000000000 +0100
+++ source/drivers/block/paride/epat.c	2004-06-11 19:22:01.000000000 +0100
@@ -31,6 +31,12 @@
 #define j44(a,b)		(((a>>4)&0x0f)+(b&0xf0))
 #define j53(a,b)		(((a>>3)&0x1f)+((b<<4)&0xe0))
 
+static int epatc8;
+
+module_param(epatc8, int, 0);
+MODULE_PARM_DESC(epatc8, "support for the Shuttle EP1284 chip, "
+	"used in any recent Imation SuperDisk (LS-120) drive.");
+
 /* cont =  0   IDE register file
    cont =  1   IDE control registers
    cont =  2   internal EPAT registers
@@ -209,15 +215,18 @@
 {       pi->saved_r0 = r0();
         pi->saved_r2 = r2();
 
-#ifdef CONFIG_PARIDE_EPATC8
  	/* Initialize the chip */
-        CPP(0);CPP(0x40);CPP(0xe0);              
-        w0(0);w2(1);w2(4);
-        WR(0x8,0x12);WR(0xc,0x14);WR(0x12,0x10);
-        WR(0xe,0xf);WR(0xf,4);
-     /* WR(0xe,0xa);WR(0xf,4); */
-        WR(0xe,0xd);WR(0xf,0);
-     /* CPP(0x30); */
+	CPP(0);
+
+	if (epatc8) {
+		CPP(0x40);CPP(0xe0);
+		w0(0);w2(1);w2(4);
+		WR(0x8,0x12);WR(0xc,0x14);WR(0x12,0x10);
+		WR(0xe,0xf);WR(0xf,4);
+		/* WR(0xe,0xa);WR(0xf,4); */
+		WR(0xe,0xd);WR(0xf,0);
+		/* CPP(0x30); */
+	}
 
         /* Connect to the chip */
 	CPP(0xe0);
@@ -227,15 +236,10 @@
           /* Request EPP */
           w0(0x40);w2(6);w2(7);w2(4);w2(0xc);w2(4);
         }
-#else
- 	CPP(0); CPP(0xe0);
-	w0(0); w2(1); w2(4);
-	if (pi->mode >= 3) {
-		w0(0); w2(1); w2(4); w2(0xc);
-		w0(0x40); w2(6); w2(7); w2(4); w2(0xc); w2(4);
+
+	if (!epatc8) {
+		WR(8,0x10); WR(0xc,0x14); WR(0xa,0x38); WR(0x12,0x10);
 	}
-	WR(8,0x10); WR(0xc,0x14); WR(0xa,0x38); WR(0x12,0x10);
-#endif
 }
 
 static void epat_disconnect (PIA *pi)
@@ -320,6 +324,9 @@
 
 static int __init epat_init(void)
 {
+#ifdef CONFIG_PARIDE_EPATC8
+	epatc8 = 1;
+#endif
 	return pi_register(&epat)-1;
 }
 
--- diff/drivers/block/rd.c	2004-06-11 19:17:27.000000000 +0100
+++ source/drivers/block/rd.c	2004-06-11 19:22:01.000000000 +0100
@@ -108,8 +108,21 @@
 		struct buffer_head *head = bh;
 
 		do {
-			if (!buffer_uptodate(bh))
+			if (!buffer_uptodate(bh)) {
 				memset(bh->b_data, 0, bh->b_size);
+				/*
+				 * akpm: I'm totally undecided about this.  The
+				 * buffer has just been magically brought "up to
+				 * date", but nobody should want to be reading
+				 * it anyway, because it hasn't been used for
+				 * anything yet.  It is still in a "not read
+				 * from disk yet" state.
+				 *
+				 * But non-uptodate buffers against an uptodate
+				 * page are against the rules.  So do it anyway.
+				 */
+				 set_buffer_uptodate(bh);
+			}
 		} while ((bh = bh->b_this_page) != head);
 	} else {
 		memset(page_address(page), 0, PAGE_CACHE_SIZE);
--- diff/drivers/cdrom/cdrom.c	2004-06-11 19:17:27.000000000 +0100
+++ source/drivers/cdrom/cdrom.c	2004-06-11 19:22:01.000000000 +0100
@@ -671,28 +671,24 @@
 {
 	struct packet_command cgc;
 	char buffer[16];
-	struct feature_header *fh;
 	__u16 *feature_code;
 	int ret;
 
 	init_cdrom_command(&cgc, buffer, sizeof(buffer), CGC_DATA_READ);
 
-	cgc.cmd[0] = GPCMD_GET_CONFIGURATION;	/* often 0x46 */
-	cgc.cmd[3] = CDF_HWDM;			/* often 0x0024 */
-	cgc.cmd[8] = sizeof(buffer);		/* often 0x10 */
+	cgc.cmd[0] = GPCMD_GET_CONFIGURATION;
+	cgc.cmd[3] = CDF_HWDM;
+	cgc.cmd[8] = sizeof(buffer);
 	cgc.quiet = 1;
 
 	if ((ret = cdi->ops->generic_packet(cdi, &cgc)))
 		return ret;
 
-	fh = (struct feature_header *)&buffer[0];
-	ret = 1;
-	if (be32_to_cpu(fh->data_len) >= (sizeof(struct feature_header)+8)) {
-		feature_code = (__u16 *)&buffer[sizeof(struct feature_header)];
-		if (CDF_HWDM == be16_to_cpu(*feature_code))
-			ret = 0;
-	}
-	return ret;
+	feature_code = (__u16 *) &buffer[sizeof(struct feature_header)];
+	if (be16_to_cpu(*feature_code) == CDF_HWDM)
+		return 0;
+
+	return 1;
 }
 
 
--- diff/drivers/char/Kconfig	2004-06-11 19:17:27.000000000 +0100
+++ source/drivers/char/Kconfig	2004-06-11 19:22:01.000000000 +0100
@@ -586,17 +586,6 @@
 	  console. This driver allows each pSeries partition to have a console
 	  which is accessed via the HMC.
 
-config PC9800_OLDLP
-	tristate "NEC PC-9800 old-style printer port support"
-	depends on X86_PC9800 && !PARPORT
-	---help---
-	  If you intend to attach a printer to the parallel port of NEC PC-9801
-	  /PC-9821 with OLD compatibility mode, Say Y.
-
-config PC9800_OLDLP_CONSOLE
-	bool "Support for console on line printer"
-	depends on PC9800_OLDLP
-
 config QIC02_TAPE
 	tristate "QIC-02 tape support"
 	help
@@ -740,7 +729,7 @@
 
 config RTC
 	tristate "Enhanced Real Time Clock Support"
-	depends on !PPC32 && !PARISC && !IA64 && !X86_PC9800 && !M68K
+	depends on !PPC32 && !PARISC && !IA64 && !M68K
 	---help---
 	  If you say Y here and create a character special file /dev/rtc with
 	  major number 10 and minor number 135 using mknod ("man mknod"), you
@@ -793,15 +782,6 @@
 	bool "EFI Real Time Clock Services"
 	depends on IA64
 
-config RTC98
-	tristate "NEC PC-9800 Real Time Clock Support"
-	depends on X86_PC9800
-	default y
-	---help---
-	  If you say Y here and create a character special file /dev/rtc with
-	  major number 10 and minor number 135 using mknod ("man mknod"), you
-	  will get access to the real time clock (or hardware clock) built
-
 config H8
 	bool "Tadpole ANA H8 Support (OBSOLETE)"
 	depends on OBSOLETE && ALPHA_BOOK1
@@ -957,6 +937,33 @@
           kernels.  Applications should simply open the device (eg /dev/hda1)
           with the O_DIRECT flag.
 
+config HPET
+	bool "HPET - High Precision Event Timer" if (X86 || IA64)
+	default n
+	depends on ACPI
+	help
+	  If you say Y here, you will have a device named "/dev/hpet/XX" for
+	  each timer supported by the HPET.  The timers are
+	  non-periodioc and/or periodic.
+
+config HPET_RTC_IRQ
+	bool "HPET Control RTC IRQ" if !HPET_EMULATE_RTC
+	default n
+	depends on HPET
+	help
+	  If you say Y here, you will disable RTC_IRQ in drivers/char/rtc.c. It
+	  is assumed the platform called hpet_alloc with the RTC IRQ values for
+	  the HPET timers.
+
+config HPET_NOMMAP
+	bool "HPET - Control mmap capability."
+	default n
+	depends on HPET
+	help
+	  If you say Y here, then the mmap interface for the HPET driver returns ENOSYS.
+	  Some hardware implementations might not want all the memory in the page the
+	  HPET control registers reside to be exposed.
+
 config MAX_RAW_DEVS
 	int "Maximum number of RAW devices to support (1-8192)"
 	depends on RAW_DRIVER
--- diff/drivers/char/Makefile	2004-06-11 19:17:27.000000000 +0100
+++ source/drivers/char/Makefile	2004-06-11 19:22:01.000000000 +0100
@@ -47,13 +47,13 @@
 
 obj-$(CONFIG_PRINTER) += lp.o
 obj-$(CONFIG_TIPAR) += tipar.o
-obj-$(CONFIG_PC9800_OLDLP) += lp_old98.o
 
 obj-$(CONFIG_DTLK) += dtlk.o
 obj-$(CONFIG_R3964) += n_r3964.o
 obj-$(CONFIG_APPLICOM) += applicom.o
 obj-$(CONFIG_SONYPI) += sonypi.o
 obj-$(CONFIG_RTC) += rtc.o
+obj-$(CONFIG_HPET) += hpet.o
 obj-$(CONFIG_GEN_RTC) += genrtc.o
 obj-$(CONFIG_EFI_RTC) += efirtc.o
 ifeq ($(CONFIG_GENERIC_NVRAM),y)
--- diff/drivers/char/agp/Kconfig	2004-05-19 22:11:35.000000000 +0100
+++ source/drivers/char/agp/Kconfig	2004-06-11 19:22:01.000000000 +0100
@@ -165,7 +165,7 @@
 	tristate "Transmeta Efficeon support"
 	depends on AGP && X86 && !X86_64
 	help
-	  This option fives you AGP support for the Transmeta Efficeon
+	  This option gives you AGP support for the Transmeta Efficeon
 	  series processors with integrated northbridges.
 
 	  You should say Y here if you use XFree86 3.3.6 or 4.x and want to
--- diff/drivers/char/drm/sis_mm.c	2004-05-19 22:11:36.000000000 +0100
+++ source/drivers/char/drm/sis_mm.c	2004-06-11 19:22:01.000000000 +0100
@@ -113,7 +113,7 @@
 
 	DRM_COPY_TO_USER_IOCTL((drm_sis_mem_t *)data, fb, sizeof(fb));
 
-	DRM_DEBUG("alloc fb, size = %d, offset = %ld\n", fb.size, req.offset);
+	DRM_DEBUG("alloc fb, size = %d, offset = %d\n", fb.size, req.offset);
 
 	return retval;
 }
@@ -130,7 +130,7 @@
 
 	if (!del_alloc_set(fb.context, VIDEO_TYPE, fb.free))
 		retval = DRM_ERR(EINVAL);
-	sis_free(fb.free);
+	sis_free((u32)fb.free);
 
 	DRM_DEBUG("free fb, offset = %lu\n", fb.free);
 
--- diff/drivers/char/keyboard.c	2004-05-19 22:11:34.000000000 +0100
+++ source/drivers/char/keyboard.c	2004-06-11 19:22:01.000000000 +0100
@@ -52,13 +52,12 @@
 
 /*
  * Some laptops take the 789uiojklm,. keys as number pad when NumLock is on.
- * This seems a good reason to start with NumLock off. On PC9800 and HIL keyboards 
+ * This seems a good reason to start with NumLock off. On HIL keyboards
  * of PARISC machines however there is no NumLock key and everyone expects the keypad 
  * to be used for numbers.
  */
 
-#if defined(CONFIG_X86_PC9800) || \
-    defined(CONFIG_PARISC) && (defined(CONFIG_KEYBOARD_HIL) || defined(CONFIG_KEYBOARD_HIL_OLD))
+#if defined(CONFIG_PARISC) && (defined(CONFIG_KEYBOARD_HIL) || defined(CONFIG_KEYBOARD_HIL_OLD))
 #define KBD_DEFLEDS (1 << VC_NUMLOCK)
 #else
 #define KBD_DEFLEDS 0
@@ -942,6 +941,9 @@
 
 #if defined(CONFIG_X86) || defined(CONFIG_IA64) || defined(CONFIG_ALPHA) || defined(CONFIG_MIPS) || defined(CONFIG_PPC) || defined(CONFIG_SPARC32) || defined(CONFIG_SPARC64) || defined(CONFIG_PARISC) || defined(CONFIG_SH_MPC1211)
 
+#define HW_RAW(dev) (test_bit(EV_MSC, dev->evbit) && test_bit(MSC_RAW, dev->mscbit) &&\
+			((dev)->id.bustype == BUS_I8042) && ((dev)->id.vendor == 0x0001) && ((dev)->id.product == 0x0001))
+
 static unsigned short x86_keycodes[256] =
 	{ 0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14, 15,
 	 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
@@ -1008,6 +1010,8 @@
 
 #else
 
+#define HW_RAW(dev)	0
+
 #warning "Cannot generate rawmode keyboard for your architecture yet."
 
 static int emulate_raw(struct vc_data *vc, unsigned int keycode, unsigned char up_flag)
@@ -1020,7 +1024,15 @@
 }
 #endif
 
-void kbd_keycode(unsigned int keycode, int down, struct pt_regs *regs)
+void kbd_rawcode(unsigned char data)
+{
+	struct vc_data *vc = vc_cons[fg_console].d;
+	kbd = kbd_table + fg_console;
+	if (kbd->kbdmode == VC_RAW)
+		put_queue(vc, data);
+}
+
+void kbd_keycode(unsigned int keycode, int down, int hw_raw, struct pt_regs *regs)
 {
 	struct vc_data *vc = vc_cons[fg_console].d;
 	unsigned short keysym, *key_map;
@@ -1054,7 +1066,7 @@
 		return;
 #endif /* CONFIG_MAC_EMUMOUSEBTN */
 
-	if ((raw_mode = (kbd->kbdmode == VC_RAW)))
+	if ((raw_mode = (kbd->kbdmode == VC_RAW)) && !hw_raw)
 		if (emulate_raw(vc, keycode, !down << 7))
 			if (keycode < BTN_MISC)
 				printk(KERN_WARNING "keyboard.c: can't emulate rawmode for keycode %d\n", keycode);
@@ -1066,6 +1078,9 @@
 	}
 	if (sysrq_down && down && !rep) {
 		handle_sysrq(kbd_sysrq_xlate[keycode], regs, tty);
+#ifdef CONFIG_KGDB_SYSRQ
+                sysrq_down = 0;        /* in case we miss the "up" event */
+#endif
 		return;
 	}
 #endif
@@ -1149,11 +1164,12 @@
 }
 
 static void kbd_event(struct input_handle *handle, unsigned int event_type, 
-		      unsigned int keycode, int down)
+		      unsigned int event_code, int value)
 {
-	if (event_type != EV_KEY)
-		return;
-	kbd_keycode(keycode, down, handle->dev->regs);
+	if (event_type == EV_MSC && event_code == MSC_RAW && HW_RAW(handle->dev))
+		kbd_rawcode(value);
+	if (event_type == EV_KEY)
+		kbd_keycode(event_code, value, HW_RAW(handle->dev), handle->dev->regs);
 	tasklet_schedule(&keyboard_tasklet);
 	do_poke_blanked_console = 1;
 	schedule_console_callback();
--- diff/drivers/char/mem.c	2004-06-11 19:17:28.000000000 +0100
+++ source/drivers/char/mem.c	2004-06-11 19:22:01.000000000 +0100
@@ -26,7 +26,6 @@
 
 #include <asm/uaccess.h>
 #include <asm/io.h>
-#include <asm/pgalloc.h>
 
 #ifdef CONFIG_IA64
 # include <linux/efi.h>
@@ -39,6 +38,7 @@
 extern void tapechar_init(void);
 #endif
 
+#ifdef pgprot_noncached
 /*
  * Architectures vary in how they handle caching for addresses
  * outside of main memory.
@@ -77,7 +77,8 @@
 	return 0;
 #elif defined(CONFIG_IA64)
 	/*
-	 * On ia64, we ignore O_SYNC because we cannot tolerate memory attribute aliases.
+	 * On ia64, we ignore O_SYNC because we cannot tolerate memory
+	 * attribute aliases.
 	 */
 	return !(efi_mem_attributes(addr) & EFI_MEMORY_WB);
 #elif defined(CONFIG_PPC64)
@@ -90,14 +91,15 @@
 	return !page_is_ram(addr);
 #else
 	/*
-	 * Accessing memory above the top the kernel knows about or through a file pointer
-	 * that was marked O_SYNC will be done non-cached.
+	 * Accessing memory above the top the kernel knows about or through a
+	 * file pointer that was marked O_SYNC will be done non-cached.
 	 */
 	if (file->f_flags & O_SYNC)
 		return 1;
 	return addr >= __pa(high_memory);
 #endif
 }
+#endif
 
 #ifndef ARCH_HAS_VALID_PHYS_ADDR_RANGE
 static inline int valid_phys_addr_range(unsigned long addr, size_t *count)
@@ -194,28 +196,24 @@
 	return do_write_mem(__va(p), p, buf, count, ppos);
 }
 
-static int mmap_mem(struct file * file, struct vm_area_struct * vma)
+static int mmap_mem(struct file *file, struct vm_area_struct *vma)
 {
 	unsigned long offset = vma->vm_pgoff << PAGE_SHIFT;
-	int uncached;
 
-	uncached = uncached_access(file, offset);
 #ifdef pgprot_noncached
-	if (uncached)
+	if (uncached_access(file, offset))
 		vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
 #endif
 
-	/* Don't try to swap out physical pages.. */
-	vma->vm_flags |= VM_RESERVED;
-
 	/*
-	 * Don't dump addresses that are not real memory to a core file.
+	 * Don't try to swap out physical pages..
+	 * And treat /dev/mem mappings as "IO" regions: they may not
+	 * describe valid pageframes.
 	 */
-	if (uncached)
-		vma->vm_flags |= VM_IO;
+	vma->vm_flags |= VM_RESERVED|VM_IO;
 
-	if (remap_page_range(vma, vma->vm_start, offset, vma->vm_end-vma->vm_start,
-			     vma->vm_page_prot))
+	if (remap_page_range(vma, vma->vm_start, offset,
+			vma->vm_end-vma->vm_start, vma->vm_page_prot))
 		return -EAGAIN;
 	return 0;
 }
--- diff/drivers/char/raw.c	2004-06-11 19:17:28.000000000 +0100
+++ source/drivers/char/raw.c	2004-06-11 19:22:01.000000000 +0100
@@ -18,6 +18,7 @@
 #include <linux/capability.h>
 #include <linux/uio.h>
 #include <linux/cdev.h>
+#include <linux/device.h>
 
 #include <asm/uaccess.h>
 
@@ -26,6 +27,7 @@
 	int inuse;
 };
 
+static struct class_simple *raw_class;
 static struct raw_device_data raw_devices[MAX_RAW_MINORS];
 static DECLARE_MUTEX(raw_mutex);
 static struct file_operations raw_ctl_fops;	     /* forward declaration */
@@ -123,6 +125,13 @@
 	return ioctl_by_bdev(bdev, command, arg);
 }
 
+static void bind_device(struct raw_config_request rq)
+{
+	class_simple_device_remove(MKDEV(RAW_MAJOR, rq.raw_minor));
+	class_simple_device_add(raw_class, MKDEV(RAW_MAJOR, rq.raw_minor),
+				      NULL, "raw%d", rq.raw_minor);
+}
+
 /*
  * Deal with ioctls against the raw-device control interface, to bind
  * and unbind other raw devices.
@@ -191,12 +200,15 @@
 			if (rq.block_major == 0 && rq.block_minor == 0) {
 				/* unbind */
 				rawdev->binding = NULL;
+				class_simple_device_remove(MKDEV(RAW_MAJOR, rq.raw_minor));
 			} else {
 				rawdev->binding = bdget(dev);
 				if (rawdev->binding == NULL)
 					err = -ENOMEM;
-				else
+				else {
 					__module_get(THIS_MODULE);
+					bind_device(rq);
+					}
 			}
 			up(&raw_mutex);
 		} else {
@@ -287,6 +299,15 @@
 		goto error;
 	}
 
+	raw_class = class_simple_create(THIS_MODULE, "raw");
+	if (IS_ERR(raw_class)) {
+		printk(KERN_ERR "Error creating raw class.\n");
+		cdev_del(&raw_cdev);
+		unregister_chrdev_region(dev, MAX_RAW_MINORS);
+		goto error;
+	}
+	class_simple_device_add(raw_class, MKDEV(RAW_MAJOR, 0), NULL, "rawctl");
+
 	devfs_mk_cdev(MKDEV(RAW_MAJOR, 0),
 		      S_IFCHR | S_IRUGO | S_IWUGO,
 		      "raw/rawctl");
@@ -309,6 +330,8 @@
 		devfs_remove("raw/raw%d", i);
 	devfs_remove("raw/rawctl");
 	devfs_remove("raw");
+	class_simple_device_remove(MKDEV(RAW_MAJOR, 0));
+	class_simple_destroy(raw_class);
 	cdev_del(&raw_cdev);
 	unregister_chrdev_region(MKDEV(RAW_MAJOR, 0), MAX_RAW_MINORS);
 }
--- diff/drivers/char/rtc.c	2004-06-11 19:17:28.000000000 +0100
+++ source/drivers/char/rtc.c	2004-06-11 19:22:01.000000000 +0100
@@ -97,6 +97,11 @@
 static int rtc_irq = PCI_IRQ_NONE;
 #endif
 
+#ifdef	CONFIG_HPET_RTC_IRQ
+#undef	RTC_IRQ
+#define	RTC_IRQ	0
+#endif
+
 #ifdef RTC_IRQ
 static int rtc_has_irq = 1;
 #endif
--- diff/drivers/char/sysrq.c	2004-06-11 19:17:28.000000000 +0100
+++ source/drivers/char/sysrq.c	2004-06-11 19:22:01.000000000 +0100
@@ -35,6 +35,25 @@
 #include <linux/spinlock.h>
 
 #include <asm/ptrace.h>
+#ifdef CONFIG_KGDB_SYSRQ
+
+#define  GDB_OP &kgdb_op
+static void kgdb_sysrq(int key, struct pt_regs *pt_regs, struct tty_struct *tty)
+{
+	printk("kgdb sysrq\n");
+	breakpoint();
+}
+
+static struct sysrq_key_op kgdb_op = {
+	.handler	= kgdb_sysrq,
+	.help_msg	= "kGdb|Fgdb",
+	.action_msg	= "Debug breakpoint\n",
+};
+
+#else
+#define  GDB_OP NULL
+#endif
+
 
 extern void reset_vc(unsigned int);
 
@@ -238,8 +257,8 @@
 /* c */ NULL,
 /* d */	NULL,
 /* e */	&sysrq_term_op,
-/* f */	NULL,
-/* g */	NULL,
+/* f */	GDB_OP,
+/* g */	GDB_OP,
 /* h */	NULL,
 /* i */	&sysrq_kill_op,
 /* j */	NULL,
--- diff/drivers/char/tty_io.c	2004-06-11 19:17:28.000000000 +0100
+++ source/drivers/char/tty_io.c	2004-06-11 19:22:01.000000000 +0100
@@ -91,6 +91,7 @@
 #include <linux/module.h>
 #include <linux/smp_lock.h>
 #include <linux/device.h>
+#include <linux/idr.h>
 
 #include <asm/uaccess.h>
 #include <asm/system.h>
@@ -128,6 +129,8 @@
 #ifdef CONFIG_UNIX98_PTYS
 extern struct tty_driver *ptm_driver;	/* Unix98 pty masters; for /dev/ptmx */
 extern int pty_limit;		/* Config limit on Unix98 ptys */
+static DEFINE_IDR(allocated_ptys);
+static DECLARE_MUTEX(allocated_ptys_lock);
 #endif
 
 extern void disable_early_printk(void);
@@ -442,21 +445,13 @@
 	}
 	file_list_unlock();
 	
-	/* FIXME! What are the locking issues here? This may me overdoing things..
-	* this question is especially important now that we've removed the irqlock. */
-	{
-		unsigned long flags;
-
-		local_irq_save(flags); // FIXME: is this safe?
-		if (tty->ldisc.flush_buffer)
-			tty->ldisc.flush_buffer(tty);
-		if (tty->driver->flush_buffer)
-			tty->driver->flush_buffer(tty);
-		if ((test_bit(TTY_DO_WRITE_WAKEUP, &tty->flags)) &&
-		    tty->ldisc.write_wakeup)
-			(tty->ldisc.write_wakeup)(tty);
-		local_irq_restore(flags); // FIXME: is this safe?
-	}
+	if (tty->ldisc.flush_buffer)
+		tty->ldisc.flush_buffer(tty);
+	if (tty->driver->flush_buffer)
+		tty->driver->flush_buffer(tty);
+	if ((test_bit(TTY_DO_WRITE_WAKEUP, &tty->flags)) &&
+	    tty->ldisc.write_wakeup)
+		(tty->ldisc.write_wakeup)(tty);
 
 	wake_up_interruptible(&tty->write_wait);
 	wake_up_interruptible(&tty->read_wait);
@@ -1065,6 +1060,7 @@
 {
 	struct tty_struct *tty, *o_tty;
 	int	pty_master, tty_closing, o_tty_closing, do_sleep;
+	int	devpts_master;
 	int	idx;
 	char	buf[64];
 	
@@ -1079,6 +1075,7 @@
 	idx = tty->index;
 	pty_master = (tty->driver->type == TTY_DRIVER_TYPE_PTY &&
 		      tty->driver->subtype == PTY_TYPE_MASTER);
+	devpts_master = pty_master && (tty->driver->flags & TTY_DRIVER_DEVPTS_MEM);
 	o_tty = tty->link;
 
 #ifdef TTY_PARANOIA_CHECK
@@ -1295,11 +1292,21 @@
 		o_tty->ldisc = ldiscs[N_TTY];
 	}
 
-	/* 
+	/*
 	 * The release_mem function takes care of the details of clearing
 	 * the slots and preserving the termios structure.
 	 */
 	release_mem(tty, idx);
+
+#ifdef CONFIG_UNIX98_PTYS
+	/* Make this pty number available for reallocation */
+	if (devpts_master) {
+		down(&allocated_ptys_lock);
+		idr_remove(&allocated_ptys, idx);
+		up(&allocated_ptys_lock);
+	}
+#endif
+
 }
 
 /*
@@ -1322,8 +1329,12 @@
 	int index;
 	dev_t device = inode->i_rdev;
 	unsigned short saved_flags = filp->f_flags;
+
 retry_open:
 	noctty = filp->f_flags & O_NOCTTY;
+	index  = -1;
+	retval = 0;
+
 	if (device == MKDEV(TTYAUX_MAJOR,0)) {
 		if (!current->signal->tty)
 			return -ENXIO;
@@ -1361,24 +1372,40 @@
 
 #ifdef CONFIG_UNIX98_PTYS
 	if (device == MKDEV(TTYAUX_MAJOR,2)) {
+		int idr_ret;
+
 		/* find a device that is not in use. */
-		static int next_ptmx_dev = 0;
-		retval = -1;
+		down(&allocated_ptys_lock);
+		if (!idr_pre_get(&allocated_ptys, GFP_KERNEL)) {
+			up(&allocated_ptys_lock);
+			return -ENOMEM;
+		}
+		idr_ret = idr_get_new(&allocated_ptys, NULL, &index);
+		if (idr_ret < 0) {
+			up(&allocated_ptys_lock);
+			if (idr_ret == -EAGAIN)
+				return -ENOMEM;
+			return -EIO;
+		}
+		if (index >= pty_limit) {
+			idr_remove(&allocated_ptys, index);
+			up(&allocated_ptys_lock);
+			return -EIO;
+		}
+		up(&allocated_ptys_lock);
+
 		driver = ptm_driver;
-		while (driver->refcount < pty_limit) {
-			index = next_ptmx_dev;
-			next_ptmx_dev = (next_ptmx_dev+1) % driver->num;
-			if (!init_dev(driver, index, &tty))
-				goto ptmx_found; /* ok! */
+		retval = init_dev(driver, index, &tty);
+		if (retval) {
+			down(&allocated_ptys_lock);
+			idr_remove(&allocated_ptys, index);
+			up(&allocated_ptys_lock);
+			return retval;
 		}
-		return -EIO; /* no free ptys */
-	ptmx_found:
+
 		set_bit(TTY_PTY_LOCK, &tty->flags); /* LOCK THE SLAVE */
-		if (devpts_pty_new(tty->link)) {
-			/* BADNESS - need to destroy both ptm and pts! */
-			return -ENOMEM;
-		}
-		noctty = 1;
+		if (devpts_pty_new(tty->link))
+			retval = -ENOMEM;
 	} else
 #endif
 	{
@@ -1400,10 +1427,12 @@
 #ifdef TTY_DEBUG_HANGUP
 	printk(KERN_DEBUG "opening %s...", tty->name);
 #endif
-	if (tty->driver->open)
-		retval = tty->driver->open(tty, filp);
-	else
-		retval = -ENODEV;
+	if (!retval) {
+		if (tty->driver->open)
+			retval = tty->driver->open(tty, filp);
+		else
+			retval = -ENODEV;
+	}
 	filp->f_flags = saved_flags;
 
 	if (!retval && test_bit(TTY_EXCLUSIVE, &tty->flags) && !capable(CAP_SYS_ADMIN))
@@ -1415,6 +1444,14 @@
 		       tty->name);
 #endif
 
+#ifdef CONFIG_UNIX98_PTYS
+		if (index != -1) {
+			down(&allocated_ptys_lock);
+			idr_remove(&allocated_ptys, index);
+			up(&allocated_ptys_lock);
+		}
+#endif
+
 		release_dev(filp);
 		if (retval != -ERESTARTSYS)
 			return retval;
--- diff/drivers/i2c/busses/i2c-piix4.c	2004-06-11 19:17:28.000000000 +0100
+++ source/drivers/i2c/busses/i2c-piix4.c	2004-06-11 19:22:01.000000000 +0100
@@ -138,7 +138,7 @@
 
 	dev_info(&PIIX4_dev->dev, "Found %s device\n", pci_name(PIIX4_dev));
 
-	if(ibm_dmi_probe()) {
+	if(ibm_dmi_probe() && PIIX4_dev->vendor == PCI_VENDOR_ID_INTEL) {
 		dev_err(&PIIX4_dev->dev, "IBM Laptop detected; this module "
 			"may corrupt your serial eeprom! Refusing to load "
 			"module!\n");
--- diff/drivers/i2c/chips/asb100.c	2004-06-11 19:17:28.000000000 +0100
+++ source/drivers/i2c/chips/asb100.c	2004-06-11 19:22:01.000000000 +0100
@@ -272,7 +272,7 @@
 	return show_in(dev, buf, 0x##offset); \
 } \
 static DEVICE_ATTR(in##offset##_input, S_IRUGO, \
-		show_in##offset, NULL) \
+		show_in##offset, NULL); \
 static ssize_t \
 	show_in##offset##_min (struct device *dev, char *buf) \
 { \
@@ -294,17 +294,17 @@
 	return set_in_max(dev, buf, count, 0x##offset); \
 } \
 static DEVICE_ATTR(in##offset##_min, S_IRUGO | S_IWUSR, \
-		show_in##offset##_min, set_in##offset##_min) \
+		show_in##offset##_min, set_in##offset##_min); \
 static DEVICE_ATTR(in##offset##_max, S_IRUGO | S_IWUSR, \
-		show_in##offset##_max, set_in##offset##_max)
+		show_in##offset##_max, set_in##offset##_max);
 
-sysfs_in(0)
-sysfs_in(1)
-sysfs_in(2)
-sysfs_in(3)
-sysfs_in(4)
-sysfs_in(5)
-sysfs_in(6)
+sysfs_in(0);
+sysfs_in(1);
+sysfs_in(2);
+sysfs_in(3);
+sysfs_in(4);
+sysfs_in(5);
+sysfs_in(6);
 
 #define device_create_file_in(client, offset) do { \
 	device_create_file(&client->dev, &dev_attr_in##offset##_input); \
@@ -410,15 +410,15 @@
 	return set_fan_div(dev, buf, count, offset - 1); \
 } \
 static DEVICE_ATTR(fan##offset##_input, S_IRUGO, \
-		show_fan##offset, NULL) \
+		show_fan##offset, NULL); \
 static DEVICE_ATTR(fan##offset##_min, S_IRUGO | S_IWUSR, \
-		show_fan##offset##_min, set_fan##offset##_min) \
+		show_fan##offset##_min, set_fan##offset##_min); \
 static DEVICE_ATTR(fan##offset##_div, S_IRUGO | S_IWUSR, \
-		show_fan##offset##_div, set_fan##offset##_div)
+		show_fan##offset##_div, set_fan##offset##_div);
 
-sysfs_fan(1)
-sysfs_fan(2)
-sysfs_fan(3)
+sysfs_fan(1);
+sysfs_fan(2);
+sysfs_fan(3);
 
 #define device_create_file_fan(client, offset) do { \
 	device_create_file(&client->dev, &dev_attr_fan##offset##_input); \
@@ -449,9 +449,9 @@
 	return sprintf_temp_from_reg(data->reg[nr], buf, nr); \
 }
 
-show_temp_reg(temp)
-show_temp_reg(temp_max)
-show_temp_reg(temp_hyst)
+show_temp_reg(temp);
+show_temp_reg(temp_max);
+show_temp_reg(temp_hyst);
 
 #define set_temp_reg(REG, reg) \
 static ssize_t set_##reg(struct device *dev, const char *buf, \
@@ -473,15 +473,15 @@
 	return count; \
 }
 
-set_temp_reg(MAX, temp_max)
-set_temp_reg(HYST, temp_hyst)
+set_temp_reg(MAX, temp_max);
+set_temp_reg(HYST, temp_hyst);
 
 #define sysfs_temp(num) \
 static ssize_t show_temp##num(struct device *dev, char *buf) \
 { \
 	return show_temp(dev, buf, num-1); \
 } \
-static DEVICE_ATTR(temp##num##_input, S_IRUGO, show_temp##num, NULL) \
+static DEVICE_ATTR(temp##num##_input, S_IRUGO, show_temp##num, NULL); \
 static ssize_t show_temp_max##num(struct device *dev, char *buf) \
 { \
 	return show_temp_max(dev, buf, num-1); \
@@ -492,7 +492,7 @@
 	return set_temp_max(dev, buf, count, num-1); \
 } \
 static DEVICE_ATTR(temp##num##_max, S_IRUGO | S_IWUSR, \
-		show_temp_max##num, set_temp_max##num) \
+		show_temp_max##num, set_temp_max##num); \
 static ssize_t show_temp_hyst##num(struct device *dev, char *buf) \
 { \
 	return show_temp_hyst(dev, buf, num-1); \
@@ -503,12 +503,12 @@
 	return set_temp_hyst(dev, buf, count, num-1); \
 } \
 static DEVICE_ATTR(temp##num##_max_hyst, S_IRUGO | S_IWUSR, \
-		show_temp_hyst##num, set_temp_hyst##num)
+		show_temp_hyst##num, set_temp_hyst##num);
 
-sysfs_temp(1)
-sysfs_temp(2)
-sysfs_temp(3)
-sysfs_temp(4)
+sysfs_temp(1);
+sysfs_temp(2);
+sysfs_temp(3);
+sysfs_temp(4);
 
 /* VID */
 #define device_create_file_temp(client, num) do { \
@@ -523,7 +523,7 @@
 	return sprintf(buf, "%d\n", vid_from_reg(data->vid, data->vrm));
 }
 
-static DEVICE_ATTR(in0_ref, S_IRUGO, show_vid, NULL)
+static DEVICE_ATTR(in0_ref, S_IRUGO, show_vid, NULL);
 #define device_create_file_vid(client) \
 device_create_file(&client->dev, &dev_attr_in0_ref)
 
@@ -544,7 +544,7 @@
 }
 
 /* Alarms */
-static DEVICE_ATTR(vrm, S_IRUGO | S_IWUSR, show_vrm, set_vrm)
+static DEVICE_ATTR(vrm, S_IRUGO | S_IWUSR, show_vrm, set_vrm);
 #define device_create_file_vrm(client) \
 device_create_file(&client->dev, &dev_attr_vrm);
 
@@ -554,7 +554,7 @@
 	return sprintf(buf, "%d\n", ALARMS_FROM_REG(data->alarms));
 }
 
-static DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL)
+static DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL);
 #define device_create_file_alarms(client) \
 device_create_file(&client->dev, &dev_attr_alarms)
 
@@ -594,9 +594,9 @@
 	return count;
 }
 
-static DEVICE_ATTR(fan1_pwm, S_IRUGO | S_IWUSR, show_pwm1, set_pwm1)
+static DEVICE_ATTR(fan1_pwm, S_IRUGO | S_IWUSR, show_pwm1, set_pwm1);
 static DEVICE_ATTR(fan1_pwm_enable, S_IRUGO | S_IWUSR,
-		show_pwm_enable1, set_pwm_enable1)
+		show_pwm_enable1, set_pwm_enable1);
 #define device_create_file_pwm1(client) do { \
 	device_create_file(&new_client->dev, &dev_attr_fan1_pwm); \
 	device_create_file(&new_client->dev, &dev_attr_fan1_pwm_enable); \
--- diff/drivers/i2c/chips/it87.c	2004-06-11 19:17:28.000000000 +0100
+++ source/drivers/i2c/chips/it87.c	2004-06-11 19:22:01.000000000 +0100
@@ -128,15 +128,15 @@
 
 #define IT87_REG_FAN(nr)       (0x0d + (nr))
 #define IT87_REG_FAN_MIN(nr)   (0x10 + (nr))
-#define IT87_REG_FAN_CTRL      0x13
+#define IT87_REG_FAN_MAIN_CTRL 0x13
 
 #define IT87_REG_VIN(nr)       (0x20 + (nr))
 #define IT87_REG_TEMP(nr)      (0x29 + (nr))
 
 #define IT87_REG_VIN_MAX(nr)   (0x30 + (nr) * 2)
 #define IT87_REG_VIN_MIN(nr)   (0x31 + (nr) * 2)
-#define IT87_REG_TEMP_HIGH(nr) (0x40 + ((nr) * 2))
-#define IT87_REG_TEMP_LOW(nr)  (0x41 + ((nr) * 2))
+#define IT87_REG_TEMP_HIGH(nr) (0x40 + (nr) * 2)
+#define IT87_REG_TEMP_LOW(nr)  (0x41 + (nr) * 2)
 
 #define IT87_REG_I2C_ADDR      0x48
 
@@ -145,8 +145,8 @@
 
 #define IT87_REG_CHIPID        0x58
 
-#define IN_TO_REG(val)  (SENSORS_LIMIT((((val) * 10 + 8)/16),0,255))
-#define IN_FROM_REG(val) (((val) *  16) / 10)
+#define IN_TO_REG(val)  (SENSORS_LIMIT((((val) + 8)/16),0,255))
+#define IN_FROM_REG(val) ((val) * 16)
 
 static inline u8 FAN_TO_REG(long rpm, int div)
 {
@@ -159,9 +159,9 @@
 
 #define FAN_FROM_REG(val,div) ((val)==0?-1:(val)==255?0:1350000/((val)*(div)))
 
-#define TEMP_TO_REG(val) (SENSORS_LIMIT(((val)<0?(((val)-5)/10):\
-					((val)+5)/10),0,255))
-#define TEMP_FROM_REG(val) (((val)>0x80?(val)-0x100:(val))*10)
+#define TEMP_TO_REG(val) (SENSORS_LIMIT(((val)<0?(((val)-500)/1000):\
+					((val)+500)/1000),-128,127))
+#define TEMP_FROM_REG(val) (((val)>0x80?(val)-0x100:(val))*1000)
 
 #define VID_FROM_REG(val) ((val)==0x1f?0:(val)>=0x10?510-(val)*10:\
 				205-(val)*5)
@@ -231,19 +231,19 @@
 static ssize_t show_in(struct device *dev, char *buf, int nr)
 {
 	struct it87_data *data = it87_update_device(dev);
-	return sprintf(buf, "%d\n", IN_FROM_REG(data->in[nr])*10 );
+	return sprintf(buf, "%d\n", IN_FROM_REG(data->in[nr]));
 }
 
 static ssize_t show_in_min(struct device *dev, char *buf, int nr)
 {
 	struct it87_data *data = it87_update_device(dev);
-	return sprintf(buf, "%d\n", IN_FROM_REG(data->in_min[nr])*10 );
+	return sprintf(buf, "%d\n", IN_FROM_REG(data->in_min[nr]));
 }
 
 static ssize_t show_in_max(struct device *dev, char *buf, int nr)
 {
 	struct it87_data *data = it87_update_device(dev);
-	return sprintf(buf, "%d\n", IN_FROM_REG(data->in_max[nr])*10 );
+	return sprintf(buf, "%d\n", IN_FROM_REG(data->in_max[nr]));
 }
 
 static ssize_t set_in_min(struct device *dev, const char *buf, 
@@ -251,7 +251,7 @@
 {
 	struct i2c_client *client = to_i2c_client(dev);
 	struct it87_data *data = i2c_get_clientdata(client);
-	unsigned long val = simple_strtoul(buf, NULL, 10)/10;
+	unsigned long val = simple_strtoul(buf, NULL, 10);
 	data->in_min[nr] = IN_TO_REG(val);
 	it87_write_value(client, IT87_REG_VIN_MIN(nr), 
 			data->in_min[nr]);
@@ -262,7 +262,7 @@
 {
 	struct i2c_client *client = to_i2c_client(dev);
 	struct it87_data *data = i2c_get_clientdata(client);
-	unsigned long val = simple_strtoul(buf, NULL, 10)/10;
+	unsigned long val = simple_strtoul(buf, NULL, 10);
 	data->in_max[nr] = IN_TO_REG(val);
 	it87_write_value(client, IT87_REG_VIN_MAX(nr), 
 			data->in_max[nr]);
@@ -275,7 +275,7 @@
 {								\
 	return show_in(dev, buf, 0x##offset);			\
 }								\
-static DEVICE_ATTR(in##offset##_input, S_IRUGO, show_in##offset, NULL)
+static DEVICE_ATTR(in##offset##_input, S_IRUGO, show_in##offset, NULL);
 
 #define limit_in_offset(offset)					\
 static ssize_t							\
@@ -299,9 +299,9 @@
 	return set_in_max(dev, buf, count, 0x##offset);		\
 }								\
 static DEVICE_ATTR(in##offset##_min, S_IRUGO | S_IWUSR, 	\
-		show_in##offset##_min, set_in##offset##_min)	\
+		show_in##offset##_min, set_in##offset##_min);	\
 static DEVICE_ATTR(in##offset##_max, S_IRUGO | S_IWUSR, 	\
-		show_in##offset##_max, set_in##offset##_max)
+		show_in##offset##_max, set_in##offset##_max);
 
 show_in_offset(0);
 limit_in_offset(0);
@@ -325,24 +325,24 @@
 static ssize_t show_temp(struct device *dev, char *buf, int nr)
 {
 	struct it87_data *data = it87_update_device(dev);
-	return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp[nr])*100 );
+	return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp[nr]));
 }
 static ssize_t show_temp_max(struct device *dev, char *buf, int nr)
 {
 	struct it87_data *data = it87_update_device(dev);
-	return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_high[nr])*100);
+	return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_high[nr]));
 }
 static ssize_t show_temp_min(struct device *dev, char *buf, int nr)
 {
 	struct it87_data *data = it87_update_device(dev);
-	return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_low[nr])*100);
+	return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_low[nr]));
 }
 static ssize_t set_temp_max(struct device *dev, const char *buf, 
 		size_t count, int nr)
 {
 	struct i2c_client *client = to_i2c_client(dev);
 	struct it87_data *data = i2c_get_clientdata(client);
-	int val = simple_strtol(buf, NULL, 10)/100;
+	int val = simple_strtol(buf, NULL, 10);
 	data->temp_high[nr] = TEMP_TO_REG(val);
 	it87_write_value(client, IT87_REG_TEMP_HIGH(nr), data->temp_high[nr]);
 	return count;
@@ -352,7 +352,7 @@
 {
 	struct i2c_client *client = to_i2c_client(dev);
 	struct it87_data *data = i2c_get_clientdata(client);
-	int val = simple_strtol(buf, NULL, 10)/100;
+	int val = simple_strtol(buf, NULL, 10);
 	data->temp_low[nr] = TEMP_TO_REG(val);
 	it87_write_value(client, IT87_REG_TEMP_LOW(nr), data->temp_low[nr]);
 	return count;
@@ -382,11 +382,11 @@
 {									\
 	return set_temp_min(dev, buf, count, 0x##offset - 1);		\
 }									\
-static DEVICE_ATTR(temp##offset##_input, S_IRUGO, show_temp_##offset, NULL) \
+static DEVICE_ATTR(temp##offset##_input, S_IRUGO, show_temp_##offset, NULL); \
 static DEVICE_ATTR(temp##offset##_max, S_IRUGO | S_IWUSR, 		\
-		show_temp_##offset##_max, set_temp_##offset##_max) 	\
+		show_temp_##offset##_max, set_temp_##offset##_max); 	\
 static DEVICE_ATTR(temp##offset##_min, S_IRUGO | S_IWUSR, 		\
-		show_temp_##offset##_min, set_temp_##offset##_min)	
+		show_temp_##offset##_min, set_temp_##offset##_min);	
 
 show_temp_offset(1);
 show_temp_offset(2);
@@ -430,8 +430,8 @@
 {									\
 	return set_sensor(dev, buf, count, 0x##offset - 1);		\
 }									\
-static DEVICE_ATTR(temp##offset##_type, S_IRUGO | S_IWUSR,	 		\
-		show_sensor_##offset, set_sensor_##offset)
+static DEVICE_ATTR(temp##offset##_type, S_IRUGO | S_IWUSR, 		\
+		show_sensor_##offset, set_sensor_##offset);
 
 show_sensor_offset(1);
 show_sensor_offset(2);
@@ -525,11 +525,11 @@
 {									\
 	return set_fan_div(dev, buf, count, 0x##offset - 1);		\
 }									\
-static DEVICE_ATTR(fan##offset##_input, S_IRUGO, show_fan_##offset, NULL) \
+static DEVICE_ATTR(fan##offset##_input, S_IRUGO, show_fan_##offset, NULL); \
 static DEVICE_ATTR(fan##offset##_min, S_IRUGO | S_IWUSR, 		\
-		show_fan_##offset##_min, set_fan_##offset##_min) 	\
+		show_fan_##offset##_min, set_fan_##offset##_min); 	\
 static DEVICE_ATTR(fan##offset##_div, S_IRUGO | S_IWUSR, 		\
-		show_fan_##offset##_div, set_fan_##offset##_div)
+		show_fan_##offset##_div, set_fan_##offset##_div);
 
 show_fan_offset(1);
 show_fan_offset(2);
@@ -773,9 +773,7 @@
    We don't want to lock the whole ISA bus, so we lock each client
    separately.
    We ignore the IT87 BUSY flag at this moment - it could lead to deadlocks,
-   would slow down the IT87 access and should not be necessary. 
-   There are some ugly typecasts here, but the good new is - they should
-   nowhere else be necessary! */
+   would slow down the IT87 access and should not be necessary. */
 static int it87_read_value(struct i2c_client *client, u8 reg)
 {
 	struct it87_data *data = i2c_get_clientdata(client);
@@ -795,9 +793,7 @@
    We don't want to lock the whole ISA bus, so we lock each client
    separately.
    We ignore the IT87 BUSY flag at this moment - it could lead to deadlocks,
-   would slow down the IT87 access and should not be necessary. 
-   There are some ugly typecasts here, but the good new is - they should
-   nowhere else be necessary! */
+   would slow down the IT87 access and should not be necessary. */
 static int it87_write_value(struct i2c_client *client, u8 reg, u8 value)
 {
 	struct it87_data *data = i2c_get_clientdata(client);
@@ -840,11 +836,11 @@
 	}
 
 	/* Check if tachometers are reset manually or by some reason */
-	tmp = it87_read_value(client, IT87_REG_FAN_CTRL);
+	tmp = it87_read_value(client, IT87_REG_FAN_MAIN_CTRL);
 	if ((tmp & 0x70) == 0) {
 		/* Enable all fan tachometers */
 		tmp = (tmp & 0x8f) | 0x70;
-		it87_write_value(client, IT87_REG_FAN_CTRL, tmp);
+		it87_write_value(client, IT87_REG_FAN_MAIN_CTRL, tmp);
 	}
 
 	/* Start monitoring */
--- diff/drivers/i2c/chips/lm78.c	2004-06-11 19:17:28.000000000 +0100
+++ source/drivers/i2c/chips/lm78.c	2004-06-11 19:22:01.000000000 +0100
@@ -281,7 +281,7 @@
 	return show_in(dev, buf, 0x##offset);			\
 }								\
 static DEVICE_ATTR(in##offset##_input, S_IRUGO, 		\
-		show_in##offset, NULL)				\
+		show_in##offset, NULL);				\
 static ssize_t							\
 	show_in##offset##_min (struct device *dev, char *buf)   \
 {								\
@@ -303,9 +303,9 @@
 	return set_in_max(dev, buf, count, 0x##offset);		\
 }								\
 static DEVICE_ATTR(in##offset##_min, S_IRUGO | S_IWUSR,		\
-		show_in##offset##_min, set_in##offset##_min)    \
+		show_in##offset##_min, set_in##offset##_min);	\
 static DEVICE_ATTR(in##offset##_max, S_IRUGO | S_IWUSR,		\
-		show_in##offset##_max, set_in##offset##_max)
+		show_in##offset##_max, set_in##offset##_max);
 
 show_in_offset(0);
 show_in_offset(1);
@@ -354,11 +354,11 @@
 	return count;
 }
 
-static DEVICE_ATTR(temp1_input, S_IRUGO, show_temp, NULL)
+static DEVICE_ATTR(temp1_input, S_IRUGO, show_temp, NULL);
 static DEVICE_ATTR(temp1_max, S_IRUGO | S_IWUSR,
-		show_temp_over, set_temp_over)
+		show_temp_over, set_temp_over);
 static DEVICE_ATTR(temp1_max_hyst, S_IRUGO | S_IWUSR,
-		show_temp_hyst, set_temp_hyst)
+		show_temp_hyst, set_temp_hyst);
 
 /* 3 Fans */
 static ssize_t show_fan(struct device *dev, char *buf, int nr)
@@ -439,9 +439,9 @@
 {									\
 	return set_fan_min(dev, buf, count, 0x##offset - 1);		\
 }									\
-static DEVICE_ATTR(fan##offset##_input, S_IRUGO, show_fan_##offset, NULL) \
+static DEVICE_ATTR(fan##offset##_input, S_IRUGO, show_fan_##offset, NULL);\
 static DEVICE_ATTR(fan##offset##_min, S_IRUGO | S_IWUSR,		\
-		show_fan_##offset##_min, set_fan_##offset##_min)
+		show_fan_##offset##_min, set_fan_##offset##_min);
 
 static ssize_t set_fan_1_div(struct device *dev, const char *buf,
 		size_t count)
@@ -461,10 +461,10 @@
 
 /* Fan 3 divisor is locked in H/W */
 static DEVICE_ATTR(fan1_div, S_IRUGO | S_IWUSR,
-		show_fan_1_div, set_fan_1_div)
+		show_fan_1_div, set_fan_1_div);
 static DEVICE_ATTR(fan2_div, S_IRUGO | S_IWUSR,
-		show_fan_2_div, set_fan_2_div)
-static DEVICE_ATTR(fan3_div, S_IRUGO, show_fan_3_div, NULL)
+		show_fan_2_div, set_fan_2_div);
+static DEVICE_ATTR(fan3_div, S_IRUGO, show_fan_3_div, NULL);
 
 /* VID */
 static ssize_t show_vid(struct device *dev, char *buf)
--- diff/drivers/i2c/chips/lm85.c	2004-05-19 22:11:40.000000000 +0100
+++ source/drivers/i2c/chips/lm85.c	2004-06-11 19:22:01.000000000 +0100
@@ -451,9 +451,9 @@
 {									\
 	return set_fan_min(dev, buf, count, 0x##offset - 1);		\
 }									\
-static DEVICE_ATTR(fan##offset##_input, S_IRUGO, show_fan_##offset, NULL) \
+static DEVICE_ATTR(fan##offset##_input, S_IRUGO, show_fan_##offset, NULL);\
 static DEVICE_ATTR(fan##offset##_min, S_IRUGO | S_IWUSR, 		\
-		show_fan_##offset##_min, set_fan_##offset##_min)
+		show_fan_##offset##_min, set_fan_##offset##_min);
 
 show_fan_offset(1);
 show_fan_offset(2);
@@ -468,7 +468,7 @@
 	return sprintf(buf, "%ld\n", (long) vid_from_reg(data->vid, data->vrm));
 }
 
-static DEVICE_ATTR(in0_ref, S_IRUGO, show_vid_reg, NULL)
+static DEVICE_ATTR(in0_ref, S_IRUGO, show_vid_reg, NULL);
 
 static ssize_t show_vrm_reg(struct device *dev, char *buf)
 {
@@ -487,7 +487,7 @@
 	return count;
 }
 
-static DEVICE_ATTR(vrm, S_IRUGO | S_IWUSR, show_vrm_reg, store_vrm_reg)
+static DEVICE_ATTR(vrm, S_IRUGO | S_IWUSR, show_vrm_reg, store_vrm_reg);
 
 static ssize_t show_alarms_reg(struct device *dev, char *buf)
 {
@@ -495,7 +495,7 @@
 	return sprintf(buf, "%ld\n", (long) ALARMS_FROM_REG(data->alarms));
 }
 
-static DEVICE_ATTR(alarms, S_IRUGO, show_alarms_reg, NULL)
+static DEVICE_ATTR(alarms, S_IRUGO, show_alarms_reg, NULL);
 
 /* pwm */
 
@@ -542,8 +542,8 @@
 	return show_pwm_enable(dev, buf, 0x##offset - 1);			\
 }									\
 static DEVICE_ATTR(fan##offset##_pwm, S_IRUGO | S_IWUSR, 			\
-		show_pwm_##offset, set_pwm_##offset)			\
-static DEVICE_ATTR(fan##offset##_pwm_enable, S_IRUGO, show_pwm_enable##offset, NULL)
+		show_pwm_##offset, set_pwm_##offset);			\
+static DEVICE_ATTR(fan##offset##_pwm_enable, S_IRUGO, show_pwm_enable##offset, NULL);
 
 show_pwm_reg(1);
 show_pwm_reg(2);
@@ -617,11 +617,11 @@
 {									\
 	return set_in_max(dev, buf, count, 0x##offset);			\
 }									\
-static DEVICE_ATTR(in##offset##_input, S_IRUGO, show_in_##offset, NULL)	\
+static DEVICE_ATTR(in##offset##_input, S_IRUGO, show_in_##offset, NULL);	\
 static DEVICE_ATTR(in##offset##_min, S_IRUGO | S_IWUSR, 		\
-		show_in_##offset##_min, set_in_##offset##_min)		\
+		show_in_##offset##_min, set_in_##offset##_min);		\
 static DEVICE_ATTR(in##offset##_max, S_IRUGO | S_IWUSR, 		\
-		show_in_##offset##_max, set_in_##offset##_max)
+		show_in_##offset##_max, set_in_##offset##_max);
 
 show_in_reg(0);
 show_in_reg(1);
@@ -697,11 +697,11 @@
 {									\
 	return set_temp_max(dev, buf, count, 0x##offset - 1);		\
 }									\
-static DEVICE_ATTR(temp##offset##_input, S_IRUGO, show_temp_##offset, NULL)	\
+static DEVICE_ATTR(temp##offset##_input, S_IRUGO, show_temp_##offset, NULL);	\
 static DEVICE_ATTR(temp##offset##_min, S_IRUGO | S_IWUSR, 		\
-		show_temp_##offset##_min, set_temp_##offset##_min)	\
+		show_temp_##offset##_min, set_temp_##offset##_min);	\
 static DEVICE_ATTR(temp##offset##_max, S_IRUGO | S_IWUSR, 		\
-		show_temp_##offset##_max, set_temp_##offset##_max)
+		show_temp_##offset##_max, set_temp_##offset##_max);
 
 show_temp_reg(1);
 show_temp_reg(2);
--- diff/drivers/i2c/chips/via686a.c	2004-06-11 19:17:28.000000000 +0100
+++ source/drivers/i2c/chips/via686a.c	2004-06-11 19:22:01.000000000 +0100
@@ -405,11 +405,11 @@
 {								\
 	return set_in_max(dev, buf, count, 0x##offset);		\
 }								\
-static DEVICE_ATTR(in##offset##_input, S_IRUGO, show_in##offset, NULL) 	\
+static DEVICE_ATTR(in##offset##_input, S_IRUGO, show_in##offset, NULL);\
 static DEVICE_ATTR(in##offset##_min, S_IRUGO | S_IWUSR, 	\
-		show_in##offset##_min, set_in##offset##_min)	\
+		show_in##offset##_min, set_in##offset##_min);	\
 static DEVICE_ATTR(in##offset##_max, S_IRUGO | S_IWUSR, 	\
-		show_in##offset##_max, set_in##offset##_max)
+		show_in##offset##_max, set_in##offset##_max);
 
 show_in_offset(0);
 show_in_offset(1);
@@ -473,11 +473,11 @@
 {									\
 	return set_temp_hyst(dev, buf, count, 0x##offset - 1);		\
 }									\
-static DEVICE_ATTR(temp##offset##_input, S_IRUGO, show_temp_##offset, NULL) \
+static DEVICE_ATTR(temp##offset##_input, S_IRUGO, show_temp_##offset, NULL);\
 static DEVICE_ATTR(temp##offset##_max, S_IRUGO | S_IWUSR, 		\
-		show_temp_##offset##_over, set_temp_##offset##_over) 	\
+		show_temp_##offset##_over, set_temp_##offset##_over);	\
 static DEVICE_ATTR(temp##offset##_max_hyst, S_IRUGO | S_IWUSR, 		\
-		show_temp_##offset##_hyst, set_temp_##offset##_hyst)	
+		show_temp_##offset##_hyst, set_temp_##offset##_hyst);	
 
 show_temp_offset(1);
 show_temp_offset(2);
@@ -542,11 +542,11 @@
 {									\
 	return set_fan_div(dev, buf, count, 0x##offset - 1);		\
 }									\
-static DEVICE_ATTR(fan##offset##_input, S_IRUGO, show_fan_##offset, NULL) \
+static DEVICE_ATTR(fan##offset##_input, S_IRUGO, show_fan_##offset, NULL);\
 static DEVICE_ATTR(fan##offset##_min, S_IRUGO | S_IWUSR, 		\
-		show_fan_##offset##_min, set_fan_##offset##_min) 	\
+		show_fan_##offset##_min, set_fan_##offset##_min);	\
 static DEVICE_ATTR(fan##offset##_div, S_IRUGO | S_IWUSR, 		\
-		show_fan_##offset##_div, set_fan_##offset##_div)
+		show_fan_##offset##_div, set_fan_##offset##_div);
 
 show_fan_offset(1);
 show_fan_offset(2);
--- diff/drivers/i2c/chips/w83627hf.c	2004-05-19 22:11:40.000000000 +0100
+++ source/drivers/i2c/chips/w83627hf.c	2004-06-11 19:22:01.000000000 +0100
@@ -199,7 +199,7 @@
 #define W83627THF_REG_PWM2		0x03	/* 697HF and 637HF too */
 #define W83627THF_REG_PWM3		0x11	/* 637HF too */
 
-#define W83627THF_REG_VRM_OVT_CFG 	0x18	/* 637HF too, unused yet */
+#define W83627THF_REG_VRM_OVT_CFG 	0x18	/* 637HF too */
 
 static const u8 regpwm_627hf[] = { W83627HF_REG_PWM1, W83627HF_REG_PWM2 };
 static const u8 regpwm[] = { W83627THF_REG_PWM1, W83627THF_REG_PWM2,
@@ -222,7 +222,7 @@
    these macros are called: arguments may be evaluated more than once.
    Fixing this is just not worth it. */
 #define IN_TO_REG(val)  (SENSORS_LIMIT((((val) + 8)/16),0,255))
-#define IN_FROM_REG(val) ((val) * 16 + 5)
+#define IN_FROM_REG(val) ((val) * 16)
 
 static inline u8 FAN_TO_REG(long rpm, int div)
 {
@@ -312,6 +312,7 @@
 				   Default = 3435.
 				   Other Betas unimplemented */
 	u8 vrm;
+	u8 vrm_ovt;		/* Register value, 627thf & 637hf only */
 };
 
 
@@ -370,7 +371,7 @@
 { \
         return show_in(dev, buf, 0x##offset); \
 } \
-static DEVICE_ATTR(in##offset##_input, S_IRUGO, show_regs_in_##offset, NULL)
+static DEVICE_ATTR(in##offset##_input, S_IRUGO, show_regs_in_##offset, NULL);
 
 #define sysfs_in_reg_offset(reg, offset) \
 static ssize_t show_regs_in_##reg##offset (struct device *dev, char *buf) \
@@ -384,22 +385,104 @@
 	return store_in_##reg (dev, buf, count, 0x##offset); \
 } \
 static DEVICE_ATTR(in##offset##_##reg, S_IRUGO| S_IWUSR, \
-		  show_regs_in_##reg##offset, store_regs_in_##reg##offset)
+		  show_regs_in_##reg##offset, store_regs_in_##reg##offset);
 
 #define sysfs_in_offsets(offset) \
 sysfs_in_offset(offset) \
 sysfs_in_reg_offset(min, offset) \
 sysfs_in_reg_offset(max, offset)
 
-sysfs_in_offsets(0)
-sysfs_in_offsets(1)
-sysfs_in_offsets(2)
-sysfs_in_offsets(3)
-sysfs_in_offsets(4)
-sysfs_in_offsets(5)
-sysfs_in_offsets(6)
-sysfs_in_offsets(7)
-sysfs_in_offsets(8)
+sysfs_in_offsets(1);
+sysfs_in_offsets(2);
+sysfs_in_offsets(3);
+sysfs_in_offsets(4);
+sysfs_in_offsets(5);
+sysfs_in_offsets(6);
+sysfs_in_offsets(7);
+sysfs_in_offsets(8);
+
+/* use a different set of functions for in0 */
+static ssize_t show_in_0(struct w83627hf_data *data, char *buf, u8 reg)
+{
+	long in0;
+
+	if ((data->vrm_ovt & 0x01) &&
+		(w83627thf == data->type || w83637hf == data->type))
+
+		/* use VRM9 calculation */
+		in0 = (long)((reg * 488 + 70000 + 50) / 100);
+	else
+		/* use VRM8 (standard) calculation */
+		in0 = (long)IN_FROM_REG(reg);
+
+	return sprintf(buf,"%ld\n", in0);
+}
+
+static ssize_t show_regs_in_0(struct device *dev, char *buf)
+{
+	struct w83627hf_data *data = w83627hf_update_device(dev);
+	return show_in_0(data, buf, data->in[0]);
+}
+
+static ssize_t show_regs_in_min0(struct device *dev, char *buf)
+{
+	struct w83627hf_data *data = w83627hf_update_device(dev);
+	return show_in_0(data, buf, data->in_min[0]);
+}
+
+static ssize_t show_regs_in_max0(struct device *dev, char *buf)
+{
+	struct w83627hf_data *data = w83627hf_update_device(dev);
+	return show_in_0(data, buf, data->in_max[0]);
+}
+
+static ssize_t store_regs_in_min0(struct device *dev,
+	const char *buf, size_t count)
+{
+	struct i2c_client *client = to_i2c_client(dev);
+	struct w83627hf_data *data = i2c_get_clientdata(client);
+	u32 val;
+
+	val = simple_strtoul(buf, NULL, 10);
+	if ((data->vrm_ovt & 0x01) &&
+		(w83627thf == data->type || w83637hf == data->type))
+
+		/* use VRM9 calculation */
+		data->in_min[0] = (u8)(((val * 100) - 70000 + 244) / 488);
+	else
+		/* use VRM8 (standard) calculation */
+		data->in_min[0] = IN_TO_REG(val);
+
+	w83627hf_write_value(client, W83781D_REG_IN_MIN(0), data->in_min[0]);
+	return count;
+}
+
+static ssize_t store_regs_in_max0(struct device *dev,
+	const char *buf, size_t count)
+{
+	struct i2c_client *client = to_i2c_client(dev);
+	struct w83627hf_data *data = i2c_get_clientdata(client);
+	u32 val;
+
+	val = simple_strtoul(buf, NULL, 10);
+	if ((data->vrm_ovt & 0x01) &&
+		(w83627thf == data->type || w83637hf == data->type))
+		
+		/* use VRM9 calculation */
+		data->in_max[0] = (u8)(((val * 100) - 70000 + 244) / 488);
+	else
+		/* use VRM8 (standard) calculation */
+		data->in_max[0] = IN_TO_REG(val);
+
+	w83627hf_write_value(client, W83781D_REG_IN_MAX(0), data->in_max[0]);
+	return count;
+}
+
+static DEVICE_ATTR(in0_input, S_IRUGO, show_regs_in_0, NULL);
+static DEVICE_ATTR(in0_min, S_IRUGO | S_IWUSR,
+	show_regs_in_min0, store_regs_in_min0);
+static DEVICE_ATTR(in0_max, S_IRUGO | S_IWUSR,
+	show_regs_in_max0, store_regs_in_max0);
 
 #define device_create_file_in(client, offset) \
 do { \
@@ -416,8 +499,8 @@
 		FAN_FROM_REG(data->reg[nr-1], \
 			    (long)DIV_FROM_REG(data->fan_div[nr-1]))); \
 }
-show_fan_reg(fan)
-show_fan_reg(fan_min)
+show_fan_reg(fan);
+show_fan_reg(fan_min);
 
 static ssize_t
 store_fan_min(struct device *dev, const char *buf, size_t count, int nr)
@@ -440,7 +523,7 @@
 { \
 	return show_fan(dev, buf, 0x##offset); \
 } \
-static DEVICE_ATTR(fan##offset##_input, S_IRUGO, show_regs_fan_##offset, NULL)
+static DEVICE_ATTR(fan##offset##_input, S_IRUGO, show_regs_fan_##offset, NULL);
 
 #define sysfs_fan_min_offset(offset) \
 static ssize_t show_regs_fan_min##offset (struct device *dev, char *buf) \
@@ -453,14 +536,14 @@
 	return store_fan_min(dev, buf, count, 0x##offset); \
 } \
 static DEVICE_ATTR(fan##offset##_min, S_IRUGO | S_IWUSR, \
-		  show_regs_fan_min##offset, store_regs_fan_min##offset)
+		  show_regs_fan_min##offset, store_regs_fan_min##offset);
 
-sysfs_fan_offset(1)
-sysfs_fan_min_offset(1)
-sysfs_fan_offset(2)
-sysfs_fan_min_offset(2)
-sysfs_fan_offset(3)
-sysfs_fan_min_offset(3)
+sysfs_fan_offset(1);
+sysfs_fan_min_offset(1);
+sysfs_fan_offset(2);
+sysfs_fan_min_offset(2);
+sysfs_fan_offset(3);
+sysfs_fan_min_offset(3);
 
 #define device_create_file_fan(client, offset) \
 do { \
@@ -479,9 +562,9 @@
 		return sprintf(buf,"%ld\n", (long)TEMP_FROM_REG(data->reg)); \
 	} \
 }
-show_temp_reg(temp)
-show_temp_reg(temp_max)
-show_temp_reg(temp_max_hyst)
+show_temp_reg(temp);
+show_temp_reg(temp_max);
+show_temp_reg(temp_max_hyst);
 
 #define store_temp_reg(REG, reg) \
 static ssize_t \
@@ -505,8 +588,8 @@
 	 \
 	return count; \
 }
-store_temp_reg(OVER, max)
-store_temp_reg(HYST, max_hyst)
+store_temp_reg(OVER, max);
+store_temp_reg(HYST, max_hyst);
 
 #define sysfs_temp_offset(offset) \
 static ssize_t \
@@ -514,7 +597,7 @@
 { \
 	return show_temp(dev, buf, 0x##offset); \
 } \
-static DEVICE_ATTR(temp##offset##_input, S_IRUGO, show_regs_temp_##offset, NULL)
+static DEVICE_ATTR(temp##offset##_input, S_IRUGO, show_regs_temp_##offset, NULL);
 
 #define sysfs_temp_reg_offset(reg, offset) \
 static ssize_t show_regs_temp_##reg##offset (struct device *dev, char *buf) \
@@ -528,16 +611,16 @@
 	return store_temp_##reg (dev, buf, count, 0x##offset); \
 } \
 static DEVICE_ATTR(temp##offset##_##reg, S_IRUGO| S_IWUSR, \
-		  show_regs_temp_##reg##offset, store_regs_temp_##reg##offset)
+		  show_regs_temp_##reg##offset, store_regs_temp_##reg##offset);
 
 #define sysfs_temp_offsets(offset) \
 sysfs_temp_offset(offset) \
 sysfs_temp_reg_offset(max, offset) \
 sysfs_temp_reg_offset(max_hyst, offset)
 
-sysfs_temp_offsets(1)
-sysfs_temp_offsets(2)
-sysfs_temp_offsets(3)
+sysfs_temp_offsets(1);
+sysfs_temp_offsets(2);
+sysfs_temp_offsets(3);
 
 #define device_create_file_temp(client, offset) \
 do { \
@@ -552,7 +635,7 @@
 	struct w83627hf_data *data = w83627hf_update_device(dev);
 	return sprintf(buf, "%ld\n", (long) vid_from_reg(data->vid, data->vrm));
 }
-static DEVICE_ATTR(in0_ref, S_IRUGO, show_vid_reg, NULL)
+static DEVICE_ATTR(in0_ref, S_IRUGO, show_vid_reg, NULL);
 #define device_create_file_vid(client) \
 device_create_file(&client->dev, &dev_attr_in0_ref)
 
@@ -574,7 +657,7 @@
 
 	return count;
 }
-static DEVICE_ATTR(vrm, S_IRUGO | S_IWUSR, show_vrm_reg, store_vrm_reg)
+static DEVICE_ATTR(vrm, S_IRUGO | S_IWUSR, show_vrm_reg, store_vrm_reg);
 #define device_create_file_vrm(client) \
 device_create_file(&client->dev, &dev_attr_vrm)
 
@@ -584,7 +667,7 @@
 	struct w83627hf_data *data = w83627hf_update_device(dev);
 	return sprintf(buf, "%ld\n", (long) data->alarms);
 }
-static DEVICE_ATTR(alarms, S_IRUGO, show_alarms_reg, NULL)
+static DEVICE_ATTR(alarms, S_IRUGO, show_alarms_reg, NULL);
 #define device_create_file_alarms(client) \
 device_create_file(&client->dev, &dev_attr_alarms)
 
@@ -641,10 +724,10 @@
 	return store_beep_reg(dev, buf, count, BEEP_##REG); \
 } \
 static DEVICE_ATTR(beep_##reg, S_IRUGO | S_IWUSR, \
-		  show_regs_beep_##reg, store_regs_beep_##reg)
+		  show_regs_beep_##reg, store_regs_beep_##reg);
 
-sysfs_beep(ENABLE, enable)
-sysfs_beep(MASK, mask)
+sysfs_beep(ENABLE, enable);
+sysfs_beep(MASK, mask);
 
 #define device_create_file_beep(client) \
 do { \
@@ -707,11 +790,11 @@
 	return store_fan_div_reg(dev, buf, count, offset - 1); \
 } \
 static DEVICE_ATTR(fan##offset##_div, S_IRUGO | S_IWUSR, \
-		  show_regs_fan_div_##offset, store_regs_fan_div_##offset)
+		  show_regs_fan_div_##offset, store_regs_fan_div_##offset);
 
-sysfs_fan_div(1)
-sysfs_fan_div(2)
-sysfs_fan_div(3)
+sysfs_fan_div(1);
+sysfs_fan_div(2);
+sysfs_fan_div(3);
 
 #define device_create_file_fan_div(client, offset) \
 do { \
@@ -763,11 +846,11 @@
 	return store_pwm_reg(dev, buf, count, offset); \
 } \
 static DEVICE_ATTR(fan##offset##_pwm, S_IRUGO | S_IWUSR, \
-		  show_regs_pwm_##offset, store_regs_pwm_##offset)
+		  show_regs_pwm_##offset, store_regs_pwm_##offset);
 
-sysfs_pwm(1)
-sysfs_pwm(2)
-sysfs_pwm(3)
+sysfs_pwm(1);
+sysfs_pwm(2);
+sysfs_pwm(3);
 
 #define device_create_file_pwm(client, offset) \
 do { \
@@ -836,11 +919,11 @@
     return store_sensor_reg(dev, buf, count, offset); \
 } \
 static DEVICE_ATTR(temp##offset##_type, S_IRUGO | S_IWUSR, \
-		  show_regs_sensor_##offset, store_regs_sensor_##offset)
+		  show_regs_sensor_##offset, store_regs_sensor_##offset);
 
-sysfs_sensor(1)
-sysfs_sensor(2)
-sysfs_sensor(3)
+sysfs_sensor(1);
+sysfs_sensor(2);
+sysfs_sensor(3);
 
 #define device_create_file_sensor(client, offset) \
 do { \
@@ -1191,6 +1274,11 @@
 		data->vid = w83627thf_read_gpio5(client) & 0x1f;
 	}
 
+	/* Read VRM & OVT Config only once */
+	if (w83627thf == data->type || w83637hf == data->type)
+		data->vrm_ovt = 
+			w83627hf_read_value(client, W83627THF_REG_VRM_OVT_CFG);
+
 	/* Convert VID to voltage based on default VRM */
 	data->vrm = DEFAULT_VRM;
 	if (type != w83697hf)
--- diff/drivers/i2c/chips/w83781d.c	2004-06-11 19:17:28.000000000 +0100
+++ source/drivers/i2c/chips/w83781d.c	2004-06-11 19:22:01.000000000 +0100
@@ -320,7 +320,7 @@
 { \
         return show_in(dev, buf, 0x##offset); \
 } \
-static DEVICE_ATTR(in##offset##_input, S_IRUGO, show_regs_in_##offset, NULL)
+static DEVICE_ATTR(in##offset##_input, S_IRUGO, show_regs_in_##offset, NULL);
 
 #define sysfs_in_reg_offset(reg, offset) \
 static ssize_t show_regs_in_##reg##offset (struct device *dev, char *buf) \
@@ -331,7 +331,7 @@
 { \
 	return store_in_##reg (dev, buf, count, 0x##offset); \
 } \
-static DEVICE_ATTR(in##offset##_##reg, S_IRUGO| S_IWUSR, show_regs_in_##reg##offset, store_regs_in_##reg##offset)
+static DEVICE_ATTR(in##offset##_##reg, S_IRUGO| S_IWUSR, show_regs_in_##reg##offset, store_regs_in_##reg##offset);
 
 #define sysfs_in_offsets(offset) \
 sysfs_in_offset(offset); \
@@ -386,7 +386,7 @@
 { \
 	return show_fan(dev, buf, 0x##offset); \
 } \
-static DEVICE_ATTR(fan##offset##_input, S_IRUGO, show_regs_fan_##offset, NULL)
+static DEVICE_ATTR(fan##offset##_input, S_IRUGO, show_regs_fan_##offset, NULL);
 
 #define sysfs_fan_min_offset(offset) \
 static ssize_t show_regs_fan_min##offset (struct device *dev, char *buf) \
@@ -397,7 +397,7 @@
 { \
 	return store_fan_min(dev, buf, count, 0x##offset); \
 } \
-static DEVICE_ATTR(fan##offset##_min, S_IRUGO | S_IWUSR, show_regs_fan_min##offset, store_regs_fan_min##offset)
+static DEVICE_ATTR(fan##offset##_min, S_IRUGO | S_IWUSR, show_regs_fan_min##offset, store_regs_fan_min##offset);
 
 sysfs_fan_offset(1);
 sysfs_fan_min_offset(1);
@@ -466,7 +466,7 @@
 { \
 	return show_temp(dev, buf, 0x##offset); \
 } \
-static DEVICE_ATTR(temp##offset##_input, S_IRUGO, show_regs_temp_##offset, NULL)
+static DEVICE_ATTR(temp##offset##_input, S_IRUGO, show_regs_temp_##offset, NULL);
 
 #define sysfs_temp_reg_offset(reg, offset) \
 static ssize_t show_regs_temp_##reg##offset (struct device *dev, char *buf) \
@@ -477,7 +477,7 @@
 { \
 	return store_temp_##reg (dev, buf, count, 0x##offset); \
 } \
-static DEVICE_ATTR(temp##offset##_##reg, S_IRUGO| S_IWUSR, show_regs_temp_##reg##offset, store_regs_temp_##reg##offset)
+static DEVICE_ATTR(temp##offset##_##reg, S_IRUGO| S_IWUSR, show_regs_temp_##reg##offset, store_regs_temp_##reg##offset);
 
 #define sysfs_temp_offsets(offset) \
 sysfs_temp_offset(offset); \
@@ -503,7 +503,7 @@
 }
 
 static
-DEVICE_ATTR(in0_ref, S_IRUGO, show_vid_reg, NULL)
+DEVICE_ATTR(in0_ref, S_IRUGO, show_vid_reg, NULL);
 #define device_create_file_vid(client) \
 device_create_file(&client->dev, &dev_attr_in0_ref);
 static ssize_t
@@ -527,7 +527,7 @@
 }
 
 static
-DEVICE_ATTR(vrm, S_IRUGO | S_IWUSR, show_vrm_reg, store_vrm_reg)
+DEVICE_ATTR(vrm, S_IRUGO | S_IWUSR, show_vrm_reg, store_vrm_reg);
 #define device_create_file_vrm(client) \
 device_create_file(&client->dev, &dev_attr_vrm);
 static ssize_t
@@ -538,7 +538,7 @@
 }
 
 static
-DEVICE_ATTR(alarms, S_IRUGO, show_alarms_reg, NULL)
+DEVICE_ATTR(alarms, S_IRUGO, show_alarms_reg, NULL);
 #define device_create_file_alarms(client) \
 device_create_file(&client->dev, &dev_attr_alarms);
 static ssize_t show_beep_mask (struct device *dev, char *buf)
@@ -598,7 +598,7 @@
 { \
 	return store_beep_reg(dev, buf, count, BEEP_##REG); \
 } \
-static DEVICE_ATTR(beep_##reg, S_IRUGO | S_IWUSR, show_regs_beep_##reg, store_regs_beep_##reg)
+static DEVICE_ATTR(beep_##reg, S_IRUGO | S_IWUSR, show_regs_beep_##reg, store_regs_beep_##reg);
 
 sysfs_beep(ENABLE, enable);
 sysfs_beep(MASK, mask);
@@ -665,7 +665,7 @@
 { \
 	return store_fan_div_reg(dev, buf, count, offset - 1); \
 } \
-static DEVICE_ATTR(fan##offset##_div, S_IRUGO | S_IWUSR, show_regs_fan_div_##offset, store_regs_fan_div_##offset)
+static DEVICE_ATTR(fan##offset##_div, S_IRUGO | S_IWUSR, show_regs_fan_div_##offset, store_regs_fan_div_##offset);
 
 sysfs_fan_div(1);
 sysfs_fan_div(2);
@@ -744,7 +744,7 @@
 { \
 	return store_pwm_reg(dev, buf, count, offset); \
 } \
-static DEVICE_ATTR(fan##offset##_pwm, S_IRUGO | S_IWUSR, show_regs_pwm_##offset, store_regs_pwm_##offset)
+static DEVICE_ATTR(fan##offset##_pwm, S_IRUGO | S_IWUSR, show_regs_pwm_##offset, store_regs_pwm_##offset);
 
 #define sysfs_pwmenable(offset) \
 static ssize_t show_regs_pwmenable_##offset (struct device *dev, char *buf) \
@@ -755,7 +755,7 @@
 { \
 	return store_pwmenable_reg(dev, buf, count, offset); \
 } \
-static DEVICE_ATTR(fan##offset##_pwm_enable, S_IRUGO | S_IWUSR, show_regs_pwmenable_##offset, store_regs_pwmenable_##offset)
+static DEVICE_ATTR(fan##offset##_pwm_enable, S_IRUGO | S_IWUSR, show_regs_pwmenable_##offset, store_regs_pwmenable_##offset);
 
 sysfs_pwm(1);
 sysfs_pwm(2);
@@ -833,7 +833,7 @@
 { \
     return store_sensor_reg(dev, buf, count, offset); \
 } \
-static DEVICE_ATTR(temp##offset##_type, S_IRUGO | S_IWUSR, show_regs_sensor_##offset, store_regs_sensor_##offset)
+static DEVICE_ATTR(temp##offset##_type, S_IRUGO | S_IWUSR, show_regs_sensor_##offset, store_regs_sensor_##offset);
 
 sysfs_sensor(1);
 sysfs_sensor(2);
@@ -891,7 +891,7 @@
 { \
     return store_rt_reg(dev, buf, count, offset); \
 } \
-static DEVICE_ATTR(rt##offset, S_IRUGO | S_IWUSR, show_regs_rt_##offset, store_regs_rt_##offset)
+static DEVICE_ATTR(rt##offset, S_IRUGO | S_IWUSR, show_regs_rt_##offset, store_regs_rt_##offset);
 
 sysfs_rt(1);
 sysfs_rt(2);
--- diff/drivers/i2c/chips/w83l785ts.c	2004-06-11 19:17:28.000000000 +0100
+++ source/drivers/i2c/chips/w83l785ts.c	2004-06-11 19:22:01.000000000 +0100
@@ -137,8 +137,8 @@
 	return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_over));
 }
 
-static DEVICE_ATTR(temp1_input, S_IRUGO, show_temp, NULL)
-static DEVICE_ATTR(temp1_max, S_IRUGO, show_temp_over, NULL)
+static DEVICE_ATTR(temp1_input, S_IRUGO, show_temp, NULL);
+static DEVICE_ATTR(temp1_max, S_IRUGO, show_temp_over, NULL);
 
 /*
  * Real code
--- diff/drivers/i2c/i2c-core.c	2004-06-11 19:17:28.000000000 +0100
+++ source/drivers/i2c/i2c-core.c	2004-06-11 19:22:01.000000000 +0100
@@ -126,7 +126,13 @@
 		goto out_unlock;
 	}
 
-	id = idr_get_new(&i2c_adapter_idr, NULL);
+	res = idr_get_new(&i2c_adapter_idr, NULL, &id);
+	if (res < 0) {
+		if (res == -EAGAIN)
+			res = -ENOMEM;
+		goto out_unlock;
+	}
+
 	adap->nr =  id & MAX_ID_MASK;
 	init_MUTEX(&adap->bus_lock);
 	init_MUTEX(&adap->clist_lock);
@@ -162,7 +168,7 @@
 
 	dev_dbg(&adap->dev, "registered as adapter #%d\n", adap->nr);
 
- out_unlock:
+out_unlock:
 	up(&core_lists);
 	return res;
 }
--- diff/drivers/ide/Kconfig	2004-06-11 19:17:28.000000000 +0100
+++ source/drivers/ide/Kconfig	2004-06-11 19:22:01.000000000 +0100
@@ -97,25 +97,7 @@
 
 config BLK_DEV_HD_IDE
 	bool "Use old disk-only driver on primary interface"
-	depends on ((X86 && X86_PC9800!=y) || SH_MPC1211)
-	---help---
-	  There are two drivers for MFM/RLL/IDE disks.  Most people use just
-	  the new enhanced driver by itself.  This option however installs the
-	  old hard disk driver to control the primary IDE/disk interface in
-	  the system, leaving the new enhanced IDE driver to take care of only
-	  the 2nd/3rd/4th IDE interfaces.  Doing this will prevent you from
-	  having an IDE/ATAPI CD-ROM or tape drive connected to the primary
-	  IDE interface.  Choosing this option may be useful for older systems
-	  which have MFM/RLL/ESDI controller+drives at the primary port
-	  address (0x1f0), along with IDE drives at the secondary/3rd/4th port
-	  addresses.
-
-	  Normally, just say N here; you will then use the new driver for all
-	  4 interfaces.
-
-config BLK_DEV_HD_IDE98
-	bool "Use old disk-only driver on primary interface"
-	depends on X86 && X86_PC9800
+	depends on (X86 || SH_MPC1211)
 	---help---
 	  There are two drivers for MFM/RLL/IDE disks.  Most people use just
 	  the new enhanced driver by itself.  This option however installs the
--- diff/drivers/ide/Makefile	2004-06-11 19:17:28.000000000 +0100
+++ source/drivers/ide/Makefile	2004-06-11 19:22:01.000000000 +0100
@@ -29,7 +29,6 @@
 ide-core-$(CONFIG_IDE_ARM)		+= arm/ide_arm.o
 
 # built-in only drivers from legacy/
-ide-core-$(CONFIG_BLK_DEV_IDE_PC9800)	+= legacy/pc9800.o
 ide-core-$(CONFIG_BLK_DEV_BUDDHA)	+= legacy/buddha.o
 ide-core-$(CONFIG_BLK_DEV_FALCON_IDE)	+= legacy/falconide.o
 ide-core-$(CONFIG_BLK_DEV_GAYLE)	+= legacy/gayle.o
--- diff/drivers/ide/ide-disk.c	2004-06-11 19:17:28.000000000 +0100
+++ source/drivers/ide/ide-disk.c	2004-06-11 19:22:01.000000000 +0100
@@ -1203,6 +1203,41 @@
 
 #endif	/* CONFIG_PROC_FS */
 
+static int idedisk_issue_flush(request_queue_t *q, struct gendisk *disk,
+			       sector_t *error_sector)
+{
+	ide_drive_t *drive = q->queuedata;
+	struct request *rq;
+	int ret;
+
+	if (!drive->wcache)
+		return 0;
+
+	rq = blk_get_request(q, WRITE, __GFP_WAIT);
+
+	memset(rq->cmd, 0, sizeof(rq->cmd));
+
+	if ((drive->id->cfs_enable_2 & 0x2400) == 0x2400)
+		rq->cmd[0] = WIN_FLUSH_CACHE_EXT;
+	else
+		rq->cmd[0] = WIN_FLUSH_CACHE;
+
+
+	rq->flags |= REQ_DRIVE_TASK | REQ_SOFTBARRIER;
+	rq->buffer = rq->cmd;
+
+	ret = blk_execute_rq(q, disk, rq);
+
+	/*
+	 * if we failed and caller wants error offset, get it
+	 */
+	if (ret && error_sector)
+		*error_sector = ide_get_error_location(drive, rq->cmd);
+
+	blk_put_request(rq);
+	return ret;
+}
+
 /*
  * This is tightly woven into the driver->do_special can not touch.
  * DON'T do it again until a total personality rewrite is committed.
@@ -1231,16 +1266,10 @@
 	return 0;
 }
 
-/* check if CACHE FLUSH (EXT) command is supported (bits defined in ATA-6) */
-#define ide_id_has_flush_cache(id)	((id)->cfs_enable_2 & 0x3000)
-
-/* some Maxtor disks have bit 13 defined incorrectly so check bit 10 too */
-#define ide_id_has_flush_cache_ext(id)	\
-	(((id)->cfs_enable_2 & 0x2400) == 0x2400)
-
 static int write_cache (ide_drive_t *drive, int arg)
 {
 	ide_task_t args;
+	int err;
 
 	if (!ide_id_has_flush_cache(drive->id))
 		return 1;
@@ -1251,7 +1280,10 @@
 	args.tfRegister[IDE_COMMAND_OFFSET]	= WIN_SETFEATURES;
 	args.command_type			= IDE_DRIVE_TASK_NO_DATA;
 	args.handler				= &task_no_data_intr;
-	(void) ide_raw_taskfile(drive, &args, NULL);
+
+	err = ide_raw_taskfile(drive, &args, NULL);
+	if (err)
+		return err;
 
 	drive->wcache = arg;
 	return 0;
@@ -1401,6 +1433,7 @@
 {
 	struct hd_driveid *id = drive->id;
 	unsigned long long capacity;
+	int barrier;
 
 	idedisk_add_settings(drive);
 
@@ -1532,6 +1565,28 @@
 		drive->wcache = 1;
 
 	write_cache(drive, 1);
+
+	/*
+	 * decide if we can sanely support flushes and barriers on
+	 * this drive. unfortunately not all drives advertise FLUSH_CACHE
+	 * support even if they support it. So assume FLUSH_CACHE is there
+	 * always. LBA48 drives are newer, so expect it to flag support
+	 * properly. We can safely support FLUSH_CACHE on lba48, if capacity
+	 * doesn't exceed lba28
+	 */
+	barrier = 1;
+	if (drive->addressing == 1) {
+		barrier = ide_id_has_flush_cache(id);
+		if (capacity > (1ULL << 28) && !ide_id_has_flush_cache_ext(id))
+			barrier = 0;
+	}
+
+	printk("%s: cache flushes %ssupported\n",
+		drive->name, barrier ? "" : "not ");
+	if (barrier) {
+		blk_queue_ordered(drive->queue, 1);
+		blk_queue_issue_flush_fn(drive->queue, idedisk_issue_flush);
+	}
 }
 
 static void ide_cacheflush_p(ide_drive_t *drive)
--- diff/drivers/ide/ide-io.c	2004-06-11 19:17:28.000000000 +0100
+++ source/drivers/ide/ide-io.c	2004-06-11 19:22:01.000000000 +0100
@@ -54,38 +54,73 @@
 #include <asm/io.h>
 #include <asm/bitops.h>
 
-/**
- *	ide_end_request		-	complete an IDE I/O
- *	@drive: IDE device for the I/O
- *	@uptodate: 
- *	@nr_sectors: number of sectors completed
- *
- *	This is our end_request wrapper function. We complete the I/O
- *	update random number input and dequeue the request, which if
- *	it was tagged may be out of order.
+static void ide_fill_flush_cmd(ide_drive_t *drive, struct request *rq)
+{
+	char *buf = rq->cmd;
+
+	/*
+	 * reuse cdb space for ata command
+	 */
+	memset(buf, 0, sizeof(rq->cmd));
+
+	rq->flags |= REQ_DRIVE_TASK | REQ_STARTED;
+	rq->buffer = buf;
+	rq->buffer[0] = WIN_FLUSH_CACHE;
+
+	if (ide_id_has_flush_cache_ext(drive->id))
+		rq->buffer[0] = WIN_FLUSH_CACHE_EXT;
+}
+
+/*
+ * preempt pending requests, and store this cache flush for immediate
+ * execution
  */
- 
-int ide_end_request (ide_drive_t *drive, int uptodate, int nr_sectors)
+static struct request *ide_queue_flush_cmd(ide_drive_t *drive,
+					   struct request *rq, int post)
 {
-	struct request *rq;
-	unsigned long flags;
-	int ret = 1;
+	struct request *flush_rq = &HWGROUP(drive)->wrq;
 
-	spin_lock_irqsave(&ide_lock, flags);
-	rq = HWGROUP(drive)->rq;
+	/*
+	 * write cache disabled, just return barrier write immediately
+	 */
+	if (!drive->wcache)
+		return rq;
 
-	BUG_ON(!(rq->flags & REQ_STARTED));
+	ide_init_drive_cmd(flush_rq);
+	ide_fill_flush_cmd(drive, flush_rq);
 
-	if (!nr_sectors)
-		nr_sectors = rq->hard_cur_sectors;
+	flush_rq->special = rq;
+	flush_rq->nr_sectors = rq->nr_sectors;
+
+	if (!post) {
+		drive->doing_barrier = 1;
+		flush_rq->flags |= REQ_BAR_PREFLUSH;
+		blkdev_dequeue_request(rq);
+	} else
+		flush_rq->flags |= REQ_BAR_POSTFLUSH;
+
+	__elv_add_request(drive->queue, flush_rq, ELEVATOR_INSERT_FRONT, 0);
+	HWGROUP(drive)->rq = NULL;
+	return flush_rq;
+}
+
+static int __ide_end_request(ide_drive_t *drive, struct request *rq,
+			     int uptodate, int nr_sectors)
+{
+	int ret = 1;
+
+	BUG_ON(!(rq->flags & REQ_STARTED));
 
 	/*
 	 * if failfast is set on a request, override number of sectors and
 	 * complete the whole request right now
 	 */
-	if (blk_noretry_request(rq) && !uptodate)
+	if (blk_noretry_request(rq) && end_io_error(uptodate))
 		nr_sectors = rq->hard_nr_sectors;
 
+	if (!blk_fs_request(rq) && end_io_error(uptodate) && !rq->errors)
+		rq->errors = -EIO;
+
 	/*
 	 * decide whether to reenable DMA -- 3 is a random magic for now,
 	 * if we DMA timeout more than 3 times, just stay in PIO
@@ -97,15 +132,56 @@
 
 	if (!end_that_request_first(rq, uptodate, nr_sectors)) {
 		add_disk_randomness(rq->rq_disk);
+
+		if (blk_rq_tagged(rq))
+			blk_queue_end_tag(drive->queue, rq);
+
 		blkdev_dequeue_request(rq);
 		HWGROUP(drive)->rq = NULL;
 		end_that_request_last(rq);
 		ret = 0;
 	}
-	spin_unlock_irqrestore(&ide_lock, flags);
 	return ret;
 }
 
+/**
+ *	ide_end_request		-	complete an IDE I/O
+ *	@drive: IDE device for the I/O
+ *	@uptodate:
+ *	@nr_sectors: number of sectors completed
+ *
+ *	This is our end_request wrapper function. We complete the I/O
+ *	update random number input and dequeue the request, which if
+ *	it was tagged may be out of order.
+ */
+
+int ide_end_request (ide_drive_t *drive, int uptodate, int nr_sectors)
+{
+	struct request *rq;
+	unsigned long flags;
+	int ret = 1;
+
+	spin_lock_irqsave(&ide_lock, flags);
+	rq = HWGROUP(drive)->rq;
+
+	if (!nr_sectors)
+		nr_sectors = rq->hard_cur_sectors;
+
+	if (!blk_barrier_rq(rq))
+		ret = __ide_end_request(drive, rq, uptodate, nr_sectors);
+	else {
+		struct request *flush_rq = &HWGROUP(drive)->wrq;
+
+		flush_rq->nr_sectors -= nr_sectors;
+		if (!flush_rq->nr_sectors) {
+			ide_queue_flush_cmd(drive, rq, 1);
+			ret = 0;
+		}
+	}
+
+	spin_unlock_irqrestore(&ide_lock, flags);
+	return ret;
+}
 EXPORT_SYMBOL(ide_end_request);
 
 /**
@@ -137,6 +213,113 @@
 	spin_unlock_irqrestore(&ide_lock, flags);
 }
 
+/*
+ * FIXME: probably move this somewhere else, name is bad too :)
+ */
+u64 ide_get_error_location(ide_drive_t *drive, char *args)
+{
+	u32 high, low;
+	u8 hcyl, lcyl, sect;
+	u64 sector;
+
+	high = 0;
+	hcyl = args[5];
+	lcyl = args[4];
+	sect = args[3];
+
+	if (ide_id_has_flush_cache_ext(drive->id)) {
+		low = (hcyl << 16) | (lcyl << 8) | sect;
+		HWIF(drive)->OUTB(drive->ctl|0x80, IDE_CONTROL_REG);
+		high = ide_read_24(drive);
+	} else {
+		u8 cur = HWIF(drive)->INB(IDE_SELECT_REG);
+		if (cur & 0x40)
+			low = (hcyl << 16) | (lcyl << 8) | sect;
+		else {
+			low = hcyl * drive->head * drive->sect;
+			low += lcyl * drive->sect;
+			low += sect - 1;
+		}
+	}
+
+	sector = ((u64) high << 24) | low;
+	return sector;
+}
+EXPORT_SYMBOL(ide_get_error_location);
+
+static void ide_complete_barrier(ide_drive_t *drive, struct request *rq,
+				 int error)
+{
+	struct request *real_rq = rq->special;
+	int good_sectors, bad_sectors;
+	sector_t sector;
+
+	if (!error) {
+		if (blk_barrier_postflush(rq)) {
+			/*
+			 * this completes the barrier write
+			 */
+			__ide_end_request(drive, real_rq, 1, real_rq->hard_nr_sectors);
+			drive->doing_barrier = 0;
+		} else {
+			/*
+			 * just indicate that we did the pre flush
+			 */
+			real_rq->flags |= REQ_BAR_PREFLUSH;
+			elv_requeue_request(drive->queue, real_rq);
+		}
+		/*
+		 * all is fine, return
+		 */
+		return;
+	}
+
+	/*
+	 * we need to end real_rq, but it's not on the queue currently.
+	 * put it back on the queue, so we don't have to special case
+	 * anything else for completing it
+	 */
+	if (!blk_barrier_postflush(rq))
+		elv_requeue_request(drive->queue, real_rq);
+
+	/*
+	 * drive aborted flush command, assume FLUSH_CACHE_* doesn't
+	 * work and disable barrier support
+	 */
+	if (error & ABRT_ERR) {
+		printk(KERN_ERR "%s: barrier support doesn't work\n", drive->name);
+		__ide_end_request(drive, real_rq, -EOPNOTSUPP, real_rq->hard_nr_sectors);
+		blk_queue_ordered(drive->queue, 0);
+		blk_queue_issue_flush_fn(drive->queue, NULL);
+	} else {
+		/*
+		 * find out what part of the request failed
+		 */
+		good_sectors = 0;
+		if (blk_barrier_postflush(rq)) {
+			sector = ide_get_error_location(drive, rq->buffer);
+
+			if ((sector >= real_rq->hard_sector) &&
+			    (sector < real_rq->hard_sector + real_rq->hard_nr_sectors))
+				good_sectors = sector - real_rq->hard_sector;
+		} else
+			sector = real_rq->hard_sector;
+
+		bad_sectors = real_rq->hard_nr_sectors - good_sectors;
+		if (good_sectors)
+			__ide_end_request(drive, real_rq, 1, good_sectors);
+		if (bad_sectors)
+			__ide_end_request(drive, real_rq, 0, bad_sectors);
+
+		printk(KERN_ERR "%s: failed barrier write: "
+				"sector=%Lx(good=%d/bad=%d)\n",
+				drive->name, (unsigned long long)sector,
+				good_sectors, bad_sectors);
+	}
+
+	drive->doing_barrier = 0;
+}
+
 /**
  *	ide_end_drive_cmd	-	end an explicit drive command
  *	@drive: command 
@@ -226,6 +409,10 @@
 
 	spin_lock_irqsave(&ide_lock, flags);
 	blkdev_dequeue_request(rq);
+
+	if (blk_barrier_preflush(rq) || blk_barrier_postflush(rq))
+		ide_complete_barrier(drive, rq, err);
+
 	HWGROUP(drive)->rq = NULL;
 	end_that_request_last(rq);
 	spin_unlock_irqrestore(&ide_lock, flags);
@@ -712,6 +899,22 @@
 repeat:	
 	best = NULL;
 	drive = hwgroup->drive;
+
+	/*
+	 * drive is doing pre-flush, ordered write, post-flush sequence. even
+	 * though that is 3 requests, it must be seen as a single transaction.
+	 * we must not preempt this drive until that is complete
+	 */
+	if (drive->doing_barrier) {
+		/*
+		 * small race where queue could get replugged during
+		 * the 3-request flush cycle, just yank the plug since
+		 * we want it to finish asap
+		 */
+		blk_remove_plug(drive->queue);
+		return drive;
+	}
+
 	do {
 		if ((!drive->sleep || time_after_eq(jiffies, drive->sleep))
 		    && !elv_queue_empty(drive->queue)) {
@@ -868,6 +1071,13 @@
 		}
 
 		/*
+		 * if rq is a barrier write, issue pre cache flush if not
+		 * already done
+		 */
+		if (blk_barrier_rq(rq) && !blk_barrier_preflush(rq))
+			rq = ide_queue_flush_cmd(drive, rq, 0);
+
+		/*
 		 * Sanity: don't accept a request that isn't a PM request
 		 * if we are currently power managed. This is very important as
 		 * blk_stop_queue() doesn't prevent the elv_next_request()
@@ -917,7 +1127,9 @@
  */
 void do_ide_request(request_queue_t *q)
 {
-	ide_do_request(q->queuedata, IDE_NO_IRQ);
+	ide_drive_t *drive = q->queuedata;
+
+	ide_do_request(HWGROUP(drive), IDE_NO_IRQ);
 }
 
 /*
@@ -1286,6 +1498,7 @@
 {
 	memset(rq, 0, sizeof(*rq));
 	rq->flags = REQ_DRIVE_CMD;
+	rq->ref_count = 1;
 }
 
 EXPORT_SYMBOL(ide_init_drive_cmd);
--- diff/drivers/ide/ide-probe.c	2004-06-11 19:17:28.000000000 +0100
+++ source/drivers/ide/ide-probe.c	2004-06-11 19:22:01.000000000 +0100
@@ -893,11 +893,15 @@
 	if (!q)
 		return 1;
 
-	q->queuedata = HWGROUP(drive);
+	q->queuedata = drive;
 	blk_queue_segment_boundary(q, 0xffff);
 
-	if (!hwif->rqsize)
-		hwif->rqsize = hwif->no_lba48 ? 256 : 65536;
+	if (!hwif->rqsize) {
+		if (hwif->max_rqsize)
+			hwif->rqsize = hwif->max_rqsize(drive);
+		else
+			hwif->rqsize = hwif->no_lba48 ? 256 : 65536;
+	}
 	if (hwif->rqsize < max_sectors)
 		max_sectors = hwif->rqsize;
 	blk_queue_max_sectors(q, max_sectors);
--- diff/drivers/ide/ide-proc.c	2004-06-11 19:17:28.000000000 +0100
+++ source/drivers/ide/ide-proc.c	2004-06-11 19:22:01.000000000 +0100
@@ -343,7 +343,6 @@
 		case ide_cy82c693:	name = "cy82c693";	break;
 		case ide_4drives:	name = "4drives";	break;
 		case ide_pmac:		name = "mac-io";	break;
-		case ide_pc9800:	name = "pc9800";	break;
 		default:		name = "(unknown)";	break;
 	}
 	len = sprintf(page, "%s\n", name);
--- diff/drivers/ide/ide.c	2004-06-11 19:17:28.000000000 +0100
+++ source/drivers/ide/ide.c	2004-06-11 19:22:01.000000000 +0100
@@ -437,6 +437,30 @@
 #endif	/* FANCY_STATUS_DUMPS */
 		printk("\n");
 	}
+	{
+		struct request *rq;
+		int opcode = 0x100;
+
+		spin_lock(&ide_lock);
+		rq = HWGROUP(drive)->rq;
+		spin_unlock(&ide_lock);
+		if (!rq)
+			goto out;
+		if (rq->flags & (REQ_DRIVE_CMD | REQ_DRIVE_TASK)) {
+			char *args = rq->buffer;
+			if (args)
+				opcode = args[0];
+		} else if (rq->flags & REQ_DRIVE_TASKFILE) {
+			ide_task_t *args = rq->special;
+			if (args) {
+				task_struct_t *tf = (task_struct_t *) args->tfRegister;
+				opcode = tf->command;
+			}
+		}
+
+		printk("ide: failed opcode was %x\n", opcode);
+	}
+out:
 	local_irq_restore(flags);
 	return err;
 }
--- diff/drivers/ide/pci/pdc202xx_new.c	2004-06-11 19:17:28.000000000 +0100
+++ source/drivers/ide/pci/pdc202xx_new.c	2004-06-11 19:22:01.000000000 +0100
@@ -404,7 +404,7 @@
 }
 #endif /* CONFIG_PPC_PMAC */
 
-static unsigned int __init init_chipset_pdcnew (struct pci_dev *dev, const char *name)
+static unsigned int __devinit init_chipset_pdcnew (struct pci_dev *dev, const char *name)
 {
 	if (dev->resource[PCI_ROM_RESOURCE].start) {
 		pci_write_config_dword(dev, PCI_ROM_ADDRESS,
@@ -429,7 +429,7 @@
 	return dev->irq;
 }
 
-static void __init init_hwif_pdc202new (ide_hwif_t *hwif)
+static void __devinit init_hwif_pdc202new (ide_hwif_t *hwif)
 {
 	hwif->autodma = 0;
 
@@ -457,12 +457,12 @@
 #endif /* PDC202_DEBUG_CABLE */
 }
 
-static void __init init_setup_pdcnew (struct pci_dev *dev, ide_pci_device_t *d)
+static void __devinit init_setup_pdcnew (struct pci_dev *dev, ide_pci_device_t *d)
 {
 	ide_setup_pci_device(dev, d);
 }
 
-static void __init init_setup_pdc20270 (struct pci_dev *dev, ide_pci_device_t *d)
+static void __devinit init_setup_pdc20270 (struct pci_dev *dev, ide_pci_device_t *d)
 {
 	struct pci_dev *findev = NULL;
 
@@ -488,7 +488,7 @@
 	ide_setup_pci_device(dev, d);
 }
 
-static void __init init_setup_pdc20276 (struct pci_dev *dev, ide_pci_device_t *d)
+static void __devinit init_setup_pdc20276 (struct pci_dev *dev, ide_pci_device_t *d)
 {
 	if ((dev->bus->self) &&
 	    (dev->bus->self->vendor == PCI_VENDOR_ID_INTEL) &&
--- diff/drivers/ide/pci/siimage.c	2004-06-11 19:17:28.000000000 +0100
+++ source/drivers/ide/pci/siimage.c	2004-06-11 19:22:01.000000000 +0100
@@ -132,13 +132,12 @@
 	else
 		pci_read_config_byte(hwif->pci_dev, 0x8A, &scsc);
 
-	if(is_sata(hwif))
-	{
-		if(strstr(drive->id->model, "Maxtor"))
+	if (is_sata(hwif)) {
+		if (strstr(drive->id->model, "Maxtor 4D060H3"))
 			return 3;
 		return 4;
 	}
-	
+
 	if ((scsc & 0x30) == 0x10)	/* 133 */
 		mode = 4;
 	else if ((scsc & 0x30) == 0x20)	/* 2xPCI */
@@ -966,25 +965,34 @@
 	hwif->mmio			= 2;
 }
 
-static int is_dev_seagate_sata(ide_drive_t *drive)
+/* TODO firmware versions should be added - eric */
+static const char * sil_blacklist [] = {
+	"ST320012AS",
+	"ST330013AS",
+	"ST340017AS",
+	"ST360015AS",
+	"ST380023AS",
+	"ST3120023AS",
+	"ST340014ASL",
+	"ST360014ASL",
+	"ST380011ASL",
+	"ST3120022ASL",
+	"ST3160021ASL",
+};
+
+static unsigned int siimage_sata_max_rqsize(ide_drive_t *drive)
 {
 	const char *s = &drive->id->model[0];
-	unsigned len;
+	unsigned int n;
 
-	if (!drive->present)
-		return 0;
-
-	len = strnlen(s, sizeof(drive->id->model));
-
-	if ((len > 4) && (!memcmp(s, "ST", 2))) {
-		if ((!memcmp(s + len - 2, "AS", 2)) ||
-		    (!memcmp(s + len - 3, "ASL", 3))) {
-			printk(KERN_INFO "%s: applying pessimistic Seagate "
-					 "errata fix\n", drive->name);
-			return 1;
+	for (n = 0; n < ARRAY_SIZE(sil_blacklist); n++)
+		if (!memcmp(sil_blacklist[n], s, strlen(sil_blacklist[n]))) {
+			printk(KERN_INFO "%s: applying Seagate errata fix\n",
+					 drive->name);
+			return 15;
 		}
-	}
-	return 0;
+
+	return 128;
 }
 
 /**
@@ -1007,9 +1015,10 @@
 	
 	hwif->hwif_data = 0;
 
-	hwif->rqsize = 128;
-	if (is_sata(hwif) && is_dev_seagate_sata(&hwif->drives[0]))
-		hwif->rqsize = 15;
+	if (is_sata(hwif) && (class_rev <= 0x01))
+		hwif->max_rqsize = siimage_sata_max_rqsize;
+	else
+		hwif->rqsize = 128;
 
 	if (pci_get_drvdata(dev) == NULL)
 		return;
--- diff/drivers/ieee1394/eth1394.c	2004-06-11 19:17:28.000000000 +0100
+++ source/drivers/ieee1394/eth1394.c	2004-06-11 19:22:01.000000000 +0100
@@ -431,9 +431,12 @@
 		if (!node)
 			return -ENOMEM;
 
-
 		node_info = kmalloc(sizeof(struct eth1394_node_info),
 				    in_interrupt() ? GFP_ATOMIC : GFP_KERNEL);
+		if (!node_info) {
+			kfree(node);
+			return -ENOMEM;
+                }
 
 		spin_lock_init(&node_info->pdg.lock);
 		INIT_LIST_HEAD(&node_info->pdg.list);
--- diff/drivers/input/keyboard/Kconfig	2004-06-11 19:17:28.000000000 +0100
+++ source/drivers/input/keyboard/Kconfig	2004-06-11 19:22:01.000000000 +0100
@@ -96,15 +96,3 @@
 
 	  To compile this driver as a module, choose M here: the
 	  module will be called amikbd.
-
-config KEYBOARD_98KBD
-	tristate "NEC PC-9800 Keyboard support"
-	depends on X86_PC9800 && INPUT && INPUT_KEYBOARD
-	select SERIO
-	help
-	  Say Y here if you want to use the NEC PC-9801/PC-9821 keyboard (or
-	  compatible) on your system.
-
-	  To compile this driver as a module, choose M here: the
-	  module will be called 98kbd.
-
--- diff/drivers/input/keyboard/atkbd.c	2004-06-11 19:17:28.000000000 +0100
+++ source/drivers/input/keyboard/atkbd.c	2004-06-11 19:22:01.000000000 +0100
@@ -47,6 +47,10 @@
 module_param_named(softrepeat, atkbd_softrepeat, bool, 0);
 MODULE_PARM_DESC(softrepeat, "Use software keyboard repeat");
 
+static int atkbd_softraw = 1;
+module_param_named(softraw, atkbd_softraw, bool, 0);
+MODULE_PARM_DESC(softraw, "Use software generated rawmode");
+
 static int atkbd_scroll;
 module_param_named(scroll, atkbd_scroll, bool, 0);
 MODULE_PARM_DESC(scroll, "Enable scroll-wheel on MS Office and similar keyboards");
@@ -80,13 +84,13 @@
 	 82, 83, 80, 76, 77, 72,  1, 69, 87, 78, 81, 74, 55, 73, 70, 99,
 
 	  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-	217,100,255,  0, 97,165,  0,  0,156,  0,  0,  0,  0,  0,  0,125,
-	173,114,  0,113,  0,  0,  0,126,128,  0,  0,140,  0,  0,  0,127,
+	217,100,255,  0, 97,165,172,  0,156,  0,  0,  0,  0,  0,187,125,
+	173,114,  0,113,  0,  0,189,126,128,  0,  0,140,  0,  0,  0,127,
 	159,  0,115,  0,164,  0,  0,116,158,  0,150,166,  0,  0,  0,142,
 	157,  0,  0,  0,  0,  0,  0,  0,155,  0, 98,  0,  0,163,  0,  0,
 	226,  0,  0,  0,  0,  0,  0,  0,  0,255, 96,  0,  0,  0,143,  0,
 	  0,  0,  0,  0,  0,  0,  0,  0,  0,107,  0,105,102,  0,  0,112,
-	110,111,108,112,106,103,  0,119,  0,118,109,  0, 99,104,119,  0,
+	110,111,108,112,106,103,171,119,  0,118,109,  0, 99,104,119,  0,
 
 	  0,  0,  0, 65, 99,
 };
@@ -164,34 +168,48 @@
 	{ ATKBD_SCR_CLICK, 0x60 },
 };
 
+#define ATKBD_FLAG_ACK		0	/* Waiting for ACK/NAK */
+#define ATKBD_FLAG_CMD		1	/* Waiting for command to finish */
+#define ATKBD_FLAG_CMD1		2	/* First byte of command response */
+#define ATKBD_FLAG_ID		3	/* First byte is not keyboard ID */
+#define ATKBD_FLAG_ENABLED	4	/* Waining for init to finish */
+
 /*
  * The atkbd control structure
  */
 
 struct atkbd {
-	unsigned char keycode[512];
-	struct input_dev dev;
-	struct serio *serio;
 
+	/* Written only during init */
 	char name[64];
 	char phys[32];
-	unsigned short id;
+	struct serio *serio;
+	struct input_dev dev;
+
 	unsigned char set;
-	unsigned int translated:1;
-	unsigned int extra:1;
-	unsigned int write:1;
+	unsigned short id;
+	unsigned char keycode[512];
+	unsigned char translated;
+	unsigned char extra;
+	unsigned char write;
+
+	/* Protected by FLAG_ACK */
+	unsigned char nak;
 
+	/* Protected by FLAG_CMD */
 	unsigned char cmdbuf[4];
 	unsigned char cmdcnt;
-	volatile signed char ack;
-	unsigned char emul;
-	unsigned int resend:1;
-	unsigned int release:1;
-	unsigned int bat_xl:1;
-	unsigned int enabled:1;
 
+	/* Accessed only from interrupt */
+	unsigned char emul;
+	unsigned char resend;
+	unsigned char release;
+	unsigned char bat_xl;
 	unsigned int last;
 	unsigned long time;
+
+	/* Flags */
+	unsigned long flags;
 };
 
 static void atkbd_report_key(struct input_dev *dev, struct pt_regs *regs, int code, int value)
@@ -224,7 +242,7 @@
 
 #if !defined(__i386__) && !defined (__x86_64__)
 	if ((flags & (SERIO_FRAME | SERIO_PARITY)) && (~flags & SERIO_TIMEOUT) && !atkbd->resend && atkbd->write) {
-		printk("atkbd.c: frame/parity error: %02x\n", flags);
+		printk(KERN_WARNING "atkbd.c: frame/parity error: %02x\n", flags);
 		serio_write(serio, ATKBD_CMD_RESEND);
 		atkbd->resend = 1;
 		goto out;
@@ -234,24 +252,45 @@
 		atkbd->resend = 0;
 #endif
 
-	if (!atkbd->ack)
+	if (test_bit(ATKBD_FLAG_ACK, &atkbd->flags))
 		switch (code) {
 			case ATKBD_RET_ACK:
-				atkbd->ack = 1;
+				atkbd->nak = 0;
+				if (atkbd->cmdcnt) {
+					set_bit(ATKBD_FLAG_CMD, &atkbd->flags);
+					set_bit(ATKBD_FLAG_CMD1, &atkbd->flags);
+					set_bit(ATKBD_FLAG_ID, &atkbd->flags);
+				}
+				clear_bit(ATKBD_FLAG_ACK, &atkbd->flags);
 				goto out;
 			case ATKBD_RET_NAK:
-				atkbd->ack = -1;
+				atkbd->nak = 1;
+				clear_bit(ATKBD_FLAG_ACK, &atkbd->flags);
 				goto out;
 		}
 
-	if (atkbd->cmdcnt) {
-		atkbd->cmdbuf[--atkbd->cmdcnt] = code;
+	if (test_bit(ATKBD_FLAG_CMD, &atkbd->flags)) {
+
+		atkbd->cmdcnt--;
+		atkbd->cmdbuf[atkbd->cmdcnt] = code;
+
+		if (atkbd->cmdcnt == 1) {
+		    	if (code != 0xab && code != 0xac)
+				clear_bit(ATKBD_FLAG_ID, &atkbd->flags);
+			clear_bit(ATKBD_FLAG_CMD1, &atkbd->flags);
+		}
+
+		if (!atkbd->cmdcnt)
+			clear_bit(ATKBD_FLAG_CMD, &atkbd->flags);
+
 		goto out;
 	}
 
-	if (!atkbd->enabled)
+	if (!test_bit(ATKBD_FLAG_ENABLED, &atkbd->flags))
 		goto out;
 
+	input_event(&atkbd->dev, EV_MSC, MSC_RAW, code);
+
 	if (atkbd->translated) {
 
 		if (atkbd->emul ||
@@ -270,6 +309,7 @@
 
 	switch (code) {
 		case ATKBD_RET_BAT:
+			clear_bit(ATKBD_FLAG_ENABLED, &atkbd->flags);
 			serio_rescan(atkbd->serio);
 			goto out;
 		case ATKBD_RET_EMUL0:
@@ -300,6 +340,9 @@
 		code |= (atkbd->set != 3) ? 0x80 : 0x100;
 	}
 
+	if (atkbd->keycode[code] != ATKBD_KEY_NULL)
+		input_event(&atkbd->dev, EV_MSC, MSC_SCAN, code);
+
 	switch (atkbd->keycode[code]) {
 		case ATKBD_KEY_NULL:
 			break;
@@ -376,18 +419,20 @@
 
 static int atkbd_sendbyte(struct atkbd *atkbd, unsigned char byte)
 {
-	int timeout = 20000; /* 200 msec */
-	atkbd->ack = 0;
+	int timeout = 200000; /* 200 msec */
 
 #ifdef ATKBD_DEBUG
 	printk(KERN_DEBUG "atkbd.c: Sent: %02x\n", byte);
 #endif
+
+	set_bit(ATKBD_FLAG_ACK, &atkbd->flags);
+	clear_bit(ATKBD_FLAG_CMD, &atkbd->flags);
 	if (serio_write(atkbd->serio, byte))
 		return -1;
+	while (test_bit(ATKBD_FLAG_ACK, &atkbd->flags) && timeout--) udelay(1);
+	clear_bit(ATKBD_FLAG_ACK, &atkbd->flags);
 
-	while (!atkbd->ack && timeout--) udelay(10);
-
-	return -(atkbd->ack <= 0);
+	return -atkbd->nak;
 }
 
 /*
@@ -405,7 +450,7 @@
 	atkbd->cmdcnt = receive;
 
 	if (command == ATKBD_CMD_RESET_BAT)
-		timeout = 2000000; /* 2 sec */
+		timeout = 4000000; /* 4 sec */
 
 	if (receive && param)
 		for (i = 0; i < receive; i++)
@@ -413,38 +458,40 @@
 
 	if (command & 0xff)
 		if (atkbd_sendbyte(atkbd, command & 0xff))
-			return (atkbd->cmdcnt = 0) - 1;
+			return -1;
 
 	for (i = 0; i < send; i++)
 		if (atkbd_sendbyte(atkbd, param[i]))
-			return (atkbd->cmdcnt = 0) - 1;
-
-	while (atkbd->cmdcnt && timeout--) {
+			return -1;
 
-		if (atkbd->cmdcnt == 1 &&
-		    command == ATKBD_CMD_RESET_BAT && timeout > 100000)
-			timeout = 100000;
+	while (test_bit(ATKBD_FLAG_CMD, &atkbd->flags) && timeout--) {
 
-		if (atkbd->cmdcnt == 1 && command == ATKBD_CMD_GETID &&
-		    atkbd->cmdbuf[1] != 0xab && atkbd->cmdbuf[1] != 0xac) {
-			atkbd->cmdcnt = 0;
-			break;
+		if (!test_bit(ATKBD_FLAG_CMD1, &atkbd->flags)) {
+		    
+			if (command == ATKBD_CMD_RESET_BAT && timeout > 100000)
+				timeout = 100000;
+
+			if (command == ATKBD_CMD_GETID && !test_bit(ATKBD_FLAG_ID, &atkbd->flags)) {
+				clear_bit(ATKBD_FLAG_CMD, &atkbd->flags);
+				atkbd->cmdcnt = 0;
+				break;
+			}
 		}
 
 		udelay(1);
 	}
 
+	clear_bit(ATKBD_FLAG_CMD, &atkbd->flags);
+
 	if (param)
 		for (i = 0; i < receive; i++)
 			param[i] = atkbd->cmdbuf[(receive - 1) - i];
 
 	if (command == ATKBD_CMD_RESET_BAT && atkbd->cmdcnt == 1)
-		atkbd->cmdcnt = 0;
+		return 0;
 
-	if (atkbd->cmdcnt) {
-		atkbd->cmdcnt = 0;
+	if (atkbd->cmdcnt)
 		return -1;
-	}
 
 	return 0;
 }
@@ -672,6 +719,7 @@
 static void atkbd_disconnect(struct serio *serio)
 {
 	struct atkbd *atkbd = serio->private;
+	clear_bit(ATKBD_FLAG_ENABLED, &atkbd->flags);
 	input_unregister_device(&atkbd->dev);
 	serio_close(serio);
 	kfree(atkbd);
@@ -709,17 +757,22 @@
 			return;
 	}
 
+	if (!atkbd->write)
+		atkbd_softrepeat = 1;
+	if (atkbd_softrepeat)
+		atkbd_softraw = 1;
+
 	if (atkbd->write) {
-		atkbd->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_LED) | BIT(EV_REP);
+		atkbd->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_LED) | BIT(EV_REP) | BIT(EV_MSC);
 		atkbd->dev.ledbit[0] = BIT(LED_NUML) | BIT(LED_CAPSL) | BIT(LED_SCROLLL);
-	} else  atkbd->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_REP);
+	} else  atkbd->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_REP) | BIT(EV_MSC);
+	atkbd->dev.mscbit[0] = atkbd_softraw ? BIT(MSC_SCAN) : BIT(MSC_RAW) | BIT(MSC_SCAN);
 
 	if (!atkbd_softrepeat) {
 		atkbd->dev.rep[REP_DELAY] = 250;
 		atkbd->dev.rep[REP_PERIOD] = 33;
-	}
+	} else atkbd_softraw = 1;
 
-	atkbd->ack = 1;
 	atkbd->serio = serio;
 
 	init_input_dev(&atkbd->dev);
@@ -754,8 +807,6 @@
 		atkbd->id = 0xab00;
 	}
 
-	atkbd->enabled = 1;
-
 	if (atkbd->extra) {
 		atkbd->dev.ledbit[0] |= BIT(LED_COMPOSE) | BIT(LED_SUSPEND) | BIT(LED_SLEEP) | BIT(LED_MUTE) | BIT(LED_MISC);
 		sprintf(atkbd->name, "AT Set 2 Extra keyboard");
@@ -797,6 +848,8 @@
 
 	input_register_device(&atkbd->dev);
 
+	set_bit(ATKBD_FLAG_ENABLED, &atkbd->flags);
+
 	printk(KERN_INFO "input: %s on %s\n", atkbd->name, serio->phys);
 }
 
@@ -832,6 +885,8 @@
 			return -1;
 	}
 
+	set_bit(ATKBD_FLAG_ENABLED, &atkbd->flags);
+
 	return 0;
 }
 
--- diff/drivers/input/misc/Kconfig	2004-06-11 19:17:28.000000000 +0100
+++ source/drivers/input/misc/Kconfig	2004-06-11 19:22:01.000000000 +0100
@@ -40,10 +40,6 @@
 	tristate "M68k Beeper support"
 	depends on M68K && INPUT && INPUT_MISC
 
-config INPUT_98SPKR
-	tristate "PC-9800 Speaker support"
-	depends on X86_PC9800 && INPUT && INPUT_MISC
-
 config INPUT_UINPUT
 	tristate "User level driver support"
 	depends on INPUT && INPUT_MISC
--- diff/drivers/input/misc/uinput.c	2004-06-11 19:17:28.000000000 +0100
+++ source/drivers/input/misc/uinput.c	2004-06-11 19:22:01.000000000 +0100
@@ -279,6 +279,9 @@
 {
 	struct uinput_device *udev = file->private_data;
 
+	if (!test_bit(UIST_CREATED, &(udev->state)))
+		return 0;
+
 	poll_wait(file, &udev->waitq, wait);
 
 	if (udev->head != udev->tail)
--- diff/drivers/input/mouse/Kconfig	2004-05-19 22:11:44.000000000 +0100
+++ source/drivers/input/mouse/Kconfig	2004-06-11 19:22:01.000000000 +0100
@@ -30,8 +30,6 @@
 	  and a new verion of GPM at:
 		http://www.geocities.com/dt_or/gpm/gpm.html
 	  to take advantage of the advanced features of the touchpad.
-	  If you do not want install specialized drivers but want tapping
-	  working please use option psmouse.proto=imps.
 
 	  If unsure, say Y.
 
@@ -130,14 +128,3 @@
 	  described in the source file). This driver should, in theory,
 	  also work with the digitizer DEC produced, but it isn't tested
 	  with that (I don't have the hardware yet).
-
-config MOUSE_PC9800
-	tristate "NEC PC-9800 busmouse"
-	depends on X86_PC9800 && INPUT && INPUT_MOUSE && ISA
-	help
-	  Say Y here if you have NEC PC-9801/PC-9821 computer and want its
-	  native mouse supported.
-
-	  To compile this driver as a module, choose M here: the
-	  module will be called 98busmouse.
-
--- diff/drivers/input/mouse/Makefile	2004-05-19 22:11:44.000000000 +0100
+++ source/drivers/input/mouse/Makefile	2004-06-11 19:22:01.000000000 +0100
@@ -10,7 +10,6 @@
 obj-$(CONFIG_MOUSE_LOGIBM)	+= logibm.o
 obj-$(CONFIG_MOUSE_MAPLE)	+= maplemouse.o
 obj-$(CONFIG_MOUSE_PC110PAD)	+= pc110pad.o
-obj-$(CONFIG_MOUSE_PC9800)	+= 98busmouse.o
 obj-$(CONFIG_MOUSE_PS2)		+= psmouse.o
 obj-$(CONFIG_MOUSE_SERIAL)	+= sermouse.o
 obj-$(CONFIG_MOUSE_VSXXXAA)	+= vsxxxaa.o
--- diff/drivers/input/mouse/logips2pp.c	2004-06-11 19:17:28.000000000 +0100
+++ source/drivers/input/mouse/logips2pp.c	2004-06-11 19:22:01.000000000 +0100
@@ -277,7 +277,7 @@
 				protocol = PSMOUSE_PS2TPP;
 			}
 
-		} else if (get_model_info(model) != NULL) {
+		} else if (model_info != NULL) {
 
 			param[0] = param[1] = param[2] = 0;
 			ps2pp_cmd(psmouse, param, 0x39); /* Magic knock */
--- diff/drivers/input/mouse/psmouse-base.c	2004-06-11 19:17:28.000000000 +0100
+++ source/drivers/input/mouse/psmouse-base.c	2004-06-11 19:22:01.000000000 +0100
@@ -142,34 +142,45 @@
 			printk(KERN_WARNING "psmouse.c: bad data from KBC -%s%s\n",
 				flags & SERIO_TIMEOUT ? " timeout" : "",
 				flags & SERIO_PARITY ? " bad parity" : "");
-		if (psmouse->acking) {
-			psmouse->ack = -1;
-			psmouse->acking = 0;
-		}
-		psmouse->pktcnt = 0;
+		psmouse->nak = 1;
+		clear_bit(PSMOUSE_FLAG_ACK, &psmouse->flags);
+		clear_bit(PSMOUSE_FLAG_CMD,  &psmouse->flags);
 		goto out;
 	}
 
-	if (psmouse->acking) {
+	if (test_bit(PSMOUSE_FLAG_ACK, &psmouse->flags))
 		switch (data) {
 			case PSMOUSE_RET_ACK:
-				psmouse->ack = 1;
+				psmouse->nak = 0;
+				clear_bit(PSMOUSE_FLAG_ACK, &psmouse->flags);
+				goto out;
 				break;
 			case PSMOUSE_RET_NAK:
-				psmouse->ack = -1;
-				break;
+				psmouse->nak = 1;
+				clear_bit(PSMOUSE_FLAG_ACK, &psmouse->flags);
+				goto out;
 			default:
-				psmouse->ack = 1;	/* Workaround for mice which don't ACK the Get ID command */
-				if (psmouse->cmdcnt)
-					psmouse->cmdbuf[--psmouse->cmdcnt] = data;
-				break;
+				psmouse->nak = 0;	/* Workaround for mice which don't ACK the Get ID command */
+				clear_bit(PSMOUSE_FLAG_ACK, &psmouse->flags);
+				if (!test_bit(PSMOUSE_FLAG_CMD, &psmouse->flags))
+					goto out;
+
 		}
-		psmouse->acking = 0;
-		goto out;
-	}
 
-	if (psmouse->cmdcnt) {
-		psmouse->cmdbuf[--psmouse->cmdcnt] = data;
+	if (test_bit(PSMOUSE_FLAG_CMD, &psmouse->flags)) {
+
+		psmouse->cmdcnt--;
+		psmouse->cmdbuf[psmouse->cmdcnt] = data;
+
+		if (psmouse->cmdcnt == 1) {
+			if (data != 0xab && data != 0xac)
+				clear_bit(PSMOUSE_FLAG_ID, &psmouse->flags);
+			clear_bit(PSMOUSE_FLAG_CMD1, &psmouse->flags);
+		}
+
+		if (!psmouse->cmdcnt)
+			clear_bit(PSMOUSE_FLAG_CMD, &psmouse->flags);
+
 		goto out;
 	}
 
@@ -242,18 +253,15 @@
 
 static int psmouse_sendbyte(struct psmouse *psmouse, unsigned char byte)
 {
-	int timeout = 10000; /* 100 msec */
-	psmouse->ack = 0;
-	psmouse->acking = 1;
+	int timeout = 200000; /* 200 msec */
 
-	if (serio_write(psmouse->serio, byte)) {
-		psmouse->acking = 0;
+	set_bit(PSMOUSE_FLAG_ACK, &psmouse->flags);
+	if (serio_write(psmouse->serio, byte))
 		return -1;
-	}
-
-	while (!psmouse->ack && timeout--) udelay(10);
+	while (test_bit(PSMOUSE_FLAG_ACK, &psmouse->flags) && timeout--) udelay(1);
+	clear_bit(PSMOUSE_FLAG_ACK, &psmouse->flags);
 
-	return -(psmouse->ack <= 0);
+	return -psmouse->nak;
 }
 
 /*
@@ -271,46 +279,62 @@
 	psmouse->cmdcnt = receive;
 
 	if (command == PSMOUSE_CMD_RESET_BAT)
-                timeout = 4000000; /* 4 sec */
+		timeout = 4000000; /* 4 sec */
 
-	/* initialize cmdbuf with preset values from param */
-	if (receive)
-	   for (i = 0; i < receive; i++)
-		psmouse->cmdbuf[(receive - 1) - i] = param[i];
+	if (receive && param)
+		for (i = 0; i < receive; i++)
+			psmouse->cmdbuf[(receive - 1) - i] = param[i];
+
+	if (receive) {
+		set_bit(PSMOUSE_FLAG_CMD, &psmouse->flags);
+		set_bit(PSMOUSE_FLAG_CMD1, &psmouse->flags);
+		set_bit(PSMOUSE_FLAG_ID, &psmouse->flags);
+	}
 
 	if (command & 0xff)
-		if (psmouse_sendbyte(psmouse, command & 0xff))
-			return (psmouse->cmdcnt = 0) - 1;
+		if (psmouse_sendbyte(psmouse, command & 0xff)) {
+			clear_bit(PSMOUSE_FLAG_CMD, &psmouse->flags);
+			return -1;
+		}
 
 	for (i = 0; i < send; i++)
-		if (psmouse_sendbyte(psmouse, param[i]))
-			return (psmouse->cmdcnt = 0) - 1;
+		if (psmouse_sendbyte(psmouse, param[i])) {
+			clear_bit(PSMOUSE_FLAG_CMD, &psmouse->flags);
+			return -1;
+		}
 
-	while (psmouse->cmdcnt && timeout--) {
+	while (test_bit(PSMOUSE_FLAG_CMD, &psmouse->flags) && timeout--) {
 
-		if (psmouse->cmdcnt == 1 && command == PSMOUSE_CMD_RESET_BAT &&
-				timeout > 100000) /* do not run in a endless loop */
-			timeout = 100000; /* 1 sec */
-
-		if (psmouse->cmdcnt == 1 && command == PSMOUSE_CMD_GETID &&
-		    psmouse->cmdbuf[1] != 0xab && psmouse->cmdbuf[1] != 0xac) {
-			psmouse->cmdcnt = 0;
-			break;
+		if (!test_bit(PSMOUSE_FLAG_CMD1, &psmouse->flags)) {
+		    
+			if (command == PSMOUSE_CMD_RESET_BAT && timeout > 100000)
+				timeout = 100000;
+
+			if (command == PSMOUSE_CMD_GETID && !test_bit(PSMOUSE_FLAG_ID, &psmouse->flags)) {
+				clear_bit(PSMOUSE_FLAG_CMD, &psmouse->flags);
+				psmouse->cmdcnt = 0;
+				break;
+			}
 		}
 
 		udelay(1);
 	}
 
-	for (i = 0; i < receive; i++)
-		param[i] = psmouse->cmdbuf[(receive - 1) - i];
+	clear_bit(PSMOUSE_FLAG_CMD, &psmouse->flags);
+
+	if (param)
+		for (i = 0; i < receive; i++)
+			param[i] = psmouse->cmdbuf[(receive - 1) - i];
+
+	if (command == PSMOUSE_CMD_RESET_BAT && psmouse->cmdcnt == 1)
+		return 0;
 
 	if (psmouse->cmdcnt)
-		return (psmouse->cmdcnt = 0) - 1;
+		return -1;
 
 	return 0;
 }
 
-
 /*
  * psmouse_sliced_command() sends an extended PS/2 command to the mouse
  * using sliced syntax, understood by advanced devices, such as Logitech
@@ -735,7 +759,12 @@
 	}
 
 	psmouse->state = PSMOUSE_CMD_MODE;
-	psmouse->acking = psmouse->cmdcnt = psmouse->pktcnt = psmouse->out_of_sync = 0;
+
+	clear_bit(PSMOUSE_FLAG_ACK, &psmouse->flags);
+	clear_bit(PSMOUSE_FLAG_CMD,  &psmouse->flags);
+
+	psmouse->pktcnt = psmouse->out_of_sync = 0;
+
 	if (psmouse->reconnect) {
 	       if (psmouse->reconnect(psmouse))
 			return -1;
--- diff/drivers/input/mouse/psmouse.h	2004-06-11 19:17:28.000000000 +0100
+++ source/drivers/input/mouse/psmouse.h	2004-06-11 19:22:01.000000000 +0100
@@ -22,6 +22,11 @@
 #define PSMOUSE_ACTIVATED	1
 #define PSMOUSE_IGNORE		2
 
+#define PSMOUSE_FLAG_ACK	0	/* Waiting for ACK/NAK */
+#define PSMOUSE_FLAG_CMD	1	/* Waiting for command to finish */
+#define PSMOUSE_FLAG_CMD1	2	/* First byte of command response */
+#define PSMOUSE_FLAG_ID		3	/* First byte is not keyboard ID */
+
 /* psmouse protocol handler return codes */
 typedef enum {
 	PSMOUSE_BAD_DATA,
@@ -54,11 +59,11 @@
 	unsigned long last;
 	unsigned long out_of_sync;
 	unsigned char state;
-	char acking;
-	volatile char ack;
+	unsigned char nak;
 	char error;
 	char devname[64];
 	char phys[32];
+	unsigned long flags;
 
 	psmouse_ret_t (*protocol_handler)(struct psmouse *psmouse, struct pt_regs *regs); 
 	int (*reconnect)(struct psmouse *psmouse);
--- diff/drivers/input/mousedev.c	2004-06-11 19:17:28.000000000 +0100
+++ source/drivers/input/mousedev.c	2004-06-11 19:22:01.000000000 +0100
@@ -48,8 +48,13 @@
 module_param(yres, uint, 0);
 MODULE_PARM_DESC(yres, "Vertical screen resolution");
 
+static unsigned tap_time = 200;
+module_param(tap_time, uint, 0);
+MODULE_PARM_DESC(tap_time, "Tap time for touchpads in absolute mode (msecs)");
+
 struct mousedev_motion {
 	int dx, dy, dz;
+	unsigned long buttons;
 };
 
 struct mousedev {
@@ -62,21 +67,31 @@
 	struct input_handle handle;
 
 	struct mousedev_motion packet;
-	unsigned long buttons;
 	unsigned int pkt_count;
 	int old_x[4], old_y[4];
-	unsigned int touch;
+	unsigned long touch;
 };
 
+enum mousedev_emul {
+	MOUSEDEV_EMUL_PS2,
+	MOUSEDEV_EMUL_IMPS,
+	MOUSEDEV_EMUL_EXPS
+} __attribute__ ((packed));
+
+#define PACKET_QUEUE_LEN	16
 struct mousedev_list {
 	struct fasync_struct *fasync;
 	struct mousedev *mousedev;
 	struct list_head node;
-	int dx, dy, dz;
-	unsigned long buttons;
+
+	struct mousedev_motion packets[PACKET_QUEUE_LEN];
+	unsigned int head, tail;
+	spinlock_t packet_lock;
+
 	signed char ps2[6];
 	unsigned char ready, buffer, bufsiz;
-	unsigned char mode, imexseq, impsseq;
+	unsigned char imexseq, impsseq;
+	enum mousedev_emul mode;
 };
 
 #define MOUSEDEV_SEQ_LEN	6
@@ -165,30 +180,70 @@
 	}
 
 	if (value) {
-		set_bit(index, &mousedev->buttons);
-		set_bit(index, &mousedev_mix.buttons);
+		set_bit(index, &mousedev->packet.buttons);
+		set_bit(index, &mousedev_mix.packet.buttons);
 	} else {
-		clear_bit(index, &mousedev->buttons);
-		clear_bit(index, &mousedev_mix.buttons);
+		clear_bit(index, &mousedev->packet.buttons);
+		clear_bit(index, &mousedev_mix.packet.buttons);
 	}
 }
 
 static void mousedev_notify_readers(struct mousedev *mousedev, struct mousedev_motion *packet)
 {
 	struct mousedev_list *list;
+	struct mousedev_motion *p;
+	unsigned long flags;
 
 	list_for_each_entry(list, &mousedev->list, node) {
-		list->dx += packet->dx;
-		list->dy += packet->dy;
-		list->dz += packet->dz;
-		list->buttons = mousedev->buttons;
+		spin_lock_irqsave(&list->packet_lock, flags);
+
+		p = &list->packets[list->head];
+		if (list->ready && p->buttons != packet->buttons) {
+			unsigned int new_head = (list->head + 1) % PACKET_QUEUE_LEN;
+			if (new_head != list->tail) {
+				p = &list->packets[list->head = new_head];
+				memset(p, 0, sizeof(struct mousedev_motion));
+			}
+		}
+
+		p->dx += packet->dx;
+		p->dy += packet->dy;
+		p->dz += packet->dz;
+		p->buttons = mousedev->packet.buttons;
+
 		list->ready = 1;
+
+		spin_unlock_irqrestore(&list->packet_lock, flags);
 		kill_fasync(&list->fasync, SIGIO, POLL_IN);
 	}
 
 	wake_up_interruptible(&mousedev->wait);
 }
 
+static void mousedev_touchpad_touch(struct mousedev *mousedev, int value)
+{
+	if (!value) {
+		if (mousedev->touch &&
+		    !time_after(jiffies, mousedev->touch + msecs_to_jiffies(tap_time))) {
+			/*
+			 * Toggle left button to emulate tap.
+			 * We rely on the fact that mousedev_mix always has 0
+			 * motion packet so we won't mess current position.
+			 */
+			set_bit(0, &mousedev->packet.buttons);
+			set_bit(0, &mousedev_mix.packet.buttons);
+			mousedev_notify_readers(mousedev, &mousedev_mix.packet);
+			mousedev_notify_readers(&mousedev_mix, &mousedev_mix.packet);
+			clear_bit(0, &mousedev->packet.buttons);
+			clear_bit(0, &mousedev_mix.packet.buttons);
+		}
+		mousedev->touch = mousedev->pkt_count = 0;
+	}
+	else
+		if (!mousedev->touch)
+			mousedev->touch = jiffies;
+}
+
 static void mousedev_event(struct input_handle *handle, unsigned int type, unsigned int code, int value)
 {
 	struct mousedev *mousedev = handle->private;
@@ -212,12 +267,8 @@
 
 		case EV_KEY:
 			if (value != 2) {
-				if (code == BTN_TOUCH && test_bit(BTN_TOOL_FINGER, handle->dev->keybit)) {
-					/* Handle touchpad data */
-					mousedev->touch = value;
-					if (!mousedev->touch)
-						mousedev->pkt_count = 0;
-				}
+				if (code == BTN_TOUCH && test_bit(BTN_TOOL_FINGER, handle->dev->keybit))
+					mousedev_touchpad_touch(mousedev, value);
 				else
 					mousedev_key_event(mousedev, code, value);
 			}
@@ -237,7 +288,7 @@
 				mousedev_notify_readers(mousedev, &mousedev->packet);
 				mousedev_notify_readers(&mousedev_mix, &mousedev->packet);
 
-				memset(&mousedev->packet, 0, sizeof(struct mousedev_motion));
+				mousedev->packet.dx = mousedev->packet.dy = mousedev->packet.dz = 0;
 			}
 			break;
 	}
@@ -322,6 +373,7 @@
 		return -ENOMEM;
 	memset(list, 0, sizeof(struct mousedev_list));
 
+	spin_lock_init(&list->packet_lock);
 	list->mousedev = mousedev_table[i];
 	list_add_tail(&list->node, &mousedev_table[i]->list);
 	file->private_data = list;
@@ -341,32 +393,56 @@
 	return 0;
 }
 
-static void mousedev_packet(struct mousedev_list *list, unsigned char off)
+static inline int mousedev_limit_delta(int delta, int limit)
 {
-	list->ps2[off] = 0x08 | ((list->dx < 0) << 4) | ((list->dy < 0) << 5) | (list->buttons & 0x07);
-	list->ps2[off + 1] = (list->dx > 127 ? 127 : (list->dx < -127 ? -127 : list->dx));
-	list->ps2[off + 2] = (list->dy > 127 ? 127 : (list->dy < -127 ? -127 : list->dy));
-	list->dx -= list->ps2[off + 1];
-	list->dy -= list->ps2[off + 2];
-	list->bufsiz = off + 3;
-
-	if (list->mode == 2) {
-		list->ps2[off + 3] = (list->dz > 7 ? 7 : (list->dz < -7 ? -7 : list->dz));
-		list->dz -= list->ps2[off + 3];
-		list->ps2[off + 3] = (list->ps2[off + 3] & 0x0f) | ((list->buttons & 0x18) << 1);
-		list->bufsiz++;
-	} else {
-		list->ps2[off] |= ((list->buttons & 0x10) >> 3) | ((list->buttons & 0x08) >> 1);
+	return delta > limit ? limit : (delta < -limit ? -limit : delta);
+}
+
+static void mousedev_packet(struct mousedev_list *list, signed char *ps2_data)
+{
+	struct mousedev_motion *p;
+	unsigned long flags;
+
+	spin_lock_irqsave(&list->packet_lock, flags);
+	p = &list->packets[list->tail];
+
+	ps2_data[0] = 0x08 | ((p->dx < 0) << 4) | ((p->dy < 0) << 5) | (p->buttons & 0x07);
+	ps2_data[1] = mousedev_limit_delta(p->dx, 127);
+	ps2_data[2] = mousedev_limit_delta(p->dy, 127);
+	p->dx -= ps2_data[1];
+	p->dy -= ps2_data[2];
+
+	switch (list->mode) {
+		case MOUSEDEV_EMUL_EXPS:
+			ps2_data[3] = mousedev_limit_delta(p->dz, 127);
+			p->dz -= ps2_data[3];
+			ps2_data[3] = (ps2_data[3] & 0x0f) | ((p->buttons & 0x18) << 1);
+			list->bufsiz = 4;
+			break;
+
+		case MOUSEDEV_EMUL_IMPS:
+			ps2_data[0] |= ((p->buttons & 0x10) >> 3) | ((p->buttons & 0x08) >> 1);
+			ps2_data[3] = mousedev_limit_delta(p->dz, 127);
+			p->dz -= ps2_data[3];
+			list->bufsiz = 4;
+			break;
+
+		case MOUSEDEV_EMUL_PS2:
+		default:
+			ps2_data[0] |= ((p->buttons & 0x10) >> 3) | ((p->buttons & 0x08) >> 1);
+			p->dz = 0;
+			list->bufsiz = 3;
+			break;
 	}
 
-	if (list->mode == 1) {
-		list->ps2[off + 3] = (list->dz > 127 ? 127 : (list->dz < -127 ? -127 : list->dz));
-		list->dz -= list->ps2[off + 3];
-		list->bufsiz++;
+	if (!p->dx && !p->dy && !p->dz) {
+		if (list->tail != list->head)
+			list->tail = (list->tail + 1) % PACKET_QUEUE_LEN;
+		if (list->tail == list->head)
+			list->ready = 0;
 	}
 
-	if (!list->dx && !list->dy && (!list->mode || !list->dz)) list->ready = 0;
-	list->buffer = list->bufsiz;
+	spin_unlock_irqrestore(&list->packet_lock, flags);
 }
 
 
@@ -384,31 +460,31 @@
 		if (c == mousedev_imex_seq[list->imexseq]) {
 			if (++list->imexseq == MOUSEDEV_SEQ_LEN) {
 				list->imexseq = 0;
-				list->mode = 2;
+				list->mode = MOUSEDEV_EMUL_EXPS;
 			}
 		} else list->imexseq = 0;
 
 		if (c == mousedev_imps_seq[list->impsseq]) {
 			if (++list->impsseq == MOUSEDEV_SEQ_LEN) {
 				list->impsseq = 0;
-				list->mode = 1;
+				list->mode = MOUSEDEV_EMUL_IMPS;
 			}
 		} else list->impsseq = 0;
 
 		list->ps2[0] = 0xfa;
-		list->bufsiz = 1;
 
 		switch (c) {
 
 			case 0xeb: /* Poll */
-				mousedev_packet(list, 1);
+				mousedev_packet(list, &list->ps2[1]);
+				list->bufsiz++; /* account for leading ACK */
 				break;
 
 			case 0xf2: /* Get ID */
 				switch (list->mode) {
-					case 0: list->ps2[1] = 0; break;
-					case 1: list->ps2[1] = 3; break;
-					case 2: list->ps2[1] = 4; break;
+					case MOUSEDEV_EMUL_PS2:  list->ps2[1] = 0; break;
+					case MOUSEDEV_EMUL_IMPS: list->ps2[1] = 3; break;
+					case MOUSEDEV_EMUL_EXPS: list->ps2[1] = 4; break;
 				}
 				list->bufsiz = 2;
 				break;
@@ -419,13 +495,15 @@
 				break;
 
 			case 0xff: /* Reset */
-				list->impsseq = 0;
-				list->imexseq = 0;
-				list->mode = 0;
-				list->ps2[1] = 0xaa;
-				list->ps2[2] = 0x00;
+				list->impsseq = list->imexseq = 0;
+				list->mode = MOUSEDEV_EMUL_PS2;
+				list->ps2[1] = 0xaa; list->ps2[2] = 0x00;
 				list->bufsiz = 3;
 				break;
+
+			default:
+				list->bufsiz = 1;
+				break;
 		}
 
 		list->buffer = list->bufsiz;
@@ -451,8 +529,10 @@
 	if (retval)
 		return retval;
 
-	if (!list->buffer && list->ready)
-		mousedev_packet(list, 0);
+	if (!list->buffer && list->ready) {
+		mousedev_packet(list, list->ps2);
+		list->buffer = list->bufsiz;
+	}
 
 	if (count > list->buffer)
 		count = list->buffer;
--- diff/drivers/input/serio/Kconfig	2004-05-19 22:11:44.000000000 +0100
+++ source/drivers/input/serio/Kconfig	2004-06-11 19:22:01.000000000 +0100
@@ -97,16 +97,6 @@
 	tristate "Intel SA1111 keyboard controller"
 	depends on SA1111 && SERIO
 
-config SERIO_98KBD
-	tristate "NEC PC-9800 keyboard controller"
-	depends on X86_PC9800 && SERIO
-	help
-	  Say Y here if you have the NEC PC-9801/PC-9821 and want to use its
-	  standard keyboard connected to its keyboard controller.
-
-	  To compile this driver as a module, choose M here: the
-	  module will be called 98kbd-io.
-
 config SERIO_GSCPS2
 	tristate "HP GSC PS/2 keyboard and PS/2 mouse controller"
 	depends on GSC && SERIO
@@ -140,3 +130,17 @@
 
 	  To compile this driver as a module, choose M here: the
 	  module will be called maceps2.
+
+config SERIO_RAW
+	tristate "Raw access to serio ports"
+	depends on SERIO
+	help
+	  Say Y here if you want to have raw access to serio ports, such as
+	  AUX ports on i8042 keyboard controller. Each serio port that is
+	  marked as providing raw access will be accessible via a char device
+	  with major 10 and dynamically allocated minor. The driver will try
+	  allocating minor 1 (that historically corresponds to /dev/psaux)
+	  first.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called serio_raw.
--- diff/drivers/input/serio/Makefile	2004-05-19 22:11:44.000000000 +0100
+++ source/drivers/input/serio/Makefile	2004-06-11 19:22:01.000000000 +0100
@@ -17,3 +17,4 @@
 obj-$(CONFIG_SERIO_GSCPS2)	+= gscps2.o
 obj-$(CONFIG_SERIO_PCIPS2)	+= pcips2.o
 obj-$(CONFIG_SERIO_MACEPS2)	+= maceps2.o
+obj-$(CONFIG_SERIO_RAW)		+= serio_raw.o
--- diff/drivers/input/serio/i8042.c	2004-06-11 19:17:28.000000000 +0100
+++ source/drivers/input/serio/i8042.c	2004-06-11 19:22:01.000000000 +0100
@@ -1,7 +1,7 @@
 /*
  *  i8042 keyboard and mouse controller driver for Linux
  *
- *  Copyright (c) 1999-2002 Vojtech Pavlik
+ *  Copyright (c) 1999-2004 Vojtech Pavlik
  */
 
 /*
@@ -52,6 +52,9 @@
 module_param_named(dumbkbd, i8042_dumbkbd, bool, 0);
 MODULE_PARM_DESC(dumbkbd, "Pretend that controller can only read data from keyboard");
 
+extern unsigned int i8042_dmi_noloop;
+static unsigned int i8042_noloop;
+
 __obsolete_setup("i8042_noaux");
 __obsolete_setup("i8042_nomux");
 __obsolete_setup("i8042_unlock");
@@ -84,6 +87,10 @@
 static struct pm_dev *i8042_pm_dev;
 struct timer_list i8042_timer;
 
+#ifdef __i386__
+extern unsigned int i8042_dmi_noloop;
+#endif
+
 /*
  * Shared IRQ's require a device pointer, but this driver doesn't support
  * multiple devices
@@ -95,6 +102,7 @@
 /*
  * The i8042_wait_read() and i8042_wait_write functions wait for the i8042 to
  * be ready for reading values from it / writing values to it.
+ * Called always with i8042_lock held.
  */
 
 static int i8042_wait_read(void)
@@ -154,6 +162,9 @@
 	unsigned long flags;
 	int retval = 0, i = 0;
 
+	if (i8042_noloop && command == I8042_CMD_AUX_LOOP)
+		return -1;
+
 	spin_lock_irqsave(&i8042_lock, flags);
 
 	retval = i8042_wait_write();
@@ -474,17 +485,8 @@
 	if (i8042_command(&param, I8042_CMD_AUX_LOOP) || param != 0xa9)
 		return -1;
 	param = 0xa4;
-	if (i8042_command(&param, I8042_CMD_AUX_LOOP) || param == 0x5b) {
-
-/*
- * Do another loop test with the 0x5a value. Doing anything else upsets
- * Profusion/ServerWorks OSB4 chipsets.
- */
-
-		param = 0x5a;
-		i8042_command(&param, I8042_CMD_AUX_LOOP);
+	if (i8042_command(&param, I8042_CMD_AUX_LOOP) || param == 0x5b)
 		return -1;
-	}
 
 	if (mux_version)
 		*mux_version = ~param;
@@ -677,6 +679,7 @@
 
 static int i8042_controller_init(void)
 {
+	unsigned long flags;
 
 /*
  * Test the i8042. We need to know if it thinks it's working correctly
@@ -723,12 +726,14 @@
  * Handle keylock.
  */
 
+	spin_lock_irqsave(&i8042_lock, flags);
 	if (~i8042_read_status() & I8042_STR_KEYLOCK) {
 		if (i8042_unlock)
 			i8042_ctr |= I8042_CTR_IGNKEYLOCK;
 		 else
 			printk(KERN_WARNING "i8042.c: Warning: Keylock active.\n");
 	}
+	spin_unlock_irqrestore(&i8042_lock, flags);
 
 /*
  * If the chip is configured into nontranslated mode by the BIOS, don't
@@ -964,6 +969,13 @@
 	if (i8042_dumbkbd)
 		i8042_kbd_port.write = NULL;
 
+#ifdef __i386__
+	if (i8042_dmi_noloop) {
+		printk(KERN_INFO "i8042.c: AUX LoopBack command disabled by DMI.\n");
+		i8042_noloop = 1;
+	}
+#endif
+
 	if (!i8042_noaux && !i8042_check_aux(&i8042_aux_values)) {
 		if (!i8042_nomux && !i8042_check_mux(&i8042_aux_values))
 			for (i = 0; i < 4; i++) {
--- diff/drivers/input/serio/serio.c	2004-06-11 19:17:28.000000000 +0100
+++ source/drivers/input/serio/serio.c	2004-06-11 19:22:01.000000000 +0100
@@ -67,12 +67,18 @@
 	struct list_head node;
 };
 
-static DECLARE_MUTEX(serio_sem);
+
+spinlock_t serio_event_lock = SPIN_LOCK_UNLOCKED;	/* protects serio_event_list */
+static DECLARE_MUTEX(serio_sem);			/* protects serio_list and serio_dev_list */
 static LIST_HEAD(serio_list);
 static LIST_HEAD(serio_dev_list);
 static LIST_HEAD(serio_event_list);
 static int serio_pid;
 
+/*
+ * serio_find_dev() must be called with serio_sem down.
+ */
+
 static void serio_find_dev(struct serio *serio)
 {
 	struct serio_dev *dev;
@@ -96,22 +102,42 @@
 static void serio_invalidate_pending_events(struct serio *serio)
 {
 	struct serio_event *event;
+	unsigned long flags;
+
+	spin_lock_irqsave(&serio_event_lock, flags);
 
 	list_for_each_entry(event, &serio_event_list, node)
 		if (event->serio == serio)
 			event->serio = NULL;
+
+	spin_unlock_irqrestore(&serio_event_lock, flags);
 }
 
 void serio_handle_events(void)
 {
-	struct list_head *node, *next;
+	struct list_head *node;
 	struct serio_event *event;
+	unsigned long flags;
+
+
+	while (1) {
+
+		spin_lock_irqsave(&serio_event_lock, flags);
+
+		if (list_empty(&serio_event_list)) {
+			spin_unlock_irqrestore(&serio_event_lock, flags);
+			break;
+		}
 
-	list_for_each_safe(node, next, &serio_event_list) {
+		node = serio_event_list.next;
 		event = container_of(node, struct serio_event, node);
+		list_del_init(node);
+
+		spin_unlock_irqrestore(&serio_event_lock, flags);
 
 		down(&serio_sem);
-		if (event->serio == NULL)
+
+		if (event->serio == NULL) /*!!!*/
 			goto event_done;
 
 		switch (event->type) {
@@ -139,7 +165,6 @@
 		}
 event_done:
 		up(&serio_sem);
-		list_del_init(node);
 		kfree(event);
 	}
 }
@@ -165,8 +190,11 @@
 
 static void serio_queue_event(struct serio *serio, int event_type)
 {
+	unsigned long flags;
 	struct serio_event *event;
 
+	spin_lock_irqsave(&serio_event_lock, flags);
+
 	if ((event = kmalloc(sizeof(struct serio_event), GFP_ATOMIC))) {
 		event->type = event_type;
 		event->serio = serio;
@@ -174,6 +202,8 @@
 		list_add_tail(&event->node, &serio_event_list);
 		wake_up(&serio_wait);
 	}
+
+	spin_unlock_irqrestore(&serio_event_lock, flags);
 }
 
 void serio_rescan(struct serio *serio)
@@ -187,21 +217,27 @@
 }
 
 irqreturn_t serio_interrupt(struct serio *serio,
-		unsigned char data, unsigned int flags, struct pt_regs *regs)
+		unsigned char data, unsigned int dfl, struct pt_regs *regs)
 {
+	unsigned long flags;
 	irqreturn_t ret = IRQ_NONE;
 
+	spin_lock_irqsave(&serio->lock, flags);
+
         if (serio->dev && serio->dev->interrupt) {
-                ret = serio->dev->interrupt(serio, data, flags, regs);
+                ret = serio->dev->interrupt(serio, data, dfl, regs);
 	} else {
-		if (!flags) {
-			if ((serio->type == SERIO_8042 ||
-				serio->type == SERIO_8042_XL) && (data != 0xaa))
-					return ret;
-			serio_rescan(serio);
-			ret = IRQ_HANDLED;
+		if (!dfl) {
+			if ((serio->type != SERIO_8042 &&
+			     serio->type != SERIO_8042_XL) || (data == 0xaa)) {
+				serio_rescan(serio);
+				ret = IRQ_HANDLED;
+			}
 		}
 	}
+
+	spin_unlock_irqrestore(&serio->lock, flags);
+
 	return ret;
 }
 
@@ -229,6 +265,7 @@
  */
 void __serio_register_port(struct serio *serio)
 {
+	spin_lock_init(&serio->lock);
 	list_add_tail(&serio->node, &serio_list);
 	serio_find_dev(serio);
 }
@@ -292,9 +329,15 @@
 /* called from serio_dev->connect/disconnect methods under serio_sem */
 int serio_open(struct serio *serio, struct serio_dev *dev)
 {
+	unsigned long flags;
+
+	spin_lock_irqsave(&serio->lock, flags);
 	serio->dev = dev;
+	spin_unlock_irqrestore(&serio->lock, flags);
 	if (serio->open && serio->open(serio)) {
+		spin_lock_irqsave(&serio->lock, flags);
 		serio->dev = NULL;
+		spin_unlock_irqrestore(&serio->lock, flags);
 		return -1;
 	}
 	return 0;
@@ -303,9 +346,13 @@
 /* called from serio_dev->connect/disconnect methods under serio_sem */
 void serio_close(struct serio *serio)
 {
+	unsigned long flags;
+
 	if (serio->close)
 		serio->close(serio);
+	spin_lock_irqsave(&serio->lock, flags);
 	serio->dev = NULL;
+	spin_unlock_irqrestore(&serio->lock, flags);
 }
 
 static int __init serio_init(void)
--- diff/drivers/input/tsdev.c	2004-05-19 22:11:43.000000000 +0100
+++ source/drivers/input/tsdev.c	2004-06-11 19:22:01.000000000 +0100
@@ -3,9 +3,17 @@
  *
  *  Copyright (c) 2001 "Crazy" james Simmons 
  *
- *  Input driver to Touchscreen device driver module.
+ *  Compaq touchscreen protocol driver. The protocol emulated by this driver
+ *  is obsolete; for new programs use the tslib library which can read directly
+ *  from evdev and perform dejittering, variance filtering and calibration -
+ *  all in user space, not at kernel level. The meaning of this driver is
+ *  to allow usage of newer input drivers with old applications that use the
+ *  old /dev/h3600_ts and /dev/h3600_tsraw devices.
  *
- *  Sponsored by Transvirtual Technology
+ *  09-Apr-2004: Andrew Zabolotny <zap@homelink.ru>
+ *      Fixed to actually work, not just output random numbers.
+ *      Added support for both h3600_ts and h3600_tsraw protocol
+ *      emulation.
  */
 
 /*
@@ -24,11 +32,13 @@
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  * 
  * Should you need to contact me, the author, you can do so either by
- * e-mail - mail your message to <jsimmons@transvirtual.com>.
+ * e-mail - mail your message to <jsimmons@infradead.org>.
  */
 
 #define TSDEV_MINOR_BASE 	128
 #define TSDEV_MINORS		32
+/* First 16 devices are h3600_ts compatible; second 16 are h3600_tsraw */
+#define TSDEV_MINOR_MASK	15
 #define TSDEV_BUFFER_SIZE	64
 
 #include <linux/slab.h>
@@ -52,48 +62,84 @@
 #define CONFIG_INPUT_TSDEV_SCREEN_Y	320
 #endif
 
+/* This driver emulates both protocols of the old h3600_ts and h3600_tsraw
+ * devices. The first one must output X/Y data in 'cooked' format, e.g.
+ * filtered, dejittered and calibrated. Second device just outputs raw
+ * data received from the hardware.
+ *
+ * This driver doesn't support filtering and dejittering; it supports only
+ * calibration. Filtering and dejittering must be done in the low-level
+ * driver, if needed, because it may gain additional benefits from knowing
+ * the low-level details, the nature of noise and so on.
+ *
+ * The driver precomputes a calibration matrix given the initial xres and
+ * yres values (quite innacurate for most touchscreens) that will result
+ * in a more or less expected range of output values. The driver supports
+ * the TS_SET_CAL ioctl, which will replace the calibration matrix with a
+ * new one, supposedly generated from the values taken from the raw device.
+ */
+
 MODULE_AUTHOR("James Simmons <jsimmons@transvirtual.com>");
 MODULE_DESCRIPTION("Input driver to touchscreen converter");
 MODULE_LICENSE("GPL");
 
 static int xres = CONFIG_INPUT_TSDEV_SCREEN_X;
 module_param(xres, uint, 0);
-MODULE_PARM_DESC(xres, "Horizontal screen resolution");
+MODULE_PARM_DESC(xres, "Horizontal screen resolution (can be negative for X-mirror)");
 
 static int yres = CONFIG_INPUT_TSDEV_SCREEN_Y;
 module_param(yres, uint, 0);
-MODULE_PARM_DESC(yres, "Vertical screen resolution");
+MODULE_PARM_DESC(yres, "Vertical screen resolution (can be negative for Y-mirror)");
+
+/* From Compaq's Touch Screen Specification version 0.2 (draft) */
+struct ts_event {
+	short pressure;
+	short x;
+	short y;
+	short millisecs;
+};
+
+struct ts_calibration {
+	int xscale;
+	int xtrans;
+	int yscale;
+	int ytrans;
+	int xyswap;
+};
 
 struct tsdev {
 	int exist;
 	int open;
 	int minor;
-	char name[16];
+	char name[8];
 	wait_queue_head_t wait;
 	struct list_head list;
 	struct input_handle handle;
+	int x, y, pressure;
+	struct ts_calibration cal;
 };
 
-/* From Compaq's Touch Screen Specification version 0.2 (draft) */
-typedef struct {
-	short pressure;
-	short x;
-	short y;
-	short millisecs;
-} TS_EVENT;
-
 struct tsdev_list {
 	struct fasync_struct *fasync;
 	struct list_head node;
 	struct tsdev *tsdev;
 	int head, tail;
-	int oldx, oldy, pendown;
-	TS_EVENT event[TSDEV_BUFFER_SIZE];
+	struct ts_event event[TSDEV_BUFFER_SIZE];
+	int raw;
 };
 
+/* The following ioctl codes are defined ONLY for backward compatibility.
+ * Don't use tsdev for new developement; use the tslib library instead.
+ * Touchscreen calibration is a fully userspace task.
+ */
+/* Use 'f' as magic number */
+#define IOC_H3600_TS_MAGIC  'f'
+#define TS_GET_CAL	_IOR(IOC_H3600_TS_MAGIC, 10, struct ts_calibration)
+#define TS_SET_CAL	_IOW(IOC_H3600_TS_MAGIC, 11, struct ts_calibration)
+
 static struct input_handler tsdev_handler;
 
-static struct tsdev *tsdev_table[TSDEV_MINORS];
+static struct tsdev *tsdev_table[TSDEV_MINORS/2];
 
 static int tsdev_fasync(int fd, struct file *file, int on)
 {
@@ -109,13 +155,16 @@
 	int i = iminor(inode) - TSDEV_MINOR_BASE;
 	struct tsdev_list *list;
 
-	if (i >= TSDEV_MINORS || !tsdev_table[i])
+	if (i >= TSDEV_MINORS || !tsdev_table[i & TSDEV_MINOR_MASK])
 		return -ENODEV;
 
 	if (!(list = kmalloc(sizeof(struct tsdev_list), GFP_KERNEL)))
 		return -ENOMEM;
 	memset(list, 0, sizeof(struct tsdev_list));
 
+	list->raw = (i >= TSDEV_MINORS/2) ? 1 : 0;
+
+	i &= TSDEV_MINOR_MASK;
 	list->tsdev = tsdev_table[i];
 	list_add_tail(&list->node, &tsdev_table[i]->list);
 	file->private_data = list;
@@ -169,11 +218,13 @@
 	if (!list->tsdev->exist)
 		return -ENODEV;
 
-	while (list->head != list->tail && retval + sizeof(TS_EVENT) <= count) {
-		if (copy_to_user (buffer + retval, list->event + list->tail, sizeof(TS_EVENT)))
+	while (list->head != list->tail &&
+	       retval + sizeof (struct ts_event) <= count) {
+		if (copy_to_user (buffer + retval, list->event + list->tail,
+				  sizeof (struct ts_event)))
 			return -EFAULT;
 		list->tail = (list->tail + 1) & (TSDEV_BUFFER_SIZE - 1);
-		retval += sizeof(TS_EVENT);
+		retval += sizeof (struct ts_event);
 	}
 
 	return retval;
@@ -193,22 +244,27 @@
 static int tsdev_ioctl(struct inode *inode, struct file *file,
 		       unsigned int cmd, unsigned long arg)
 {
-/*
 	struct tsdev_list *list = file->private_data;
-        struct tsdev *evdev = list->tsdev;
-        struct input_dev *dev = tsdev->handle.dev;
-        int retval;
-	
+	struct tsdev *tsdev = list->tsdev;
+	int retval = 0;
+
 	switch (cmd) {
-		case HHEHE:
-			return 0;
-		case hjff:
-			return 0;
-		default:
-			return 0;
+	case TS_GET_CAL:
+		if (copy_to_user ((void *)arg, &tsdev->cal,
+				  sizeof (struct ts_calibration)))
+			retval = -EFAULT;
+		break;
+	case TS_SET_CAL:
+		if (copy_from_user (&tsdev->cal, (void *)arg,
+				    sizeof (struct ts_calibration)))
+			retval = -EFAULT;
+		break;
+	default:
+		retval = -EINVAL;
+		break;
 	}
-*/
-	return -EINVAL;
+
+	return retval;
 }
 
 struct file_operations tsdev_fops = {
@@ -227,82 +283,85 @@
 	struct tsdev *tsdev = handle->private;
 	struct tsdev_list *list;
 	struct timeval time;
-	int size;
 
-	list_for_each_entry(list, &tsdev->list, node) {
-		switch (type) {
-		case EV_ABS:
-			switch (code) {
-			case ABS_X:
-				if (!list->pendown)
-					return;
-				size = handle->dev->absmax[ABS_X] - handle->dev->absmin[ABS_X];
-				if (size > 0)
-					list->oldx = ((value - handle->dev->absmin[ABS_X]) * xres / size);
-				else
-					list->oldx = ((value - handle->dev->absmin[ABS_X]));
-				break;
-			case ABS_Y:
-				if (!list->pendown)
-					return;
-				size = handle->dev->absmax[ABS_Y] - handle->dev->absmin[ABS_Y];
-				if (size > 0)
-					list->oldy = ((value - handle->dev->absmin[ABS_Y]) * yres / size);
-				else
-					list->oldy = ((value - handle->dev->absmin[ABS_Y]));
-				break;
-			case ABS_PRESSURE:
-				list->pendown = ((value > handle->dev-> absmin[ABS_PRESSURE])) ?
-				    value - handle->dev->absmin[ABS_PRESSURE] : 0;
-				break;
-			}
+	switch (type) {
+	case EV_ABS:
+		switch (code) {
+		case ABS_X:
+			tsdev->x = value;
+			break;
+		case ABS_Y:
+			tsdev->y = value;
+			break;
+		case ABS_PRESSURE:
+			if (value > handle->dev->absmax[ABS_PRESSURE])
+				value = handle->dev->absmax[ABS_PRESSURE];
+			value -= handle->dev->absmin[ABS_PRESSURE];
+			if (value < 0)
+				value = 0;
+			tsdev->pressure = value;
+			break;
+		}
+		break;
+
+	case EV_REL:
+		switch (code) {
+		case REL_X:
+			tsdev->x += value;
+			if (tsdev->x < 0)
+				tsdev->x = 0;
+			else if (tsdev->x > xres)
+				tsdev->x = xres;
+			break;
+		case REL_Y:
+			tsdev->y += value;
+			if (tsdev->y < 0)
+				tsdev->y = 0;
+			else if (tsdev->y > yres)
+				tsdev->y = yres;
 			break;
+		}
+		break;
 
-		case EV_REL:
-			switch (code) {
-			case REL_X:
-				if (!list->pendown)
-					return;
-				list->oldx += value;
-				if (list->oldx < 0)
-					list->oldx = 0;
-				else if (list->oldx > xres)
-					list->oldx = xres;
+	case EV_KEY:
+		if (code == BTN_TOUCH || code == BTN_MOUSE) {
+			switch (value) {
+			case 0:
+				tsdev->pressure = 0;
 				break;
-			case REL_Y:
-				if (!list->pendown)
-					return;
-				list->oldy += value;
-				if (list->oldy < 0)
-					list->oldy = 0;
-				else if (list->oldy > xres)
-					list->oldy = xres;
+			case 1:
+				if (!tsdev->pressure)
+					tsdev->pressure = 1;
 				break;
 			}
-			break;
-
-		case EV_KEY:
-			if (code == BTN_TOUCH || code == BTN_MOUSE) {
-				switch (value) {
-				case 0:
-					list->pendown = 0;
-					break;
-				case 1:
-					if (!list->pendown)
-						list->pendown = 1;
-					break;
-				case 2:
-					return;
-				}
-			} else
-				return;
-			break;
 		}
+		break;
+	}
+
+	if (type != EV_SYN || code != SYN_REPORT)
+		return;
+
+	list_for_each_entry(list, &tsdev->list, node) {
+		int x, y, tmp;
+
 		do_gettimeofday(&time);
 		list->event[list->head].millisecs = time.tv_usec / 100;
-		list->event[list->head].pressure = list->pendown;
-		list->event[list->head].x = list->oldx;
-		list->event[list->head].y = list->oldy;
+		list->event[list->head].pressure = tsdev->pressure;
+
+		x = tsdev->x;
+		y = tsdev->y;
+
+		/* Calibration */
+		if (!list->raw) {
+			x = ((x * tsdev->cal.xscale) >> 8) + tsdev->cal.xtrans;
+			y = ((y * tsdev->cal.yscale) >> 8) + tsdev->cal.ytrans;
+			if (tsdev->cal.xyswap) {
+				tmp = x; x = y; y = tmp;
+			}
+		}
+
+		list->event[list->head].x = x;
+		list->event[list->head].y = y;
 		list->head = (list->head + 1) & (TSDEV_BUFFER_SIZE - 1);
 		kill_fasync(&list->fasync, SIGIO, POLL_IN);
 	}
@@ -314,11 +373,11 @@
 					  struct input_device_id *id)
 {
 	struct tsdev *tsdev;
-	int minor;
+	int minor, delta;
 
-	for (minor = 0; minor < TSDEV_MINORS && tsdev_table[minor];
+	for (minor = 0; minor < TSDEV_MINORS/2 && tsdev_table[minor];
 	     minor++);
-	if (minor == TSDEV_MINORS) {
+	if (minor >= TSDEV_MINORS/2) {
 		printk(KERN_ERR
 		       "tsdev: You have way too many touchscreens\n");
 		return NULL;
@@ -340,10 +399,25 @@
 	tsdev->handle.handler = handler;
 	tsdev->handle.private = tsdev;
 
+	/* Precompute the rough calibration matrix */
+	delta = dev->absmax [ABS_X] - dev->absmin [ABS_X] + 1;
+	if (delta == 0)
+		delta = 1;
+	tsdev->cal.xscale = (xres << 8) / delta;
+	tsdev->cal.xtrans = - ((dev->absmin [ABS_X] * tsdev->cal.xscale) >> 8);
+
+	delta = dev->absmax [ABS_Y] - dev->absmin [ABS_Y] + 1;
+	if (delta == 0)
+		delta = 1;
+	tsdev->cal.yscale = (yres << 8) / delta;
+	tsdev->cal.ytrans = - ((dev->absmin [ABS_Y] * tsdev->cal.yscale) >> 8);
+
 	tsdev_table[minor] = tsdev;
-	
+
 	devfs_mk_cdev(MKDEV(INPUT_MAJOR, TSDEV_MINOR_BASE + minor),
 			S_IFCHR|S_IRUGO|S_IWUSR, "input/ts%d", minor);
+	devfs_mk_cdev(MKDEV(INPUT_MAJOR, TSDEV_MINOR_BASE + minor + TSDEV_MINORS/2),
+			S_IFCHR|S_IRUGO|S_IWUSR, "input/tsraw%d", minor);
 	class_simple_device_add(input_class, 
 				MKDEV(INPUT_MAJOR, TSDEV_MINOR_BASE + minor),
 				dev->dev, "ts%d", minor);
@@ -362,6 +436,7 @@
 		wake_up_interruptible(&tsdev->wait);
 	} else
 		tsdev_free(tsdev);
+	devfs_remove("input/tsraw%d", tsdev->minor);
 }
 
 static struct input_device_id tsdev_ids[] = {
@@ -379,6 +454,12 @@
 	      .absbit	= { BIT(ABS_X) | BIT(ABS_Y) },
 	 },/* A tablet like device, at least touch detection, two absolute axes */
 
+	{
+	      .flags	= INPUT_DEVICE_ID_MATCH_EVBIT | INPUT_DEVICE_ID_MATCH_ABSBIT,
+	      .evbit	= { BIT(EV_ABS) },
+	      .absbit	= { BIT(ABS_X) | BIT(ABS_Y) | BIT(ABS_PRESSURE) },
+	 },/* A tablet like device with several gradations of pressure */
+
 	{},/* Terminating entry */
 };
 
--- diff/drivers/md/Kconfig	2004-05-19 22:11:47.000000000 +0100
+++ source/drivers/md/Kconfig	2004-06-11 19:22:02.000000000 +0100
@@ -180,5 +180,25 @@
 
 	  If unsure, say N.
 
+config DM_SNAPSHOT
+       tristate "Snapshot target (EXPERIMENTAL)"
+       depends on BLK_DEV_DM && EXPERIMENTAL
+       ---help---
+         Allow volume managers to take writeable snapshots of a device.
+
+config DM_MIRROR
+       tristate "Mirror target (EXPERIMENTAL)"
+       depends on BLK_DEV_DM && EXPERIMENTAL
+       ---help---
+         Allow volume managers to mirror logical volumes, also
+         needed for live data migration tools such as 'pvmove'.
+
+config DM_ZERO
+	tristate "Zero target (EXPERIMENTAL)"
+	depends on BLK_DEV_DM && EXPERIMENTAL
+	---help---
+	  A target that discards writes, and returns all zeroes for
+	  reads.  Useful in some recovery situations.
+
 endmenu
 
--- diff/drivers/md/Makefile	2004-05-19 22:11:47.000000000 +0100
+++ source/drivers/md/Makefile	2004-06-11 19:22:02.000000000 +0100
@@ -3,7 +3,9 @@
 #
 
 dm-mod-objs	:= dm.o dm-table.o dm-target.o dm-linear.o dm-stripe.o \
-		   dm-ioctl.o
+		   dm-ioctl.o dm-io.o kcopyd.o
+dm-snapshot-objs := dm-snap.o dm-exception-store.o
+dm-mirror-objs	:= dm-log.o dm-raid1.o
 raid6-objs	:= raid6main.o raid6algos.o raid6recov.o raid6tables.o \
 		   raid6int1.o raid6int2.o raid6int4.o \
 		   raid6int8.o raid6int16.o raid6int32.o \
@@ -24,6 +26,9 @@
 obj-$(CONFIG_BLK_DEV_MD)	+= md.o
 obj-$(CONFIG_BLK_DEV_DM)	+= dm-mod.o
 obj-$(CONFIG_DM_CRYPT)		+= dm-crypt.o
+obj-$(CONFIG_DM_SNAPSHOT)	+= dm-snapshot.o
+obj-$(CONFIG_DM_MIRROR)		+= dm-mirror.o
+obj-$(CONFIG_DM_ZERO)		+= dm-zero.o
 
 quiet_cmd_unroll = UNROLL  $@
       cmd_unroll = $(PERL) $(srctree)/$(src)/unroll.pl $(UNROLL) \
--- diff/drivers/md/dm-table.c	2004-06-11 19:17:28.000000000 +0100
+++ source/drivers/md/dm-table.c	2004-06-11 19:22:02.000000000 +0100
@@ -900,6 +900,28 @@
 	}
 }
 
+int dm_table_flush_all(struct dm_table *t)
+{
+	struct list_head *d, *devices = dm_table_get_devices(t);
+	int ret = 0;
+
+	for (d = devices->next; d != devices; d = d->next) {
+		struct dm_dev *dd = list_entry(d, struct dm_dev, list);
+		request_queue_t *q = bdev_get_queue(dd->bdev);
+		int err;
+
+		if (!q->issue_flush_fn)
+			err = -EOPNOTSUPP;
+		else
+			err = q->issue_flush_fn(q, dd->bdev->bd_disk, NULL);
+
+		if (!ret)
+			ret = err;
+	}
+
+	return ret;
+}
+
 EXPORT_SYMBOL(dm_vcalloc);
 EXPORT_SYMBOL(dm_get_device);
 EXPORT_SYMBOL(dm_put_device);
@@ -908,3 +930,4 @@
 EXPORT_SYMBOL(dm_table_put);
 EXPORT_SYMBOL(dm_table_get);
 EXPORT_SYMBOL(dm_table_unplug_all);
+EXPORT_SYMBOL(dm_table_flush_all);
--- diff/drivers/md/dm.c	2004-06-11 19:17:28.000000000 +0100
+++ source/drivers/md/dm.c	2004-06-11 19:22:02.000000000 +0100
@@ -153,6 +153,7 @@
 	xx(dm_target)
 	xx(dm_linear)
 	xx(dm_stripe)
+	xx(kcopyd)
 	xx(dm_interface)
 #undef xx
 };
@@ -586,6 +587,21 @@
 	return 0;
 }
 
+static int dm_flush_all(request_queue_t *q, struct gendisk *disk,
+			sector_t *error_sector)
+{
+	struct mapped_device *md = q->queuedata;
+	struct dm_table *map = dm_get_table(md);
+	int ret = -ENXIO;
+
+	if (map) {
+		ret = dm_table_flush_all(md->map);
+		dm_table_put(map);
+	}
+
+	return ret;
+}
+
 static void dm_unplug_all(request_queue_t *q)
 {
 	struct mapped_device *md = q->queuedata;
@@ -698,6 +714,7 @@
 	md->queue->backing_dev_info.congested_data = md;
 	blk_queue_make_request(md->queue, dm_request);
 	md->queue->unplug_fn = dm_unplug_all;
+	md->queue->issue_flush_fn = dm_flush_all;
 
 	md->io_pool = mempool_create(MIN_IOS, mempool_alloc_slab,
 				     mempool_free_slab, _io_cache);
--- diff/drivers/md/dm.h	2004-06-11 19:17:28.000000000 +0100
+++ source/drivers/md/dm.h	2004-06-11 19:22:02.000000000 +0100
@@ -113,6 +113,7 @@
 void dm_table_resume_targets(struct dm_table *t);
 int dm_table_any_congested(struct dm_table *t, int bdi_bits);
 void dm_table_unplug_all(struct dm_table *t);
+int dm_table_flush_all(struct dm_table *t);
 
 /*-----------------------------------------------------------------
  * A registry of target types.
@@ -177,6 +178,9 @@
 int dm_stripe_init(void);
 void dm_stripe_exit(void);
 
+int kcopyd_init(void);
+void kcopyd_exit(void);
+
 void *dm_vcalloc(unsigned long nmemb, unsigned long elem_size);
 
 #endif
--- diff/drivers/md/linear.c	2004-05-19 22:11:47.000000000 +0100
+++ source/drivers/md/linear.c	2004-06-11 19:22:02.000000000 +0100
@@ -47,7 +47,6 @@
 		return hash->dev0;
 }
 
-
 /**
  *	linear_mergeable_bvec -- tell bio layer if a two requests can be merged
  *	@q: request queue
@@ -93,6 +92,27 @@
 	}
 }
 
+static int linear_issue_flush(request_queue_t *q, struct gendisk *disk,
+			      sector_t *error_sector)
+{
+	mddev_t *mddev = q->queuedata;
+	linear_conf_t *conf = mddev_to_conf(mddev);
+	int i, ret = 0;
+
+	for (i=0; i < mddev->raid_disks; i++) {
+		struct block_device *bdev = conf->disks[i].rdev->bdev;
+		request_queue_t *r_queue = bdev_get_queue(bdev);
+
+		if (!r_queue->issue_flush_fn) {
+			ret = -EOPNOTSUPP;
+			break;
+		}
+		ret = r_queue->issue_flush_fn(r_queue, bdev->bd_disk, error_sector);
+		if (ret)
+			break;
+	}
+	return ret;
+}
 
 static int linear_run (mddev_t *mddev)
 {
@@ -200,6 +220,7 @@
 
 	blk_queue_merge_bvec(mddev->queue, linear_mergeable_bvec);
 	mddev->queue->unplug_fn = linear_unplug;
+	mddev->queue->issue_flush_fn = linear_issue_flush;
 	return 0;
 
 out:
--- diff/drivers/md/md.c	2004-06-11 19:17:28.000000000 +0100
+++ source/drivers/md/md.c	2004-06-11 19:22:02.000000000 +0100
@@ -154,6 +154,39 @@
 		tmp = tmp->next;})					\
 		)
 
+int md_flush_mddev(mddev_t *mddev, sector_t *error_sector)
+{
+	struct list_head *tmp;
+	mdk_rdev_t *rdev;
+	int ret = 0;
+
+	/*
+	 * this list iteration is done without any locking in md?!
+	 */
+	ITERATE_RDEV(mddev, rdev, tmp) {
+		request_queue_t *r_queue = bdev_get_queue(rdev->bdev);
+		int err;
+
+		if (!r_queue->unplug_fn)
+			err = -EOPNOTSUPP;
+		else
+			err = r_queue->issue_flush_fn(r_queue, rdev->bdev->bd_disk, error_sector);
+
+		if (!ret)
+			ret = err;
+	}
+
+	return ret;
+}
+
+static int md_flush_all(request_queue_t *q, struct gendisk *disk,
+			 sector_t *error_sector)
+{
+	mddev_t *mddev = q->queuedata;
+
+	return md_flush_mddev(mddev, error_sector);
+}
+
 static int md_fail_request (request_queue_t *q, struct bio *bio)
 {
 	bio_io_error(bio, bio->bi_size);
@@ -1645,6 +1678,7 @@
 	 */
 	mddev->queue->queuedata = mddev;
 	mddev->queue->make_request_fn = mddev->pers->make_request;
+	mddev->queue->issue_flush_fn = md_flush_all;
 
 	mddev->changed = 1;
 	return 0;
--- diff/drivers/md/multipath.c	2004-06-11 19:17:28.000000000 +0100
+++ source/drivers/md/multipath.c	2004-06-11 19:22:02.000000000 +0100
@@ -216,6 +216,31 @@
 	seq_printf (seq, "]");
 }
 
+static int multipath_issue_flush(request_queue_t *q, struct gendisk *disk,
+				 sector_t *error_sector)
+{
+	mddev_t *mddev = q->queuedata;
+	multipath_conf_t *conf = mddev_to_conf(mddev);
+	int i, ret = 0;
+
+	for (i=0; i<mddev->raid_disks; i++) {
+		mdk_rdev_t *rdev = conf->multipaths[i].rdev;
+		if (rdev && !rdev->faulty) {
+			struct block_device *bdev = rdev->bdev;
+			request_queue_t *r_queue = bdev_get_queue(bdev);
+
+			if (!r_queue->issue_flush_fn) {
+				ret = -EOPNOTSUPP;
+				break;
+			}
+
+			ret = r_queue->issue_flush_fn(r_queue, bdev->bd_disk, error_sector);
+			if (ret)
+				break;
+		}
+	}
+	return ret;
+}
 
 /*
  * Careful, this can execute in IRQ contexts as well!
@@ -430,6 +455,8 @@
 
 	mddev->queue->unplug_fn = multipath_unplug;
 
+	mddev->queue->issue_flush_fn = multipath_issue_flush;
+
 	conf->working_disks = 0;
 	ITERATE_RDEV(mddev,rdev,tmp) {
 		disk_idx = rdev->raid_disk;
--- diff/drivers/md/raid0.c	2004-05-19 22:11:47.000000000 +0100
+++ source/drivers/md/raid0.c	2004-06-11 19:22:02.000000000 +0100
@@ -40,6 +40,31 @@
 	}
 }
 
+static int raid0_issue_flush(request_queue_t *q, struct gendisk *disk,
+			     sector_t *error_sector)
+{
+	mddev_t *mddev = q->queuedata;
+	raid0_conf_t *conf = mddev_to_conf(mddev);
+	mdk_rdev_t **devlist = conf->strip_zone[0].dev;
+	int i, ret = 0;
+
+	for (i=0; i<mddev->raid_disks; i++) {
+		struct block_device *bdev = devlist[i]->bdev;
+		request_queue_t *r_queue = bdev_get_queue(bdev);
+
+		if (!r_queue->issue_flush_fn) {
+			ret = -EOPNOTSUPP;
+			break;
+		}
+
+		ret =r_queue->issue_flush_fn(r_queue, bdev->bd_disk, error_sector);
+		if (ret)
+			break;
+	}
+	return ret;
+}
+
+
 static int create_strip_zones (mddev_t *mddev)
 {
 	int i, c, j;
@@ -219,6 +244,8 @@
 
 	mddev->queue->unplug_fn = raid0_unplug;
 
+	mddev->queue->issue_flush_fn = raid0_issue_flush;
+
 	printk("raid0: done.\n");
 	return 0;
  abort:
--- diff/drivers/md/raid1.c	2004-06-11 19:17:28.000000000 +0100
+++ source/drivers/md/raid1.c	2004-06-11 19:22:02.000000000 +0100
@@ -480,6 +480,32 @@
 	unplug_slaves(q->queuedata);
 }
 
+static int raid1_issue_flush(request_queue_t *q, struct gendisk *disk,
+			     sector_t *error_sector)
+{
+	mddev_t *mddev = q->queuedata;
+	conf_t *conf = mddev_to_conf(mddev);
+	unsigned long flags;
+	int i, ret = 0;
+
+	spin_lock_irqsave(&conf->device_lock, flags);
+	for (i=0; i<mddev->raid_disks; i++) {
+		mdk_rdev_t *rdev = conf->mirrors[i].rdev;
+		if (rdev && !rdev->faulty) {
+			struct block_device *bdev = rdev->bdev;
+			request_queue_t *r_queue = bdev_get_queue(bdev);
+
+			if (r_queue->issue_flush_fn) {
+				ret = r_queue->issue_flush_fn(r_queue, bdev->bd_disk, error_sector);
+				if (ret)
+					break;
+			}
+		}
+	}
+	spin_unlock_irqrestore(&conf->device_lock, flags);
+	return ret;
+}
+
 /*
  * Throttle resync depth, so that we can both get proper overlapping of
  * requests, but are still able to handle normal requests quickly.
@@ -1163,6 +1189,7 @@
 
 	mddev->queue->unplug_fn = raid1_unplug;
 
+	mddev->queue->issue_flush_fn = raid1_issue_flush;
 
 	ITERATE_RDEV(mddev, rdev, tmp) {
 		disk_idx = rdev->raid_disk;
--- diff/drivers/md/raid5.c	2004-06-11 19:17:28.000000000 +0100
+++ source/drivers/md/raid5.c	2004-06-11 19:22:02.000000000 +0100
@@ -1339,6 +1339,39 @@
 	unplug_slaves(mddev);
 }
 
+static int raid5_issue_flush(request_queue_t *q, struct gendisk *disk,
+			     sector_t *error_sector)
+{
+	mddev_t *mddev = q->queuedata;
+	raid5_conf_t *conf = mddev_to_conf(mddev);
+	int i, ret = 0;
+
+	for (i=0; i<mddev->raid_disks; i++) {
+		mdk_rdev_t *rdev = conf->disks[i].rdev;
+		if (rdev && !rdev->faulty) {
+			struct block_device *bdev = rdev->bdev;
+			request_queue_t *r_queue;
+
+			if (!bdev)
+				continue;
+
+			r_queue = bdev_get_queue(bdev);
+			if (!r_queue)
+				continue;
+
+			if (!r_queue->issue_flush_fn) {
+				ret = -EOPNOTSUPP;
+				break;
+			}
+
+			ret = r_queue->issue_flush_fn(r_queue, bdev->bd_disk, error_sector);
+			if (ret)
+				break;
+		}
+	}
+	return ret;
+}
+
 static inline void raid5_plug_device(raid5_conf_t *conf)
 {
 	spin_lock_irq(&conf->device_lock);
@@ -1545,6 +1578,7 @@
 	atomic_set(&conf->preread_active_stripes, 0);
 
 	mddev->queue->unplug_fn = raid5_unplug_device;
+	mddev->queue->issue_flush_fn = raid5_issue_flush;
 
 	PRINTK("raid5: run(%s) called.\n", mdname(mddev));
 
--- diff/drivers/md/raid6main.c	2004-06-11 19:17:28.000000000 +0100
+++ source/drivers/md/raid6main.c	2004-06-11 19:22:02.000000000 +0100
@@ -1157,7 +1157,7 @@
 	 * parity, or to satisfy requests
 	 * or to load a block that is being partially written.
 	 */
-	if (to_read || non_overwrite || (syncing && (uptodate+failed < disks))) {
+	if (to_read || non_overwrite || (syncing && (uptodate < disks))) {
 		for (i=disks; i--;) {
 			dev = &sh->dev[i];
 			if (!test_bit(R5_LOCKED, &dev->flags) && !test_bit(R5_UPTODATE, &dev->flags) &&
@@ -1501,6 +1501,39 @@
 	unplug_slaves(mddev);
 }
 
+static int raid6_issue_flush(request_queue_t *q, struct gendisk *disk,
+			     sector_t *error_sector)
+{
+	mddev_t *mddev = q->queuedata;
+	raid6_conf_t *conf = mddev_to_conf(mddev);
+	int i, ret = 0;
+
+	for (i=0; i<mddev->raid_disks; i++) {
+		mdk_rdev_t *rdev = conf->disks[i].rdev;
+		if (rdev && !rdev->faulty) {
+			struct block_device *bdev = rdev->bdev;
+			request_queue_t *r_queue;
+
+			if (!bdev)
+				continue;
+
+			r_queue = bdev_get_queue(bdev);
+			if (!r_queue)
+				continue;
+
+			if (!r_queue->issue_flush_fn) {
+				ret = -EOPNOTSUPP;
+				break;
+			}
+
+			ret = r_queue->issue_flush_fn(r_queue, bdev->bd_disk, error_sector);
+			if (ret)
+				break;
+		}
+	}
+	return ret;
+}
+
 static inline void raid6_plug_device(raid6_conf_t *conf)
 {
 	spin_lock_irq(&conf->device_lock);
@@ -1708,6 +1741,7 @@
 	atomic_set(&conf->preread_active_stripes, 0);
 
 	mddev->queue->unplug_fn = raid6_unplug_device;
+	mddev->queue->issue_flush_fn = raid6_issue_flush;
 
 	PRINTK("raid6: run(%s) called.\n", mdname(mddev));
 
--- diff/drivers/media/dvb/frontends/tda1004x.c	2004-05-19 22:11:48.000000000 +0100
+++ source/drivers/media/dvb/frontends/tda1004x.c	2004-06-11 19:22:02.000000000 +0100
@@ -190,6 +190,7 @@
 static struct fwinfo tda10046h_fwinfo[] = { {.file_size = 286720,.fw_offset = 0x3c4f9,.fw_size = 24479} };
 static int tda10046h_fwinfo_count = sizeof(tda10046h_fwinfo) / sizeof(struct fwinfo);
 
+static int errno;
 
 
 static int tda1004x_write_byte(struct dvb_i2c_bus *i2c, struct tda1004x_state *tda_state, int reg, int data)
--- diff/drivers/message/fusion/isense.c	2004-05-19 22:11:51.000000000 +0100
+++ source/drivers/message/fusion/isense.c	2004-06-11 19:22:02.000000000 +0100
@@ -56,14 +56,6 @@
 #include <linux/errno.h>
 #include <linux/init.h>
 #include <asm/io.h>
-#if defined (__sparc__)
-#include <linux/timer.h>
-#endif
-
-/* Hmmm, avoid undefined spinlock_t on lk-2.2.14-5.0 */
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0)
-#include <asm/spinlock.h>
-#endif
 
 #define MODULEAUTHOR "Steven J. Ralston"
 #define COPYRIGHT "Copyright (c) 2001-2004 " MODULEAUTHOR
--- diff/drivers/message/fusion/linux_compat.h	2004-05-19 22:11:51.000000000 +0100
+++ source/drivers/message/fusion/linux_compat.h	2004-06-11 19:22:02.000000000 +0100
@@ -2,196 +2,7 @@
 
 #ifndef FUSION_LINUX_COMPAT_H
 #define FUSION_LINUX_COMPAT_H
-/*{-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 
-#include <linux/version.h>
-#include <linux/config.h>
-#include <linux/kernel.h>
-#include <linux/pci.h>
-
-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
-
-#ifndef rwlock_init
-#define rwlock_init(x) do { *(x) = RW_LOCK_UNLOCKED; } while(0)
-#endif
-
-#define SET_NICE(current,x) do {(current)->nice = (x);} while (0)
-
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0)
-#	if LINUX_VERSION_CODE < KERNEL_VERSION(2,2,18)
-		typedef unsigned int dma_addr_t;
-#	endif
-#else
-#	if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,42)
-		typedef unsigned int dma_addr_t;
-#	endif
-#endif
-
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,2,18)
-/*{-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
-
-/* This block snipped from lk-2.2.18/include/linux/init.h { */
-/*
- * Used for initialization calls..
- */
-typedef int (*initcall_t)(void);
-typedef void (*exitcall_t)(void);
-
-#define __init_call	__attribute__ ((unused,__section__ (".initcall.init")))
-#define __exit_call	__attribute__ ((unused,__section__ (".exitcall.exit")))
-
-extern initcall_t __initcall_start, __initcall_end;
-
-#define __initcall(fn)								\
-	static initcall_t __initcall_##fn __init_call = fn
-#define __exitcall(fn)								\
-	static exitcall_t __exitcall_##fn __exit_call = fn
-
-#ifdef MODULE
-/* These macros create a dummy inline: gcc 2.9x does not count alias
- as usage, hence the `unused function' warning when __init functions
- are declared static. We use the dummy __*_module_inline functions
- both to kill the warning and check the type of the init/cleanup
- function. */
-typedef int (*__init_module_func_t)(void);
-typedef void (*__cleanup_module_func_t)(void);
-#define module_init(x) \
-	int init_module(void) __attribute__((alias(#x))); \
-	static inline __init_module_func_t __init_module_inline(void) \
-	{ return x; }
-#define module_exit(x) \
-	void cleanup_module(void) __attribute__((alias(#x))); \
-	static inline __cleanup_module_func_t __cleanup_module_inline(void) \
-	{ return x; }
-
-#else
-#define module_init(x)	__initcall(x);
-#define module_exit(x)	__exitcall(x);
-#endif
-/* } block snipped from lk-2.2.18/include/linux/init.h */
-
-/* This block snipped from lk-2.2.18/include/linux/sched.h { */
-/*
- * Used prior to schedule_timeout calls..
- */
-#define __set_current_state(state_value)	do { current->state = state_value; } while (0)
-#ifdef CONFIG_SMP
-#define set_current_state(state_value)		do { __set_current_state(state_value); mb(); } while (0)
-#else
-#define set_current_state(state_value)		__set_current_state(state_value)
-#endif
-/* } block snipped from lk-2.2.18/include/linux/sched.h */
-
-/* procfs compat stuff... */
-#define proc_mkdir(x,y)			create_proc_entry(x, S_IFDIR, y)
-
-/* MUTEX compat stuff... */
-#define DECLARE_MUTEX(name)		struct semaphore name=MUTEX
-#define DECLARE_MUTEX_LOCKED(name)	struct semaphore name=MUTEX_LOCKED
-#define init_MUTEX(x)			*(x)=MUTEX
-#define init_MUTEX_LOCKED(x)		*(x)=MUTEX_LOCKED
-
-/* Wait queues. */
-#define DECLARE_WAIT_QUEUE_HEAD(name)	\
-	struct wait_queue * (name) = NULL
-#define DECLARE_WAITQUEUE(name, task)	\
-	struct wait_queue (name) = { (task), NULL }
-
-#if defined(__sparc__) && defined(__sparc_v9__)
-/* The sparc64 ioremap implementation is wrong in 2.2.x,
- * but fixing it would break all of the drivers which
- * workaround it.  Fixed in 2.3.x onward. -DaveM
- */
-#define ARCH_IOREMAP(base)	((unsigned long) (base))
-#else
-#define ARCH_IOREMAP(base)	ioremap(base)
-#endif
-
-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
-#else		/* LINUX_VERSION_CODE must be >= KERNEL_VERSION(2,2,18) */
-
-/* No ioremap bugs in >2.3.x kernels. */
-#define ARCH_IOREMAP(base)	ioremap(base)
-
-/*}-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
-#endif		/* LINUX_VERSION_CODE < KERNEL_VERSION(2,2,18) */
-
-
-/*
- * Inclined to use:
- *   #if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,10)
- * here, but MODULE_LICENSE defined in 2.4.9-6 and 2.4.9-13
- * breaks the rule:-(
- */
-#ifndef MODULE_LICENSE
-#define MODULE_LICENSE(license)
-#endif
-
-
-/* PCI/driver subsystem { */
-#define PCI_BASEADDR_FLAGS(idx)         resource[idx].flags
-#define PCI_BASEADDR_START(idx)         resource[idx].start
-#define PCI_BASEADDR_SIZE(dev,idx)      (dev)->resource[idx].end - (dev)->resource[idx].start + 1
-
-/* Compatability for the 2.3.x PCI DMA API. */
-#ifndef PCI_DMA_BIDIRECTIONAL
-/*{-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
-
-#define PCI_DMA_BIDIRECTIONAL	0
-#define PCI_DMA_TODEVICE	1
-#define PCI_DMA_FROMDEVICE	2
-#define PCI_DMA_NONE		3
-
-#ifdef __KERNEL__
-#include <asm/page.h>
-/* Pure 2^n version of get_order */
-static __inline__ int __get_order(unsigned long size)
-{
-	int order;
-
-	size = (size-1) >> (PAGE_SHIFT-1);
-	order = -1;
-	do {
-		size >>= 1;
-		order++;
-	} while (size);
-	return order;
-}
-#endif
-
-#define pci_alloc_consistent(hwdev, size, dma_handle) \
-({	void *__ret = (void *)__get_free_pages(GFP_ATOMIC, __get_order(size)); \
-	if (__ret != NULL) { \
-		memset(__ret, 0, size); \
-		*(dma_handle) = virt_to_bus(__ret); \
-	} \
-	__ret; \
-})
-
-#define pci_free_consistent(hwdev, size, vaddr, dma_handle) \
-	free_pages((unsigned long)vaddr, __get_order(size))
-
-#define pci_map_single(hwdev, ptr, size, direction) \
-	virt_to_bus(ptr);
-
-#define pci_unmap_single(hwdev, dma_addr, size, direction) \
-	do { /* Nothing to do */ } while (0)
-
-#define pci_map_sg(hwdev, sg, nents, direction)	(nents)
-#define pci_unmap_sg(hwdev, sg, nents, direction) \
-	do { /* Nothing to do */ } while(0)
-
-#define sg_dma_address(sg)	(virt_to_bus((sg)->address))
-#define sg_dma_len(sg)		((sg)->length)
-
-/*}-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
-#endif /* PCI_DMA_BIDIRECTIONAL */
-
-
-#define mpt_work_struct work_struct
-#define MPT_INIT_WORK(_task, _func, _data) INIT_WORK(_task, _func, _data)
-#define mpt_sync_irq(_irq) synchronize_irq(_irq)
 
 /*}-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 #endif /* _LINUX_COMPAT_H */
-
--- diff/drivers/message/fusion/mptbase.c	2004-06-11 19:17:28.000000000 +0100
+++ source/drivers/message/fusion/mptbase.c	2004-06-11 19:22:02.000000000 +0100
@@ -1311,14 +1311,14 @@
 	mem_phys = msize = 0;
 	port = psize = 0;
 	for (ii=0; ii < DEVICE_COUNT_RESOURCE; ii++) {
-		if (pdev->PCI_BASEADDR_FLAGS(ii) & PCI_BASE_ADDRESS_SPACE_IO) {
+		if (pci_resource_flags(pdev, ii) & PCI_BASE_ADDRESS_SPACE_IO) {
 			/* Get I/O space! */
-			port = pdev->PCI_BASEADDR_START(ii);
-			psize = PCI_BASEADDR_SIZE(pdev,ii);
+			port = pci_resource_start(pdev, ii);
+			psize = pci_resource_len(pdev,ii);
 		} else {
 			/* Get memmap */
-			mem_phys = pdev->PCI_BASEADDR_START(ii);
-			msize = PCI_BASEADDR_SIZE(pdev,ii);
+			mem_phys = pci_resource_start(pdev, ii);
+			msize = pci_resource_len(pdev,ii);
 			break;
 		}
 	}
@@ -1524,7 +1524,7 @@
 	CHIPREG_WRITE32(&ioc->chip->IntMask, 0xFFFFFFFF);
 
 	ioc->active = 0;
-	mpt_sync_irq(pdev->irq);
+	synchronize_irq(pdev->irq);
 
 	/* Clear any lingering interrupt */
 	CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
@@ -3799,7 +3799,8 @@
 
 		/*  Prime reply FIFO...  */
 		dprintk((KERN_INFO MYNAM ": %s.reply_alloc  @ %p[%p], sz=%d bytes\n",
-			 	ioc->name, mem, (void *)(ulong)ioc->reply_alloc_dma, reply_buffer_sz));
+			ioc->name, ioc->reply_alloc, 
+			(void *)(ulong)ioc->reply_alloc_dma, reply_buffer_sz));
 
 		b = (unsigned long) ioc->reply_alloc;
 		b = (b + (0x80UL - 1UL)) & ~(0x80UL - 1UL); /* round up to 128-byte boundary */
@@ -3812,7 +3813,8 @@
 	
 		/*  Request FIFO - WE manage this!  */
 		dprintk((KERN_INFO MYNAM ": %s.req_alloc    @ %p[%p], sz=%d bytes\n",
-			 	ioc->name, mem, (void *)(ulong)ioc->req_alloc_dma, request_buffer_sz));
+			ioc->name, ioc->req_alloc,
+			(void *)(ulong)ioc->req_alloc_dma, request_buffer_sz));
 
 		b = (unsigned long) ioc->req_alloc;
 		b = (b + (0x80UL - 1UL)) & ~(0x80UL - 1UL); /* round up to 128-byte boundary */
--- diff/drivers/message/fusion/mptbase.h	2004-06-11 19:17:28.000000000 +0100
+++ source/drivers/message/fusion/mptbase.h	2004-06-11 19:22:02.000000000 +0100
@@ -55,7 +55,11 @@
 #define MPTBASE_H_INCLUDED
 /*{-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 
-#include "linux_compat.h"	/* linux-2.2.x (vs. -2.4.x) tweaks */
+#include <linux/version.h>
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/pci.h>
+
 #include "scsi3.h"		/* SCSI defines */
 
 #include "lsi/mpi_type.h"
@@ -81,8 +85,8 @@
 #define COPYRIGHT	"Copyright (c) 1999-2004 " MODULEAUTHOR
 #endif
 
-#define MPT_LINUX_VERSION_COMMON	"3.01.06"
-#define MPT_LINUX_PACKAGE_NAME		"@(#)mptlinux-3.01.06"
+#define MPT_LINUX_VERSION_COMMON	"3.01.07"
+#define MPT_LINUX_PACKAGE_NAME		"@(#)mptlinux-3.01.07"
 #define WHAT_MAGIC_STRING		"@" "(" "#" ")"
 
 #define show_mptmod_ver(s,ver)  \
--- diff/drivers/message/fusion/mptctl.c	2004-06-11 19:17:28.000000000 +0100
+++ source/drivers/message/fusion/mptctl.c	2004-06-11 19:22:02.000000000 +0100
@@ -102,9 +102,6 @@
 #define my_VERSION	MPT_LINUX_VERSION_COMMON
 #define MYNAM		"mptctl"
 
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,62)
-EXPORT_NO_SYMBOLS;
-#endif
 MODULE_AUTHOR(MODULEAUTHOR);
 MODULE_DESCRIPTION(my_NAME);
 MODULE_LICENSE("GPL");
@@ -547,38 +544,6 @@
 
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 /*
- *  struct file_operations functionality.
- *  Members:
- *	llseek, write, read, ioctl, open, release
- */
-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,9)
-static loff_t
-mptctl_llseek(struct file *file, loff_t offset, int origin)
-{
-	return -ESPIPE;
-}
-#define no_llseek mptctl_llseek
-#endif
-
-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
-static ssize_t
-mptctl_write(struct file *file, const char *buf, size_t count, loff_t *ppos)
-{
-	printk(KERN_ERR MYNAM ": ioctl WRITE not yet supported\n");
-	return 0;
-}
-
-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
-static ssize_t
-mptctl_read(struct file *file, char *buf, size_t count, loff_t *ptr)
-{
-	printk(KERN_ERR MYNAM ": ioctl READ not yet supported\n");
-	return 0;
-}
-
-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
-/*
  *  MPT ioctl handler
  *  cmd - specify the particular IOCTL command to be issued
  *  arg - data specific to the command. Must not be null.
@@ -700,21 +665,6 @@
 }
 
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
-static int mptctl_open(struct inode *inode, struct file *file)
-{
-	/*
-	 * Should support multiple management users
-	 */
-	return 0;
-}
-
-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
-static int mptctl_release(struct inode *inode, struct file *file)
-{
-	return 0;
-}
-
-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 /*
  * MPT FW download function.  Cast the arg into the mpt_fw_xfer structure.
  * This structure contains: iocnum, firmware length (bytes),
@@ -1278,10 +1228,8 @@
 	karg->pciId = pdev->device;
 	pci_read_config_byte(pdev, PCI_CLASS_REVISION, &revision);
 	karg->hwRev = revision;
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
 	karg->subSystemDevice = pdev->subsystem_device;
 	karg->subSystemVendor = pdev->subsystem_vendor;
-#endif
 
 	if (cim_rev == 1) {
 		/* Get the PCI bus, device, and function numbers for the IOC
@@ -2455,10 +2403,8 @@
 
 	karg.vendor = pdev->vendor;
 	karg.device = pdev->device;
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
 	karg.subsystem_id = pdev->subsystem_device;
 	karg.subsystem_vendor = pdev->subsystem_vendor;
-#endif
 	karg.devfn = pdev->devfn;
 	karg.bus = pdev->bus->number;
 
@@ -2540,7 +2486,7 @@
 		break;
 	}
 
-	karg.base_io_addr = pdev->PCI_BASEADDR_START(0);
+	karg.base_io_addr = pci_resource_start(pdev, 0);
 
 	if ((int)ioc->chip_type <= (int) FC929)
 		karg.bus_phys_width = HP_BUS_WIDTH_UNK;
@@ -2739,20 +2685,10 @@
 
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,51)
-#define	owner_THIS_MODULE  .owner = THIS_MODULE,
-#else
-#define	owner_THIS_MODULE
-#endif
-
 static struct file_operations mptctl_fops = {
-	owner_THIS_MODULE
+	.owner =	THIS_MODULE,
 	.llseek =	no_llseek,
-	.read =		mptctl_read,
-	.write =	mptctl_write,
 	.ioctl =	mptctl_ioctl,
-	.open =		mptctl_open,
-	.release =	mptctl_release,
 };
 
 static struct miscdevice mptctl_miscdev = {
--- diff/drivers/message/fusion/mptlan.c	2004-05-19 22:11:51.000000000 +0100
+++ source/drivers/message/fusion/mptlan.c	2004-06-11 19:22:02.000000000 +0100
@@ -133,7 +133,7 @@
 	u32 total_received;
 	struct net_device_stats stats;	/* Per device statistics */
 
-	struct mpt_work_struct post_buckets_task;
+	struct work_struct post_buckets_task;
 	unsigned long post_buckets_active;
 };
 
@@ -880,18 +880,9 @@
 	
 	if (test_and_set_bit(0, &priv->post_buckets_active) == 0) {
 		if (priority) {
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,41)
 			schedule_work(&priv->post_buckets_task);
-#else
-			queue_task(&priv->post_buckets_task, &tq_immediate);
-			mark_bh(IMMEDIATE_BH);
-#endif
 		} else {
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,41)
 			schedule_delayed_work(&priv->post_buckets_task, 1);
-#else
-			queue_task(&priv->post_buckets_task, &tq_timer);
-#endif
 			dioprintk((KERN_INFO MYNAM ": post_buckets queued on "
 				   "timer.\n"));
 		}
@@ -1391,8 +1382,8 @@
 	priv->mpt_dev = mpt_dev;
 	priv->pnum = pnum;
 
-	memset(&priv->post_buckets_task, 0, sizeof(struct mpt_work_struct));
-	MPT_INIT_WORK(&priv->post_buckets_task, mpt_lan_post_receive_buckets, dev);
+	memset(&priv->post_buckets_task, 0, sizeof(struct work_struct));
+	INIT_WORK(&priv->post_buckets_task, mpt_lan_post_receive_buckets, dev);
 	priv->post_buckets_active = 0;
 
 	dlprintk((KERN_INFO MYNAM "@%d: bucketlen = %d\n",
@@ -1566,10 +1557,6 @@
 }
 
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,59)
-MODULE_PARM(tx_max_out_p, "i");
-MODULE_PARM(max_buckets_out, "i"); // Debug stuff. FIXME!
-#endif
 
 module_init(mpt_lan_init);
 module_exit(mpt_lan_exit);
--- diff/drivers/message/fusion/mptscsih.c	2004-06-11 19:17:28.000000000 +0100
+++ source/drivers/message/fusion/mptscsih.c	2004-06-11 19:22:02.000000000 +0100
@@ -74,6 +74,8 @@
 #include <linux/delay.h>	/* for mdelay */
 #include <linux/interrupt.h>	/* needed for in_interrupt() proto */
 #include <linux/reboot.h>	/* notifier code */
+#include <linux/sched.h>
+#include <linux/workqueue.h>
 #include "../../scsi/scsi.h"
 #include <scsi/scsi_host.h>
 
@@ -185,7 +187,7 @@
 static int	mptscsih_do_cmd(MPT_SCSI_HOST *hd, INTERNAL_CMD *iocmd);
 static int	mptscsih_synchronize_cache(MPT_SCSI_HOST *hd, int portnum);
 
-static struct mpt_work_struct   mptscsih_rstTask;
+static struct work_struct   mptscsih_rstTask;
 
 #ifdef MPTSCSIH_ENABLE_DOMAIN_VALIDATION
 static int	mptscsih_do_raid(MPT_SCSI_HOST *hd, u8 action, INTERNAL_CMD *io);
@@ -231,7 +233,7 @@
 static spinlock_t dvtaskQ_lock = SPIN_LOCK_UNLOCKED;
 static int dvtaskQ_active = 0;
 static int dvtaskQ_release = 0;
-static struct mpt_work_struct	mptscsih_dvTask;
+static struct work_struct	mptscsih_dvTask;
 #endif
 
 /*
@@ -249,31 +251,7 @@
 static Scsi_Cmnd *foo_to[8];
 #endif
 
-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
-
-/* see mptscsih.h */
-
-static struct scsi_host_template driver_template = {
-	.proc_name			= "mptscsih",
-	.proc_info			= x_scsi_proc_info,
-	.name				= "MPT SCSI Host",
-	.info				= x_scsi_info,
-	.queuecommand			= x_scsi_queuecommand,
-	.slave_alloc			= x_scsi_slave_alloc,
-	.slave_configure		= x_scsi_slave_configure,
-	.slave_destroy			= x_scsi_slave_destroy,
-	.eh_abort_handler		= x_scsi_abort,
-	.eh_device_reset_handler	= x_scsi_dev_reset,
-	.eh_bus_reset_handler		= x_scsi_bus_reset,
-	.eh_host_reset_handler		= x_scsi_host_reset,
-	.bios_param			= x_scsi_bios_param,
-	.can_queue			= MPT_SCSI_CAN_QUEUE,
-	.this_id			= -1,
-	.sg_tablesize			= MPT_SCSI_SG_DEPTH,
-	.max_sectors			= MPT_SCSI_MAX_SECTORS,
-	.cmd_per_lun			= MPT_SCSI_CMD_PER_LUN,
-	.use_clustering			= ENABLE_CLUSTERING,
-};
+static struct scsi_host_template driver_template;
 
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 /*
@@ -1459,7 +1437,6 @@
 	}
 		
 	sh->max_lun = MPT_LAST_LUN + 1;
-	sh->max_sectors = MPT_SCSI_MAX_SECTORS;
 	sh->max_channel = 0;
 	sh->this_id = ioc->pfacts[0].PortSCSIID;
 		
@@ -1800,8 +1777,8 @@
 		}
 
 		dprintk((MYIOC_s_INFO_FMT
-		  "Free'd ScsiLookup (%d), chain (%d) and Target (%d+%d) memory\n",
-		  hd->ioc->name, sz1, szchain, sz3, sztarget));
+		  "Free'd ScsiLookup (%d) Target (%d+%d) memory\n",
+		  hd->ioc->name, sz1, sz3, sztarget));
 		dprintk(("Free'd done and free Q (%d) memory\n", szQ));
 
 		/* NULL the Scsi_Host pointer
@@ -1879,9 +1856,9 @@
 	if (!dvtaskQ_active) {
 		dvtaskQ_active = 1;
 		spin_unlock_irqrestore(&dvtaskQ_lock, lflags);
-		MPT_INIT_WORK(&mptscsih_dvTask,
+		INIT_WORK(&mptscsih_dvTask,
 		  mptscsih_domainValidation, (void *) hd);
-		SCHEDULE_TASK(&mptscsih_dvTask);
+		schedule_work(&mptscsih_dvTask);
 	} else {
 		spin_unlock_irqrestore(&dvtaskQ_lock, lflags);
 	}
@@ -1902,7 +1879,6 @@
 #endif
 };
 
-
 /*  SCSI host fops start here...  */
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 /**
@@ -2434,9 +2410,9 @@
 					if (!dvtaskQ_active) {
 						dvtaskQ_active = 1;
 						spin_unlock_irqrestore(&dvtaskQ_lock, lflags);
-						MPT_INIT_WORK(&mptscsih_dvTask, mptscsih_domainValidation, (void *) hd);
+						INIT_WORK(&mptscsih_dvTask, mptscsih_domainValidation, (void *) hd);
 
-						SCHEDULE_TASK(&mptscsih_dvTask);
+						schedule_work(&mptscsih_dvTask);
 					} else {
 						spin_unlock_irqrestore(&dvtaskQ_lock, lflags);
 					}
@@ -3905,6 +3881,29 @@
 	return 1;		/* currently means nothing really */
 }
 
+static struct scsi_host_template driver_template = {
+	.proc_name			= "mptscsih",
+	.proc_info			= mptscsih_proc_info,
+	.name				= "MPT SCSI Host",
+	.info				= mptscsih_info,
+	.queuecommand			= mptscsih_qcmd,
+	.slave_alloc			= mptscsih_slave_alloc,
+	.slave_configure		= mptscsih_slave_configure,
+	.slave_destroy			= mptscsih_slave_destroy,
+	.eh_abort_handler		= mptscsih_abort,
+	.eh_device_reset_handler	= mptscsih_dev_reset,
+	.eh_bus_reset_handler		= mptscsih_bus_reset,
+	.eh_host_reset_handler		= mptscsih_host_reset,
+	.bios_param			= mptscsih_bios_param,
+	.can_queue			= MPT_SCSI_CAN_QUEUE,
+	.this_id			= -1,
+	.sg_tablesize			= MPT_SCSI_SG_DEPTH,
+	.max_sectors			= 8192,
+	.cmd_per_lun			= 7,
+	.use_clustering			= ENABLE_CLUSTERING,
+};
+
+
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 /*
  *  Private data...
@@ -4950,8 +4949,8 @@
 	/* Call the reset handler. Already had a TM request
 	 * timeout - so issue a diagnostic reset
 	 */
-	MPT_INIT_WORK(&mptscsih_rstTask, mptscsih_schedule_reset, (void *)hd);
-	SCHEDULE_TASK(&mptscsih_rstTask);
+	INIT_WORK(&mptscsih_rstTask, mptscsih_schedule_reset, (void *)hd);
+	schedule_work(&mptscsih_rstTask);
 	return;
 }
 
--- diff/drivers/message/fusion/mptscsih.h	2004-05-19 22:11:51.000000000 +0100
+++ source/drivers/message/fusion/mptscsih.h	2004-06-11 19:22:02.000000000 +0100
@@ -108,75 +108,4 @@
         MPTSCSIH_SAF_TE,                        \
 }
 
-
-
-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
-/*
- *	Various bits and pieces broke within the lk-2.4.0-testN series:-(
- *	So here are various HACKS to work around them.
- */
-
-/*
- *	tq_scheduler disappeared @ lk-2.4.0-test12
- *	(right when <linux/sched.h> newly defined TQ_ACTIVE)
- *	tq_struct reworked in 2.5.41. Include workqueue.h.
- */
-#	include <linux/sched.h>
-#	include <linux/workqueue.h>
-#define SCHEDULE_TASK(x)		\
-	if (schedule_work(x) == 0) {	\
-		/*MOD_DEC_USE_COUNT*/;	\
-	}
-
-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
-
-#define x_scsi_info		mptscsih_info
-#define x_scsi_queuecommand	mptscsih_qcmd
-#define x_scsi_abort		mptscsih_abort
-#define x_scsi_bus_reset	mptscsih_bus_reset
-#define x_scsi_dev_reset	mptscsih_dev_reset
-#define x_scsi_host_reset	mptscsih_host_reset
-#define x_scsi_bios_param	mptscsih_bios_param
-
-#define x_scsi_slave_alloc	mptscsih_slave_alloc
-#define x_scsi_slave_configure	mptscsih_slave_configure
-#define x_scsi_slave_destroy	mptscsih_slave_destroy
-#define x_scsi_proc_info	mptscsih_proc_info
-
-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
-/*
- *	MPT SCSI Host / Initiator decls...
- */
-extern	const char	*x_scsi_info(struct Scsi_Host *);
-extern	int		 x_scsi_queuecommand(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *));
-extern	int		 x_scsi_abort(Scsi_Cmnd *);
-extern	int		 x_scsi_bus_reset(Scsi_Cmnd *);
-extern	int		 x_scsi_dev_reset(Scsi_Cmnd *);
-extern	int		 x_scsi_host_reset(Scsi_Cmnd *);
-extern int		 x_scsi_bios_param(struct scsi_device * sdev, struct block_device *bdev,
-				sector_t capacity, int geom[]);
-extern	int		 x_scsi_slave_alloc(Scsi_Device *);
-extern	int		 x_scsi_slave_configure(Scsi_Device *);
-extern	void		 x_scsi_slave_destroy(Scsi_Device *);
-extern	int		 x_scsi_proc_info(struct Scsi_Host *, char *, char **, off_t, int, int);
-
-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
-
-/*  include/scsi/scsi.h may not be quite complete...  */
-#ifndef RESERVE_10
-#define RESERVE_10		0x56
-#endif
-#ifndef RELEASE_10
-#define RELEASE_10		0x57
-#endif
-#ifndef PERSISTENT_RESERVE_IN
-#define PERSISTENT_RESERVE_IN	0x5e
-#endif
-#ifndef PERSISTENT_RESERVE_OUT
-#define PERSISTENT_RESERVE_OUT	0x5f
 #endif
-
-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
-
-#endif
-
--- diff/drivers/message/i2o/i2o_block.c	2004-06-11 19:17:28.000000000 +0100
+++ source/drivers/message/i2o/i2o_block.c	2004-06-11 19:22:02.000000000 +0100
@@ -280,8 +280,8 @@
 {
 	struct i2o_controller *c = dev->controller;
 	int tid = dev->tid;
-	unsigned long msg;
-	unsigned long mptr;
+	void *msg;
+	void *mptr;
 	u64 offset;
 	struct request *req = ireq->req;
 	int count = req->nr_sectors<<9;
@@ -291,7 +291,7 @@
 
 	// printk(KERN_INFO "i2ob_send called\n");
 	/* Map the message to a virtual address */
-	msg = c->mem_offset + m;
+	msg = c->msg_virt + m;
 	
 	sgnum = i2ob_build_sglist(dev, ireq);
 	
@@ -479,7 +479,7 @@
 		/* Now flush the message by making it a NOP */
 		m[0]&=0x00FFFFFF;
 		m[0]|=(I2O_CMD_UTIL_NOP)<<24;
-		i2o_post_message(c, ((unsigned long)m) - c->mem_offset);
+		i2o_post_message(c, (unsigned long) m - (unsigned long) c->msg_virt);
 
 		return;
 	}
--- diff/drivers/message/i2o/i2o_config.c	2004-06-11 19:17:28.000000000 +0100
+++ source/drivers/message/i2o/i2o_config.c	2004-06-11 19:22:02.000000000 +0100
@@ -97,7 +97,7 @@
 	u32 *msg = (u32 *)m;
 
 	if (msg[0] & MSG_FAIL) {
-		u32 *preserved_msg = (u32*)(c->mem_offset + msg[7]);
+		u32 *preserved_msg = (u32*)(c->msg_virt + msg[7]);
 
 		printk(KERN_ERR "i2o_config: IOP failed to process the msg.\n");
 
--- diff/drivers/message/i2o/i2o_core.c	2004-06-11 19:17:28.000000000 +0100
+++ source/drivers/message/i2o/i2o_core.c	2004-06-11 19:22:02.000000000 +0100
@@ -354,7 +354,7 @@
 
 	if (msg[0] & MSG_FAIL) // Fail bit is set
 	{
-		u32 *preserved_msg = (u32*)(c->mem_offset + msg[7]);
+		u32 *preserved_msg = (u32*)(c->msg_virt + msg[7]);
 
 		i2o_report_status(KERN_INFO, "i2o_core", msg);
 		i2o_dump_message(preserved_msg);
@@ -1794,7 +1794,7 @@
 	m=i2o_wait_message(c, "AdapterReset");
 	if(m==0xFFFFFFFF)	
 		return -ETIMEDOUT;
-	msg=(u32 *)(c->mem_offset+m);
+	msg=(u32 *)(c->msg_virt+m);
 	
 	status = pci_alloc_consistent(c->pdev, 4, &status_phys);
 	if(status == NULL) {
@@ -1923,7 +1923,7 @@
 	m=i2o_wait_message(c, "StatusGet");
 	if(m==0xFFFFFFFF)
 		return -ETIMEDOUT;	
-	msg=(u32 *)(c->mem_offset+m);
+	msg=(u32 *)(c->msg_virt+m);
 
 	msg[0]=NINE_WORD_MSG_SIZE|SGL_OFFSET_0;
 	msg[1]=I2O_CMD_STATUS_GET<<24|HOST_TID<<12|ADAPTER_TID;
@@ -2344,7 +2344,7 @@
 	m=i2o_wait_message(c, "OutboundInit");
 	if(m==0xFFFFFFFF)
 		return -ETIMEDOUT;
-	msg=(u32 *)(c->mem_offset+m);
+	msg=(u32 *)(c->msg_virt+m);
 
 	status = pci_alloc_consistent(c->pdev, 4, &status_phys);
 	if (status==NULL) {
@@ -2618,7 +2618,7 @@
 		sys_tbl->iops[count].last_changed = sys_tbl_ind - 1; // ??
 		sys_tbl->iops[count].iop_capabilities = 
 				iop->status_block->iop_capabilities;
-		sys_tbl->iops[count].inbound_low = iop->post_port;
+		sys_tbl->iops[count].inbound_low = (u32)iop->post_port;
 		sys_tbl->iops[count].inbound_high = 0;	// FIXME: 64-bit support
 
 		count++;
@@ -2666,7 +2666,7 @@
 		       c->name);
 		return -ETIMEDOUT;
 	}
-	msg = (u32 *)(c->mem_offset + m);
+	msg = (u32 *)(c->msg_virt + m);
  	memcpy_toio(msg, data, len);
 	i2o_post_message(c,m);
 	return 0;
@@ -3592,7 +3592,9 @@
 	I2O_IRQ_WRITE32(c,0xFFFFFFFF);
 	if(c->irq > 0)
 		free_irq(c->irq, c);
-	iounmap(((u8 *)c->post_port)-0x40);
+	iounmap(c->base_virt);
+	if(c->raptor)
+		iounmap(c->msg_virt);
 
 #ifdef CONFIG_MTRR
 	if(c->mtrr_reg0 > 0)
@@ -3633,9 +3635,12 @@
 {
 	struct i2o_controller *c=kmalloc(sizeof(struct i2o_controller),
 						GFP_KERNEL);
-	unsigned long mem;
-	u32 memptr = 0;
-	u32 size;
+	void *bar0_virt;
+	void *bar1_virt;
+	unsigned long bar0_phys = 0;
+	unsigned long bar1_phys = 0;
+	unsigned long bar0_size = 0;
+	unsigned long bar1_size = 0;
 	
 	int i;
 
@@ -3646,37 +3651,9 @@
 	}
 	memset(c, 0, sizeof(*c));
 
-	for(i=0; i<6; i++)
-	{
-		/* Skip I/O spaces */
-		if(!(pci_resource_flags(dev, i) & IORESOURCE_IO))
-		{
-			memptr = pci_resource_start(dev, i);
-			break;
-		}
-	}
-	
-	if(i==6)
-	{
-		printk(KERN_ERR "i2o: I2O controller has no memory regions defined.\n");
-		kfree(c);
-		return -EINVAL;
-	}
-	
-	size = dev->resource[i].end-dev->resource[i].start+1;	
-	/* Map the I2O controller */
-	
-	printk(KERN_INFO "i2o: PCI I2O controller at 0x%08X size=%d\n", memptr, size);
-	mem = (unsigned long)ioremap(memptr, size);
-	if(mem==0)
-	{
-		printk(KERN_ERR "i2o: Unable to map controller.\n");
-		kfree(c);
-		return -EINVAL;
-	}
-
 	c->irq = -1;
 	c->dpt = 0;
+	c->raptor = 0;
 	c->short_req = 0;
 	c->pdev = dev;
 
@@ -3684,13 +3661,6 @@
 	c->context_list_lock = SPIN_LOCK_UNLOCKED;
 #endif
 
-	c->irq_mask = mem+0x34;
-	c->post_port = mem+0x40;
-	c->reply_port = mem+0x44;
-
-	c->mem_phys = memptr;
-	c->mem_offset = mem;
-	
 	/*
 	 *	Cards that fall apart if you hit them with large I/O
 	 *	loads...
@@ -3701,6 +3671,7 @@
 		c->short_req = 1;
 		printk(KERN_INFO "I2O: Symbios FC920 workarounds activated.\n");
 	}
+
 	if(dev->subsystem_vendor == PCI_VENDOR_ID_PROMISE)
 	{
 		c->promise = 1;
@@ -3712,15 +3683,85 @@
 	 *	them
 	 */
 	 
-	if(dev->vendor == PCI_VENDOR_ID_DPT)
+	if(dev->vendor == PCI_VENDOR_ID_DPT) {
 		c->dpt=1;
+		if(dev->device == 0xA511)
+			c->raptor=1;
+	}
+
+	for(i=0; i<6; i++)
+	{
+		/* Skip I/O spaces */
+		if(!(pci_resource_flags(dev, i) & IORESOURCE_IO))
+		{
+			if(!bar0_phys)
+			{
+				bar0_phys = pci_resource_start(dev, i);
+				bar0_size = pci_resource_len(dev, i);
+				if(!c->raptor)
+					break;
+			}
+			else
+			{
+				bar1_phys = pci_resource_start(dev, i);
+				bar1_size = pci_resource_len(dev, i);
+				break;
+			}
+		}
+	}
+
+	if(i==6)
+	{
+		printk(KERN_ERR "i2o: I2O controller has no memory regions defined.\n");
+		kfree(c);
+		return -EINVAL;
+	}
+
+
+	/* Map the I2O controller */
+	if(!c->raptor)
+		printk(KERN_INFO "i2o: PCI I2O controller at %08lX size=%ld\n", bar0_phys, bar0_size);
+	else
+		printk(KERN_INFO "i2o: PCI I2O controller\n    BAR0 at 0x%08lX size=%ld\n    BAR1 at 0x%08lX size=%ld\n", bar0_phys, bar0_size, bar1_phys, bar1_size);
+
+	bar0_virt = ioremap(bar0_phys, bar0_size);
+	if(bar0_virt==0)
+	{
+		printk(KERN_ERR "i2o: Unable to map controller.\n");
+		kfree(c);
+		return -EINVAL;
+	}
+
+	if(c->raptor)
+	{
+		bar1_virt = ioremap(bar1_phys, bar1_size);
+		if(bar1_virt==0)
+		{
+			printk(KERN_ERR "i2o: Unable to map controller.\n");
+			kfree(c);
+			iounmap(bar0_virt);
+			return -EINVAL;
+		}
+	} else {
+		bar1_virt = bar0_virt;
+		bar1_phys = bar0_phys;
+		bar1_size = bar0_size;
+	}
+
+	c->irq_mask = bar0_virt+0x34;
+	c->post_port = bar0_virt+0x40;
+	c->reply_port = bar0_virt+0x44;
+
+	c->base_phys = bar0_phys;
+	c->base_virt = bar0_virt;
+	c->msg_phys = bar1_phys;
+	c->msg_virt = bar1_virt;
 	
 	/* 
 	 * Enable Write Combining MTRR for IOP's memory region
 	 */
 #ifdef CONFIG_MTRR
-	c->mtrr_reg0 =
-		mtrr_add(c->mem_phys, size, MTRR_TYPE_WRCOMB, 1);
+	c->mtrr_reg0 = mtrr_add(c->base_phys, bar0_size, MTRR_TYPE_WRCOMB, 1);
 	/*
 	 * If it is an INTEL i960 I/O processor then set the first 64K to
 	 * Uncacheable since the region contains the Messaging unit which
@@ -3730,14 +3771,16 @@
 	if(dev->vendor == PCI_VENDOR_ID_INTEL || dev->vendor == PCI_VENDOR_ID_DPT)
 	{
 		printk(KERN_INFO "I2O: MTRR workaround for Intel i960 processor\n"); 
-		c->mtrr_reg1 =	mtrr_add(c->mem_phys, 65536, MTRR_TYPE_UNCACHABLE, 1);
+		c->mtrr_reg1 =	mtrr_add(c->base_phys, 65536, MTRR_TYPE_UNCACHABLE, 1);
 		if(c->mtrr_reg1< 0)
 		{
 			printk(KERN_INFO "i2o_pci: Error in setting MTRR_TYPE_UNCACHABLE\n");
-			mtrr_del(c->mtrr_reg0, c->mem_phys, size);
+			mtrr_del(c->mtrr_reg0, c->msg_phys, bar1_size);
 			c->mtrr_reg0 = -1;
 		}
 	}
+	if(c->raptor)
+		c->mtrr_reg1 = mtrr_add(c->msg_phys, bar1_size, MTRR_TYPE_WRCOMB, 1);
 
 #endif
 
@@ -3749,7 +3792,9 @@
 	{
 		printk(KERN_ERR "i2o: Unable to install controller.\n");
 		kfree(c);
-		iounmap((void *)mem);
+		iounmap(bar0_virt);
+		if(c->raptor)
+			iounmap(bar1_virt);
 		return i;
 	}
 
@@ -3764,7 +3809,9 @@
 				c->name, dev->irq);
 			c->irq = -1;
 			i2o_delete_controller(c);
-			iounmap((void *)mem);
+			iounmap(bar0_virt);
+			if(c->raptor)
+				iounmap(bar1_virt);
 			return -EBUSY;
 		}
 	}
@@ -3797,10 +3844,12 @@
 
 	while ((dev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL)
 	{
-		if((dev->class>>8)!=PCI_CLASS_INTELLIGENT_I2O)
+		if((dev->class>>8)!=PCI_CLASS_INTELLIGENT_I2O &&
+		   (dev->vendor!=PCI_VENDOR_ID_DPT || dev->device!=0xA511))
 			continue;
 
-		if((dev->class&0xFF)>1)
+		if((dev->class>>8)==PCI_CLASS_INTELLIGENT_I2O &&
+		   (dev->class&0xFF)>1)
 		{
 			printk(KERN_INFO "i2o: I2O Controller found but does not support I2O 1.5 (skipping).\n");
 			continue;
--- diff/drivers/message/i2o/i2o_scsi.c	2004-06-11 19:17:29.000000000 +0100
+++ source/drivers/message/i2o/i2o_scsi.c	2004-06-11 19:22:02.000000000 +0100
@@ -59,9 +59,11 @@
 #include <asm/atomic.h>
 #include <linux/blkdev.h>
 #include <linux/i2o.h>
-#include "../../scsi/scsi.h"
-#include "../../scsi/hosts.h"
 
+#include <scsi/scsi.h>
+#include <scsi/scsi_cmnd.h>
+#include <scsi/scsi_device.h>
+#include <scsi/scsi_host.h>
 
 
 #define VERSION_STRING        "Version 0.1.2"
@@ -186,7 +188,7 @@
 
 static void i2o_scsi_reply(struct i2o_handler *h, struct i2o_controller *c, struct i2o_message *msg)
 {
-	Scsi_Cmnd *current_command;
+	struct scsi_cmnd *current_command;
 	spinlock_t *lock;
 	u32 *m = (u32 *)msg;
 	u8 as,ds,st;
@@ -230,7 +232,7 @@
 		{
 			spin_unlock_irqrestore(&retry_lock, flags);
 			/* Create a scsi error for this */
-			current_command = (Scsi_Cmnd *)i2o_context_list_get(m[3], c);
+			current_command = (struct scsi_cmnd *)i2o_context_list_get(m[3], c);
 			if(!current_command)
 				return;
 
@@ -277,7 +279,7 @@
 		return;
 	}
 
-	current_command = (Scsi_Cmnd *)i2o_context_list_get(m[3], c);
+	current_command = (struct scsi_cmnd *)i2o_context_list_get(m[3], c);
 	
 	/*
 	 *	Is this a control request coming back - eg an abort ?
@@ -330,10 +332,17 @@
 		 */		
 		current_command->result = DID_OK << 16 | ds;
 
-	if (current_command->use_sg)
-		pci_unmap_sg(c->pdev, (struct scatterlist *)current_command->buffer, current_command->use_sg, scsi_to_pci_dma_dir(current_command->sc_data_direction));
-	else if (current_command->request_bufflen)
-		pci_unmap_single(c->pdev, (dma_addr_t)((long)current_command->SCp.ptr), current_command->request_bufflen, scsi_to_pci_dma_dir(current_command->sc_data_direction));
+	if (current_command->use_sg) {
+		pci_unmap_sg(c->pdev,
+			(struct scatterlist *)current_command->buffer,
+			current_command->use_sg,
+			current_command->sc_data_direction);
+	} else if (current_command->request_bufflen) {
+		pci_unmap_single(c->pdev,
+			(dma_addr_t)((long)current_command->SCp.ptr),
+			current_command->request_bufflen,
+			current_command->sc_data_direction);
+	}
 
 	lock = current_command->device->host->host_lock;
 	spin_lock_irqsave(lock, flags);
@@ -461,7 +470,7 @@
  *	scsi controller and then let the enumeration fake up the rest
  */
  
-static int i2o_scsi_detect(Scsi_Host_Template * tpnt)
+static int i2o_scsi_detect(struct scsi_host_template * tpnt)
 {
 	struct Scsi_Host *shpnt = NULL;
 	int i;
@@ -592,12 +601,13 @@
  *	Locks: takes the controller lock on error path only
  */
  
-static int i2o_scsi_queuecommand(Scsi_Cmnd * SCpnt, void (*done) (Scsi_Cmnd *))
+static int i2o_scsi_queuecommand(struct scsi_cmnd *SCpnt,
+				 void (*done) (struct scsi_cmnd *))
 {
 	int i;
 	int tid;
 	struct i2o_controller *c;
-	Scsi_Cmnd *current_command;
+	struct scsi_cmnd *current_command;
 	struct Scsi_Host *host;
 	struct i2o_scsi_host *hostdata;
 	u32 *msg, *mptr;
@@ -659,7 +669,7 @@
 	if(m==0xFFFFFFFF)
 		return 1;
 
-	msg = (u32 *)(c->mem_offset + m);
+	msg = (u32 *)(c->msg_virt + m);
 	
 	/*
 	 *	Put together a scsi execscb message
@@ -668,19 +678,14 @@
 	len = SCpnt->request_bufflen;
 	direction = 0x00000000;			// SGL IN  (osm<--iop)
 	
-	if(SCpnt->sc_data_direction == SCSI_DATA_NONE)
+	if (SCpnt->sc_data_direction == DMA_NONE) {
 		scsidir = 0x00000000;			// DATA NO XFER
-	else if(SCpnt->sc_data_direction == SCSI_DATA_WRITE)
-	{
-		direction=0x04000000;	// SGL OUT  (osm-->iop)
-		scsidir  =0x80000000;	// DATA OUT (iop-->dev)
-	}
-	else if(SCpnt->sc_data_direction == SCSI_DATA_READ)
-	{
-		scsidir  =0x40000000;	// DATA IN  (iop<--dev)
-	}
-	else
-	{
+	} else if (SCpnt->sc_data_direction == DMA_TO_DEVICE) {
+		direction = 0x04000000;	// SGL OUT  (osm-->iop)
+		scsidir = 0x80000000;	// DATA OUT (iop-->dev)
+	} else if(SCpnt->sc_data_direction == DMA_FROM_DEVICE) {
+		scsidir = 0x40000000;	// DATA IN  (iop<--dev)
+	} else {
 		/* Unknown - kill the command */
 		SCpnt->result = DID_NO_CONNECT << 16;
 		
@@ -768,7 +773,7 @@
 		len = 0;
 
 		sg_count = pci_map_sg(c->pdev, sg, SCpnt->use_sg,
-				      scsi_to_pci_dma_dir(SCpnt->sc_data_direction));
+				SCpnt->sc_data_direction);
 
 		/* FIXME: handle fail */
 		if(!sg_count)
@@ -840,7 +845,7 @@
 			dma_addr = pci_map_single(c->pdev,
 					       SCpnt->request_buffer,
 					       SCpnt->request_bufflen,
-					       scsi_to_pci_dma_dir(SCpnt->sc_data_direction));
+					       SCpnt->sc_data_direction);
 			if(dma_addr == 0)
 				BUG();	/* How to handle ?? */
 			SCpnt->SCp.ptr = (char *)(unsigned long) dma_addr;
@@ -883,7 +888,7 @@
  *	Locks: no locks are held or needed
  */
  
-int i2o_scsi_abort(Scsi_Cmnd * SCpnt)
+static int i2o_scsi_abort(struct scsi_cmnd * SCpnt)
 {
 	struct i2o_controller *c;
 	struct Scsi_Host *host;
@@ -929,14 +934,14 @@
  *	Locks: called with no lock held, requires no locks.
  */
  
-static int i2o_scsi_bus_reset(Scsi_Cmnd * SCpnt)
+static int i2o_scsi_bus_reset(struct scsi_cmnd * SCpnt)
 {
 	int tid;
 	struct i2o_controller *c;
 	struct Scsi_Host *host;
 	struct i2o_scsi_host *hostdata;
 	u32 m;
-	unsigned long msg;
+	void *msg;
 	unsigned long timeout;
 
 	
@@ -974,7 +979,7 @@
 	while(time_before(jiffies, timeout));
 	
 	
-	msg = c->mem_offset + m;
+	msg = c->msg_virt + m;
 	i2o_raw_writel(FOUR_WORD_MSG_SIZE|SGL_OFFSET_0, msg);
 	i2o_raw_writel(I2O_CMD_SCSI_BUSRESET<<24|HOST_TID<<12|tid, msg+4);
 	i2o_raw_writel(scsi_context|0x80000000, msg+8);
@@ -992,32 +997,6 @@
 }
 
 /**
- *	i2o_scsi_host_reset	-	host reset callback
- *	@SCpnt: command causing the reset
- *
- *	An I2O controller can be many things at once. While we can
- *	reset a controller the potential mess from doing so is vast, and
- *	it's better to simply hold on and pray
- */
- 
-static int i2o_scsi_host_reset(Scsi_Cmnd * SCpnt)
-{
-	return FAILED;
-}
-
-/**
- *	i2o_scsi_device_reset	-	device reset callback
- *	@SCpnt: command causing the reset
- *
- *	I2O does not (AFAIK) support doing a device reset
- */
- 
-static int i2o_scsi_device_reset(Scsi_Cmnd * SCpnt)
-{
-	return FAILED;
-}
-
-/**
  *	i2o_scsi_bios_param	-	Invent disk geometry
  *	@sdev: scsi device 
  *	@dev: block layer device
@@ -1048,7 +1027,7 @@
 MODULE_LICENSE("GPL");
 
 
-static Scsi_Host_Template driver_template = {
+static struct scsi_host_template driver_template = {
 	.proc_name		= "i2o_scsi",
 	.name			= "I2O SCSI Layer",
 	.detect			= i2o_scsi_detect,
@@ -1057,8 +1036,6 @@
 	.queuecommand		= i2o_scsi_queuecommand,
 	.eh_abort_handler	= i2o_scsi_abort,
 	.eh_bus_reset_handler	= i2o_scsi_bus_reset,
-	.eh_device_reset_handler= i2o_scsi_device_reset,
-	.eh_host_reset_handler	= i2o_scsi_host_reset,
 	.bios_param		= i2o_scsi_bios_param,
 	.can_queue		= I2O_SCSI_CAN_QUEUE,
 	.this_id		= 15,
--- diff/drivers/mtd/maps/Kconfig	2004-06-11 19:17:29.000000000 +0100
+++ source/drivers/mtd/maps/Kconfig	2004-06-11 19:22:02.000000000 +0100
@@ -489,5 +489,13 @@
 	help
 	  Map driver to support image based filesystems for uClinux.
 
+config MTD_WRSBC8260
+	tristate "Map driver for WindRiver PowerQUICC II MPC82xx board"
+	depends on MTD_PARTITIONS && SBC82xx
+	help
+	  Map driver for WindRiver PowerQUICC II MPC82xx board. Drives
+	  all three flash regions on CS0, CS1 and CS6 if they are configured
+	  correctly by the boot loader.
+
 endmenu
 
--- diff/drivers/mtd/maps/Makefile	2004-06-11 19:17:29.000000000 +0100
+++ source/drivers/mtd/maps/Makefile	2004-06-11 19:22:02.000000000 +0100
@@ -56,3 +56,4 @@
 obj-$(CONFIG_MTD_ARCTIC)	+= arctic-mtd.o
 obj-$(CONFIG_MTD_H720X)		+= h720x-flash.o
 obj-$(CONFIG_MTD_IXP4XX)	+= ixp4xx.o
+obj-$(CONFIG_MTD_WRSBC8260)	+= wr_sbc82xx_flash.o
--- diff/drivers/mtd/mtdblock.c	2004-05-19 22:11:52.000000000 +0100
+++ source/drivers/mtd/mtdblock.c	2004-06-11 19:22:02.000000000 +0100
@@ -275,7 +275,7 @@
 	
 	/* OK, it's not open. Create cache info for it */
 	mtdblk = kmalloc(sizeof(struct mtdblk_dev), GFP_KERNEL);
-	if (!mtdblks)
+	if (!mtdblk)
 		return -ENOMEM;
 
 	memset(mtdblk, 0, sizeof(*mtdblk));
--- diff/drivers/net/3c501.c	2004-05-19 22:11:52.000000000 +0100
+++ source/drivers/net/3c501.c	2004-06-11 19:22:02.000000000 +0100
@@ -225,7 +225,7 @@
 	 *	Reserve I/O resource for exclusive use by this driver
 	 */
 
-	if (!request_region(ioaddr, EL1_IO_EXTENT, dev->name))
+	if (!request_region(ioaddr, EL1_IO_EXTENT, DRV_NAME))
 		return -ENODEV;
 
 	/*
--- diff/drivers/net/3c503.c	2004-05-19 22:11:53.000000000 +0100
+++ source/drivers/net/3c503.c	2004-06-11 19:22:02.000000000 +0100
@@ -147,6 +147,7 @@
 	release_region(dev->base_addr, EL2_IO_EXTENT);
 }
 
+#ifndef MODULE
 struct net_device * __init el2_probe(int unit)
 {
 	struct net_device *dev = alloc_ei_netdev();
@@ -171,6 +172,7 @@
 	free_netdev(dev);
 	return ERR_PTR(err);
 }
+#endif
 
 /* Probe for the Etherlink II card at I/O port base IOADDR,
    returning non-zero on success.  If found, set the station
@@ -182,10 +184,10 @@
     static unsigned version_printed;
     unsigned long vendor_id;
 
-    if (!request_region(ioaddr, EL2_IO_EXTENT, dev->name))
+    if (!request_region(ioaddr, EL2_IO_EXTENT, DRV_NAME))
 	return -EBUSY;
 
-    if (!request_region(ioaddr + 0x400, 8, dev->name)) {
+    if (!request_region(ioaddr + 0x400, 8, DRV_NAME)) {
 	retval = -EBUSY;
 	goto out;
     }
--- diff/drivers/net/3c505.c	2004-05-19 22:11:53.000000000 +0100
+++ source/drivers/net/3c505.c	2004-06-11 19:22:02.000000000 +0100
@@ -1614,6 +1614,7 @@
 	return err;
 }
 
+#ifndef MODULE
 struct net_device * __init elplus_probe(int unit)
 {
 	struct net_device *dev = alloc_etherdev(sizeof(elp_device));
@@ -1632,7 +1633,7 @@
 	return dev;
 }
 
-#ifdef MODULE
+#else
 static struct net_device *dev_3c505[ELP_MAX_CARDS];
 static int io[ELP_MAX_CARDS];
 static int irq[ELP_MAX_CARDS];
--- diff/drivers/net/3c507.c	2004-05-19 22:11:53.000000000 +0100
+++ source/drivers/net/3c507.c	2004-06-11 19:22:02.000000000 +0100
@@ -373,7 +373,7 @@
 		init_ID_done = 1;
 	}
 
-	if (!request_region(ioaddr, EL16_IO_EXTENT, dev->name))
+	if (!request_region(ioaddr, EL16_IO_EXTENT, DRV_NAME))
 		return -ENODEV;
 
 	if ((inb(ioaddr) != '*') || (inb(ioaddr + 1) != '3') || 
@@ -392,7 +392,7 @@
 
 	irq = inb(ioaddr + IRQ_CONFIG) & 0x0f;
 
-	irqval = request_irq(irq, &el16_interrupt, 0, dev->name, dev);
+	irqval = request_irq(irq, &el16_interrupt, 0, DRV_NAME, dev);
 	if (irqval) {
 		printk ("unable to get IRQ %d (irqval=%d).\n", irq, irqval);
 		retval = -EAGAIN;
--- diff/drivers/net/3c509.c	2004-06-11 19:17:29.000000000 +0100
+++ source/drivers/net/3c509.c	2004-06-11 19:22:02.000000000 +0100
@@ -56,10 +56,6 @@
 		v1.19b 08Nov2002 Marc Zyngier <maz@wild-wind.fr.eu.org>
 		    - Introduce driver model for EISA cards.
 */
-/*
-  FIXES for PC-9800:
-  Shu Iwanaga: 3c569B(PC-9801 C-bus) support
-*/
 
 #define DRV_NAME	"3c509"
 #define DRV_VERSION	"1.19b"
@@ -265,7 +261,7 @@
 };
 #endif /* CONFIG_MCA */
 
-#if defined(__ISAPNP__) && !defined(CONFIG_X86_PC9800)
+#if defined(__ISAPNP__)
 static struct isapnp_device_id el3_isapnp_adapters[] __initdata = {
 	{	ISAPNP_ANY_ID, ISAPNP_ANY_ID,
 		ISAPNP_VENDOR('T', 'C', 'M'), ISAPNP_FUNCTION(0x5090),
@@ -362,7 +358,7 @@
 	if (lp->pmdev)
 		pm_unregister(lp->pmdev);
 #endif
-#if defined(__ISAPNP__) && !defined(CONFIG_X86_PC9800)
+#if defined(__ISAPNP__)
 	if (lp->type == EL3_PNP)
 		pnp_device_detach(to_pnp_dev(lp->dev));
 #endif
@@ -381,7 +377,7 @@
 	u16 phys_addr[3];
 	static int current_tag;
 	int err = -ENODEV;
-#if defined(__ISAPNP__) && !defined(CONFIG_X86_PC9800)
+#if defined(__ISAPNP__)
 	static int pnp_cards;
 	struct pnp_dev *idev = NULL;
 
@@ -436,9 +432,6 @@
 no_pnp:
 #endif /* __ISAPNP__ */
 
-#ifdef CONFIG_X86_PC9800
-	id_port = 0x71d0;
-#else
 	/* Select an open I/O location at 0x1*0 to do contention select. */
 	for ( ; id_port < 0x200; id_port += 0x10) {
 		if (!request_region(id_port, 1, "3c509"))
@@ -456,7 +449,7 @@
 		printk(" WARNING: No I/O port available for 3c509 activation.\n");
 		return -ENODEV;
 	}
-#endif /* CONFIG_X86_PC9800 */
+
 	/* Next check for all ISA bus boards by sending the ID sequence to the
 	   ID_PORT.  We find cards past the first by setting the 'current_tag'
 	   on cards as they are found.  Cards with their tag set will not
@@ -487,7 +480,7 @@
 		phys_addr[i] = htons(id_read_eeprom(i));
 	}
 
-#if defined(__ISAPNP__) && !defined(CONFIG_X86_PC9800)
+#if defined(__ISAPNP__)
 	if (nopnp == 0) {
 		/* The ISA PnP 3c509 cards respond to the ID sequence.
 		   This check is needed in order not to register them twice. */
@@ -512,19 +505,9 @@
 	{
 		unsigned int iobase = id_read_eeprom(8);
 		if_port = iobase >> 14;
-#ifdef CONFIG_X86_PC9800
-		ioaddr = 0x40d0 + ((iobase & 0x1f) << 8);
-#else
 		ioaddr = 0x200 + ((iobase & 0x1f) << 4);
-#endif
 	}
 	irq = id_read_eeprom(9) >> 12;
-#ifdef CONFIG_X86_PC9800
-	if (irq == 7)
-		irq = 6;
-	else if (irq == 15)
-		irq = 13;
-#endif
 
 	dev = alloc_etherdev(sizeof (struct el3_private));
 	if (!dev)
@@ -555,11 +538,7 @@
 	outb(0xd0 + ++current_tag, id_port);
 
 	/* Activate the adaptor at the EEPROM location. */
-#ifdef CONFIG_X86_PC9800
-	outb((ioaddr >> 8) | 0xe0, id_port);
-#else
 	outb((ioaddr >> 4) | 0xe0, id_port);
-#endif
 
 	EL3WINDOW(0);
 	if (inw(ioaddr) != 0x6d50)
@@ -568,7 +547,7 @@
 	/* Free the interrupt so that some other card can use it. */
 	outw(0x0f00, ioaddr + WN0_IRQ);
 
-#if defined(__ISAPNP__) && !defined(CONFIG_X86_PC9800)
+#if defined(__ISAPNP__)
  found:							/* PNP jumps here... */
 #endif /* __ISAPNP__ */
 
@@ -577,7 +556,7 @@
 	dev->irq = irq;
 	dev->if_port = if_port;
 	lp = netdev_priv(dev);
-#if defined(__ISAPNP__) && !defined(CONFIG_X86_PC9800)
+#if defined(__ISAPNP__)
 	lp->dev = &idev->dev;
 #endif
 	err = el3_common_init(dev);
@@ -601,7 +580,7 @@
 	return 0;
 
 out1:
-#if defined(__ISAPNP__) && !defined(CONFIG_X86_PC9800)
+#if defined(__ISAPNP__)
 	if (idev)
 		pnp_device_detach(idev);
 #endif
@@ -1461,12 +1440,6 @@
 	outw(0x0001, ioaddr + 4);
 
 	/* Set the IRQ line. */
-#ifdef CONFIG_X86_PC9800
-	if (dev->irq == 6)
-		dev->irq = 7;
-	else if (dev->irq == 13)
-		dev->irq = 15;
-#endif
 	outw((dev->irq << 12) | 0x0f00, ioaddr + WN0_IRQ);
 
 	/* Set the station address in window 2 each time opened. */
@@ -1629,7 +1602,7 @@
 MODULE_PARM_DESC(irq, "IRQ number(s) (assigned)");
 MODULE_PARM_DESC(xcvr,"transceiver(s) (0=internal, 1=external)");
 MODULE_PARM_DESC(max_interrupt_work, "maximum events handled per interrupt");
-#if defined(__ISAPNP__) && !defined(CONFIG_X86_PC9800)
+#if defined(__ISAPNP__)
 MODULE_PARM(nopnp, "i");
 MODULE_PARM_DESC(nopnp, "disable ISA PnP support (0-1)");
 MODULE_DEVICE_TABLE(isapnp, el3_isapnp_adapters);
--- diff/drivers/net/3c523.c	2004-05-19 22:11:53.000000000 +0100
+++ source/drivers/net/3c523.c	2004-06-11 19:22:02.000000000 +0100
@@ -445,7 +445,7 @@
 			slot = mca_find_adapter(ELMC_MCA_ID, slot + 1);
 			continue;
 		}
-		if (!request_region(dev->base_addr, ELMC_IO_EXTENT, dev->name)) {
+		if (!request_region(dev->base_addr, ELMC_IO_EXTENT, DRV_NAME)) {
 			slot = mca_find_adapter(ELMC_MCA_ID, slot + 1);
 			continue;
 		}
@@ -585,6 +585,7 @@
 	release_region(dev->base_addr, ELMC_IO_EXTENT);
 }
 
+#ifndef MODULE
 struct net_device * __init elmc_probe(int unit)
 {
 	struct net_device *dev = alloc_etherdev(sizeof(struct priv));
@@ -609,6 +610,7 @@
 	free_netdev(dev);
 	return ERR_PTR(err);
 }
+#endif
 
 /**********************************************
  * init the chip (elmc-interrupt should be disabled?!)
--- diff/drivers/net/3c527.c	2004-05-19 22:11:53.000000000 +0100
+++ source/drivers/net/3c527.c	2004-06-11 19:22:02.000000000 +0100
@@ -287,6 +287,7 @@
 			
 		}
 	}
+	free_netdev(dev);
 	return ERR_PTR(-ENODEV);
 }
 
@@ -434,10 +435,10 @@
 	 *	Grab the IRQ
 	 */
 
-	err = request_irq(dev->irq, &mc32_interrupt, SA_SHIRQ | SA_SAMPLE_RANDOM, dev->name, dev);
+	err = request_irq(dev->irq, &mc32_interrupt, SA_SHIRQ | SA_SAMPLE_RANDOM, DRV_NAME, dev);
 	if (err) {
 		release_region(dev->base_addr, MC32_IO_EXTENT);
-		printk(KERN_ERR "%s: unable to get IRQ %d.\n", dev->name, dev->irq);
+		printk(KERN_ERR "%s: unable to get IRQ %d.\n", DRV_NAME, dev->irq);
 		goto err_exit_ports;
 	}
 
--- diff/drivers/net/3c59x.c	2004-06-11 19:17:29.000000000 +0100
+++ source/drivers/net/3c59x.c	2004-06-11 19:22:02.000000000 +0100
@@ -446,6 +446,7 @@
 	CH_3C905B_2,
 	CH_3C905B_FX,
 	CH_3C905C,
+	CH_3C9202,
 	CH_3C980,
 	CH_3C9805,
 
@@ -520,12 +521,14 @@
 	{"3c905B-FX Cyclone 100baseFx",
 	 PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|HAS_HWCKSM, 128, },
 	{"3c905C Tornado",
-	 PCI_USES_IO|PCI_USES_MASTER, IS_TORNADO|HAS_NWAY|HAS_HWCKSM, 128, },
+	PCI_USES_IO|PCI_USES_MASTER, IS_TORNADO|HAS_NWAY|HAS_HWCKSM|EXTRA_PREAMBLE, 128, },
+	{"3c920B-EMB-WNM (ATI Radeon 9100 IGP)",
+	 PCI_USES_IO|PCI_USES_MASTER, IS_TORNADO|HAS_MII|HAS_HWCKSM, 128, },
 	{"3c980 Cyclone",
 	 PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|HAS_HWCKSM, 128, },
+
 	{"3c980C Python-T",
 	 PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|HAS_NWAY|HAS_HWCKSM, 128, },
-
 	{"3cSOHO100-TX Hurricane",
 	 PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|HAS_NWAY|HAS_HWCKSM, 128, },
 	{"3c555 Laptop Hurricane",
@@ -536,9 +539,9 @@
 	{"3c556B Laptop Hurricane",
 	 PCI_USES_IO|PCI_USES_MASTER, IS_TORNADO|HAS_NWAY|EEPROM_OFFSET|HAS_CB_FNS|INVERT_MII_PWR|
 	                                WNO_XCVR_PWR|HAS_HWCKSM, 128, },
+
 	{"3c575 [Megahertz] 10/100 LAN 	CardBus",
 	PCI_USES_IO|PCI_USES_MASTER, IS_BOOMERANG|HAS_MII|EEPROM_8BIT, 128, },
-
 	{"3c575 Boomerang CardBus",
 	 PCI_USES_IO|PCI_USES_MASTER, IS_BOOMERANG|HAS_MII|EEPROM_8BIT, 128, },
 	{"3CCFE575BT Cyclone CardBus",
@@ -550,10 +553,10 @@
 	{"3CCFE656 Cyclone CardBus",
 	 PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|HAS_NWAY|HAS_CB_FNS|EEPROM_8BIT|INVERT_MII_PWR|
 									INVERT_LED_PWR|HAS_HWCKSM, 128, },
+
 	{"3CCFEM656B Cyclone+Winmodem CardBus",
 	 PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|HAS_NWAY|HAS_CB_FNS|EEPROM_8BIT|INVERT_MII_PWR|
 									INVERT_LED_PWR|HAS_HWCKSM, 128, },
-
 	{"3CXFEM656C Tornado+Winmodem CardBus",			/* From pcmcia-cs-3.1.5 */
 	 PCI_USES_IO|PCI_USES_MASTER, IS_TORNADO|HAS_NWAY|HAS_CB_FNS|EEPROM_8BIT|INVERT_MII_PWR|
 									MAX_COLLISION_RESET|HAS_HWCKSM, 128, },
@@ -563,9 +566,9 @@
 	 PCI_USES_IO|PCI_USES_MASTER, IS_TORNADO|HAS_NWAY|HAS_HWCKSM, 128, },
 	{"3c982 Hydra Dual Port A",
 	 PCI_USES_IO|PCI_USES_MASTER, IS_TORNADO|HAS_HWCKSM|HAS_NWAY, 128, },
+
 	{"3c982 Hydra Dual Port B",
 	 PCI_USES_IO|PCI_USES_MASTER, IS_TORNADO|HAS_HWCKSM|HAS_NWAY, 128, },
-
 	{"3c905B-T4",
 	 PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|HAS_NWAY|HAS_HWCKSM|EXTRA_PREAMBLE, 128, },
 	{"3c920B-EMB-WNM Tornado",
@@ -597,6 +600,7 @@
 	{ 0x10B7, 0x9058, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3C905B_2 },
 	{ 0x10B7, 0x905A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3C905B_FX },
 	{ 0x10B7, 0x9200, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3C905C },
+	{ 0x10B7, 0x9202, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3C9202 },
 	{ 0x10B7, 0x9800, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3C980 },
 	{ 0x10B7, 0x9805, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3C9805 },
 
@@ -884,7 +888,7 @@
 static int vortex_probe1(struct device *gendev, long ioaddr, int irq,
 				   int chip_idx, int card_idx);
 static void vortex_up(struct net_device *dev);
-static void vortex_down(struct net_device *dev);
+static void vortex_down(struct net_device *dev, int final);
 static int vortex_open(struct net_device *dev);
 static void mdio_sync(long ioaddr, int bits);
 static int mdio_read(struct net_device *dev, int phy_id, int location);
@@ -948,7 +952,7 @@
 	if (dev && dev->priv) {
 		if (netif_running(dev)) {
 			netif_device_detach(dev);
-			vortex_down(dev);
+			vortex_down(dev, 1);
 		}
 	}
 	return 0;
@@ -2059,7 +2063,8 @@
 				printk(KERN_ERR "%s: PCI bus error, bus status %8.8x\n", dev->name, bus_status);
 
 			/* In this case, blow the card away */
-			vortex_down(dev);
+			/* Must not enter D3 or we can't legally issue the reset! */
+			vortex_down(dev, 0);
 			issue_and_wait(dev, TotalReset | 0xff);
 			vortex_up(dev);		/* AKPM: bug.  vortex_up() assumes that the rx ring is full. It may not be. */
 		} else if (fifo_diag & 0x0400)
@@ -2656,7 +2661,7 @@
 }
 
 static void
-vortex_down(struct net_device *dev)
+vortex_down(struct net_device *dev, int final_down)
 {
 	struct vortex_private *vp = netdev_priv(dev);
 	long ioaddr = dev->base_addr;
@@ -2685,7 +2690,7 @@
 	if (vp->full_bus_master_tx)
 		outl(0, ioaddr + DownListPtr);
 
-	if (VORTEX_PCI(vp) && vp->enable_wol) {
+	if (final_down && VORTEX_PCI(vp) && vp->enable_wol) {
 		pci_save_state(VORTEX_PCI(vp), vp->power_state);
 		acpi_set_WOL(dev);
 	}
@@ -2699,7 +2704,7 @@
 	int i;
 
 	if (netif_device_present(dev))
-		vortex_down(dev);
+		vortex_down(dev, 1);
 
 	if (vortex_debug > 1) {
 		printk(KERN_DEBUG"%s: vortex_close() status %4.4x, Tx status %2.2x.\n",
@@ -2869,7 +2874,7 @@
 	.get_drvinfo =		vortex_get_drvinfo,
 };
 
-static int vortex_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
+static int vortex_do_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
 {
 	struct vortex_private *vp = netdev_priv(dev);
 	long ioaddr = dev->base_addr;
@@ -2904,6 +2909,30 @@
 	return retval;
 }
 
+/*
+ *	Must power the device up to do MDIO operations
+ */
+static int vortex_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
+{
+	int err;
+	struct vortex_private *vp = netdev_priv(dev);
+	int state = 0;
+
+	if(VORTEX_PCI(vp))
+		state = VORTEX_PCI(vp)->current_state;
+
+	/* The kernel core really should have pci_get_power_state() */
+
+	if(state != 0)
+		pci_set_power_state(VORTEX_PCI(vp), 0);
+	err = vortex_do_ioctl(dev, rq, cmd);
+	if(state != 0)
+		pci_set_power_state(VORTEX_PCI(vp), state);
+
+	return err;
+}
+
+
 /* Pre-Cyclone chips have no documented multicast filter, so the only
    multicast setting is to receive all multicast frames.  At least
    the chip has a very clean way to set the mode, unlike many others. */
@@ -3059,14 +3088,14 @@
 	 * here
 	 */
 	unregister_netdev(dev);
-	/* Should really use issue_and_wait() here */
-	outw(TotalReset|0x14, dev->base_addr + EL3_CMD);
 
 	if (VORTEX_PCI(vp) && vp->enable_wol) {
 		pci_set_power_state(VORTEX_PCI(vp), 0);	/* Go active */
 		if (vp->pm_state_valid)
 			pci_restore_state(VORTEX_PCI(vp), vp->power_state);
 	}
+	/* Should really use issue_and_wait() here */
+	outw(TotalReset|0x14, dev->base_addr + EL3_CMD);
 
 	pci_free_consistent(pdev,
 						sizeof(struct boom_rx_desc) * RX_RING_SIZE
--- diff/drivers/net/82596.c	2004-05-19 22:11:53.000000000 +0100
+++ source/drivers/net/82596.c	2004-06-11 19:22:02.000000000 +0100
@@ -58,11 +58,12 @@
 #include <asm/io.h>
 #include <asm/dma.h>
 #include <asm/pgtable.h>
-#include <asm/pgalloc.h>
 
 static char version[] __initdata =
 	"82596.c $Revision: 1.5 $\n";
 
+#define DRV_NAME	"82596"
+
 /* DEBUG flags
  */
 
@@ -1191,7 +1192,7 @@
 		/* this is easy the ethernet interface can only be at 0x300 */
 		/* first check nothing is already registered here */
 
-		if (!request_region(ioaddr, I596_TOTAL_SIZE, dev->name)) {
+		if (!request_region(ioaddr, I596_TOTAL_SIZE, DRV_NAME)) {
 			printk(KERN_ERR "82596: IO address 0x%04x in use\n", ioaddr);
 			err = -EBUSY;
 			goto out;
--- diff/drivers/net/Kconfig	2004-06-11 19:17:29.000000000 +0100
+++ source/drivers/net/Kconfig	2004-06-11 19:22:02.000000000 +0100
@@ -922,7 +922,7 @@
 
 config NET_ISA
 	bool "Other ISA cards"
-	depends on NET_ETHERNET && ISA && !X86_PC9800
+	depends on NET_ETHERNET && ISA
 	---help---
 	  If your network (Ethernet) card hasn't been mentioned yet and its
 	  bus system (that's the way the cards talks to the other components
@@ -1105,56 +1105,6 @@
 	  the Ethernet-HOWTO, available from
 	  <http://www.tldp.org/docs.html#howto>.
 
-config NET_CBUS
-	bool "NEC PC-9800 C-bus cards"
-	depends on NET_ETHERNET && ISA && X86_PC9800
-	---help---
-	  If your network (Ethernet) card hasn't been mentioned yet and its
-	  bus system (that's the way the cards talks to the other components
-	  of your computer) is NEC PC-9800 C-Bus, say Y.
-
-config NE2K_CBUS
-	tristate "Most NE2000-based Ethernet support"
-	depends on NET_CBUS
-	select CRC32
-
-config NE2K_CBUS_EGY98
-	bool "Melco EGY-98 support"
-	depends on NE2K_CBUS
-
-config NE2K_CBUS_LGY98
-	bool "Melco LGY-98 support"
-	depends on NE2K_CBUS
-
-config NE2K_CBUS_ICM
-	bool "ICM IF-27xxET support"
-	depends on NE2K_CBUS
-
-config NE2K_CBUS_IOLA98
-	bool "I-O DATA LA-98 support"
-	depends on NE2K_CBUS
-
-config NE2K_CBUS_CNET98EL
-	bool "Contec C-NET(98)E/L support"
-	depends on NE2K_CBUS
-
-config NE2K_CBUS_CNET98EL_IO_BASE
-	hex "C-NET(98)E/L I/O base address (0xaaed or 0x55ed)"
-	depends on NE2K_CBUS_CNET98EL
-	default "0xaaed"
-
-config NE2K_CBUS_ATLA98
-	bool "Allied Telesis LA-98 Support"
-	depends on NE2K_CBUS
-
-config NE2K_CBUS_BDN
-	bool "ELECOM Laneed LD-BDN[123]A Support"
-	depends on NE2K_CBUS
-
-config NE2K_CBUS_NEC108
-	bool "NEC PC-9801-108 Support"
-	depends on NE2K_CBUS
-
 config SKMC
 	tristate "SKnet MCA support"
 	depends on NET_ETHERNET && MCA && BROKEN
@@ -1745,6 +1695,17 @@
 
 	  If unsure, say Y.
 
+config VIA_VELOCITY
+	tristate "VIA Velocity support"
+	depends on NET_PCI && PCI
+	select CRC32
+	select MII
+	help
+	  If you have a VIA "Velocity" based network card say Y here.
+
+	  To compile this driver as a module, choose M here. The module
+	  will be called via-velocity.
+
 config LAN_SAA9730
 	bool "Philips SAA9730 Ethernet support (EXPERIMENTAL)"
 	depends on NET_PCI && EXPERIMENTAL && MIPS
@@ -2020,6 +1981,11 @@
 	  To compile this driver as a module, choose M here: the module
 	  will be called r8169.  This is recommended.
 
+config R8169_NAPI
+	bool "Use Rx and Tx Polling (NAPI) (EXPERIMENTAL)"
+	depends on R8169 && EXPERIMENTAL 
+
+
 config SK98LIN
 	tristate "Marvell Yukon Chipset / SysKonnect SK-98xx Support"
 	depends on PCI
--- diff/drivers/net/Makefile	2004-06-11 19:17:29.000000000 +0100
+++ source/drivers/net/Makefile	2004-06-11 19:22:02.000000000 +0100
@@ -52,6 +52,7 @@
 obj-$(CONFIG_SK98LIN) += sk98lin/
 obj-$(CONFIG_SKFP) += skfp/
 obj-$(CONFIG_VIA_RHINE) += via-rhine.o
+obj-$(CONFIG_VIA_VELOCITY) += via-velocity.o
 obj-$(CONFIG_ADAPTEC_STARFIRE) += starfire.o
 
 #
@@ -79,7 +80,6 @@
 obj-$(CONFIG_WD80x3) += wd.o 8390.o
 obj-$(CONFIG_EL2) += 3c503.o 8390.o
 obj-$(CONFIG_NE2000) += ne.o 8390.o
-obj-$(CONFIG_NE2K_CBUS) += ne2k_cbus.o 8390.o
 obj-$(CONFIG_NE2_MCA) += ne2.o 8390.o
 obj-$(CONFIG_HPLAN) += hp.o 8390.o
 obj-$(CONFIG_HPLAN_PLUS) += hp-plus.o 8390.o
@@ -188,4 +188,6 @@
 obj-$(CONFIG_HAMRADIO) += hamradio/
 obj-$(CONFIG_IRDA) += irda/
 
+# Must come after all NICs that might use them
 obj-$(CONFIG_NETCONSOLE) += netconsole.o
+obj-$(CONFIG_KGDB) += kgdb_eth.o
--- diff/drivers/net/Space.c	2004-06-11 19:17:29.000000000 +0100
+++ source/drivers/net/Space.c	2004-06-11 19:22:03.000000000 +0100
@@ -191,8 +191,8 @@
 #ifdef CONFIG_E2100		/* Cabletron E21xx series. */
 	{e2100_probe, 0},
 #endif
-#if defined(CONFIG_NE2000) || defined(CONFIG_NE2K_CBUS)	|| \
-    defined(CONFIG_NE_H8300)  /* ISA & PC-9800 CBUS (use ne2k-pci for PCI cards) */
+#if defined(CONFIG_NE2000) || \
+    defined(CONFIG_NE_H8300)  /* ISA (use ne2k-pci for PCI cards) */
 	{ne_probe, 0},
 #endif
 #ifdef CONFIG_LANCE		/* ISA/VLB (use pcnet32 for PCI cards) */
--- diff/drivers/net/ac3200.c	2004-05-19 22:11:53.000000000 +0100
+++ source/drivers/net/ac3200.c	2004-06-11 19:22:02.000000000 +0100
@@ -39,6 +39,8 @@
 
 #include "8390.h"
 
+#define DRV_NAME	"ac3200"
+
 /* Offsets from the base address. */
 #define AC_NIC_BASE	0x00
 #define AC_SA_PROM	0x16			/* The station address PROM. */
@@ -130,6 +132,7 @@
 		iounmap((void *)dev->mem_start);
 }
 
+#ifndef MODULE
 struct net_device * __init ac3200_probe(int unit)
 {
 	struct net_device *dev = alloc_ei_netdev();
@@ -154,12 +157,13 @@
 	free_netdev(dev);
 	return ERR_PTR(err);
 }
+#endif
 
 static int __init ac_probe1(int ioaddr, struct net_device *dev)
 {
 	int i, retval;
 
-	if (!request_region(ioaddr, AC_IO_EXTENT, dev->name))
+	if (!request_region(ioaddr, AC_IO_EXTENT, DRV_NAME))
 		return -EBUSY;
 
 	if (inb_p(ioaddr + AC_ID_PORT) == 0xff) {
@@ -203,7 +207,7 @@
 		printk(", assigning");
 	}
 
-	retval = request_irq(dev->irq, ei_interrupt, 0, dev->name, dev);
+	retval = request_irq(dev->irq, ei_interrupt, 0, DRV_NAME, dev);
 	if (retval) {
 		printk (" nothing! Unable to get IRQ %d.\n", dev->irq);
 		goto out1;
--- diff/drivers/net/acenic.c	2004-06-11 19:17:29.000000000 +0100
+++ source/drivers/net/acenic.c	2004-06-11 19:22:02.000000000 +0100
@@ -85,6 +85,8 @@
 #include <asm/uaccess.h>
 
 
+#define DRV_NAME "acenic"
+
 #undef INDEX_DEBUG
 
 #ifdef CONFIG_ACENIC_OMIT_TIGON_I
@@ -1195,10 +1197,10 @@
 	}
 
 	ecode = request_irq(pdev->irq, ace_interrupt, SA_SHIRQ,
-			    dev->name, dev);
+			    DRV_NAME, dev);
 	if (ecode) {
 		printk(KERN_WARNING "%s: Requested IRQ %d is busy\n",
-		       dev->name, pdev->irq);
+		       DRV_NAME, pdev->irq);
 		goto init_error;
 	} else
 		dev->irq = pdev->irq;
--- diff/drivers/net/apne.c	2004-05-19 22:11:53.000000000 +0100
+++ source/drivers/net/apne.c	2004-06-11 19:22:02.000000000 +0100
@@ -49,6 +49,8 @@
 
 /* ---- No user-serviceable parts below ---- */
 
+#define DRV_NAME "apne"
+
 #define NE_BASE	 (dev->base_addr)
 #define NE_CMD	 		0x00
 #define NE_DATAPORT		0x10            /* NatSemi-defined port window offset. */
@@ -168,7 +170,7 @@
 		return ERR_PTR(-ENODEV);
 	}
 
-	if (!request_region(IOBASE, 0x20, dev->name)) {
+	if (!request_region(IOBASE, 0x20, DRV_NAME)) {
 		free_netdev(dev);
 		return ERR_PTR(-EBUSY);
 	}
@@ -310,7 +312,7 @@
     dev->base_addr = ioaddr;
 
     /* Install the Interrupt handler */
-    i = request_irq(IRQ_AMIGA_PORTS, apne_interrupt, SA_SHIRQ, dev->name, dev);
+    i = request_irq(IRQ_AMIGA_PORTS, apne_interrupt, SA_SHIRQ, DRV_NAME, dev);
     if (i) return i;
 
     for(i = 0; i < ETHER_ADDR_LEN; i++) {
--- diff/drivers/net/at1700.c	2004-05-19 22:11:53.000000000 +0100
+++ source/drivers/net/at1700.c	2004-06-11 19:22:02.000000000 +0100
@@ -65,6 +65,8 @@
 static char version[] __initdata =
 	"at1700.c:v1.15 4/7/98  Donald Becker (becker@cesdis.gsfc.nasa.gov)\n";
 
+#define DRV_NAME "at1700"
+
 /* Tunable parameters. */
 
 /* When to switch from the 64-entry multicast filter to Rx-all-multicast. */
@@ -80,17 +82,10 @@
  *	ISA
  */
 
-#ifndef CONFIG_X86_PC9800
 static unsigned at1700_probe_list[] __initdata = {
 	0x260, 0x280, 0x2a0, 0x240, 0x340, 0x320, 0x380, 0x300, 0
 };
 
-#else /* CONFIG_X86_PC9800 */
-static unsigned at1700_probe_list[] __initdata = {
-	0x1d6, 0x1d8, 0x1da, 0x1d4, 0xd4, 0xd2, 0xd8, 0xd0, 0
-};
-
-#endif /* CONFIG_X86_PC9800 */
 /*
  *	MCA
  */
@@ -133,7 +128,6 @@
 
 
 /* Offsets from the base address. */
-#ifndef CONFIG_X86_PC9800
 #define STATUS			0
 #define TX_STATUS		0
 #define RX_STATUS		1
@@ -161,34 +155,6 @@
 #define RESET			31		/* Write to reset some parts of the chip. */
 #define AT1700_IO_EXTENT	32
 #define PORT_OFFSET(o) (o)
-#else /* CONFIG_X86_PC9800 */
-#define STATUS			(0x0000)
-#define TX_STATUS		(0x0000)
-#define RX_STATUS		(0x0001)
-#define TX_INTR			(0x0200)/* Bit-mapped interrupt enable registers. */
-#define RX_INTR			(0x0201)
-#define TX_MODE			(0x0400)
-#define RX_MODE			(0x0401)
-#define CONFIG_0		(0x0600)/* Misc. configuration settings. */
-#define CONFIG_1		(0x0601)
-/* Run-time register bank 2 definitions. */
-#define DATAPORT		(0x0800)/* Word-wide DMA or programmed-I/O dataport. */
-#define TX_START		(0x0a00)
-#define COL16CNTL		(0x0a01)/* Controll Reg for 16 collisions */
-#define MODE13			(0x0c01)
-#define RX_CTRL			(0x0e00)
-/* Configuration registers only on the '865A/B chips. */
-#define EEPROM_Ctrl 	(0x1000)
-#define EEPROM_Data 	(0x1200)
-#define CARDSTATUS	16			/* FMV-18x Card Status */
-#define CARDSTATUS1	17			/* FMV-18x Card Status */
-#define IOCONFIG		(0x1400)/* Either read the jumper, or move the I/O. */
-#define IOCONFIG1		(0x1600)
-#define	SAPROM			20		/* The station address PROM, if no EEPROM. */
-#define	MODE24			(0x1800)/* The station address PROM, if no EEPROM. */
-#define RESET			(0x1e01)/* Write to reset some parts of the chip. */
-#define PORT_OFFSET(o) ({ int _o_ = (o); (_o_ & ~1) * 0x100 + (_o_ & 1); })
-#endif /* CONFIG_X86_PC9800 */
 
 
 #define TX_TIMEOUT		10
@@ -230,11 +196,7 @@
    (detachable devices only).
    */
 
-#ifndef CONFIG_X86_PC9800
 static int io = 0x260;
-#else
-static int io = 0xd0;
-#endif
 
 static int irq;
 
@@ -242,19 +204,11 @@
 {
 #ifdef CONFIG_MCA	
 	struct net_local *lp = netdev_priv(dev);
-	if (lp->mca_slot)
+	if (lp->mca_slot >= 0)
 		mca_mark_as_unused(lp->mca_slot);
 #endif	
 	free_irq(dev->irq, NULL);
-#ifndef CONFIG_X86_PC9800
 	release_region(dev->base_addr, AT1700_IO_EXTENT);
-#else
-	{
-		int i;
-		for (i = 0; i < 0x2000; i += 0x200)
-			release_region(dev->base_addr + i, 2);
-	}
-#endif
 }
 
 struct net_device * __init at1700_probe(int unit)
@@ -321,20 +275,8 @@
 	int slot, ret = -ENODEV;
 	struct net_local *lp = netdev_priv(dev);
 
-#ifndef CONFIG_X86_PC9800
-	if (!request_region(ioaddr, AT1700_IO_EXTENT, dev->name))
+	if (!request_region(ioaddr, AT1700_IO_EXTENT, DRV_NAME))
 		return -EBUSY;
-#else
-	for (i = 0; i < 0x2000; i += 0x0200) {
-		if (!request_region(ioaddr + i, 2, dev->name)) {
-			while (i > 0) {
-				i -= 0x0200;
-				release_region(ioaddr + i, 2);
-			}
-			return -EBUSY;
-		}
-	}
-#endif
 
 	/* Resetting the chip doesn't reset the ISA interface, so don't bother.
 	   That means we have to be careful with the register values we probe
@@ -425,15 +367,8 @@
 	outb(0, ioaddr + RESET);
 
 	if (is_at1700) {
-#ifndef CONFIG_X86_PC9800
 		irq = at1700_irqmap[(read_eeprom(ioaddr, 12)&0x04)
 						   | (read_eeprom(ioaddr, 0)>>14)];
-#else
-		{
-			char re1000plus_irqmap[4] = {3, 5, 6, 12};
-			irq = re1000plus_irqmap[inb(ioaddr + IOCONFIG1) >> 6];
-		}
-#endif
 	} else {
 		/* Check PnP mode for FMV-183/184/183A/184A. */
 		/* This PnP routine is very poor. IO and IRQ should be known. */
@@ -444,11 +379,11 @@
 					break;
 			}
 			if (i == 8) {
-				goto err_out;
+				goto err_mca;
 			}
 		} else {
 			if (fmv18x_probe_list[inb(ioaddr + IOCONFIG) & 0x07] != ioaddr)
-				goto err_out;
+				goto err_mca;
 			irq = fmv_irqmap[(inb(ioaddr + IOCONFIG)>>6) & 0x03];
 		}
 	}
@@ -517,11 +452,7 @@
 	/* Switch to bank 2 */
 	/* Lock our I/O address, and set manual processing mode for 16 collisions. */
 	outb(0x08, ioaddr + CONFIG_1);
-#ifndef CONFIG_X86_PC9800
 	outb(dev->if_port, ioaddr + MODE13);
-#else
-	outb(0, ioaddr + MODE13);
-#endif
 	outb(0x00, ioaddr + COL16CNTL);
 
 	if (net_debug)
@@ -542,22 +473,22 @@
 	lp->jumpered = is_fmv18x;
 	lp->mca_slot = slot;
 	/* Snarf the interrupt vector now. */
-	ret = request_irq(irq, &net_interrupt, 0, dev->name, dev);
+	ret = request_irq(irq, &net_interrupt, 0, DRV_NAME, dev);
 	if (ret) {
 		printk ("  AT1700 at %#3x is unusable due to a conflict on"
 				"IRQ %d.\n", ioaddr, irq);
-		goto err_out;
+		goto err_mca;
 	}
 
 	return 0;
 
+err_mca:
+#ifdef CONFIG_MCA
+	if (slot >= 0)
+		mca_mark_as_unused(slot);
+#endif
 err_out:
-#ifndef CONFIG_X86_PC9800
 	release_region(ioaddr, AT1700_IO_EXTENT);
-#else
-	for (i = 0; i < 0x2000; i += 0x0200)
-		release_region(ioaddr + i, 2);
-#endif
 	return ret;
 }
 
@@ -568,13 +499,6 @@
 #define EE_DATA_WRITE	0x80	/* EEPROM chip data in, in reg. 17. */
 #define EE_DATA_READ	0x80	/* EEPROM chip data out, in reg. 17. */
 
-/* Delay between EEPROM clock transitions. */
-#ifndef CONFIG_X86_PC9800
-#define eeprom_delay()	do { } while (0)
-#else
-#define eeprom_delay()	__asm__ ("out%B0 %%al,%0" :: "N"(0x5f))
-#endif
-
 /* The EEPROM commands include the alway-set leading bit. */
 #define EE_WRITE_CMD	(5 << 6)
 #define EE_READ_CMD		(6 << 6)
@@ -593,22 +517,17 @@
 		short dataval = (read_cmd & (1 << i)) ? EE_DATA_WRITE : 0;
 		outb(EE_CS, ee_addr);
 		outb(dataval, ee_daddr);
-		eeprom_delay();
 		outb(EE_CS | EE_SHIFT_CLK, ee_addr);	/* EEPROM clock tick. */
-		eeprom_delay();
 	}
 	outb(EE_DATA_WRITE, ee_daddr);
 	for (i = 16; i > 0; i--) {
 		outb(EE_CS, ee_addr);
-		eeprom_delay();
 		outb(EE_CS | EE_SHIFT_CLK, ee_addr);
-		eeprom_delay();
 		retval = (retval << 1) | ((inb(ee_daddr) & EE_DATA_READ) ? 1 : 0);
 	}
 
 	/* Terminate the EEPROM access. */
 	outb(EE_CS, ee_addr);
-	eeprom_delay();
 	outb(EE_SHIFT_CLK, ee_addr);
 	outb(0, ee_addr);
 	return retval;
--- diff/drivers/net/cs89x0.c	2004-05-19 22:11:53.000000000 +0100
+++ source/drivers/net/cs89x0.c	2004-06-11 19:22:02.000000000 +0100
@@ -141,6 +141,8 @@
 static char version[] __initdata =
 "cs89x0.c: v2.4.3-pre1 Russell Nelson <nelson@crynwr.com>, Andrew Morton <andrewm@uow.edu.au>\n";
 
+#define DRV_NAME "cs89x0"
+
 /* First, a few definitions that the brave might change.
    A zero-terminated list of I/O addresses to be probed. Some special flags..
       Addr & 1 = Read back the address port, look for signature and reset
@@ -261,7 +263,6 @@
 }
 
 __setup("cs89x0_media=", media_fn);
-#endif
 
 
 /* Check for a network adaptor of this type, and return '0' iff one exists.
@@ -318,6 +319,7 @@
 	printk(KERN_WARNING "cs89x0: no cs8900 or cs8920 detected.  Be sure to disable PnP with SETUP\n");
 	return ERR_PTR(err);
 }
+#endif
 
 static int
 readreg(struct net_device *dev, int portno)
@@ -425,9 +427,9 @@
 
 	/* Grab the region so we can find another board if autoIRQ fails. */
 	/* WTF is going on here? */
-	if (!request_region(ioaddr & ~3, NETCARD_IO_EXTENT, dev->name)) {
+	if (!request_region(ioaddr & ~3, NETCARD_IO_EXTENT, DRV_NAME)) {
 		printk(KERN_ERR "%s: request_region(0x%x, 0x%x) failed\n",
-				dev->name, ioaddr, NETCARD_IO_EXTENT);
+				DRV_NAME, ioaddr, NETCARD_IO_EXTENT);
 		retval = -EBUSY;
 		goto out1;
 	}
--- diff/drivers/net/defxx.c	2004-05-19 22:11:53.000000000 +0100
+++ source/drivers/net/defxx.c	2004-06-11 19:22:02.000000000 +0100
@@ -219,6 +219,8 @@
 static char version[] __devinitdata =
 	"defxx.c:v1.06 2003/08/04  Lawrence V. Stefani and others\n";
 
+#define DRV_NAME "defxx"
+
 #define DYNAMIC_BUFFERS 1
 
 #define SKBUFF_RX_COPYBREAK 200
@@ -435,9 +437,9 @@
 
 	bp = dev->priv;
 
-	if (!request_region (ioaddr, pdev ? PFI_K_CSR_IO_LEN : PI_ESIC_K_CSR_IO_LEN, dev->name)) {
+	if (!request_region (ioaddr, pdev ? PFI_K_CSR_IO_LEN : PI_ESIC_K_CSR_IO_LEN, DRV_NAME)) {
 		printk (KERN_ERR "%s: Cannot reserve I/O resource 0x%x @ 0x%lx, aborting\n",
-			dev->name, PFI_K_CSR_IO_LEN, ioaddr);
+			DRV_NAME, PFI_K_CSR_IO_LEN, ioaddr);
 		err = -EBUSY;
 		goto err_out;
 	}
--- diff/drivers/net/e1000/e1000_main.c	2004-06-11 19:17:29.000000000 +0100
+++ source/drivers/net/e1000/e1000_main.c	2004-06-11 19:22:02.000000000 +0100
@@ -52,7 +52,7 @@
 
 char e1000_driver_name[] = "e1000";
 char e1000_driver_string[] = "Intel(R) PRO/1000 Network Driver";
-char e1000_driver_version[] = "5.2.52-k2";
+char e1000_driver_version[] = "5.2.52-k4";
 char e1000_copyright[] = "Copyright (c) 1999-2004 Intel Corporation.";
 
 /* e1000_pci_tbl - PCI Device ID Table
@@ -2143,6 +2143,7 @@
 	if(work_done < work_to_do || !netif_running(netdev)) {
 		netif_rx_complete(netdev);
 		e1000_irq_enable(adapter);
+		return 0;
 	}
 
 	return (work_done >= work_to_do);
@@ -2857,6 +2858,8 @@
 		}
 	}
 
+	pci_disable_device(pdev);
+
 	state = (state > 0) ? 3 : 0;
 	pci_set_power_state(pdev, state);
 
@@ -2871,6 +2874,7 @@
 	struct e1000_adapter *adapter = netdev->priv;
 	uint32_t manc;
 
+	pci_enable_device(pdev);
 	pci_set_power_state(pdev, 0);
 	pci_restore_state(pdev, adapter->pci_state);
 
--- diff/drivers/net/e2100.c	2004-05-19 22:11:53.000000000 +0100
+++ source/drivers/net/e2100.c	2004-06-11 19:22:02.000000000 +0100
@@ -51,6 +51,8 @@
 
 #include "8390.h"
 
+#define DRV_NAME "e2100"
+
 static int e21_probe_list[] = {0x300, 0x280, 0x380, 0x220, 0};
 
 /* Offsets from the base_addr.
@@ -144,6 +146,7 @@
 	release_region(dev->base_addr, E21_IO_EXTENT);
 }
 
+#ifndef MODULE
 struct net_device * __init e2100_probe(int unit)
 {
 	struct net_device *dev = alloc_ei_netdev();
@@ -168,6 +171,7 @@
 	free_netdev(dev);
 	return ERR_PTR(err);
 }
+#endif
 
 static int __init e21_probe1(struct net_device *dev, int ioaddr)
 {
@@ -175,7 +179,7 @@
 	unsigned char *station_addr = dev->dev_addr;
 	static unsigned version_printed;
 
-	if (!request_region(ioaddr, E21_IO_EXTENT, dev->name))
+	if (!request_region(ioaddr, E21_IO_EXTENT, DRV_NAME))
 		return -EBUSY;
 
 	/* First check the station address for the Ctron prefix. */
--- diff/drivers/net/eepro.c	2004-05-19 22:11:53.000000000 +0100
+++ source/drivers/net/eepro.c	2004-06-11 19:22:02.000000000 +0100
@@ -151,6 +151,8 @@
 #include <asm/io.h>
 #include <asm/dma.h>
 
+#define DRV_NAME "eepro"
+
 #define compat_dev_kfree_skb( skb, mode ) dev_kfree_skb( (skb) )
 /* I had reports of looong delays with SLOW_DOWN defined as udelay(2) */
 #define SLOW_DOWN inb(0x80)
@@ -577,6 +579,7 @@
 	return -ENODEV;
 }
 
+#ifndef MODULE
 struct net_device * __init eepro_probe(int unit)
 {
 	struct net_device *dev = alloc_etherdev(sizeof(struct eepro_local));
@@ -603,6 +606,7 @@
 	free_netdev(dev);
 	return ERR_PTR(err);
 }
+#endif
 
 static void __init printEEPROMInfo(short ioaddr, struct net_device *dev)
 {
@@ -745,7 +749,7 @@
 	int ioaddr = dev->base_addr;
 
 	/* Grab the region so we can find another board if autoIRQ fails. */
-	if (!request_region(ioaddr, EEPRO_IO_EXTENT, dev->name)) { 
+	if (!request_region(ioaddr, EEPRO_IO_EXTENT, DRV_NAME)) { 
 		if (!autoprobe)
 			printk(KERN_WARNING "EEPRO: io-port 0x%04x in use \n",
 				ioaddr);
--- diff/drivers/net/eexpress.c	2004-05-19 22:11:53.000000000 +0100
+++ source/drivers/net/eexpress.c	2004-06-11 19:22:02.000000000 +0100
@@ -423,6 +423,7 @@
 	return -ENODEV;
 }
 
+#ifndef MODULE
 struct net_device * __init express_probe(int unit)
 {
 	struct net_device *dev = alloc_etherdev(sizeof(struct net_local));
@@ -443,6 +444,7 @@
 	free_netdev(dev);
 	return ERR_PTR(err);
 }
+#endif
 
 /*
  * open and initialize the adapter, ready for use
--- diff/drivers/net/epic100.c	2004-06-11 19:17:29.000000000 +0100
+++ source/drivers/net/epic100.c	2004-06-11 19:22:02.000000000 +0100
@@ -66,19 +66,20 @@
 	LK1.1.14 (Kryzsztof Halasa):
 	* fix spurious bad initializations
 	* pound phy a la SMSC's app note on the subject
+	
+	AC1.1.14ac
+	* fix power up/down for ethtool that broke in 1.11
 
 */
 
 #define DRV_NAME        "epic100"
-#define DRV_VERSION     "1.11+LK1.1.14"
-#define DRV_RELDATE     "Aug 4, 2002"
+#define DRV_VERSION     "1.11+LK1.1.14+AC1.1.14"
+#define DRV_RELDATE     "June 2, 2004"
 
 /* The user-configurable values.
    These may be modified when a driver module is loaded.*/
 
 static int debug = 1;			/* 1 normal messages, 0 quiet .. 7 verbose. */
-/* Maximum events (Rx packets, etc.) to handle at each interrupt. */
-static int max_interrupt_work = 32;
 
 /* Used to pass the full-duplex flag, etc. */
 #define MAX_UNITS 8		/* More are supported, limit only on options */
@@ -96,9 +97,9 @@
    Making the Tx ring too large decreases the effectiveness of channel
    bonding and packet priority.
    There are no ill effects from too-large receive rings. */
-#define TX_RING_SIZE	16
-#define TX_QUEUE_LEN	10		/* Limit ring entries actually used.  */
-#define RX_RING_SIZE	32
+#define TX_RING_SIZE	256
+#define TX_QUEUE_LEN	240		/* Limit ring entries actually used.  */
+#define RX_RING_SIZE	256
 #define TX_TOTAL_SIZE	TX_RING_SIZE*sizeof(struct epic_tx_desc)
 #define RX_TOTAL_SIZE	RX_RING_SIZE*sizeof(struct epic_rx_desc)
 
@@ -155,12 +156,10 @@
 MODULE_LICENSE("GPL");
 
 MODULE_PARM(debug, "i");
-MODULE_PARM(max_interrupt_work, "i");
 MODULE_PARM(rx_copybreak, "i");
 MODULE_PARM(options, "1-" __MODULE_STRING(MAX_UNITS) "i");
 MODULE_PARM(full_duplex, "1-" __MODULE_STRING(MAX_UNITS) "i");
 MODULE_PARM_DESC(debug, "EPIC/100 debug level (0-5)");
-MODULE_PARM_DESC(max_interrupt_work, "EPIC/100 maximum events handled per interrupt");
 MODULE_PARM_DESC(options, "EPIC/100: Bits 0-3: media type, bit 4: full duplex");
 MODULE_PARM_DESC(rx_copybreak, "EPIC/100 copy breakpoint for copy-only-tiny-frames");
 MODULE_PARM_DESC(full_duplex, "EPIC/100 full duplex setting(s) (1)");
@@ -292,6 +291,12 @@
 	StopTxDMA=0x20, StopRxDMA=0x40, RestartTx=0x80,
 };
 
+#define EpicRemoved	0xffffffff	/* Chip failed or removed (CardBus) */
+
+#define EpicNapiEvent	(TxEmpty | TxDone | \
+			 RxDone | RxStarted | RxEarlyWarn | RxOverflow | RxFull)
+#define EpicNormalEvent	(0x0000ffff & ~EpicNapiEvent)
+
 static u16 media2miictl[16] = {
 	0, 0x0C00, 0x0C00, 0x2000,  0x0100, 0x2100, 0, 0,
 	0, 0, 0, 0,  0, 0, 0, 0 };
@@ -330,9 +335,12 @@
 
 	/* Ring pointers. */
 	spinlock_t lock;				/* Group with Tx control cache line. */
+	spinlock_t napi_lock;
+	unsigned int reschedule_in_poll;
 	unsigned int cur_tx, dirty_tx;
 
 	unsigned int cur_rx, dirty_rx;
+	u32 irq_mask;
 	unsigned int rx_buf_sz;				/* Based on MTU+slack. */
 
 	struct pci_dev *pci_dev;			/* PCI bus location. */
@@ -359,7 +367,8 @@
 static void epic_tx_timeout(struct net_device *dev);
 static void epic_init_ring(struct net_device *dev);
 static int epic_start_xmit(struct sk_buff *skb, struct net_device *dev);
-static int epic_rx(struct net_device *dev);
+static int epic_rx(struct net_device *dev, int budget);
+static int epic_poll(struct net_device *dev, int *budget);
 static irqreturn_t epic_interrupt(int irq, void *dev_instance, struct pt_regs *regs);
 static int netdev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
 static struct ethtool_ops netdev_ethtool_ops;
@@ -378,7 +387,7 @@
 	int irq;
 	struct net_device *dev;
 	struct epic_private *ep;
-	int i, option = 0, duplex = 0;
+	int i, ret, option = 0, duplex = 0;
 	void *ring_space;
 	dma_addr_t ring_dma;
 
@@ -392,29 +401,33 @@
 	
 	card_idx++;
 	
-	i = pci_enable_device(pdev);
-	if (i)
-		return i;
+	ret = pci_enable_device(pdev);
+	if (ret)
+		goto out;
 	irq = pdev->irq;
 
 	if (pci_resource_len(pdev, 0) < pci_id_tbl[chip_idx].io_size) {
 		printk (KERN_ERR "card %d: no PCI region space\n", card_idx);
-		return -ENODEV;
+		ret = -ENODEV;
+		goto err_out_disable;
 	}
 	
 	pci_set_master(pdev);
 
+	ret = pci_request_regions(pdev, DRV_NAME);
+	if (ret < 0)
+		goto err_out_disable;
+
+	ret = -ENOMEM;
+
 	dev = alloc_etherdev(sizeof (*ep));
 	if (!dev) {
 		printk (KERN_ERR "card %d: no memory for eth device\n", card_idx);
-		return -ENOMEM;
+		goto err_out_free_res;
 	}
 	SET_MODULE_OWNER(dev);
 	SET_NETDEV_DEV(dev, &pdev->dev);
 
-	if (pci_request_regions(pdev, DRV_NAME))
-		goto err_out_free_netdev;
-
 #ifdef USE_IO_OPS
 	ioaddr = pci_resource_start (pdev, 0);
 #else
@@ -422,7 +435,7 @@
 	ioaddr = (long) ioremap (ioaddr, pci_resource_len (pdev, 1));
 	if (!ioaddr) {
 		printk (KERN_ERR DRV_NAME " %d: ioremap failed\n", card_idx);
-		goto err_out_free_res;
+		goto err_out_free_netdev;
 	}
 #endif
 
@@ -459,7 +472,9 @@
 	dev->base_addr = ioaddr;
 	dev->irq = irq;
 
-	spin_lock_init (&ep->lock);
+	spin_lock_init(&ep->lock);
+	spin_lock_init(&ep->napi_lock);
+	ep->reschedule_in_poll = 0;
 
 	/* Bring the chip out of low-power mode. */
 	outl(0x4200, ioaddr + GENCTL);
@@ -489,6 +504,9 @@
 	ep->pci_dev = pdev;
 	ep->chip_id = chip_idx;
 	ep->chip_flags = pci_id_tbl[chip_idx].drv_flags;
+	ep->irq_mask = 
+		(ep->chip_flags & TYPE2_INTR ?  PCIBusErr175 : PCIBusErr170)
+		 | CntFull | TxUnderrun | EpicNapiEvent;
 
 	/* Find the connected MII xcvrs.
 	   Doing this in open() would allow detecting external xcvrs later, but
@@ -543,10 +561,12 @@
 	dev->ethtool_ops = &netdev_ethtool_ops;
 	dev->watchdog_timeo = TX_TIMEOUT;
 	dev->tx_timeout = &epic_tx_timeout;
+	dev->poll = epic_poll;
+	dev->weight = 64;
 
-	i = register_netdev(dev);
-	if (i)
-		goto err_out_unmap_tx;
+	ret = register_netdev(dev);
+	if (ret < 0)
+		goto err_out_unmap_rx;
 
 	printk(KERN_INFO "%s: %s at %#lx, IRQ %d, ",
 		   dev->name, pci_id_tbl[chip_idx].name, ioaddr, dev->irq);
@@ -554,19 +574,24 @@
 		printk("%2.2x:", dev->dev_addr[i]);
 	printk("%2.2x.\n", dev->dev_addr[i]);
 
-	return 0;
+out:
+	return ret;
 
+err_out_unmap_rx:
+	pci_free_consistent(pdev, RX_TOTAL_SIZE, ep->rx_ring, ep->rx_ring_dma);
 err_out_unmap_tx:
 	pci_free_consistent(pdev, TX_TOTAL_SIZE, ep->tx_ring, ep->tx_ring_dma);
 err_out_iounmap:
 #ifndef USE_IO_OPS
 	iounmap(ioaddr);
-err_out_free_res:
-#endif
-	pci_release_regions(pdev);
 err_out_free_netdev:
+#endif
 	free_netdev(dev);
-	return -ENODEV;
+err_out_free_res:
+	pci_release_regions(pdev);
+err_out_disable:
+	pci_disable_device(pdev);
+	goto out;
 }
 
 /* Serial EEPROM section. */
@@ -592,6 +617,38 @@
 #define EE_READ256_CMD	(6 << 8)
 #define EE_ERASE_CMD	(7 << 6)
 
+static void epic_disable_int(struct net_device *dev, struct epic_private *ep)
+{
+	long ioaddr = dev->base_addr;
+
+	outl(0x00000000, ioaddr + INTMASK);
+}
+
+static inline void __epic_pci_commit(long ioaddr)
+{
+#ifndef USE_IO_OPS
+	inl(ioaddr + INTMASK);
+#endif
+}
+
+static inline void epic_napi_irq_off(struct net_device *dev,
+				     struct epic_private *ep)
+{
+	long ioaddr = dev->base_addr;
+
+	outl(ep->irq_mask & ~EpicNapiEvent, ioaddr + INTMASK);
+	__epic_pci_commit(ioaddr);
+}
+
+static inline void epic_napi_irq_on(struct net_device *dev,
+				    struct epic_private *ep)
+{
+	long ioaddr = dev->base_addr;
+
+	/* No need to commit possible posted write */
+	outl(ep->irq_mask | EpicNapiEvent, ioaddr + INTMASK);
+}
+
 static int __devinit read_eeprom(long ioaddr, int location)
 {
 	int i;
@@ -752,9 +809,8 @@
 
 	/* Enable interrupts by setting the interrupt mask. */
 	outl((ep->chip_flags & TYPE2_INTR ? PCIBusErr175 : PCIBusErr170)
-		 | CntFull | TxUnderrun | TxDone | TxEmpty
-		 | RxError | RxOverflow | RxFull | RxHeader | RxDone,
-		 ioaddr + INTMASK);
+		 | CntFull | TxUnderrun 
+		 | RxError | RxHeader | EpicNapiEvent, ioaddr + INTMASK);
 
 	if (debug > 1)
 		printk(KERN_DEBUG "%s: epic_open() ioaddr %lx IRQ %d status %4.4x "
@@ -795,7 +851,7 @@
 	}
 
 	/* Remove the packets on the Rx queue. */
-	epic_rx(dev);
+	epic_rx(dev, RX_RING_SIZE);
 }
 
 static void epic_restart(struct net_device *dev)
@@ -841,9 +897,9 @@
 
 	/* Enable interrupts by setting the interrupt mask. */
 	outl((ep->chip_flags & TYPE2_INTR ? PCIBusErr175 : PCIBusErr170)
-		 | CntFull | TxUnderrun | TxDone | TxEmpty
-		 | RxError | RxOverflow | RxFull | RxHeader | RxDone,
-		 ioaddr + INTMASK);
+		 | CntFull | TxUnderrun
+		 | RxError | RxHeader | EpicNapiEvent, ioaddr + INTMASK);
+
 	printk(KERN_DEBUG "%s: epic_restart() done, cmd status %4.4x, ctl %4.4x"
 		   " interrupt %4.4x.\n",
 		   dev->name, (int)inl(ioaddr + COMMAND), (int)inl(ioaddr + GENCTL),
@@ -929,7 +985,6 @@
 	int i;
 
 	ep->tx_full = 0;
-	ep->lock = (spinlock_t) SPIN_LOCK_UNLOCKED;
 	ep->dirty_tx = ep->cur_tx = 0;
 	ep->cur_rx = ep->dirty_rx = 0;
 	ep->rx_buf_sz = (dev->mtu <= 1500 ? PKT_BUF_SZ : dev->mtu + 32);
@@ -1029,6 +1084,76 @@
 	return 0;
 }
 
+static void epic_tx_error(struct net_device *dev, struct epic_private *ep,
+			  int status)
+{
+	struct net_device_stats *stats = &ep->stats;
+
+#ifndef final_version
+	/* There was an major error, log it. */
+	if (debug > 1)
+		printk(KERN_DEBUG "%s: Transmit error, Tx status %8.8x.\n",
+		       dev->name, status);
+#endif
+	stats->tx_errors++;
+	if (status & 0x1050)
+		stats->tx_aborted_errors++;
+	if (status & 0x0008)
+		stats->tx_carrier_errors++;
+	if (status & 0x0040)
+		stats->tx_window_errors++;
+	if (status & 0x0010)
+		stats->tx_fifo_errors++;
+}
+
+static void epic_tx(struct net_device *dev, struct epic_private *ep)
+{
+	unsigned int dirty_tx, cur_tx;
+
+	/*
+	 * Note: if this lock becomes a problem we can narrow the locked
+	 * region at the cost of occasionally grabbing the lock more times.
+	 */
+	cur_tx = ep->cur_tx;
+	for (dirty_tx = ep->dirty_tx; cur_tx - dirty_tx > 0; dirty_tx++) {
+		struct sk_buff *skb;
+		int entry = dirty_tx % TX_RING_SIZE;
+		int txstatus = le32_to_cpu(ep->tx_ring[entry].txstatus);
+
+		if (txstatus & DescOwn)
+			break;	/* It still hasn't been Txed */
+
+		if (likely(txstatus & 0x0001)) {
+			ep->stats.collisions += (txstatus >> 8) & 15;
+			ep->stats.tx_packets++;
+			ep->stats.tx_bytes += ep->tx_skbuff[entry]->len;
+		} else
+			epic_tx_error(dev, ep, txstatus);
+
+		/* Free the original skb. */
+		skb = ep->tx_skbuff[entry];
+		pci_unmap_single(ep->pci_dev, ep->tx_ring[entry].bufaddr, 
+				 skb->len, PCI_DMA_TODEVICE);
+		dev_kfree_skb_irq(skb);
+		ep->tx_skbuff[entry] = 0;
+	}
+
+#ifndef final_version
+	if (cur_tx - dirty_tx > TX_RING_SIZE) {
+		printk(KERN_WARNING
+		       "%s: Out-of-sync dirty pointer, %d vs. %d, full=%d.\n",
+		       dev->name, dirty_tx, cur_tx, ep->tx_full);
+		dirty_tx += TX_RING_SIZE;
+	}
+#endif
+	ep->dirty_tx = dirty_tx;
+	if (ep->tx_full && cur_tx - dirty_tx < TX_QUEUE_LEN - 4) {
+		/* The ring is no longer full, allow new TX entries. */
+		ep->tx_full = 0;
+		netif_wake_queue(dev);
+	}
+}
+
 /* The interrupt handler does all of the Rx thread work and cleans up
    after the Tx thread. */
 static irqreturn_t epic_interrupt(int irq, void *dev_instance, struct pt_regs *regs)
@@ -1036,135 +1161,71 @@
 	struct net_device *dev = dev_instance;
 	struct epic_private *ep = dev->priv;
 	long ioaddr = dev->base_addr;
-	int status, boguscnt = max_interrupt_work;
 	unsigned int handled = 0;
+	int status;
 
-	do {
-		status = inl(ioaddr + INTSTAT);
-		/* Acknowledge all of the current interrupt sources ASAP. */
-		outl(status & 0x00007fff, ioaddr + INTSTAT);
-
-		if (debug > 4)
-			printk(KERN_DEBUG "%s: Interrupt, status=%#8.8x new "
-				   "intstat=%#8.8x.\n",
-				   dev->name, status, (int)inl(ioaddr + INTSTAT));
-
-		if ((status & IntrSummary) == 0)
-			break;
-		handled = 1;
+	status = inl(ioaddr + INTSTAT);
+	/* Acknowledge all of the current interrupt sources ASAP. */
+	outl(status & EpicNormalEvent, ioaddr + INTSTAT);
 
-		if (status & (RxDone | RxStarted | RxEarlyWarn | RxOverflow))
-			epic_rx(dev);
+	if (debug > 4) {
+		printk(KERN_DEBUG "%s: Interrupt, status=%#8.8x new "
+				   "intstat=%#8.8x.\n", dev->name, status,
+				   (int)inl(ioaddr + INTSTAT));
+	}
 
-		if (status & (TxEmpty | TxDone)) {
-			unsigned int dirty_tx, cur_tx;
+	if ((status & IntrSummary) == 0)
+		goto out;
 
-			/* Note: if this lock becomes a problem we can narrow the locked
-			   region at the cost of occasionally grabbing the lock more
-			   times. */
-			spin_lock(&ep->lock);
-			cur_tx = ep->cur_tx;
-			dirty_tx = ep->dirty_tx;
-			for (; cur_tx - dirty_tx > 0; dirty_tx++) {
-				struct sk_buff *skb;
-				int entry = dirty_tx % TX_RING_SIZE;
-				int txstatus = le32_to_cpu(ep->tx_ring[entry].txstatus);
+	handled = 1;
 
-				if (txstatus & DescOwn)
-					break;			/* It still hasn't been Txed */
+	if ((status & EpicNapiEvent) && !ep->reschedule_in_poll) {
+		spin_lock(&ep->napi_lock);
+		if (netif_rx_schedule_prep(dev)) {
+			epic_napi_irq_off(dev, ep);
+			__netif_rx_schedule(dev);
+		} else
+			ep->reschedule_in_poll++;
+		spin_unlock(&ep->napi_lock);
+	}
+	status &= ~EpicNapiEvent;
 
-				if ( ! (txstatus & 0x0001)) {
-					/* There was an major error, log it. */
-#ifndef final_version
-					if (debug > 1)
-						printk(KERN_DEBUG "%s: Transmit error, Tx status %8.8x.\n",
-							   dev->name, txstatus);
-#endif
-					ep->stats.tx_errors++;
-					if (txstatus & 0x1050) ep->stats.tx_aborted_errors++;
-					if (txstatus & 0x0008) ep->stats.tx_carrier_errors++;
-					if (txstatus & 0x0040) ep->stats.tx_window_errors++;
-					if (txstatus & 0x0010) ep->stats.tx_fifo_errors++;
-				} else {
-					ep->stats.collisions += (txstatus >> 8) & 15;
-					ep->stats.tx_packets++;
-					ep->stats.tx_bytes += ep->tx_skbuff[entry]->len;
-				}
-
-				/* Free the original skb. */
-				skb = ep->tx_skbuff[entry];
-				pci_unmap_single(ep->pci_dev, ep->tx_ring[entry].bufaddr, 
-						 skb->len, PCI_DMA_TODEVICE);
-				dev_kfree_skb_irq(skb);
-				ep->tx_skbuff[entry] = 0;
-			}
+	/* Check uncommon events all at once. */
+	if (status & (CntFull | TxUnderrun | PCIBusErr170 | PCIBusErr175)) {
+		if (status == EpicRemoved)
+			goto out;
 
-#ifndef final_version
-			if (cur_tx - dirty_tx > TX_RING_SIZE) {
-				printk(KERN_WARNING "%s: Out-of-sync dirty pointer, %d vs. %d, full=%d.\n",
-					   dev->name, dirty_tx, cur_tx, ep->tx_full);
-				dirty_tx += TX_RING_SIZE;
-			}
-#endif
-			ep->dirty_tx = dirty_tx;
-			if (ep->tx_full
-				&& cur_tx - dirty_tx < TX_QUEUE_LEN - 4) {
-				/* The ring is no longer full, allow new TX entries. */
-				ep->tx_full = 0;
-				spin_unlock(&ep->lock);
-				netif_wake_queue(dev);
-			} else
-				spin_unlock(&ep->lock);
-		}
+		/* Always update the error counts to avoid overhead later. */
+		ep->stats.rx_missed_errors += inb(ioaddr + MPCNT);
+		ep->stats.rx_frame_errors += inb(ioaddr + ALICNT);
+		ep->stats.rx_crc_errors += inb(ioaddr + CRCCNT);
 
-		/* Check uncommon events all at once. */
-		if (status & (CntFull | TxUnderrun | RxOverflow | RxFull |
-					  PCIBusErr170 | PCIBusErr175)) {
-			if (status == 0xffffffff) /* Chip failed or removed (CardBus). */
-				break;
-			/* Always update the error counts to avoid overhead later. */
-			ep->stats.rx_missed_errors += inb(ioaddr + MPCNT);
-			ep->stats.rx_frame_errors += inb(ioaddr + ALICNT);
-			ep->stats.rx_crc_errors += inb(ioaddr + CRCCNT);
-
-			if (status & TxUnderrun) { /* Tx FIFO underflow. */
-				ep->stats.tx_fifo_errors++;
-				outl(ep->tx_threshold += 128, ioaddr + TxThresh);
-				/* Restart the transmit process. */
-				outl(RestartTx, ioaddr + COMMAND);
-			}
-			if (status & RxOverflow) {		/* Missed a Rx frame. */
-				ep->stats.rx_errors++;
-			}
-			if (status & (RxOverflow | RxFull))
-				outw(RxQueued, ioaddr + COMMAND);
-			if (status & PCIBusErr170) {
-				printk(KERN_ERR "%s: PCI Bus Error!  EPIC status %4.4x.\n",
-					   dev->name, status);
-				epic_pause(dev);
-				epic_restart(dev);
-			}
-			/* Clear all error sources. */
-			outl(status & 0x7f18, ioaddr + INTSTAT);
+		if (status & TxUnderrun) { /* Tx FIFO underflow. */
+			ep->stats.tx_fifo_errors++;
+			outl(ep->tx_threshold += 128, ioaddr + TxThresh);
+			/* Restart the transmit process. */
+			outl(RestartTx, ioaddr + COMMAND);
 		}
-		if (--boguscnt < 0) {
-			printk(KERN_ERR "%s: Too much work at interrupt, "
-				   "IntrStatus=0x%8.8x.\n",
-				   dev->name, status);
-			/* Clear all interrupt sources. */
-			outl(0x0001ffff, ioaddr + INTSTAT);
-			break;
+		if (status & PCIBusErr170) {
+			printk(KERN_ERR "%s: PCI Bus Error! status %4.4x.\n",
+					 dev->name, status);
+			epic_pause(dev);
+			epic_restart(dev);
 		}
-	} while (1);
+		/* Clear all error sources. */
+		outl(status & 0x7f18, ioaddr + INTSTAT);
+	}
 
-	if (debug > 3)
-		printk(KERN_DEBUG "%s: exiting interrupt, intr_status=%#4.4x.\n",
-			   dev->name, status);
+out:
+	if (debug > 3) {
+		printk(KERN_DEBUG "%s: exit interrupt, intr_status=%#4.4x.\n",
+				   dev->name, status);
+	}
 
 	return IRQ_RETVAL(handled);
 }
 
-static int epic_rx(struct net_device *dev)
+static int epic_rx(struct net_device *dev, int budget)
 {
 	struct epic_private *ep = dev->priv;
 	int entry = ep->cur_rx % RX_RING_SIZE;
@@ -1174,6 +1235,10 @@
 	if (debug > 4)
 		printk(KERN_DEBUG " In epic_rx(), entry %d %8.8x.\n", entry,
 			   ep->rx_ring[entry].rxstatus);
+
+	if (rx_work_limit > budget)
+		rx_work_limit = budget;
+
 	/* If we own the next entry, it's a new packet. Send it up. */
 	while ((ep->rx_ring[entry].rxstatus & cpu_to_le32(DescOwn)) == 0) {
 		int status = le32_to_cpu(ep->rx_ring[entry].rxstatus);
@@ -1215,13 +1280,8 @@
 							    ep->rx_ring[entry].bufaddr,
 							    ep->rx_buf_sz,
 							    PCI_DMA_FROMDEVICE);
-#if 1 /* HAS_IP_COPYSUM */
 				eth_copy_and_sum(skb, ep->rx_skbuff[entry]->tail, pkt_len, 0);
 				skb_put(skb, pkt_len);
-#else
-				memcpy(skb_put(skb, pkt_len), ep->rx_skbuff[entry]->tail,
-					   pkt_len);
-#endif
 				pci_dma_sync_single_for_device(ep->pci_dev,
 							       ep->rx_ring[entry].bufaddr,
 							       ep->rx_buf_sz,
@@ -1234,7 +1294,7 @@
 				ep->rx_skbuff[entry] = NULL;
 			}
 			skb->protocol = eth_type_trans(skb, dev);
-			netif_rx(skb);
+			netif_receive_skb(skb);
 			dev->last_rx = jiffies;
 			ep->stats.rx_packets++;
 			ep->stats.rx_bytes += pkt_len;
@@ -1262,6 +1322,65 @@
 	return work_done;
 }
 
+static void epic_rx_err(struct net_device *dev, struct epic_private *ep)
+{
+	long ioaddr = dev->base_addr;
+	int status;
+
+	status = inl(ioaddr + INTSTAT);
+
+	if (status == EpicRemoved)
+		return;
+	if (status & RxOverflow) 	/* Missed a Rx frame. */
+		ep->stats.rx_errors++;
+	if (status & (RxOverflow | RxFull))
+		outw(RxQueued, ioaddr + COMMAND);
+}
+
+static int epic_poll(struct net_device *dev, int *budget)
+{
+	struct epic_private *ep = dev->priv;
+	int work_done, orig_budget;
+	long ioaddr = dev->base_addr;
+
+	orig_budget = (*budget > dev->quota) ? dev->quota : *budget;
+
+rx_action:
+
+	epic_tx(dev, ep);
+
+	work_done = epic_rx(dev, *budget);
+
+	epic_rx_err(dev, ep);
+
+	*budget -= work_done;
+	dev->quota -= work_done;
+
+	if (netif_running(dev) && (work_done < orig_budget)) {
+		unsigned long flags;
+		int more;
+
+		/* A bit baroque but it avoids a (space hungry) spin_unlock */
+
+		spin_lock_irqsave(&ep->napi_lock, flags);
+
+		more = ep->reschedule_in_poll;
+		if (!more) {
+			__netif_rx_complete(dev);
+			outl(EpicNapiEvent, ioaddr + INTSTAT);
+			epic_napi_irq_on(dev, ep);
+		} else
+			ep->reschedule_in_poll--;
+
+		spin_unlock_irqrestore(&ep->napi_lock, flags);
+
+		if (more)
+			goto rx_action;
+	}
+
+	return (work_done >= orig_budget);
+}
+
 static int epic_close(struct net_device *dev)
 {
 	long ioaddr = dev->base_addr;
@@ -1276,9 +1395,13 @@
 			   dev->name, (int)inl(ioaddr + INTSTAT));
 
 	del_timer_sync(&ep->timer);
-	epic_pause(dev);
+
+	epic_disable_int(dev, ep);
+
 	free_irq(dev->irq, dev);
 
+	epic_pause(dev);
+
 	/* Free all the skbuffs in the Rx queue. */
 	for (i = 0; i < RX_RING_SIZE; i++) {
 		skb = ep->rx_skbuff[i];
@@ -1424,6 +1547,27 @@
 	debug = value;
 }
 
+static int ethtool_begin(struct net_device *dev)
+{
+	unsigned long ioaddr = dev->base_addr;
+	/* power-up, if interface is down */
+	if (! netif_running(dev)) {
+		outl(0x0200, ioaddr + GENCTL);
+		outl((inl(ioaddr + NVCTL) & ~0x003C) | 0x4800, ioaddr + NVCTL);
+	}
+	return 0;
+}
+
+static void ethtool_complete(struct net_device *dev)
+{
+	unsigned long ioaddr = dev->base_addr;
+	/* power-down, if interface is down */
+	if (! netif_running(dev)) {
+		outl(0x0008, ioaddr + GENCTL);
+		outl((inl(ioaddr + NVCTL) & ~0x483C) | 0x0000, ioaddr + NVCTL);
+	}
+}
+
 static struct ethtool_ops netdev_ethtool_ops = {
 	.get_drvinfo		= netdev_get_drvinfo,
 	.get_settings		= netdev_get_settings,
@@ -1434,6 +1578,8 @@
 	.set_msglevel		= netdev_set_msglevel,
 	.get_sg			= ethtool_op_get_sg,
 	.get_tx_csum		= ethtool_op_get_tx_csum,
+	.begin			= ethtool_begin,
+	.complete		= ethtool_complete
 };
 
 static int netdev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
@@ -1476,6 +1622,7 @@
 #endif
 	pci_release_regions(pdev);
 	free_netdev(dev);
+	pci_disable_device(pdev);
 	pci_set_drvdata(pdev, NULL);
 	/* pci_power_off(pdev, -1); */
 }
--- diff/drivers/net/es3210.c	2004-05-19 22:11:53.000000000 +0100
+++ source/drivers/net/es3210.c	2004-06-11 19:22:02.000000000 +0100
@@ -161,6 +161,7 @@
 	release_region(dev->base_addr, ES_IO_EXTENT);
 }
 
+#ifndef MODULE
 struct net_device * __init es_probe(int unit)
 {
 	struct net_device *dev = alloc_ei_netdev();
@@ -185,6 +186,7 @@
 	free_netdev(dev);
 	return ERR_PTR(err);
 }
+#endif
 
 static int __init es_probe1(struct net_device *dev, int ioaddr)
 {
--- diff/drivers/net/eth16i.c	2004-05-19 22:11:53.000000000 +0100
+++ source/drivers/net/eth16i.c	2004-06-11 19:22:02.000000000 +0100
@@ -458,6 +458,7 @@
 	return -ENODEV;
 }
 
+#ifndef MODULE
 struct net_device * __init eth16i_probe(int unit)
 {
 	struct net_device *dev = alloc_etherdev(sizeof(struct eth16i_local));
@@ -483,6 +484,7 @@
 	free_netdev(dev);
 	return ERR_PTR(err);
 }
+#endif
 
 static int __init eth16i_probe1(struct net_device *dev, int ioaddr)
 {
@@ -491,7 +493,7 @@
 	int retval;
 
 	/* Let's grab the region */
-	if (!request_region(ioaddr, ETH16I_IO_EXTENT, dev->name))
+	if (!request_region(ioaddr, ETH16I_IO_EXTENT, cardname))
 		return -EBUSY;
 
 	/*
@@ -538,9 +540,9 @@
 
 	/* Try to obtain interrupt vector */
 
-	if ((retval = request_irq(dev->irq, (void *)&eth16i_interrupt, 0, dev->name, dev))) {
-		printk(KERN_WARNING "%s: %s at %#3x, but is unusable due conflicting IRQ %d.\n", 
-		       dev->name, cardname, ioaddr, dev->irq);
+	if ((retval = request_irq(dev->irq, (void *)&eth16i_interrupt, 0, cardname, dev))) {
+		printk(KERN_WARNING "%s at %#3x, but is unusable due to conflicting IRQ %d.\n", 
+		       cardname, ioaddr, dev->irq);
 		goto out;
 	}
 
--- diff/drivers/net/ewrk3.c	2004-06-11 19:17:29.000000000 +0100
+++ source/drivers/net/ewrk3.c	2004-06-11 19:22:02.000000000 +0100
@@ -341,6 +341,7 @@
     mdelay(1);\
 }
 
+#ifndef MODULE
 struct net_device * __init ewrk3_probe(int unit)
 {
 	struct net_device *dev = alloc_etherdev(sizeof(struct ewrk3_private));
@@ -364,6 +365,7 @@
 	return ERR_PTR(err);
 	
 }
+#endif
 
 static int __init ewrk3_probe1(struct net_device *dev, u_long iobase, int irq)
 {
@@ -1269,7 +1271,7 @@
 	for (; (i < maxSlots) && (dev != NULL);
 	     iobase += EWRK3_IOP_INC, i++)
 	{
-		if (request_region(iobase, EWRK3_TOTAL_SIZE, dev->name)) {
+		if (request_region(iobase, EWRK3_TOTAL_SIZE, DRV_NAME)) {
 			if (DevicePresent(iobase) == 0) {
 				int irq = dev->irq;
 				ret = ewrk3_hw_init(dev, iobase);
@@ -1310,7 +1312,7 @@
 
 	for (i = 1; (i < maxSlots) && (dev != NULL); i++, iobase += EISA_SLOT_INC) {
 		if (EISA_signature(name, EISA_ID) == 0) {
-			if (request_region(iobase, EWRK3_TOTAL_SIZE, dev->name) &&
+			if (request_region(iobase, EWRK3_TOTAL_SIZE, DRV_NAME) &&
 			    DevicePresent(iobase) == 0) {
 				int irq = dev->irq;
 				ret = ewrk3_hw_init(dev, iobase);
--- diff/drivers/net/fealnx.c	2004-06-11 19:17:29.000000000 +0100
+++ source/drivers/net/fealnx.c	2004-06-11 19:22:02.000000000 +0100
@@ -858,12 +858,17 @@
 {
 	struct netdev_private *np = dev->priv;
 	long ioaddr = dev->base_addr;
+	int i;
 
 	writel(0x00000001, ioaddr + BCR);	/* Reset */
 
 	if (request_irq(dev->irq, &intr_handler, SA_SHIRQ, dev->name, dev))
 		return -EAGAIN;
 
+	for (i = 0; i < 3; i++)
+		writew(((unsigned short*)dev->dev_addr)[i],
+				ioaddr + PAR0 + i*2);
+
 	init_ring(dev);
 
 	writel(np->rx_ring_dma, ioaddr + RXLBA);
--- diff/drivers/net/fmv18x.c	2004-05-19 22:11:54.000000000 +0100
+++ source/drivers/net/fmv18x.c	2004-06-11 19:22:02.000000000 +0100
@@ -57,6 +57,8 @@
 #include <asm/io.h>
 #include <asm/dma.h>
 
+#define DRV_NAME "fmv18x"
+
 static unsigned fmv18x_probe_list[] __initdata = {
 	0x220, 0x240, 0x260, 0x280, 0x2a0, 0x2c0, 0x300, 0x340, 0
 };
@@ -192,7 +194,7 @@
 	   That means we have to be careful with the register values we probe for.
 	   */
 
-	if (!request_region(ioaddr, FMV18X_IO_EXTENT, dev->name))
+	if (!request_region(ioaddr, FMV18X_IO_EXTENT, DRV_NAME))
 		return -EBUSY;
 
 	dev->irq = irq;
@@ -224,7 +226,7 @@
 	}
 
 	/* Snarf the interrupt vector now. */
-	retval = request_irq(dev->irq, &net_interrupt, 0, dev->name, dev);
+	retval = request_irq(dev->irq, &net_interrupt, 0, DRV_NAME, dev);
 	if (retval) {
 		printk ("FMV-18x found at %#3x, but it's unusable due to a conflict on"
 				"IRQ %d.\n", ioaddr, dev->irq);
--- diff/drivers/net/forcedeth.c	2004-06-11 19:17:29.000000000 +0100
+++ source/drivers/net/forcedeth.c	2004-06-11 19:22:02.000000000 +0100
@@ -81,6 +81,7 @@
  * superfluous timer interrupts from the nic.
  */
 #define FORCEDETH_VERSION		"0.25"
+#define DRV_NAME			"forcedeth"
 
 #include <linux/module.h>
 #include <linux/types.h>
@@ -1424,7 +1425,7 @@
 
 	pci_set_master(pci_dev);
 
-	err = pci_request_regions(pci_dev, dev->name);
+	err = pci_request_regions(pci_dev, DRV_NAME);
 	if (err < 0)
 		goto out_disable;
 
--- diff/drivers/net/hp-plus.c	2004-05-19 22:11:54.000000000 +0100
+++ source/drivers/net/hp-plus.c	2004-06-11 19:22:02.000000000 +0100
@@ -37,6 +37,8 @@
 
 #include "8390.h"
 
+#define DRV_NAME "hp-plus"
+
 /* A zero-terminated list of I/O addresses to be probed. */
 static unsigned int hpplus_portlist[] __initdata =
 {0x200, 0x240, 0x280, 0x2C0, 0x300, 0x320, 0x340, 0};
@@ -142,6 +144,7 @@
 	release_region(dev->base_addr - NIC_OFFSET, HP_IO_EXTENT);
 }
 
+#ifndef MODULE
 struct net_device * __init hp_plus_probe(int unit)
 {
 	struct net_device *dev = alloc_ei_netdev();
@@ -166,6 +169,7 @@
 	free_netdev(dev);
 	return ERR_PTR(err);
 }
+#endif
 
 /* Do the interesting part of the probe at a single address. */
 static int __init hpp_probe1(struct net_device *dev, int ioaddr)
@@ -176,7 +180,7 @@
 	int mem_start;
 	static unsigned version_printed;
 
-	if (!request_region(ioaddr, HP_IO_EXTENT, dev->name))
+	if (!request_region(ioaddr, HP_IO_EXTENT, DRV_NAME))
 		return -EBUSY;
 
 	/* Check for the HP+ signature, 50 48 0x 53. */
--- diff/drivers/net/hp.c	2004-05-19 22:11:54.000000000 +0100
+++ source/drivers/net/hp.c	2004-06-11 19:22:02.000000000 +0100
@@ -37,6 +37,8 @@
 
 #include "8390.h"
 
+#define DRV_NAME "hp"
+
 /* A zero-terminated list of I/O addresses to be probed. */
 static unsigned int hppclan_portlist[] __initdata =
 { 0x300, 0x320, 0x340, 0x280, 0x2C0, 0x200, 0x240, 0};
@@ -106,6 +108,7 @@
 	release_region(dev->base_addr - NIC_OFFSET, HP_IO_EXTENT);
 }
 
+#ifndef MODULE
 struct net_device * __init hp_probe(int unit)
 {
 	struct net_device *dev = alloc_ei_netdev();
@@ -130,6 +133,7 @@
 	free_netdev(dev);
 	return ERR_PTR(err);
 }
+#endif
 
 static int __init hp_probe1(struct net_device *dev, int ioaddr)
 {
@@ -137,7 +141,7 @@
 	const char *name;
 	static unsigned version_printed;
 
-	if (!request_region(ioaddr, HP_IO_EXTENT, dev->name))
+	if (!request_region(ioaddr, HP_IO_EXTENT, DRV_NAME))
 		return -EBUSY;
 
 	/* Check for the HP physical address, 08 00 09 xx xx xx. */
@@ -182,7 +186,7 @@
 				outb_p(irqmap[irq] | HP_RUN, ioaddr + HP_CONFIGURE);
 				outb_p( 0x00 | HP_RUN, ioaddr + HP_CONFIGURE);
 				if (irq == probe_irq_off(cookie)		 /* It's a good IRQ line! */
-					&& request_irq (irq, ei_interrupt, 0, dev->name, dev) == 0) {
+					&& request_irq (irq, ei_interrupt, 0, DRV_NAME, dev) == 0) {
 					printk(" selecting IRQ %d.\n", irq);
 					dev->irq = *irqp;
 					break;
@@ -197,7 +201,7 @@
 	} else {
 		if (dev->irq == 2)
 			dev->irq = 9;
-		if ((retval = request_irq(dev->irq, ei_interrupt, 0, dev->name, dev))) {
+		if ((retval = request_irq(dev->irq, ei_interrupt, 0, DRV_NAME, dev))) {
 			printk (" unable to get IRQ %d.\n", dev->irq);
 			goto out;
 		}
--- diff/drivers/net/hp100.c	2004-05-19 22:11:54.000000000 +0100
+++ source/drivers/net/hp100.c	2004-06-11 19:22:02.000000000 +0100
@@ -386,6 +386,7 @@
 }
 
 
+#ifndef MODULE
 struct net_device * __init hp100_probe(int unit)
 {
 	struct net_device *dev = alloc_etherdev(sizeof(struct hp100_private));
@@ -420,6 +421,7 @@
 	free_netdev(dev);
 	return ERR_PTR(err);
 }
+#endif
 
 static int __init hp100_probe1(struct net_device *dev, int ioaddr,
 			       u_char bus, struct pci_dev *pci_dev)
--- diff/drivers/net/ibmlana.c	2004-06-11 19:17:29.000000000 +0100
+++ source/drivers/net/ibmlana.c	2004-06-11 19:22:02.000000000 +0100
@@ -98,6 +98,8 @@
 
 #undef DEBUG
 
+#define DRV_NAME "ibmlana"
+
 /* ------------------------------------------------------------------------
  * global static data - not more since we can handle multiple boards and
  * have to pack all state info into the device struct!
@@ -952,8 +954,8 @@
 	printk(KERN_INFO "%s: IBM LAN Adapter/A found in slot %d\n", dev->name, slot + 1);
 
 	/* try to obtain I/O range */
-	if (!request_region(iobase, IBM_LANA_IORANGE, dev->name)) {
-		printk(KERN_ERR "%s: cannot allocate I/O range at %#x!\n", dev->name, iobase);
+	if (!request_region(iobase, IBM_LANA_IORANGE, DRV_NAME)) {
+		printk(KERN_ERR "%s: cannot allocate I/O range at %#x!\n", DRV_NAME, iobase);
 		startslot = slot + 1;
 		return -EBUSY;
 	}
--- diff/drivers/net/ibmveth.c	2004-06-11 19:17:29.000000000 +0100
+++ source/drivers/net/ibmveth.c	2004-06-11 19:22:02.000000000 +0100
@@ -901,7 +901,7 @@
 
 	adapter = netdev->priv;
 	memset(adapter, 0, sizeof(adapter));
-	dev->driver_data = netdev;
+	dev->dev.driver_data = netdev;
 
 	adapter->vdev = dev;
 	adapter->netdev = netdev;
@@ -971,7 +971,7 @@
 
 static int __devexit ibmveth_remove(struct vio_dev *dev)
 {
-	struct net_device *netdev = dev->driver_data;
+	struct net_device *netdev = dev->dev.driver_data;
 	struct ibmveth_adapter *adapter = netdev->priv;
 
 	unregister_netdev(netdev);
--- diff/drivers/net/isa-skeleton.c	2004-05-19 22:11:54.000000000 +0100
+++ source/drivers/net/isa-skeleton.c	2004-06-11 19:22:02.000000000 +0100
@@ -161,6 +161,7 @@
 	release_region(dev->base_addr, NETCARD_IO_EXTENT);
 }
 
+#ifndef MODULE
 struct net_device * __init netcard_probe(int unit)
 {
 	struct net_device *dev = alloc_etherdev(sizeof(struct net_local));
@@ -185,6 +186,7 @@
 	free_netdev(dev);
 	return ERR_PTR(err);
 }
+#endif
 
 /*
  * This is the real probe routine. Linux has a history of friendly device
--- diff/drivers/net/jazzsonic.c	2004-05-19 22:11:55.000000000 +0100
+++ source/drivers/net/jazzsonic.c	2004-06-11 19:22:02.000000000 +0100
@@ -37,6 +37,8 @@
 #include <asm/jazz.h>
 #include <asm/jazzdma.h>
 
+#define DRV_NAME "jazzsonic"
+
 #define SREGS_PAD(n)    u16 n;
 
 #include "sonic.h"
@@ -151,7 +153,7 @@
 	int err = -ENODEV;
 	int i;
 
-	if (!request_region(base_addr, 0x100, dev->name))
+	if (!request_region(base_addr, 0x100, DRV_NAME))
 		return -EBUSY;
 	/*
 	 * get the Silicon Revision ID. If this is one of the known
--- diff/drivers/net/lance.c	2004-06-11 19:17:29.000000000 +0100
+++ source/drivers/net/lance.c	2004-06-11 19:22:02.000000000 +0100
@@ -432,6 +432,7 @@
 	return -ENODEV;
 }
 
+#ifndef MODULE
 struct net_device * __init lance_probe(int unit)
 {
 	struct net_device *dev = alloc_etherdev(0);
@@ -456,6 +457,7 @@
 	free_netdev(dev);
 	return ERR_PTR(err);
 }
+#endif
 
 static int __init lance_probe1(struct net_device *dev, int ioaddr, int irq, int options)
 {
--- diff/drivers/net/lasi_82596.c	2004-05-19 22:11:55.000000000 +0100
+++ source/drivers/net/lasi_82596.c	2004-06-11 19:22:02.000000000 +0100
@@ -87,7 +87,6 @@
 #include <asm/bitops.h>
 #include <asm/io.h>
 #include <asm/pgtable.h>
-#include <asm/pgalloc.h>
 #include <asm/irq.h>
 #include <asm/pdc.h>
 #include <asm/cache.h>
--- diff/drivers/net/lne390.c	2004-05-19 22:11:55.000000000 +0100
+++ source/drivers/net/lne390.c	2004-06-11 19:22:02.000000000 +0100
@@ -49,6 +49,8 @@
 
 #include "8390.h"
 
+#define DRV_NAME "lne390"
+
 static int lne390_probe1(struct net_device *dev, int ioaddr);
 
 static int lne390_open(struct net_device *dev);
@@ -112,7 +114,7 @@
 	SET_MODULE_OWNER(dev);
 
 	if (ioaddr > 0x1ff) {		/* Check a single specified location. */
-		if (!request_region(ioaddr, LNE390_IO_EXTENT, dev->name))
+		if (!request_region(ioaddr, LNE390_IO_EXTENT, DRV_NAME))
 			return -EBUSY;
 		ret = lne390_probe1(dev, ioaddr);
 		if (ret)
@@ -131,7 +133,7 @@
 
 	/* EISA spec allows for up to 16 slots, but 8 is typical. */
 	for (ioaddr = 0x1000; ioaddr < 0x9000; ioaddr += 0x1000) {
-		if (!request_region(ioaddr, LNE390_IO_EXTENT, dev->name))
+		if (!request_region(ioaddr, LNE390_IO_EXTENT, DRV_NAME))
 			continue;
 		if (lne390_probe1(dev, ioaddr) == 0)
 			return 0;
@@ -151,6 +153,7 @@
 		iounmap((void *)dev->mem_start);
 }
 
+#ifndef MODULE
 struct net_device * __init lne390_probe(int unit)
 {
 	struct net_device *dev = alloc_ei_netdev();
@@ -175,6 +178,7 @@
 	free_netdev(dev);
 	return ERR_PTR(err);
 }
+#endif
 
 static int __init lne390_probe1(struct net_device *dev, int ioaddr)
 {
@@ -228,7 +232,7 @@
 	}
 	printk(" IRQ %d,", dev->irq);
 
-	if ((ret = request_irq(dev->irq, ei_interrupt, 0, dev->name, dev))) {
+	if ((ret = request_irq(dev->irq, ei_interrupt, 0, DRV_NAME, dev))) {
 		printk (" unable to get IRQ %d.\n", dev->irq);
 		return ret;
 	}
--- diff/drivers/net/lp486e.c	2004-05-19 22:11:55.000000000 +0100
+++ source/drivers/net/lp486e.c	2004-06-11 19:22:02.000000000 +0100
@@ -75,6 +75,8 @@
 #include <asm/io.h>
 #include <asm/dma.h>
 
+#define DRV_NAME "lp486e"
+
 /* debug print flags */
 #define LOG_SRCDST    0x80000000
 #define LOG_STATINT   0x40000000
@@ -970,7 +972,7 @@
 		return -ENODEV;
 	probed++;
 
-	if (!request_region(IOADDR, LP486E_TOTAL_SIZE, dev->name)) {
+	if (!request_region(IOADDR, LP486E_TOTAL_SIZE, DRV_NAME)) {
 		printk(KERN_ERR "lp486e: IO address 0x%x in use\n", IOADDR);
 		return -EBUSY;
 	}
--- diff/drivers/net/macsonic.c	2004-05-19 22:11:55.000000000 +0100
+++ source/drivers/net/macsonic.c	2004-06-11 19:22:02.000000000 +0100
@@ -53,7 +53,6 @@
 #include <asm/macintosh.h>
 #include <asm/macints.h>
 #include <asm/mac_via.h>
-#include <asm/pgalloc.h>
 
 #define SREGS_PAD(n)    u16 n;
 
--- diff/drivers/net/natsemi.c	2004-06-11 19:17:29.000000000 +0100
+++ source/drivers/net/natsemi.c	2004-06-11 19:22:02.000000000 +0100
@@ -766,7 +766,7 @@
 	SET_MODULE_OWNER(dev);
 	SET_NETDEV_DEV(dev, &pdev->dev);
 
-	i = pci_request_regions(pdev, dev->name);
+	i = pci_request_regions(pdev, DRV_NAME);
 	if (i)
 		goto err_pci_request_regions;
 
@@ -1798,14 +1798,9 @@
 					np->rx_dma[entry],
 					buflen,
 					PCI_DMA_FROMDEVICE);
-#if HAS_IP_COPYSUM
 				eth_copy_and_sum(skb,
 					np->rx_skbuff[entry]->tail, pkt_len, 0);
 				skb_put(skb, pkt_len);
-#else
-				memcpy(skb_put(skb, pkt_len),
-					np->rx_skbuff[entry]->tail, pkt_len);
-#endif
 				pci_dma_sync_single_for_device(np->pci_dev,
 					np->rx_dma[entry],
 					buflen,
--- diff/drivers/net/ne-h8300.c	2004-06-11 19:17:29.000000000 +0100
+++ source/drivers/net/ne-h8300.c	2004-06-11 19:22:02.000000000 +0100
@@ -34,6 +34,8 @@
 
 #include "8390.h"
 
+#define DRV_NAME "ne-h8300"
+
 /* Some defines that people can play with if so inclined. */
 
 /* Do we perform extra sanity checks on stuff ? */
@@ -156,6 +158,7 @@
 	release_region(dev->base_addr, NE_IO_EXTENT);
 }
 
+#ifndef MODULE
 struct net_device * __init ne_probe(int unit)
 {
 	struct net_device *dev = alloc_ei_netdev();
@@ -187,6 +190,7 @@
 	free_netdev(dev);
 	return ERR_PTR(err);
 }
+#endif
 
 static int __init ne_probe1(struct net_device *dev, int ioaddr)
 {
@@ -200,7 +204,7 @@
 	struct ei_device *ei_local = (struct ei_device *) netdev_priv(dev);
 	unsigned char bus_width;
 
-	if (!request_region(ioaddr, NE_IO_EXTENT, dev->name))
+	if (!request_region(ioaddr, NE_IO_EXTENT, DRV_NAME))
 		return -EBUSY;
 
 	reg0 = inb_p(ioaddr);
--- diff/drivers/net/ne.c	2004-05-19 22:11:55.000000000 +0100
+++ source/drivers/net/ne.c	2004-06-11 19:22:02.000000000 +0100
@@ -55,6 +55,8 @@
 
 #include "8390.h"
 
+#define DRV_NAME "ne"
+
 /* Some defines that people can play with if so inclined. */
 
 /* Do we support clones that don't adhere to 14,15 of the SAprom ? */
@@ -203,6 +205,7 @@
 	release_region(dev->base_addr, NE_IO_EXTENT);
 }
 
+#ifndef MODULE
 struct net_device * __init ne_probe(int unit)
 {
 	struct net_device *dev = alloc_ei_netdev();
@@ -227,6 +230,7 @@
 	free_netdev(dev);
 	return ERR_PTR(err);
 }
+#endif
 
 static int __init ne_probe_isapnp(struct net_device *dev)
 {
@@ -284,7 +288,7 @@
 	int reg0, ret;
 	static unsigned version_printed;
 
-	if (!request_region(ioaddr, NE_IO_EXTENT, dev->name))
+	if (!request_region(ioaddr, NE_IO_EXTENT, DRV_NAME))
 		return -EBUSY;
 
 	reg0 = inb_p(ioaddr);
--- diff/drivers/net/ne2.c	2004-05-19 22:11:55.000000000 +0100
+++ source/drivers/net/ne2.c	2004-06-11 19:22:02.000000000 +0100
@@ -82,6 +82,8 @@
 
 #include "8390.h"
 
+#define DRV_NAME "ne2"
+
 /* Some defines that people can play with if so inclined. */
 
 /* Do we perform extra sanity checks on stuff ? */
@@ -284,6 +286,7 @@
 	release_region(dev->base_addr, NE_IO_EXTENT);
 }
 
+#ifndef MODULE
 struct net_device * __init ne2_probe(int unit)
 {
 	struct net_device *dev = alloc_ei_netdev();
@@ -308,6 +311,7 @@
 	free_netdev(dev);
 	return ERR_PTR(err);
 }
+#endif
 
 static int ne2_procinfo(char *buf, int slot, struct net_device *dev)
 {
@@ -368,7 +372,7 @@
 		irq = irqs[(POS & 0x60)>>5];
 	}
 
-	if (!request_region(base_addr, NE_IO_EXTENT, dev->name))
+	if (!request_region(base_addr, NE_IO_EXTENT, DRV_NAME))
 		return -EBUSY;
 
 #ifdef DEBUG
@@ -470,7 +474,7 @@
 
 	/* Snarf the interrupt now.  There's no point in waiting since we cannot
 	   share and the board will usually be enabled. */
-	retval = request_irq(dev->irq, ei_interrupt, 0, dev->name, dev);
+	retval = request_irq(dev->irq, ei_interrupt, 0, DRV_NAME, dev);
 	if (retval) {
 		printk (" unable to get IRQ %d (irqval=%d).\n", 
 				dev->irq, retval);
--- diff/drivers/net/ne2k_cbus.c	2004-05-19 22:11:55.000000000 +0100
+++ source/drivers/net/ne2k_cbus.c	2004-06-11 19:22:02.000000000 +0100
@@ -37,6 +37,8 @@
 
 #include "8390.h"
 
+#define DRV_NAME "ne2k_cbus"
+
 /* Some defines that people can play with if so inclined. */
 
 /* Do we support clones that don't adhere to 14,15 of the SAprom ? */
@@ -187,6 +189,7 @@
 	ne2k_cbus_destroy(dev);
 }
 
+#ifndef MODULE
 struct net_device * __init ne_probe(int unit)
 {
 	struct net_device *dev = alloc_ei_netdev();
@@ -211,6 +214,7 @@
 	free_netdev(dev);
 	return ERR_PTR(err);
 }
+#endif
 
 static int __init ne_probe_cbus(struct net_device *dev, const struct ne2k_cbus_hwinfo *hw, int ioaddr, int irq)
 {
@@ -263,7 +267,7 @@
 
 	for (rlist = hw->regionlist; rlist->range; rlist++)
 		if (!request_region(ioaddr + rlist->start,
-					rlist->range, dev->name)) {
+					rlist->range, DRV_NAME)) {
 			ret = -EBUSY;
 			goto err_out;
 		}
--- diff/drivers/net/ne3210.c	2004-05-19 22:11:55.000000000 +0100
+++ source/drivers/net/ne3210.c	2004-06-11 19:22:02.000000000 +0100
@@ -45,6 +45,8 @@
 
 #include "8390.h"
 
+#define DRV_NAME "ne3210"
+
 static int ne3210_open(struct net_device *dev);
 static int ne3210_close(struct net_device *dev);
 
@@ -111,13 +113,13 @@
 	device->driver_data = dev;
 	ioaddr = edev->base_addr;
 
-	if (!request_region(ioaddr, NE3210_IO_EXTENT, dev->name)) {
+	if (!request_region(ioaddr, NE3210_IO_EXTENT, DRV_NAME)) {
 		retval = -EBUSY;
 		goto out;
 	}
 
 	if (!request_region(ioaddr + NE3210_CFG1,
-			    NE3210_CFG_EXTENT, dev->name)) {
+			    NE3210_CFG_EXTENT, DRV_NAME)) {
 		retval = -EBUSY;
 		goto out1;
 	}
@@ -140,7 +142,7 @@
 	dev->irq = irq_map[(inb(ioaddr + NE3210_CFG2) >> 3) & 0x07];
 	printk(".\nne3210.c: using IRQ %d, ", dev->irq);
 
-	retval = request_irq(dev->irq, ei_interrupt, 0, dev->name, dev);
+	retval = request_irq(dev->irq, ei_interrupt, 0, DRV_NAME, dev);
 	if (retval) {
 		printk (" unable to get IRQ %d.\n", dev->irq);
 		goto out2;
@@ -163,7 +165,7 @@
 		}
 	}
 	
-	if (!request_mem_region (phys_mem, NE3210_STOP_PG*0x100, dev->name)) {
+	if (!request_mem_region (phys_mem, NE3210_STOP_PG*0x100, DRV_NAME)) {
 		printk ("ne3210.c: Unable to request shared memory at physical address %#lx\n",
 			phys_mem);
 		goto out3;
--- diff/drivers/net/ni52.c	2004-05-19 22:11:55.000000000 +0100
+++ source/drivers/net/ni52.c	2004-06-11 19:22:02.000000000 +0100
@@ -124,6 +124,8 @@
 
 #include "ni52.h"
 
+#define DRV_NAME "ni52"
+
 #define DEBUG       /* debug on */
 #define SYSBUSVAL 1 /* 8 Bit */
 
@@ -424,7 +426,7 @@
 	dev->mem_start = memstart;
 	dev->mem_end = memend;
 
-	if (!request_region(ioaddr, NI52_TOTAL_SIZE, dev->name))
+	if (!request_region(ioaddr, NI52_TOTAL_SIZE, DRV_NAME))
 		return -EBUSY;
 
 	if( !(inb(ioaddr+NI52_MAGIC1) == NI52_MAGICVAL1) ||
--- diff/drivers/net/ns83820.c	2004-06-11 19:17:30.000000000 +0100
+++ source/drivers/net/ns83820.c	2004-06-11 19:22:02.000000000 +0100
@@ -113,6 +113,8 @@
 #include <asm/uaccess.h>
 #include <asm/system.h>
 
+#define DRV_NAME "ns83820"
+
 /* Global parameters.  See MODULE_PARM near the bottom. */
 static int ihr = 2;
 static int reset_phy = 0;
@@ -1851,7 +1853,7 @@
 		0);
 
 	err = request_irq(pci_dev->irq, ns83820_irq, SA_SHIRQ,
-			  ndev->name, ndev);
+			  DRV_NAME, ndev);
 	if (err) {
 		printk(KERN_INFO "ns83820: unable to register irq %d\n",
 			pci_dev->irq);
--- diff/drivers/net/oaknet.c	2004-05-19 22:11:55.000000000 +0100
+++ source/drivers/net/oaknet.c	2004-06-11 19:22:02.000000000 +0100
@@ -164,7 +164,7 @@
 	ret = -EAGAIN;
 	if (request_irq(dev->irq, ei_interrupt, 0, name, dev)) {
 		printk("%s: unable to request interrupt %d.\n",
-		       dev->name, dev->irq);
+		       name, dev->irq);
 		goto out_region;
 	}
 
--- diff/drivers/net/r8169.c	2004-06-11 19:17:30.000000000 +0100
+++ source/drivers/net/r8169.c	2004-06-11 19:22:03.000000000 +0100
@@ -7,7 +7,7 @@
  Feb  4 2002	- created initially by ShuChen <shuchen@realtek.com.tw>.
  May 20 2002	- Add link status force-mode and TBI mode support.
 =========================================================================
-  1. The media can be forced in 5 modes.
+  1. [DEPRECATED: use ethtool instead] The media can be forced in 5 modes.
 	 Command: 'insmod r8169 media = SET_MEDIA'
 	 Ex:	  'insmod r8169 media = 0x04' will force PHY to operate in 100Mpbs Half-duplex.
 	
@@ -41,6 +41,7 @@
 #include <linux/etherdevice.h>
 #include <linux/delay.h>
 #include <linux/ethtool.h>
+#include <linux/mii.h>
 #include <linux/crc32.h>
 #include <linux/init.h>
 #include <linux/dma-mapping.h>
@@ -64,6 +65,14 @@
 #define dprintk(fmt, args...)	do {} while (0)
 #endif /* RTL8169_DEBUG */
 
+#ifdef CONFIG_R8169_NAPI
+#define rtl8169_rx_skb			netif_receive_skb
+#define rtl8169_rx_quota(count, quota)	min(count, quota)
+#else
+#define rtl8169_rx_skb			netif_rx
+#define rtl8169_rx_quota(count, quota)	count
+#endif
+
 /* media options */
 #define MAX_UNITS 8
 static int media[MAX_UNITS] = { -1, -1, -1, -1, -1, -1, -1, -1 };
@@ -90,15 +99,16 @@
 #define RxPacketMaxSize	0x0800	/* Maximum size supported is 16K-1 */
 #define InterFrameGap	0x03	/* 3 means InterFrameGap = the shortest one */
 
+#define R8169_NAPI_WEIGHT	64
 #define NUM_TX_DESC	64	/* Number of Tx descriptor registers */
-#define NUM_RX_DESC	64	/* Number of Rx descriptor registers */
+#define NUM_RX_DESC	256	/* Number of Rx descriptor registers */
 #define RX_BUF_SIZE	1536	/* Rx Buffer size */
 #define R8169_TX_RING_BYTES	(NUM_TX_DESC * sizeof(struct TxDesc))
 #define R8169_RX_RING_BYTES	(NUM_RX_DESC * sizeof(struct RxDesc))
 
 #define RTL_MIN_IO_SIZE 0x80
 #define RTL8169_TX_TIMEOUT	(6*HZ)
-#define RTL8169_PHY_TIMEOUT	(HZ) 
+#define RTL8169_PHY_TIMEOUT	(10*HZ)
 
 /* write/read MMIO register */
 #define RTL_W8(reg, val8)	writeb ((val8), ioaddr + (reg))
@@ -194,7 +204,7 @@
 	SWInt = 0x0100,
 	TxDescUnavail = 0x80,
 	RxFIFOOver = 0x40,
-	RxUnderrun = 0x20,
+	LinkChg = 0x20,
 	RxOverflow = 0x10,
 	TxErr = 0x08,
 	TxOK = 0x04,
@@ -233,6 +243,14 @@
 	TxInterFrameGapShift = 24,
 	TxDMAShift = 8,	/* DMA burst value (0-7) is shift this many bits */
 
+	/* TBICSR p.28 */
+	TBIReset	= 0x80000000,
+	TBILoopback	= 0x40000000,
+	TBINwEnable	= 0x20000000,
+	TBINwRestart	= 0x10000000,
+	TBILinkOk	= 0x02000000,
+	TBINwComplete	= 0x01000000,
+
 	/* CPlusCmd p.31 */
 	RxVlan		= (1 << 6),
 	RxChkSum	= (1 << 5),
@@ -306,10 +324,10 @@
 };
 
 struct rtl8169_private {
-	void *mmio_addr;	/* memory map physical address */
+	void *mmio_addr;		/* memory map physical address */
 	struct pci_dev *pci_dev;	/* Index of PCI device  */
 	struct net_device_stats stats;	/* statistics of net device */
-	spinlock_t lock;	/* spin lock flag */
+	spinlock_t lock;		/* spin lock flag */
 	int chipset;
 	int mac_version;
 	int phy_version;
@@ -317,15 +335,23 @@
 	u32 cur_tx; /* Index into the Tx descriptor buffer of next Rx pkt. */
 	u32 dirty_rx;
 	u32 dirty_tx;
-	struct TxDesc *TxDescArray;	/* Index of 256-alignment Tx Descriptor buffer */
-	struct RxDesc *RxDescArray;	/* Index of 256-alignment Rx Descriptor buffer */
+	struct TxDesc *TxDescArray;	/* 256-aligned Tx descriptor ring */
+	struct RxDesc *RxDescArray;	/* 256-aligned Rx descriptor ring */
 	dma_addr_t TxPhyAddr;
 	dma_addr_t RxPhyAddr;
 	struct sk_buff *Rx_skbuff[NUM_RX_DESC];	/* Rx data buffers */
-	struct sk_buff *Tx_skbuff[NUM_TX_DESC];	/* Index of Transmit data buffer */
+	struct sk_buff *Tx_skbuff[NUM_TX_DESC];	/* Tx data buffers */
 	struct timer_list timer;
-	unsigned long phy_link_down_cnt;
 	u16 cp_cmd;
+	u16 intr_mask;
+	int phy_auto_nego_reg;
+	int phy_1000_ctrl_reg;
+
+	int (*set_speed)(struct net_device *, u8 autoneg, u16 speed, u8 duplex);
+	void (*get_settings)(struct net_device *, struct ethtool_cmd *);
+	void (*phy_reset_enable)(void *);
+	unsigned int (*phy_reset_pending)(void *);
+	unsigned int (*link_ok)(void *);
 };
 
 MODULE_AUTHOR("Realtek");
@@ -344,9 +370,14 @@
 static void rtl8169_set_rx_mode(struct net_device *dev);
 static void rtl8169_tx_timeout(struct net_device *dev);
 static struct net_device_stats *rtl8169_get_stats(struct net_device *netdev);
+#ifdef CONFIG_R8169_NAPI
+static int rtl8169_poll(struct net_device *dev, int *budget);
+#endif
 
 static const u16 rtl8169_intr_mask =
-    RxUnderrun | RxOverflow | RxFIFOOver | TxErr | TxOK | RxErr | RxOK;
+	LinkChg | RxOverflow | RxFIFOOver | TxErr | TxOK | RxErr | RxOK;
+static const u16 rtl8169_napi_event =
+	RxOK | RxOverflow | RxFIFOOver | TxOK | TxErr;
 static const unsigned int rtl8169_rx_config =
     (RX_FIFO_THRESH << RxCfgFIFOShift) | (RX_DMA_BURST << RxCfgDMAShift);
 
@@ -364,11 +395,9 @@
 
 	for (i = 2000; i > 0; i--) {
 		// Check if the RTL8169 has completed writing to the specified MII register
-		if (!(RTL_R32(PHYAR) & 0x80000000)) {
+		if (!(RTL_R32(PHYAR) & 0x80000000)) 
 			break;
-		} else {
-			udelay(100);
-		}
+		udelay(100);
 	}
 }
 
@@ -390,18 +419,264 @@
 	return value;
 }
 
+static unsigned int rtl8169_tbi_reset_pending(void *ioaddr)
+{
+	return RTL_R32(TBICSR) & TBIReset;
+}
+
+static unsigned int rtl8169_xmii_reset_pending(void *ioaddr)
+{
+	return mdio_read(ioaddr, 0) & 0x8000;
+}
+
+static unsigned int rtl8169_tbi_link_ok(void *ioaddr)
+{
+	return RTL_R32(TBICSR) & TBILinkOk;
+}
+
+static unsigned int rtl8169_xmii_link_ok(void *ioaddr)
+{
+	return RTL_R8(PHYstatus) & LinkStatus;
+}
+
+static void rtl8169_tbi_reset_enable(void *ioaddr)
+{
+	RTL_W32(TBICSR, RTL_R32(TBICSR) | TBIReset);
+}
+
+static void rtl8169_xmii_reset_enable(void *ioaddr)
+{
+	unsigned int val;
+
+	val = (mdio_read(ioaddr, PHY_CTRL_REG) | 0x8000) & 0xffff;
+	mdio_write(ioaddr, PHY_CTRL_REG, val);
+}
+
+static void rtl8169_check_link_status(struct net_device *dev,
+				      struct rtl8169_private *tp, void *ioaddr)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&tp->lock, flags);
+	if (tp->link_ok(ioaddr)) {
+		netif_carrier_on(dev);
+		printk(KERN_INFO PFX "%s: link up\n", dev->name);
+	} else
+		netif_carrier_off(dev);
+	spin_unlock_irqrestore(&tp->lock, flags);
+}
+
+static void rtl8169_link_option(int idx, u8 *autoneg, u16 *speed, u8 *duplex)
+{
+	struct {
+		u16 speed;
+		u8 duplex;
+		u8 autoneg;
+		u8 media;
+	} link_settings[] = {
+		{ SPEED_10,	DUPLEX_HALF, AUTONEG_DISABLE,	_10_Half },
+		{ SPEED_10,	DUPLEX_FULL, AUTONEG_DISABLE,	_10_Full },
+		{ SPEED_100,	DUPLEX_HALF, AUTONEG_DISABLE,	_100_Half },
+		{ SPEED_100,	DUPLEX_FULL, AUTONEG_DISABLE,	_100_Full },
+		{ SPEED_1000,	DUPLEX_FULL, AUTONEG_DISABLE,	_1000_Full },
+		/* Make TBI happy */
+		{ SPEED_1000,	DUPLEX_FULL, AUTONEG_ENABLE,	0xff }
+	}, *p;
+	unsigned char option;
+	
+	option = ((idx < MAX_UNITS) && (idx >= 0)) ? media[idx] : 0xff;
+
+	if ((option != 0xff) && !idx)
+		printk(KERN_WARNING PFX "media option is deprecated.\n");
+
+	for (p = link_settings; p->media != 0xff; p++) {
+		if (p->media == option)
+			break;
+	}
+	*autoneg = p->autoneg;
+	*speed = p->speed;
+	*duplex = p->duplex;
+}
+
 static void rtl8169_get_drvinfo(struct net_device *dev,
 				struct ethtool_drvinfo *info)
 {
-	struct rtl8169_private *tp = dev->priv;
+	struct rtl8169_private *tp = netdev_priv(dev);
 
 	strcpy(info->driver, RTL8169_DRIVER_NAME);
 	strcpy(info->version, RTL8169_VERSION );
 	strcpy(info->bus_info, pci_name(tp->pci_dev));
 }
 
+static int rtl8169_set_speed_tbi(struct net_device *dev,
+				 u8 autoneg, u16 speed, u8 duplex)
+{
+	struct rtl8169_private *tp = netdev_priv(dev);
+	void *ioaddr = tp->mmio_addr;
+	int ret = 0;
+	u32 reg;
+
+	reg = RTL_R32(TBICSR);
+	if ((autoneg == AUTONEG_DISABLE) && (speed == SPEED_1000) &&
+	    (duplex == DUPLEX_FULL)) {
+		RTL_W32(TBICSR, reg & ~(TBINwEnable | TBINwRestart));
+	} else if (autoneg == AUTONEG_ENABLE)
+		RTL_W32(TBICSR, reg | TBINwEnable | TBINwRestart);
+	else {
+		printk(KERN_WARNING PFX
+		       "%s: incorrect speed setting refused in TBI mode\n",
+		       dev->name);
+		ret = -EOPNOTSUPP;
+	}
+
+	return ret;
+}
+
+static int rtl8169_set_speed_xmii(struct net_device *dev,
+				  u8 autoneg, u16 speed, u8 duplex)
+{
+	struct rtl8169_private *tp = netdev_priv(dev);
+	void *ioaddr = tp->mmio_addr;
+	int auto_nego, giga_ctrl;
+
+	auto_nego = mdio_read(ioaddr, PHY_AUTO_NEGO_REG);
+	auto_nego &= ~(PHY_Cap_10_Half | PHY_Cap_10_Full |
+		       PHY_Cap_100_Half | PHY_Cap_100_Full);
+	giga_ctrl = mdio_read(ioaddr, PHY_1000_CTRL_REG);
+	giga_ctrl &= ~(PHY_Cap_1000_Full | PHY_Cap_Null);
+
+	if (autoneg == AUTONEG_ENABLE) {
+		auto_nego |= (PHY_Cap_10_Half | PHY_Cap_10_Full |
+			      PHY_Cap_100_Half | PHY_Cap_100_Full);
+		giga_ctrl |= PHY_Cap_1000_Full;
+	} else {
+		if (speed == SPEED_10)
+			auto_nego |= PHY_Cap_10_Half | PHY_Cap_10_Full;
+		else if (speed == SPEED_100)
+			auto_nego |= PHY_Cap_100_Half | PHY_Cap_100_Full;
+		else if (speed == SPEED_1000)
+			giga_ctrl |= PHY_Cap_1000_Full;
+
+		if (duplex == DUPLEX_HALF)
+			auto_nego &= ~(PHY_Cap_10_Full | PHY_Cap_100_Full);
+	}
+
+	tp->phy_auto_nego_reg = auto_nego;
+	tp->phy_1000_ctrl_reg = giga_ctrl;
+
+	mdio_write(ioaddr, PHY_AUTO_NEGO_REG, auto_nego);
+	mdio_write(ioaddr, PHY_1000_CTRL_REG, giga_ctrl);
+	mdio_write(ioaddr, PHY_CTRL_REG, PHY_Enable_Auto_Nego |
+					 PHY_Restart_Auto_Nego);
+	return 0;
+}
+
+static int rtl8169_set_speed(struct net_device *dev,
+			     u8 autoneg, u16 speed, u8 duplex)
+{
+	struct rtl8169_private *tp = netdev_priv(dev);
+	int ret;
+
+	ret = tp->set_speed(dev, autoneg, speed, duplex);
+
+	if (netif_running(dev) && (tp->phy_1000_ctrl_reg & PHY_Cap_1000_Full))
+		mod_timer(&tp->timer, jiffies + RTL8169_PHY_TIMEOUT);
+
+	return ret;
+}
+
+static int rtl8169_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
+{
+	struct rtl8169_private *tp = netdev_priv(dev);
+	unsigned long flags;
+	int ret;
+
+	spin_lock_irqsave(&tp->lock, flags);
+	ret = rtl8169_set_speed(dev, cmd->autoneg, cmd->speed, cmd->duplex);
+	spin_unlock_irqrestore(&tp->lock, flags);
+	
+	return ret;
+}
+
+static void rtl8169_gset_tbi(struct net_device *dev, struct ethtool_cmd *cmd)
+{
+	struct rtl8169_private *tp = netdev_priv(dev);
+	void *ioaddr = tp->mmio_addr;
+	u32 status;
+
+	cmd->supported =
+		SUPPORTED_1000baseT_Full | SUPPORTED_Autoneg | SUPPORTED_FIBRE;
+	cmd->port = PORT_FIBRE;
+	cmd->transceiver = XCVR_INTERNAL;
+
+	status = RTL_R32(TBICSR);
+	cmd->advertising = (status & TBINwEnable) ?  ADVERTISED_Autoneg : 0;
+	cmd->autoneg = !!(status & TBINwEnable);
+
+	cmd->speed = SPEED_1000;
+	cmd->duplex = DUPLEX_FULL; /* Always set */
+}
+
+static void rtl8169_gset_xmii(struct net_device *dev, struct ethtool_cmd *cmd)
+{
+	struct rtl8169_private *tp = netdev_priv(dev);
+	void *ioaddr = tp->mmio_addr;
+	u8 status;
+
+	cmd->supported = SUPPORTED_10baseT_Half |
+			 SUPPORTED_10baseT_Full |
+			 SUPPORTED_100baseT_Half |
+			 SUPPORTED_100baseT_Full |
+			 SUPPORTED_1000baseT_Full |
+			 SUPPORTED_Autoneg |
+		         SUPPORTED_TP;
+
+	cmd->autoneg = 1;
+	cmd->advertising = ADVERTISED_TP | ADVERTISED_Autoneg;
+
+	if (tp->phy_auto_nego_reg & PHY_Cap_10_Half)
+		cmd->advertising |= ADVERTISED_10baseT_Half;
+	if (tp->phy_auto_nego_reg & PHY_Cap_10_Full)
+		cmd->advertising |= ADVERTISED_10baseT_Full;
+	if (tp->phy_auto_nego_reg & PHY_Cap_100_Half)
+		cmd->advertising |= ADVERTISED_100baseT_Half;
+	if (tp->phy_auto_nego_reg & PHY_Cap_100_Full)
+		cmd->advertising |= ADVERTISED_100baseT_Full;
+	if (tp->phy_1000_ctrl_reg & PHY_Cap_1000_Full)
+		cmd->advertising |= ADVERTISED_1000baseT_Full;
+
+	status = RTL_R8(PHYstatus);
+
+	if (status & _1000bpsF)
+		cmd->speed = SPEED_1000;
+	else if (status & _100bps)
+		cmd->speed = SPEED_100;
+	else if (status & _10bps)
+		cmd->speed = SPEED_10;
+
+	cmd->duplex = ((status & _1000bpsF) || (status & FullDup)) ?
+		      DUPLEX_FULL : DUPLEX_HALF;
+}
+
+static int rtl8169_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
+{
+	struct rtl8169_private *tp = netdev_priv(dev);
+	unsigned long flags;
+
+	spin_lock_irqsave(&tp->lock, flags);
+
+	tp->get_settings(dev, cmd);
+
+	spin_unlock_irqrestore(&tp->lock, flags);
+	return 0;
+}
+
+
 static struct ethtool_ops rtl8169_ethtool_ops = {
 	.get_drvinfo		= rtl8169_get_drvinfo,
+	.get_link		= ethtool_op_get_link,
+	.get_settings		= rtl8169_get_settings,
+	.set_settings		= rtl8169_set_settings,
 };
 
 static void rtl8169_write_gmii_reg_bit(void *ioaddr, int reg, int bitnum,
@@ -500,7 +775,7 @@
 
 static void rtl8169_hw_phy_config(struct net_device *dev)
 {
-	struct rtl8169_private *tp = dev->priv;
+	struct rtl8169_private *tp = netdev_priv(dev);
 	void *ioaddr = tp->mmio_addr;
 	struct {
 		u16 regs[5]; /* Beware of bit-sign propagation */
@@ -566,61 +841,47 @@
 	mdio_write(ioaddr, 31, 0x0000); //w 31 2 0 0
 }
 
-static void rtl8169_hw_phy_reset(struct net_device *dev)
-{
-	struct rtl8169_private *tp = dev->priv;
-	void *ioaddr = tp->mmio_addr;
-	int i, val;
-
-	printk(KERN_WARNING PFX "%s: Reset RTL8169s PHY\n", dev->name);
-
-	val = (mdio_read(ioaddr, 0) | 0x8000) & 0xffff;
-	mdio_write(ioaddr, 0, val);
-
-	for (i = 50; i >= 0; i--) {
-		if (!(mdio_read(ioaddr, 0) & 0x8000))
-			break;
-		udelay(100); /* Gross */
-	}
-
-	if (i < 0) {
-		printk(KERN_WARNING PFX "%s: no PHY Reset ack. Giving up.\n",
-		       dev->name);
-	}
-}
-
 static void rtl8169_phy_timer(unsigned long __opaque)
 {
 	struct net_device *dev = (struct net_device *)__opaque;
-	struct rtl8169_private *tp = dev->priv;
+	struct rtl8169_private *tp = netdev_priv(dev);
 	struct timer_list *timer = &tp->timer;
 	void *ioaddr = tp->mmio_addr;
+	unsigned long timeout = RTL8169_PHY_TIMEOUT;
 
 	assert(tp->mac_version > RTL_GIGA_MAC_VER_B);
 	assert(tp->phy_version < RTL_GIGA_PHY_VER_G);
 
-	if (RTL_R8(PHYstatus) & LinkStatus)
-		tp->phy_link_down_cnt = 0;
-	else {
-		tp->phy_link_down_cnt++;
-		if (tp->phy_link_down_cnt >= 12) {
-			int reg;
-
-			// If link on 1000, perform phy reset.
-			reg = mdio_read(ioaddr, PHY_1000_CTRL_REG);
-			if (reg & PHY_Cap_1000_Full) 
-				rtl8169_hw_phy_reset(dev);
+	if (!(tp->phy_1000_ctrl_reg & PHY_Cap_1000_Full))
+		return;
 
-			tp->phy_link_down_cnt = 0;
-		}
+	spin_lock_irq(&tp->lock);
+
+	if (tp->phy_reset_pending(ioaddr)) {
+		/* 
+		 * A busy loop could burn quite a few cycles on nowadays CPU.
+		 * Let's delay the execution of the timer for a few ticks.
+		 */
+		timeout = HZ/10;
+		goto out_mod_timer;
 	}
 
-	mod_timer(timer, jiffies + RTL8169_PHY_TIMEOUT);
+	if (tp->link_ok(ioaddr))
+		goto out_unlock;
+
+	printk(KERN_WARNING PFX "%s: PHY reset until link up\n", dev->name);
+
+	tp->phy_reset_enable(ioaddr);
+
+out_mod_timer:
+	mod_timer(timer, jiffies + timeout);
+out_unlock:
+	spin_unlock_irq(&tp->lock);
 }
 
 static inline void rtl8169_delete_timer(struct net_device *dev)
 {
-	struct rtl8169_private *tp = dev->priv;
+	struct rtl8169_private *tp = netdev_priv(dev);
 	struct timer_list *timer = &tp->timer;
 
 	if ((tp->mac_version <= RTL_GIGA_MAC_VER_B) ||
@@ -628,21 +889,17 @@
 		return;
 
 	del_timer_sync(timer);
-
-	tp->phy_link_down_cnt = 0;
 }
 
 static inline void rtl8169_request_timer(struct net_device *dev)
 {
-	struct rtl8169_private *tp = dev->priv;
+	struct rtl8169_private *tp = netdev_priv(dev);
 	struct timer_list *timer = &tp->timer;
 
 	if ((tp->mac_version <= RTL_GIGA_MAC_VER_B) ||
 	    (tp->phy_version >= RTL_GIGA_PHY_VER_G))
 		return;
 
-	tp->phy_link_down_cnt = 0;
-
 	init_timer(timer);
 	timer->expires = jiffies + RTL8169_PHY_TIMEOUT;
 	timer->data = (unsigned long)(dev);
@@ -681,7 +938,7 @@
 	// enable device (incl. PCI PM wakeup and hotplug setup)
 	rc = pci_enable_device(pdev);
 	if (rc) {
-		printk(KERN_ERR PFX "%s: unable to enable device\n", pdev->slot_name);
+		printk(KERN_ERR PFX "%s: enable failure\n", pdev->slot_name);
 		goto err_out;
 	}
 
@@ -693,7 +950,8 @@
 		pci_read_config_word(pdev, pm_cap + PCI_PM_CTRL, &pwr_command);
 		acpi_idle_state = pwr_command & PCI_PM_CTRL_STATE_MASK;
 	} else {
-		printk(KERN_ERR PFX "Cannot find PowerManagement capability, aborting.\n");
+		printk(KERN_ERR PFX
+		       "Cannot find PowerManagement capability, aborting.\n");
 		goto err_out_free_res;
 	}
 
@@ -716,9 +974,10 @@
 		goto err_out_disable;
 	}
 
-	rc = pci_request_regions(pdev, dev->name);
+	rc = pci_request_regions(pdev, MODULENAME);
 	if (rc) {
-		printk(KERN_ERR PFX "%s: Could not request regions.\n", pdev->slot_name);
+		printk(KERN_ERR PFX "%s: could not request regions.\n",
+		       pdev->slot_name);
 		goto err_out_disable;
 	}
 
@@ -800,8 +1059,9 @@
 	void *ioaddr = NULL;
 	static int board_idx = -1;
 	static int printed_version = 0;
+	u8 autoneg, duplex;
+	u16 speed;
 	int i, rc;
-	int option = -1, Cap10_100 = 0, Cap1000 = 0;
 
 	assert(pdev != NULL);
 	assert(ent != NULL);
@@ -822,6 +1082,22 @@
 	assert(dev != NULL);
 	assert(tp != NULL);
 
+	if (RTL_R8(PHYstatus) & TBI_Enable) {
+		tp->set_speed = rtl8169_set_speed_tbi;
+		tp->get_settings = rtl8169_gset_tbi;
+		tp->phy_reset_enable = rtl8169_tbi_reset_enable;
+		tp->phy_reset_pending = rtl8169_tbi_reset_pending;
+		tp->link_ok = rtl8169_tbi_link_ok;
+
+		tp->phy_1000_ctrl_reg = PHY_Cap_1000_Full; /* Implied by TBI */
+	} else {
+		tp->set_speed = rtl8169_set_speed_xmii;
+		tp->get_settings = rtl8169_gset_xmii;
+		tp->phy_reset_enable = rtl8169_xmii_reset_enable;
+		tp->phy_reset_pending = rtl8169_xmii_reset_pending;
+		tp->link_ok = rtl8169_xmii_link_ok;
+	}
+
 	// Get MAC address.  FIXME: read EEPROM
 	for (i = 0; i < MAC_ADDR_LEN; i++)
 		dev->dev_addr[i] = RTL_R8(MAC0 + i);
@@ -836,9 +1112,12 @@
 	dev->watchdog_timeo = RTL8169_TX_TIMEOUT;
 	dev->irq = pdev->irq;
 	dev->base_addr = (unsigned long) ioaddr;
-//      dev->do_ioctl           = mii_ioctl;
-
-	tp = dev->priv;		// private data //
+#ifdef CONFIG_R8169_NAPI
+	dev->poll = rtl8169_poll;
+	dev->weight = R8169_NAPI_WEIGHT;
+	printk(KERN_INFO PFX "NAPI enabled\n");
+#endif
+	tp->intr_mask = 0xffff;
 	tp->pci_dev = pdev;
 	tp->mmio_addr = ioaddr;
 
@@ -885,95 +1164,12 @@
 		mdio_write(ioaddr, 0x0b, 0x0000); //w 0x0b 15 0 0
 	}
 
-	// if TBI is not endbled
-	if (!(RTL_R8(PHYstatus) & TBI_Enable)) {
-		int val = mdio_read(ioaddr, PHY_AUTO_NEGO_REG);
-
-		option = (board_idx >= MAX_UNITS) ? 0 : media[board_idx];
-		// Force RTL8169 in 10/100/1000 Full/Half mode.
-		if (option > 0) {
-			printk(KERN_INFO "%s: Force-mode Enabled.\n",
-			       dev->name);
-			Cap10_100 = 0, Cap1000 = 0;
-			switch (option) {
-			case _10_Half:
-				Cap10_100 = PHY_Cap_10_Half_Or_Less;
-				Cap1000 = PHY_Cap_Null;
-				break;
-			case _10_Full:
-				Cap10_100 = PHY_Cap_10_Full_Or_Less;
-				Cap1000 = PHY_Cap_Null;
-				break;
-			case _100_Half:
-				Cap10_100 = PHY_Cap_100_Half_Or_Less;
-				Cap1000 = PHY_Cap_Null;
-				break;
-			case _100_Full:
-				Cap10_100 = PHY_Cap_100_Full_Or_Less;
-				Cap1000 = PHY_Cap_Null;
-				break;
-			case _1000_Full:
-				Cap10_100 = PHY_Cap_100_Full_Or_Less;
-				Cap1000 = PHY_Cap_1000_Full;
-				break;
-			default:
-				break;
-			}
-			mdio_write(ioaddr, PHY_AUTO_NEGO_REG, Cap10_100 | (val & 0x1F));	//leave PHY_AUTO_NEGO_REG bit4:0 unchanged
-			mdio_write(ioaddr, PHY_1000_CTRL_REG, Cap1000);
-		} else {
-			printk(KERN_INFO "%s: Auto-negotiation Enabled.\n",
-			       dev->name);
+	rtl8169_link_option(board_idx, &autoneg, &speed, &duplex);
 
-			// enable 10/100 Full/Half Mode, leave PHY_AUTO_NEGO_REG bit4:0 unchanged
-			mdio_write(ioaddr, PHY_AUTO_NEGO_REG,
-				   PHY_Cap_100_Full_Or_Less | (val & 0x1f));
-
-			// enable 1000 Full Mode
-			mdio_write(ioaddr, PHY_1000_CTRL_REG,
-				   PHY_Cap_1000_Full);
-
-		}
-
-		// Enable auto-negotiation and restart auto-nigotiation
-		mdio_write(ioaddr, PHY_CTRL_REG,
-			   PHY_Enable_Auto_Nego | PHY_Restart_Auto_Nego);
-		udelay(100);
-
-		// wait for auto-negotiation process
-		for (i = 10000; i > 0; i--) {
-			//check if auto-negotiation complete
-			if (mdio_read(ioaddr, PHY_STAT_REG) &
-			    PHY_Auto_Neco_Comp) {
-				udelay(100);
-				option = RTL_R8(PHYstatus);
-				if (option & _1000bpsF) {
-					printk(KERN_INFO
-					       "%s: 1000Mbps Full-duplex operation.\n",
-					       dev->name);
-				} else {
-					printk(KERN_INFO
-					       "%s: %sMbps %s-duplex operation.\n",
-					       dev->name,
-					       (option & _100bps) ? "100" :
-					       "10",
-					       (option & FullDup) ? "Full" :
-					       "Half");
-				}
-				break;
-			} else {
-				udelay(100);
-			}
-		}		// end for-loop to wait for auto-negotiation process
-
-	} else {
-		udelay(100);
-		printk(KERN_INFO
-		       "%s: 1000Mbps Full-duplex operation, TBI Link %s!\n",
-		       dev->name,
-		       (RTL_R32(TBICSR) & TBILinkOK) ? "OK" : "Failed");
-
-	}
+	rtl8169_set_speed(dev, autoneg, speed, duplex);
+	
+	if (RTL_R8(PHYstatus) & TBI_Enable)
+		printk(KERN_INFO PFX "%s: TBI auto-negotiating\n", dev->name);
 
 	return 0;
 }
@@ -982,7 +1178,7 @@
 rtl8169_remove_one(struct pci_dev *pdev)
 {
 	struct net_device *dev = pci_get_drvdata(pdev);
-	struct rtl8169_private *tp = dev->priv;
+	struct rtl8169_private *tp = netdev_priv(dev);
 
 	assert(dev != NULL);
 	assert(tp != NULL);
@@ -1001,7 +1197,7 @@
 static int rtl8169_suspend(struct pci_dev *pdev, u32 state)
 {
 	struct net_device *dev = pci_get_drvdata(pdev);
-	struct rtl8169_private *tp = dev->priv;
+	struct rtl8169_private *tp = netdev_priv(dev);
 	void *ioaddr = tp->mmio_addr;
 	unsigned long flags;
 
@@ -1042,7 +1238,7 @@
 static int
 rtl8169_open(struct net_device *dev)
 {
-	struct rtl8169_private *tp = dev->priv;
+	struct rtl8169_private *tp = netdev_priv(dev);
 	struct pci_dev *pdev = tp->pci_dev;
 	int retval;
 
@@ -1074,6 +1270,8 @@
 	rtl8169_hw_start(dev);
 
 	rtl8169_request_timer(dev);
+
+	rtl8169_check_link_status(dev, tp, tp->mmio_addr);
 out:
 	return retval;
 
@@ -1091,7 +1289,7 @@
 static void
 rtl8169_hw_start(struct net_device *dev)
 {
-	struct rtl8169_private *tp = dev->priv;
+	struct rtl8169_private *tp = netdev_priv(dev);
 	void *ioaddr = tp->mmio_addr;
 	u32 i;
 
@@ -1102,8 +1300,7 @@
 	for (i = 1000; i > 0; i--) {
 		if ((RTL_R8(ChipCmd) & CmdReset) == 0)
 			break;
-		else
-			udelay(10);
+		udelay(10);
 	}
 
 	RTL_W8(Cfg9346, Cfg9346_Unlock);
@@ -1114,8 +1311,8 @@
 	RTL_W16(RxMaxSize, RxPacketMaxSize);
 
 	// Set Rx Config register
-	i = rtl8169_rx_config | (RTL_R32(RxConfig) & rtl_chip_info[tp->chipset].
-				 RxConfigMask);
+	i = rtl8169_rx_config |
+		(RTL_R32(RxConfig) & rtl_chip_info[tp->chipset].RxConfigMask);
 	RTL_W32(RxConfig, i);
 
 	/* Set DMA burst size and Interframe Gap Time */
@@ -1126,7 +1323,8 @@
 	RTL_W16(CPlusCmd, tp->cp_cmd);
 
 	if (tp->mac_version == RTL_GIGA_MAC_VER_D) {
-		dprintk(KERN_INFO PFX "Set MAC Reg C+CR Offset 0xE0: bit-3 and bit-14 MUST be 1\n");
+		dprintk(KERN_INFO PFX "Set MAC Reg C+CR Offset 0xE0. "
+			"Bit-3 and bit-14 MUST be 1\n");
 		tp->cp_cmd |= (1 << 14) | PCIMulRW;
 		RTL_W16(CPlusCmd, tp->cp_cmd);
 	}
@@ -1151,7 +1349,6 @@
 	RTL_W16(IntrMask, rtl8169_intr_mask);
 
 	netif_start_queue(dev);
-
 }
 
 static inline void rtl8169_make_unusable_by_asic(struct RxDesc *desc)
@@ -1248,7 +1445,7 @@
 
 static int rtl8169_init_ring(struct net_device *dev)
 {
-	struct rtl8169_private *tp = dev->priv;
+	struct rtl8169_private *tp = netdev_priv(dev);
 
 	tp->cur_rx = tp->dirty_rx = 0;
 	tp->cur_tx = tp->dirty_tx = 0;
@@ -1302,10 +1499,11 @@
 static void
 rtl8169_tx_timeout(struct net_device *dev)
 {
-	struct rtl8169_private *tp = dev->priv;
+	struct rtl8169_private *tp = netdev_priv(dev);
 	void *ioaddr = tp->mmio_addr;
 	u8 tmp8;
 
+	printk(KERN_INFO "%s: TX Timeout\n", dev->name);
 	/* disable Tx, if not already */
 	tmp8 = RTL_R8(ChipCmd);
 	if (tmp8 & CmdTxEnb)
@@ -1328,9 +1526,9 @@
 static int
 rtl8169_start_xmit(struct sk_buff *skb, struct net_device *dev)
 {
-	struct rtl8169_private *tp = dev->priv;
+	struct rtl8169_private *tp = netdev_priv(dev);
 	void *ioaddr = tp->mmio_addr;
-	int entry = tp->cur_tx % NUM_TX_DESC;
+	unsigned int entry = tp->cur_tx % NUM_TX_DESC;
 	u32 len = skb->len;
 
 	if (unlikely(skb->len < ETH_ZLEN)) {
@@ -1340,10 +1538,9 @@
 		len = ETH_ZLEN;
 	}
 	
-	spin_lock_irq(&tp->lock);
-
 	if (!(le32_to_cpu(tp->TxDescArray[entry].status) & OWNbit)) {
 		dma_addr_t mapping;
+		u32 status;
 
 		mapping = pci_map_single(tp->pci_dev, skb->data, len,
 					 PCI_DMA_TODEVICE);
@@ -1351,24 +1548,30 @@
 		tp->Tx_skbuff[entry] = skb;
 		tp->TxDescArray[entry].addr = cpu_to_le64(mapping);
 
-		tp->TxDescArray[entry].status = cpu_to_le32(OWNbit | FSbit |
-			LSbit | len | (EORbit * !((entry + 1) % NUM_TX_DESC)));
+		/* anti gcc 2.95.3 bugware */
+		status = OWNbit | FSbit | LSbit | len |
+			 (EORbit * !((entry + 1) % NUM_TX_DESC));
+		tp->TxDescArray[entry].status = cpu_to_le32(status);
 			
 		RTL_W8(TxPoll, 0x40);	//set polling bit
 
 		dev->trans_start = jiffies;
 
 		tp->cur_tx++;
+		smp_wmb();
 	} else
 		goto err_drop;
 
-
 	if ((tp->cur_tx - NUM_TX_DESC) == tp->dirty_tx) {
+		u32 dirty = tp->dirty_tx;
+	
 		netif_stop_queue(dev);
+		smp_rmb();
+		if (dirty != tp->dirty_tx)
+			netif_wake_queue(dev);
 	}
-out:
-	spin_unlock_irq(&tp->lock);
 
+out:
 	return 0;
 
 err_drop:
@@ -1382,17 +1585,18 @@
 rtl8169_tx_interrupt(struct net_device *dev, struct rtl8169_private *tp,
 		     void *ioaddr)
 {
-	unsigned long dirty_tx, tx_left;
+	unsigned int dirty_tx, tx_left;
 
 	assert(dev != NULL);
 	assert(tp != NULL);
 	assert(ioaddr != NULL);
 
 	dirty_tx = tp->dirty_tx;
+	smp_rmb();
 	tx_left = tp->cur_tx - dirty_tx;
 
 	while (tx_left > 0) {
-		int entry = dirty_tx % NUM_TX_DESC;
+		unsigned int entry = dirty_tx % NUM_TX_DESC;
 		struct sk_buff *skb = tp->Tx_skbuff[entry];
 		u32 status;
 
@@ -1415,6 +1619,7 @@
 
 	if (tp->dirty_tx != dirty_tx) {
 		tp->dirty_tx = dirty_tx;
+		smp_wmb();
 		if (netif_queue_stopped(dev))
 			netif_wake_queue(dev);
 	}
@@ -1442,11 +1647,11 @@
 	return ret;
 }
 
-static void
+static int
 rtl8169_rx_interrupt(struct net_device *dev, struct rtl8169_private *tp,
 		     void *ioaddr)
 {
-	unsigned long cur_rx, rx_left;
+	unsigned int cur_rx, rx_left, count;
 	int delta;
 
 	assert(dev != NULL);
@@ -1455,9 +1660,10 @@
 
 	cur_rx = tp->cur_rx;
 	rx_left = NUM_RX_DESC + tp->dirty_rx - cur_rx;
+	rx_left = rtl8169_rx_quota(rx_left, (u32) dev->quota);
 
 	while (rx_left > 0) {
-		int entry = cur_rx % NUM_RX_DESC;
+		unsigned int entry = cur_rx % NUM_RX_DESC;
 		u32 status;
 
 		rmb();
@@ -1494,7 +1700,7 @@
 
 			skb_put(skb, pkt_size);
 			skb->protocol = eth_type_trans(skb, dev);
-			netif_rx(skb);
+			rtl8169_rx_skb(skb);
 
 			dev->last_rx = jiffies;
 			tp->stats.rx_bytes += pkt_size;
@@ -1505,13 +1711,15 @@
 		rx_left--;
 	}
 
+	count = cur_rx - tp->cur_rx;
 	tp->cur_rx = cur_rx;
 
 	delta = rtl8169_rx_fill(tp, dev, tp->dirty_rx, tp->cur_rx);
-	if (delta > 0)
-		tp->dirty_rx += delta;
-	else if (delta < 0)
+	if (delta < 0) {
 		printk(KERN_INFO "%s: no Rx buffer allocated\n", dev->name);
+		delta = 0;
+	}
+	tp->dirty_rx += delta;
 
 	/*
 	 * FIXME: until there is periodic timer to try and refill the ring,
@@ -1522,6 +1730,8 @@
 	 */
 	if (tp->dirty_rx + NUM_RX_DESC == tp->cur_rx)
 		printk(KERN_EMERG "%s: Rx buffers exhausted\n", dev->name);
+
+	return count;
 }
 
 /* The interrupt handler does all of the Rx thread work and cleans up after the Tx thread. */
@@ -1529,7 +1739,7 @@
 rtl8169_interrupt(int irq, void *dev_instance, struct pt_regs *regs)
 {
 	struct net_device *dev = (struct net_device *) dev_instance;
-	struct rtl8169_private *tp = dev->priv;
+	struct rtl8169_private *tp = netdev_priv(dev);
 	int boguscnt = max_interrupt_work;
 	void *ioaddr = tp->mmio_addr;
 	int status = 0;
@@ -1543,26 +1753,37 @@
 			break;
 
 		handled = 1;
-/*
-		if (status & RxUnderrun)
-			link_changed = RTL_R16 (CSCR) & CSCR_LinkChangeBit;
-*/
+
+		status &= tp->intr_mask;
 		RTL_W16(IntrStatus,
 			(status & RxFIFOOver) ? (status | RxOverflow) : status);
 
 		if (!(status & rtl8169_intr_mask))
 			break;
 
+		if (status & LinkChg)
+			rtl8169_check_link_status(dev, tp, ioaddr);
+
+#ifdef CONFIG_R8169_NAPI
+		RTL_W16(IntrMask, rtl8169_intr_mask & ~rtl8169_napi_event);
+		tp->intr_mask = ~rtl8169_napi_event;
+
+		if (likely(netif_rx_schedule_prep(dev)))
+			__netif_rx_schedule(dev);
+		else {
+			printk(KERN_INFO "%s: interrupt %x taken in poll\n",
+			       dev->name, status);	
+		}
+		break;
+#else
 		// Rx interrupt 
-		if (status & (RxOK | RxUnderrun | RxOverflow | RxFIFOOver)) {
+		if (status & (RxOK | RxOverflow | RxFIFOOver)) {
 			rtl8169_rx_interrupt(dev, tp, ioaddr);
 		}
 		// Tx interrupt
-		if (status & (TxOK | TxErr)) {
-			spin_lock(&tp->lock);
+		if (status & (TxOK | TxErr))
 			rtl8169_tx_interrupt(dev, tp, ioaddr);
-			spin_unlock(&tp->lock);
-		}
+#endif
 
 		boguscnt--;
 	} while (boguscnt > 0);
@@ -1576,10 +1797,40 @@
 	return IRQ_RETVAL(handled);
 }
 
+#ifdef CONFIG_R8169_NAPI
+static int rtl8169_poll(struct net_device *dev, int *budget)
+{
+	unsigned int work_done, work_to_do = min(*budget, dev->quota);
+	struct rtl8169_private *tp = netdev_priv(dev);
+	void *ioaddr = tp->mmio_addr;
+
+	work_done = rtl8169_rx_interrupt(dev, tp, ioaddr);
+	rtl8169_tx_interrupt(dev, tp, ioaddr);
+
+	*budget -= work_done;
+	dev->quota -= work_done;
+
+	if ((work_done < work_to_do) || !netif_running(dev)) {
+		netif_rx_complete(dev);
+		tp->intr_mask = 0xffff;
+		/*
+		 * 20040426: the barrier is not strictly required but the
+		 * behavior of the irq handler could be less predictable
+		 * without it. Btw, the lack of flush for the posted pci
+		 * write is safe - FR
+		 */
+		smp_wmb();
+		RTL_W16(IntrMask, rtl8169_intr_mask);
+	}
+
+	return (work_done >= work_to_do);
+}
+#endif
+
 static int
 rtl8169_close(struct net_device *dev)
 {
-	struct rtl8169_private *tp = dev->priv;
+	struct rtl8169_private *tp = netdev_priv(dev);
 	struct pci_dev *pdev = tp->pci_dev;
 	void *ioaddr = tp->mmio_addr;
 
@@ -1621,7 +1872,7 @@
 static void
 rtl8169_set_rx_mode(struct net_device *dev)
 {
-	struct rtl8169_private *tp = dev->priv;
+	struct rtl8169_private *tp = netdev_priv(dev);
 	void *ioaddr = tp->mmio_addr;
 	unsigned long flags;
 	u32 mc_filter[2];	/* Multicast hash filter */
@@ -1655,10 +1906,8 @@
 
 	spin_lock_irqsave(&tp->lock, flags);
 
-	tmp =
-	    rtl8169_rx_config | rx_mode | (RTL_R32(RxConfig) &
-					   rtl_chip_info[tp->chipset].
-					   RxConfigMask);
+	tmp = rtl8169_rx_config | rx_mode |
+	      (RTL_R32(RxConfig) & rtl_chip_info[tp->chipset].RxConfigMask);
 
 	RTL_W32(RxConfig, tmp);
 	RTL_W32(MAR0 + 0, mc_filter[0]);
@@ -1675,7 +1924,7 @@
  */
 static struct net_device_stats *rtl8169_get_stats(struct net_device *dev)
 {
-	struct rtl8169_private *tp = dev->priv;
+	struct rtl8169_private *tp = netdev_priv(dev);
 	void *ioaddr = tp->mmio_addr;
 	unsigned long flags;
 
--- diff/drivers/net/s2io.h	2004-06-11 19:17:30.000000000 +0100
+++ source/drivers/net/s2io.h	2004-06-11 19:22:03.000000000 +0100
@@ -748,27 +748,6 @@
 #define SMALL_RXD_CNT	40 * (MAX_RXDS_PER_BLOCK+1)
 #define LARGE_RXD_CNT	100 * (MAX_RXDS_PER_BLOCK+1)
 
-/*  OS related system calls */
-#ifndef readq
-static inline u64 readq(void *addr)
-{
-	u64 ret = 0;
-	ret = readl(addr + 4);
-	ret <<= 32;
-	ret |= readl(addr);
-
-	return ret;
-}
-#endif
-
-#ifndef writeq
-static inline void writeq(u64 val, void *addr)
-{
-	writel((u32) (val), addr);
-	writel((u32) (val >> 32), (addr + 4));
-}
-#endif
-
 /*  Interrupt related values of Xena */
 
 #define ENABLE_INTRS    1
--- diff/drivers/net/sis900.c	2004-06-11 19:17:30.000000000 +0100
+++ source/drivers/net/sis900.c	2004-06-11 19:22:03.000000000 +0100
@@ -116,6 +116,7 @@
 #define	HOME 	0x0001
 #define LAN	0x0002
 #define MIX	0x0003
+#define UNKNOWN	0x0
 } mii_chip_table[] = {
 	{ "SiS 900 Internal MII PHY", 		0x001d, 0x8000, LAN },
 	{ "SiS 7014 Physical Layer Solution", 	0x0016, 0xf830, LAN },
@@ -577,9 +578,11 @@
 				break;
 			}
 			
-		if( !mii_chip_table[i].phy_id1 )
+		if( !mii_chip_table[i].phy_id1 ) {
 			printk(KERN_INFO "%s: Unknown PHY transceiver found at address %d.\n",
-			       net_dev->name, phy_addr);			
+			       net_dev->name, phy_addr);
+			mii_phy->phy_types = UNKNOWN;
+		}
 	}
 	
 	if (sis_priv->mii == NULL) {
@@ -644,15 +647,15 @@
 static u16 sis900_default_phy(struct net_device * net_dev)
 {
 	struct sis900_private * sis_priv = net_dev->priv;
- 	struct mii_phy *phy = NULL, *phy_home = NULL, *default_phy = NULL;
+ 	struct mii_phy *phy = NULL, *phy_home = NULL, *default_phy = NULL, *phy_lan = NULL;
 	u16 status;
 
         for( phy=sis_priv->first_mii; phy; phy=phy->next ){
 		status = mdio_read(net_dev, phy->phy_addr, MII_STATUS);
 		status = mdio_read(net_dev, phy->phy_addr, MII_STATUS);
 
-		/* Link ON & Not select deafalut PHY */
-		 if ( (status & MII_STAT_LINK) && !(default_phy) )
+		/* Link ON & Not select default PHY & not ghost PHY */
+		 if ( (status & MII_STAT_LINK) && !default_phy && (phy->phy_types != UNKNOWN) )
 		 	default_phy = phy;
 		 else{
 			status = mdio_read(net_dev, phy->phy_addr, MII_CONTROL);
@@ -660,12 +663,16 @@
 				status | MII_CNTL_AUTO | MII_CNTL_ISOLATE);
 			if( phy->phy_types == HOME )
 				phy_home = phy;
+			else if (phy->phy_types == LAN)
+				phy_lan = phy;
 		 }
 	}
 
-	if( (!default_phy) && phy_home )
+	if( !default_phy && phy_home )
 		default_phy = phy_home;
-	else if(!default_phy)
+	else if( !default_phy && phy_lan )
+		default_phy = phy_lan;
+	else if ( !default_phy )
 		default_phy = sis_priv->first_mii;
 
 	if( sis_priv->mii != default_phy ){
--- diff/drivers/net/smc-mca.c	2004-05-19 22:11:56.000000000 +0100
+++ source/drivers/net/smc-mca.c	2004-06-11 19:22:03.000000000 +0100
@@ -51,6 +51,8 @@
 #include "8390.h"
 #include "smc-mca.h"
 
+#define DRV_NAME "smc-mca"
+
 static int ultramca_open(struct net_device *dev);
 static void ultramca_reset_8390(struct net_device *dev);
 static void ultramca_get_8390_hdr(struct net_device *dev,
@@ -265,7 +267,7 @@
 		goto err_unclaim;
 	}
 
-	if (!request_region(ioaddr, ULTRA_IO_EXTENT, dev->name)) {
+	if (!request_region(ioaddr, ULTRA_IO_EXTENT, DRV_NAME)) {
 		rc = -ENODEV;
 		goto err_unclaim;
 	}
--- diff/drivers/net/smc-ultra.c	2004-05-19 22:11:56.000000000 +0100
+++ source/drivers/net/smc-ultra.c	2004-06-11 19:22:03.000000000 +0100
@@ -72,6 +72,8 @@
 
 #include "8390.h"
 
+#define DRV_NAME "smc-ultra"
+
 /* A zero-terminated list of I/O addresses to be probed. */
 static unsigned int ultra_portlist[] __initdata =
 {0x200, 0x220, 0x240, 0x280, 0x300, 0x340, 0x380, 0};
@@ -178,6 +180,7 @@
 	release_region(dev->base_addr - ULTRA_NIC_OFFSET, ULTRA_IO_EXTENT);
 }
 
+#ifndef MODULE
 struct net_device * __init ultra_probe(int unit)
 {
 	struct net_device *dev = alloc_ei_netdev();
@@ -202,6 +205,7 @@
 	free_netdev(dev);
 	return ERR_PTR(err);
 }
+#endif
 
 static int __init ultra_probe1(struct net_device *dev, int ioaddr)
 {
@@ -215,7 +219,7 @@
 	unsigned char idreg = inb(ioaddr + 7);
 	unsigned char reg4 = inb(ioaddr + 4) & 0x7f;
 
-	if (!request_region(ioaddr, ULTRA_IO_EXTENT, dev->name))
+	if (!request_region(ioaddr, ULTRA_IO_EXTENT, DRV_NAME))
 		return -EBUSY;
 
 	/* Check the ID nibble. */
--- diff/drivers/net/smc-ultra32.c	2004-05-19 22:11:56.000000000 +0100
+++ source/drivers/net/smc-ultra32.c	2004-06-11 19:22:03.000000000 +0100
@@ -61,6 +61,8 @@
 
 #include "8390.h"
 
+#define DRV_NAME "smc-ultra32"
+
 static int ultra32_probe1(struct net_device *dev, int ioaddr);
 static int ultra32_open(struct net_device *dev);
 static void ultra32_reset_8390(struct net_device *dev);
@@ -163,7 +165,7 @@
 	unsigned char reg4;
 	const char *ifmap[] = {"UTP No Link", "", "UTP/AUI", "UTP/BNC"};
 
-	if (!request_region(ioaddr, ULTRA32_IO_EXTENT, dev->name))
+	if (!request_region(ioaddr, ULTRA32_IO_EXTENT, DRV_NAME))
 		return -EBUSY;
 
 	if (inb(ioaddr + ULTRA32_IDPORT) == 0xff ||
--- diff/drivers/net/smc9194.c	2004-05-19 22:11:56.000000000 +0100
+++ source/drivers/net/smc9194.c	2004-06-11 19:22:03.000000000 +0100
@@ -78,6 +78,8 @@
 
 #include "smc9194.h"
 
+#define DRV_NAME "smc9194"
+
 /*------------------------------------------------------------------------
  .
  . Configuration options, for the experienced user to change.
@@ -843,7 +845,7 @@
 	word memory_cfg_register;
 
 	/* Grab the region so that no one else tries to probe our ioports. */
-	if (!request_region(ioaddr, SMC_IO_EXTENT, dev->name))
+	if (!request_region(ioaddr, SMC_IO_EXTENT, DRV_NAME))
 		return -EBUSY;
 
 	dev->irq = irq;
@@ -1001,9 +1003,9 @@
 	memset(dev->priv, 0, sizeof(struct smc_local));
 
 	/* Grab the IRQ */
-      	retval = request_irq(dev->irq, &smc_interrupt, 0, dev->name, dev);
+      	retval = request_irq(dev->irq, &smc_interrupt, 0, DRV_NAME, dev);
       	if (retval) {
-		printk("%s: unable to get IRQ %d (irqval=%d).\n", dev->name,
+		printk("%s: unable to get IRQ %d (irqval=%d).\n", DRV_NAME,
 			dev->irq, retval);
   	  	goto err_out;
       	}
--- diff/drivers/net/starfire.c	2004-06-11 19:17:30.000000000 +0100
+++ source/drivers/net/starfire.c	2004-06-11 19:22:03.000000000 +0100
@@ -880,7 +880,7 @@
 
 	irq = pdev->irq;
 
-	if (pci_request_regions (pdev, dev->name)) {
+	if (pci_request_regions (pdev, DRV_NAME)) {
 		printk(KERN_ERR DRV_NAME " %d: cannot reserve PCI resources, aborting\n", card_idx);
 		goto err_out_free_netdev;
 	}
--- diff/drivers/net/stnic.c	2004-05-19 22:11:56.000000000 +0100
+++ source/drivers/net/stnic.c	2004-06-11 19:22:03.000000000 +0100
@@ -28,6 +28,8 @@
 
 #include "8390.h"
 
+#define DRV_NAME "stnic"
+
 #define byte	unsigned char
 #define half	unsigned short
 #define word	unsigned int
@@ -130,7 +132,7 @@
 
   /* Snarf the interrupt now.  There's no point in waiting since we cannot
      share and the board will usually be enabled. */
-  err = request_irq (dev->irq, ei_interrupt, 0, dev->name, dev);
+  err = request_irq (dev->irq, ei_interrupt, 0, DRV_NAME, dev);
   if (err)  {
       printk (KERN_EMERG " unable to get IRQ %d.\n", dev->irq);
       free_netdev(dev);
--- diff/drivers/net/sun3_82586.c	2004-05-19 22:11:56.000000000 +0100
+++ source/drivers/net/sun3_82586.c	2004-06-11 19:22:03.000000000 +0100
@@ -53,6 +53,8 @@
 
 #include "sun3_82586.h"
 
+#define DRV_NAME "sun3_82586"
+
 #define DEBUG       /* debug on */
 #define SYSBUSVAL 0 /* 16 Bit */
 #define SUN3_82586_TOTAL_SIZE	PAGE_SIZE
@@ -336,7 +338,7 @@
 {
 	int i, size, retval;
 
-	if (!request_region(ioaddr, SUN3_82586_TOTAL_SIZE, dev->name))
+	if (!request_region(ioaddr, SUN3_82586_TOTAL_SIZE, DRV_NAME))
 		return -EBUSY;
 
 	/* copy in the ethernet address from the prom */
--- diff/drivers/net/sun3lance.c	2004-05-19 22:11:56.000000000 +0100
+++ source/drivers/net/sun3lance.c	2004-06-11 19:22:03.000000000 +0100
@@ -42,7 +42,6 @@
 #include <asm/bitops.h>
 #include <asm/io.h>
 #include <asm/pgtable.h>
-#include <asm/pgalloc.h>
 #include <asm/dvma.h>
 #include <asm/idprom.h>
 #include <asm/machines.h>
--- diff/drivers/net/sungem.c	2004-06-11 19:17:30.000000000 +0100
+++ source/drivers/net/sungem.c	2004-06-11 19:22:03.000000000 +0100
@@ -2717,7 +2717,7 @@
 
 	gp = dev->priv;
 
-	err = pci_request_regions(pdev, dev->name);
+	err = pci_request_regions(pdev, DRV_NAME);
 	if (err) {
 		printk(KERN_ERR PFX "Cannot obtain PCI resources, "
 		       "aborting.\n");
--- diff/drivers/net/sunhme.c	2004-05-19 22:11:56.000000000 +0100
+++ source/drivers/net/sunhme.c	2004-06-11 19:22:03.000000000 +0100
@@ -68,6 +68,8 @@
 #include "sunhme.h"
 
 
+#define DRV_NAME "sunhme"
+
 static int macaddr[6];
 
 /* accept MAC address of the form macaddr=0x08,0x00,0x20,0x30,0x40,0x50 */
@@ -3085,7 +3087,7 @@
 		printk(KERN_ERR "happymeal(PCI): Cannot find proper PCI device base address.\n");
 		goto err_out_clear_quattro;
 	}
-	if (pci_request_regions(pdev, dev->name)) {
+	if (pci_request_regions(pdev, DRV_NAME)) {
 		printk(KERN_ERR "happymeal(PCI): Cannot obtain PCI resources, "
 		       "aborting.\n");
 		goto err_out_clear_quattro;
--- diff/drivers/net/tulip/interrupt.c	2004-05-19 22:11:59.000000000 +0100
+++ source/drivers/net/tulip/interrupt.c	2004-06-11 19:22:03.000000000 +0100
@@ -133,6 +133,10 @@
 			   tp->rx_ring[entry].status);
 
        do {
+		if (inl(dev->base_addr + CSR5) == 0xffffffff) {
+			printk(KERN_DEBUG " In tulip_poll(), hardware disappeared.\n");
+			break;
+		}
                /* Acknowledge current RX interrupt sources. */
                outl((RxIntr | RxNoBuf), dev->base_addr + CSR5);
  
--- diff/drivers/net/tulip/tulip_core.c	2004-06-11 19:17:30.000000000 +0100
+++ source/drivers/net/tulip/tulip_core.c	2004-06-11 19:22:03.000000000 +0100
@@ -1535,7 +1535,7 @@
 		}
 	}
 	/* Lite-On boards have the address byte-swapped. */
-	if ((dev->dev_addr[0] == 0xA0  ||  dev->dev_addr[0] == 0xC0)
+	if ((dev->dev_addr[0] == 0xA0  ||  dev->dev_addr[0] == 0xC0 || dev->dev_addr[0] == 0x02)
 		&&  dev->dev_addr[1] == 0x00)
 		for (i = 0; i < 6; i+=2) {
 			char tmp = dev->dev_addr[i];
--- diff/drivers/net/tulip/winbond-840.c	2004-06-11 19:17:30.000000000 +0100
+++ source/drivers/net/tulip/winbond-840.c	2004-06-11 19:22:03.000000000 +0100
@@ -1292,14 +1292,8 @@
 				pci_dma_sync_single_for_cpu(np->pci_dev,np->rx_addr[entry],
 							    np->rx_skbuff[entry]->len,
 							    PCI_DMA_FROMDEVICE);
-				/* Call copy + cksum if available. */
-#if HAS_IP_COPYSUM
 				eth_copy_and_sum(skb, np->rx_skbuff[entry]->tail, pkt_len, 0);
 				skb_put(skb, pkt_len);
-#else
-				memcpy(skb_put(skb, pkt_len), np->rx_skbuff[entry]->tail,
-					   pkt_len);
-#endif
 				pci_dma_sync_single_for_device(np->pci_dev,np->rx_addr[entry],
 							       np->rx_skbuff[entry]->len,
 							       PCI_DMA_FROMDEVICE);
--- diff/drivers/net/via-rhine.c	2004-06-11 19:17:30.000000000 +0100
+++ source/drivers/net/via-rhine.c	2004-06-11 19:22:03.000000000 +0100
@@ -354,59 +354,46 @@
    second only the 1234 card.
 */
 
-enum pci_flags_bit {
-	PCI_USES_IO=1, PCI_USES_MEM=2, PCI_USES_MASTER=4,
-	PCI_ADDR0=0x10<<0, PCI_ADDR1=0x10<<1, PCI_ADDR2=0x10<<2, PCI_ADDR3=0x10<<3,
+enum rhine_revs {
+	VT86C100A	= 0x00,
+	VT6102		= 0x40,
+	VT8231		= 0x50,	/* Integrated MAC */
+	VT8233		= 0x60,	/* Integrated MAC */
+	VT8235		= 0x74,	/* Integrated MAC */
+	VT8237		= 0x78,	/* Integrated MAC */
+	VTunknown0	= 0x7C,
+	VT6105		= 0x80,
+	VT6105_B0	= 0x83,
+	VT6105L		= 0x8A,
+	VT6107		= 0x8C,
+	VTunknown1	= 0x8E,
+	VT6105M		= 0x90,
 };
 
-enum rhine_chips {
-	VT86C100A = 0,
-	VT6102,
-	VT6105,
-	VT6105M
-};
-
-struct rhine_chip_info {
-	const char *name;
-	u16 pci_flags;
-	int io_size;
-	int drv_flags;
-};
-
-
-enum chip_capability_flags {
-	CanHaveMII=1, HasESIPhy=2, HasDavicomPhy=4,
-	ReqTxAlign=0x10, HasWOL=0x20,
+enum rhine_quirks {
+	rqWOL		= 0x0001,	/* Wake-On-LAN support */
+	rqForceReset	= 0x0002,
+	rqDavicomPhy	= 0x0020,
+	rq6patterns	= 0x0040,	/* 6 instead of 4 patterns for WOL */
+	rqStatusWBRace	= 0x0080,	/* Tx Status Writeback Error possible */
+	rqRhineI	= 0x0100,	/* See comment below */
 };
+/*
+ * rqRhineI: VT86C100A (aka Rhine-I) uses different bits to enable
+ * MMIO as well as for the collision counter and the Tx FIFO underflow
+ * indicator. In addition, Tx and Rx buffers need to 4 byte aligned.
+ */
 
-#ifdef USE_MMIO
-#define RHINE_IOTYPE (PCI_USES_MEM | PCI_USES_MASTER | PCI_ADDR1)
-#else
-#define RHINE_IOTYPE (PCI_USES_IO  | PCI_USES_MASTER | PCI_ADDR0)
-#endif
 /* Beware of PCI posted writes */
 #define IOSYNC	do { readb(dev->base_addr + StationAddr); } while (0)
 
-/* directly indexed by enum rhine_chips, above */
-static struct rhine_chip_info rhine_chip_info[] __devinitdata =
-{
-	{ "VIA VT86C100A Rhine", RHINE_IOTYPE, 128,
-	  CanHaveMII | ReqTxAlign | HasDavicomPhy },
-	{ "VIA VT6102 Rhine-II", RHINE_IOTYPE, 256,
-	  CanHaveMII | HasWOL },
-	{ "VIA VT6105 Rhine-III", RHINE_IOTYPE, 256,
-	  CanHaveMII | HasWOL },
-	{ "VIA VT6105M Rhine-III", RHINE_IOTYPE, 256,
-	  CanHaveMII | HasWOL },
-};
-
 static struct pci_device_id rhine_pci_tbl[] =
 {
-	{0x1106, 0x3043, PCI_ANY_ID, PCI_ANY_ID, 0, 0, VT86C100A},
-	{0x1106, 0x3065, PCI_ANY_ID, PCI_ANY_ID, 0, 0, VT6102},
-	{0x1106, 0x3106, PCI_ANY_ID, PCI_ANY_ID, 0, 0, VT6105}, /* 6105{,L,LOM} */
-	{0x1106, 0x3053, PCI_ANY_ID, PCI_ANY_ID, 0, 0, VT6105M},
-	{0,}	/* terminate list */
+	{0x1106, 0x3043, PCI_ANY_ID, PCI_ANY_ID, 0, 0, }, /* VT86C100A */
+	{0x1106, 0x3065, PCI_ANY_ID, PCI_ANY_ID, 0, 0, }, /* VT6102 */
+	{0x1106, 0x3106, PCI_ANY_ID, PCI_ANY_ID, 0, 0, }, /* 6105{,L,LOM} */
+	{0x1106, 0x3053, PCI_ANY_ID, PCI_ANY_ID, 0, 0, }, /* VT6105M */
+	{ }	/* terminate list */
 };
 MODULE_DEVICE_TABLE(pci, rhine_pci_tbl);
 
@@ -421,8 +408,10 @@
 	MIICmd=0x70, MIIRegAddr=0x71, MIIData=0x72, MACRegEEcsr=0x74,
 	ConfigA=0x78, ConfigB=0x79, ConfigC=0x7A, ConfigD=0x7B,
 	RxMissed=0x7C, RxCRCErrs=0x7E, MiscCmd=0x81,
-	StickyHW=0x83, IntrStatus2=0x84, WOLcrClr=0xA4, WOLcgClr=0xA7,
-	PwrcsrClr=0xAC,
+	StickyHW=0x83, IntrStatus2=0x84,
+	WOLcrSet=0xA0, WOLcrClr=0xA4, WOLcrClr1=0xA6,
+	WOLcgClr=0xA7,
+	PwrcsrSet=0xA8, PwrcsrSet1=0xA9, PwrcsrClr=0xAC, PwrcsrClr1=0xAD,
 };
 
 /* Bits in ConfigD */
@@ -514,7 +503,7 @@
 	spinlock_t lock;
 
 	/* Frequently used values: keep some adjacent for cache effect. */
-	int chip_id, drv_flags;
+	u32 quirks;
 	struct rx_desc *rx_head_desc;
 	unsigned int cur_rx, dirty_rx;	/* Producer/consumer ring indices */
 	unsigned int cur_tx, dirty_tx;
@@ -522,7 +511,6 @@
 	u16 chip_cmd;			/* Current setting for ChipCmd */
 
 	/* These values are keep track of the transceiver/media in use. */
-	unsigned int default_port:4;	/* Last dev->if_port value. */
 	u8 tx_thresh, rx_thresh;
 
 	/* MII transceiver section. */
@@ -557,12 +545,41 @@
 
 	intr_status = readw(ioaddr + IntrStatus);
 	/* On Rhine-II, Bit 3 indicates Tx descriptor write-back race. */
-	if (rp->chip_id == VT6102)
+	if (rp->quirks & rqStatusWBRace)
 		intr_status |= readb(ioaddr + IntrStatus2) << 16;
 	return intr_status;
 }
 
-static void wait_for_reset(struct net_device *dev, int chip_id, char *name)
+/*
+ * Get power related registers into sane state.
+ * Returns content of power-event (WOL) registers.
+ */
+static void rhine_power_init(struct net_device *dev)
+{
+	long ioaddr = dev->base_addr;
+	struct rhine_private *rp = netdev_priv(dev);
+
+	if (rp->quirks & rqWOL) {
+		/* Make sure chip is in power state D0 */
+		writeb(readb(ioaddr + StickyHW) & 0xFC, ioaddr + StickyHW);
+
+		/* Disable "force PME-enable" */
+		writeb(0x80, ioaddr + WOLcgClr);
+
+		/* Clear power-event config bits (WOL) */
+		writeb(0xFF, ioaddr + WOLcrClr);
+		/* More recent cards can manage two additional patterns */
+		if (rp->quirks & rq6patterns)
+			writeb(0x03, ioaddr + WOLcrClr1);
+
+		/* Clear power-event status bits */
+		writeb(0xFF, ioaddr + PwrcsrClr);
+		if (rp->quirks & rq6patterns)
+			writeb(0x03, ioaddr + PwrcsrClr1);
+	}
+}
+
+static void wait_for_reset(struct net_device *dev, u32 quirks, char *name)
 {
 	long ioaddr = dev->base_addr;
 	int boguscnt = 20;
@@ -574,7 +591,7 @@
 			"Trying harder.\n", name);
 
 		/* Rhine-II needs to be forced sometimes */
-		if (chip_id == VT6102)
+		if (quirks & rqForceReset)
 			writeb(0x40, ioaddr + MiscCmd);
 
 		/* VT86C100A may need long delay after reset (dlink) */
@@ -590,10 +607,10 @@
 }
 
 #ifdef USE_MMIO
-static void __devinit enable_mmio(long ioaddr, int chip_id)
+static void __devinit enable_mmio(long ioaddr, u32 quirks)
 {
 	int n;
-	if (chip_id == VT86C100A) {
+	if (quirks & rqRhineI) {
 		/* More recent docs say that this bit is reserved ... */
 		n = inb(ioaddr + ConfigA) | 0x20;
 		outb(n, ioaddr + ConfigA);
@@ -628,16 +645,18 @@
 {
 	struct net_device *dev;
 	struct rhine_private *rp;
-	int i, option;
-	int chip_id = (int) ent->driver_data;
+	int i, option, rc;
+	u8 pci_rev;
+	u32 quirks;
 	static int card_idx = -1;
 	long ioaddr;
 	long memaddr;
 	int io_size;
-	int pci_flags;
+	int phy, phy_idx = 0;
 #ifdef USE_MMIO
 	long ioaddr0;
 #endif
+	const char *name;
 
 /* when built into the kernel, we only print version if device is found */
 #ifndef MODULE
@@ -648,14 +667,34 @@
 
 	card_idx++;
 	option = card_idx < MAX_UNITS ? options[card_idx] : 0;
-	io_size = rhine_chip_info[chip_id].io_size;
-	pci_flags = rhine_chip_info[chip_id].pci_flags;
+	pci_read_config_byte(pdev, PCI_REVISION_ID, &pci_rev);
 
-	if (pci_enable_device(pdev))
+	io_size = 256;
+	if (pci_rev < VT6102) {
+		quirks = rqRhineI | rqDavicomPhy;
+		io_size = 128;
+		name = "VT86C100A Rhine";
+	}
+	else {
+		quirks = rqWOL | rqForceReset;
+		if (pci_rev < VT6105) {
+			name = "Rhine II";
+			quirks |= rqStatusWBRace;	/* Rhine-II exclusive */
+		}
+		else {
+			name = "Rhine III";
+			if (pci_rev >= VT6105_B0)
+				quirks |= rq6patterns;
+		}
+	}
+
+	rc = pci_enable_device(pdev);
+	if (rc)
 		goto err_out;
 
 	/* this should always be supported */
-	if (pci_set_dma_mask(pdev, 0xffffffff)) {
+	rc = pci_set_dma_mask(pdev, 0xffffffff);
+	if (rc) {
 		printk(KERN_ERR "32-bit PCI DMA addresses not supported by "
 		       "the card!?\n");
 		goto err_out;
@@ -664,6 +703,7 @@
 	/* sanity check */
 	if ((pci_resource_len(pdev, 0) < io_size) ||
 	    (pci_resource_len(pdev, 1) < io_size)) {
+		rc = -EIO;
 		printk(KERN_ERR "Insufficient PCI resources, aborting\n");
 		goto err_out;
 	}
@@ -671,11 +711,11 @@
 	ioaddr = pci_resource_start(pdev, 0);
 	memaddr = pci_resource_start(pdev, 1);
 
-	if (pci_flags & PCI_USES_MASTER)
-		pci_set_master(pdev);
+	pci_set_master(pdev);
 
 	dev = alloc_etherdev(sizeof(*rp));
 	if (dev == NULL) {
+		rc = -ENOMEM;
 		printk(KERN_ERR "init_ethernet failed for card #%d\n",
 		       card_idx);
 		goto err_out;
@@ -683,15 +723,17 @@
 	SET_MODULE_OWNER(dev);
 	SET_NETDEV_DEV(dev, &pdev->dev);
 
-	if (pci_request_regions(pdev, shortname))
+	rc = pci_request_regions(pdev, shortname);
+	if (rc)
 		goto err_out_free_netdev;
 
 #ifdef USE_MMIO
 	ioaddr0 = ioaddr;
-	enable_mmio(ioaddr0, chip_id);
+	enable_mmio(ioaddr0, quirks);
 
 	ioaddr = (long) ioremap(memaddr, io_size);
 	if (!ioaddr) {
+		rc = -EIO;
 		printk(KERN_ERR "ioremap failed for device %s, region 0x%X "
 		       "@ 0x%lX\n", pci_name(pdev), io_size, memaddr);
 		goto err_out_free_res;
@@ -704,36 +746,21 @@
 		unsigned char a = inb(ioaddr0+reg);
 		unsigned char b = readb(ioaddr+reg);
 		if (a != b) {
+			rc = -EIO;
 			printk(KERN_ERR "MMIO do not match PIO [%02x] "
 			       "(%02x != %02x)\n", reg, a, b);
 			goto err_out_unmap;
 		}
 	}
 #endif /* USE_MMIO */
+	dev->base_addr = ioaddr;
 
-	/* D-Link provided reset code (with comment additions) */
-	if (rhine_chip_info[chip_id].drv_flags & HasWOL) {
-		unsigned char byOrgValue;
-
-		/* clear sticky bit before reset & read ethernet address */
-		byOrgValue = readb(ioaddr + StickyHW);
-		byOrgValue = byOrgValue & 0xFC;
-		writeb(byOrgValue, ioaddr + StickyHW);
-
-		/* (bits written are cleared?) */
-		/* disable force PME-enable */
-		writeb(0x80, ioaddr + WOLcgClr);
-		/* disable power-event config bit */
-		writeb(0xFF, ioaddr + WOLcrClr);
-		/* clear power status (undocumented in vt6102 docs?) */
-		writeb(0xFF, ioaddr + PwrcsrClr);
-	}
+	rhine_power_init(dev);
 
 	/* Reset the chip to erase previous misconfiguration. */
 	writew(CmdReset, ioaddr + ChipCmd);
 
-	dev->base_addr = ioaddr;
-	wait_for_reset(dev, chip_id, shortname);
+	wait_for_reset(dev, quirks, shortname);
 
 	/* Reload the station address from the EEPROM. */
 #ifdef USE_MMIO
@@ -741,7 +768,7 @@
 	/* Reloading from eeprom overwrites cfgA-D, so we must re-enable MMIO.
 	   If reload_eeprom() was done first this could be avoided, but it is
 	   not known if that still works with the "win98-reboot" problem. */
-	enable_mmio(ioaddr0, chip_id);
+	enable_mmio(ioaddr0, quirks);
 #else
 	reload_eeprom(ioaddr);
 #endif
@@ -750,11 +777,12 @@
 		dev->dev_addr[i] = readb(ioaddr + StationAddr + i);
 
 	if (!is_valid_ether_addr(dev->dev_addr)) {
+		rc = -EIO;
 		printk(KERN_ERR "Invalid MAC address for card #%d\n", card_idx);
 		goto err_out_unmap;
 	}
 
-	if (chip_id == VT6102) {
+	if (quirks & rqWOL) {
 		/*
 		 * for 3065D, EEPROM reloaded will cause bit 0 in MAC_REG_CFGA
 		 * turned on. it makes MAC receive magic packet
@@ -772,9 +800,8 @@
 
 	rp = netdev_priv(dev);
 	spin_lock_init(&rp->lock);
-	rp->chip_id = chip_id;
-	rp->drv_flags = rhine_chip_info[chip_id].drv_flags;
 	rp->pdev = pdev;
+	rp->quirks = quirks;
 	rp->mii_if.dev = dev;
 	rp->mii_if.mdio_read = mdio_read;
 	rp->mii_if.mdio_write = mdio_write;
@@ -797,19 +824,18 @@
 #ifdef CONFIG_NET_POLL_CONTROLLER
 	dev->poll_controller = rhine_poll;
 #endif
-	if (rp->drv_flags & ReqTxAlign)
+	if (rp->quirks & rqRhineI)
 		dev->features |= NETIF_F_SG|NETIF_F_HW_CSUM;
 
 	/* dev->name not defined before register_netdev()! */
-	i = register_netdev(dev);
-	if (i)
+	rc = register_netdev(dev);
+	if (rc)
 		goto err_out_unmap;
 
 	/* The lower four bits are the media type. */
 	if (option > 0) {
 		if (option & 0x220)
 			rp->mii_if.full_duplex = 1;
-		rp->default_port = option & 15;
 	}
 	if (card_idx < MAX_UNITS && full_duplex[card_idx] > 0)
 		rp->mii_if.full_duplex = 1;
@@ -820,9 +846,14 @@
 		rp->mii_if.force_media = 1;
 	}
 
-	printk(KERN_INFO "%s: %s at 0x%lx, ",
-	       dev->name, rhine_chip_info[chip_id].name,
-	       (pci_flags & PCI_USES_IO) ? ioaddr : memaddr);
+	printk(KERN_INFO "%s: VIA %s at 0x%lx, ",
+	       dev->name, name,
+#ifdef USE_MMIO
+		memaddr
+#else
+		ioaddr
+#endif
+		 );
 
 	for (i = 0; i < 5; i++)
 		printk("%2.2x:", dev->dev_addr[i]);
@@ -830,41 +861,35 @@
 
 	pci_set_drvdata(pdev, dev);
 
-	if (rp->drv_flags & CanHaveMII) {
-		int phy, phy_idx = 0;
-		rp->phys[0] = 1;		/* Standard for this chip. */
-		for (phy = 1; phy < 32 && phy_idx < MAX_MII_CNT; phy++) {
-			int mii_status = mdio_read(dev, phy, 1);
-			if (mii_status != 0xffff && mii_status != 0x0000) {
-				rp->phys[phy_idx++] = phy;
-				rp->mii_if.advertising = mdio_read(dev, phy, 4);
-				printk(KERN_INFO "%s: MII PHY found at address "
-				       "%d, status 0x%4.4x advertising %4.4x "
-				       "Link %4.4x.\n", dev->name, phy,
-				       mii_status, rp->mii_if.advertising,
-				       mdio_read(dev, phy, 5));
-
-				/* set IFF_RUNNING */
-				if (mii_status & BMSR_LSTATUS)
-					netif_carrier_on(dev);
-				else
-					netif_carrier_off(dev);
+	rp->phys[0] = 1;		/* Standard for this chip. */
+	for (phy = 1; phy < 32 && phy_idx < MAX_MII_CNT; phy++) {
+		int mii_status = mdio_read(dev, phy, 1);
+		if (mii_status != 0xffff && mii_status != 0x0000) {
+			rp->phys[phy_idx++] = phy;
+			rp->mii_if.advertising = mdio_read(dev, phy, 4);
+			printk(KERN_INFO "%s: MII PHY found at address "
+			       "%d, status 0x%4.4x advertising %4.4x "
+			       "Link %4.4x.\n", dev->name, phy,
+			       mii_status, rp->mii_if.advertising,
+			       mdio_read(dev, phy, 5));
+
+			/* set IFF_RUNNING */
+			if (mii_status & BMSR_LSTATUS)
+				netif_carrier_on(dev);
+			else
+				netif_carrier_off(dev);
 
-				break;
-			}
+			break;
 		}
-		rp->mii_cnt = phy_idx;
-		rp->mii_if.phy_id = rp->phys[0];
 	}
+	rp->mii_cnt = phy_idx;
+	rp->mii_if.phy_id = rp->phys[0];
 
 	/* Allow forcing the media type. */
 	if (option > 0) {
 		if (option & 0x220)
 			rp->mii_if.full_duplex = 1;
-		rp->default_port = option & 0x3ff;
 		if (option & 0x330) {
-			/* FIXME: shouldn't someone check this variable? */
-			/* rp->medialock = 1; */
 			printk(KERN_INFO " Forcing %dMbs %s-duplex "
 				"operation.\n",
 			       (option & 0x300 ? 100 : 10),
@@ -887,7 +912,7 @@
 err_out_free_netdev:
 	free_netdev(dev);
 err_out:
-	return -ENODEV;
+	return rc;
 }
 
 static int alloc_ring(struct net_device* dev)
@@ -904,7 +929,7 @@
 		printk(KERN_ERR "Could not allocate DMA memory.\n");
 		return -ENOMEM;
 	}
-	if (rp->drv_flags & ReqTxAlign) {
+	if (rp->quirks & rqRhineI) {
 		rp->tx_bufs = pci_alloc_consistent(rp->pdev,
 						   PKT_BUF_SZ * TX_RING_SIZE,
 						   &rp->tx_bufs_dma);
@@ -1063,9 +1088,6 @@
 	rp->rx_thresh = 0x60;		/* Written in rhine_set_rx_mode(). */
 	rp->mii_if.full_duplex = 0;
 
-	if (dev->if_port == 0)
-		dev->if_port = rp->default_port;
-
 	writel(rp->rx_ring_dma, ioaddr + RxRingPtr);
 	writel(rp->tx_ring_dma, ioaddr + TxRingPtr);
 
@@ -1087,9 +1109,8 @@
 
 	/* The LED outputs of various MII xcvrs should be configured. */
 	/* For NS or Mison phys, turn on bit 1 in register 0x17 */
-	/* For ESI phys, turn on bit 7 in register 0x17. */
 	mdio_write(dev, rp->phys[0], 0x17, mdio_read(dev, rp->phys[0], 0x17) |
-		   (rp->drv_flags & HasESIPhy) ? 0x0080 : 0x0001);
+		   0x0001);
 }
 
 /* Read and write over the MII Management Data I/O (MDIO) interface. */
@@ -1166,7 +1187,7 @@
 		return i;
 	alloc_rbufs(dev);
 	alloc_tbufs(dev);
-	wait_for_reset(dev, rp->chip_id, dev->name);
+	wait_for_reset(dev, rp->quirks, dev->name);
 	init_registers(dev);
 	if (debug > 2)
 		printk(KERN_DEBUG "%s: Done rhine_open(), status %4.4x "
@@ -1257,8 +1278,6 @@
 	       dev->name, readw(ioaddr + IntrStatus),
 	       mdio_read(dev, rp->phys[0], MII_BMSR));
 
-	dev->if_port = 0;
-
 	/* protect against concurrent rx interrupts */
 	disable_irq(rp->pdev->irq);
 
@@ -1274,7 +1293,7 @@
 	alloc_rbufs(dev);
 
 	/* Reinitialize the hardware. */
-	wait_for_reset(dev, rp->chip_id, dev->name);
+	wait_for_reset(dev, rp->quirks, dev->name);
 	init_registers(dev);
 
 	spin_unlock(&rp->lock);
@@ -1305,7 +1324,7 @@
 
 	rp->tx_skbuff[entry] = skb;
 
-	if ((rp->drv_flags & ReqTxAlign) &&
+	if ((rp->quirks & rqRhineI) &&
 	    (((long)skb->data & 3) || skb_shinfo(skb)->nr_frags != 0 || skb->ip_summed == CHECKSUM_HW)) {
 		/* Must use alignment buffer. */
 		if (skb->len > PKT_BUF_SZ) {
@@ -1454,7 +1473,7 @@
 			if (txstatus & 0x0200) rp->stats.tx_window_errors++;
 			if (txstatus & 0x0100) rp->stats.tx_aborted_errors++;
 			if (txstatus & 0x0080) rp->stats.tx_heartbeat_errors++;
-			if (((rp->chip_id == VT86C100A) && txstatus & 0x0002) ||
+			if (((rp->quirks & rqRhineI) && txstatus & 0x0002) ||
 			    (txstatus & 0x0800) || (txstatus & 0x1000)) {
 				rp->stats.tx_fifo_errors++;
 				rp->tx_ring[entry].tx_status = cpu_to_le32(DescOwn);
@@ -1462,7 +1481,7 @@
 			}
 			/* Transmitter restarted in 'abnormal' handler. */
 		} else {
-			if (rp->chip_id == VT86C100A)
+			if (rp->quirks & rqRhineI)
 				rp->stats.collisions += (txstatus >> 3) & 0x0F;
 			else
 				rp->stats.collisions += txstatus & 0x0F;
@@ -1563,15 +1582,10 @@
 				   eth_copy_and_sum is memcpy for all archs so
 				   this is kind of pointless right now
 				   ... or? */
-#if HAS_IP_COPYSUM		/* Call copy + cksum if available. */
 				eth_copy_and_sum(skb,
 						 rp->rx_skbuff[entry]->tail,
 						 pkt_len, 0);
 				skb_put(skb, pkt_len);
-#else
-				memcpy(skb_put(skb, pkt_len),
-				       rp->rx_skbuff[entry]->tail, pkt_len);
-#endif
 				pci_dma_sync_single_for_device(rp->pdev,
 							       rp->rx_skbuff_dma[entry],
 							       rp->rx_buf_sz,
@@ -1679,7 +1693,7 @@
 	if (intr_status & (IntrLinkChange)) {
 		if (readb(ioaddr + MIIStatus) & 0x02) {
 			/* Link failed, restart autonegotiation. */
-			if (rp->drv_flags & HasDavicomPhy)
+			if (rp->quirks & rqRhineI)
 				mdio_write(dev, rp->phys[0], MII_BMCR, 0x3300);
 		} else
 			rhine_check_duplex(dev);
@@ -1805,9 +1819,6 @@
 	struct rhine_private *rp = netdev_priv(dev);
 	int rc;
 
-	if (!(rp->drv_flags & CanHaveMII))
-		return -EINVAL;
-
 	spin_lock_irq(&rp->lock);
 	rc = mii_ethtool_gset(&rp->mii_if, cmd);
 	spin_unlock_irq(&rp->lock);
@@ -1820,9 +1831,6 @@
 	struct rhine_private *rp = netdev_priv(dev);
 	int rc;
 
-	if (!(rp->drv_flags & CanHaveMII))
-		return -EINVAL;
-
 	spin_lock_irq(&rp->lock);
 	rc = mii_ethtool_sset(&rp->mii_if, cmd);
 	spin_unlock_irq(&rp->lock);
@@ -1834,9 +1842,6 @@
 {
 	struct rhine_private *rp = netdev_priv(dev);
 
-	if (!(rp->drv_flags & CanHaveMII))
-		return -EINVAL;
-
 	return mii_nway_restart(&rp->mii_if);
 }
 
@@ -1844,9 +1849,6 @@
 {
 	struct rhine_private *rp = netdev_priv(dev);
 
-	if (!(rp->drv_flags & CanHaveMII))
-		return 0;	/* -EINVAL */
-
 	return mii_link_ok(&rp->mii_if);
 }
 
--- diff/drivers/net/wan/Kconfig	2004-06-11 19:17:30.000000000 +0100
+++ source/drivers/net/wan/Kconfig	2004-06-11 19:22:03.000000000 +0100
@@ -248,7 +248,7 @@
 
 config WANXL_BUILD_FIRMWARE
 	bool "rebuild wanXL firmware"
-	depends on WANXL
+	depends on WANXL && M68K_TOOLCHAIN
 	help
 	  Allows you to rebuild firmware run by the QUICC processor.
 	  It requires as68k, ld68k and hexdump programs.
--- diff/drivers/net/wd.c	2004-05-19 22:11:56.000000000 +0100
+++ source/drivers/net/wd.c	2004-06-11 19:22:03.000000000 +0100
@@ -43,6 +43,8 @@
 
 #include "8390.h"
 
+#define DRV_NAME "wd"
+
 /* A zero-terminated list of I/O addresses to be probed. */
 static unsigned int wd_portlist[] __initdata =
 {0x300, 0x280, 0x380, 0x240, 0};
@@ -131,6 +133,7 @@
 	release_region(dev->base_addr - WD_NIC_OFFSET, WD_IO_EXTENT);
 }
 
+#ifndef MODULE
 struct net_device * __init wd_probe(int unit)
 {
 	struct net_device *dev = alloc_ei_netdev();
@@ -155,6 +158,7 @@
 	free_netdev(dev);
 	return ERR_PTR(err);
 }
+#endif
 
 static int __init wd_probe1(struct net_device *dev, int ioaddr)
 {
@@ -300,7 +304,7 @@
 
 	/* Snarf the interrupt now.  There's no point in waiting since we cannot
 	   share and the board will usually be enabled. */
-	i = request_irq(dev->irq, ei_interrupt, 0, dev->name, dev);
+	i = request_irq(dev->irq, ei_interrupt, 0, DRV_NAME, dev);
 	if (i) {
 		printk (" unable to get IRQ %d.\n", dev->irq);
 		return i;
--- diff/drivers/net/yellowfin.c	2004-06-11 19:17:30.000000000 +0100
+++ source/drivers/net/yellowfin.c	2004-06-11 19:22:03.000000000 +0100
@@ -448,7 +448,7 @@
 
 	np = dev->priv;
 
-	if (pci_request_regions(pdev, dev->name))
+	if (pci_request_regions(pdev, DRV_NAME))
 		goto err_out_free_netdev;
 
 	pci_set_master (pdev);
@@ -1201,13 +1201,8 @@
 					break;
 				skb->dev = dev;
 				skb_reserve(skb, 2);	/* 16 byte align the IP header */
-#if HAS_IP_COPYSUM
 				eth_copy_and_sum(skb, rx_skb->tail, pkt_len, 0);
 				skb_put(skb, pkt_len);
-#else
-				memcpy(skb_put(skb, pkt_len), 
-					rx_skb->tail, pkt_len);
-#endif
 				pci_dma_sync_single_for_device(yp->pci_dev, desc->addr,
 											   yp->rx_buf_sz,
 											   PCI_DMA_FROMDEVICE);
--- diff/drivers/net/zorro8390.c	2004-05-19 22:11:56.000000000 +0100
+++ source/drivers/net/zorro8390.c	2004-06-11 19:22:03.000000000 +0100
@@ -36,6 +36,8 @@
 #include "8390.h"
 
 
+#define DRV_NAME	"zorro8390"
+
 #define NE_BASE		(dev->base_addr)
 #define NE_CMD		(0x00*2)
 #define NE_DATAPORT	(0x10*2)	/* NatSemi-defined port window offset. */
@@ -115,7 +117,7 @@
     if (!dev)
 	return -ENOMEM;
     SET_MODULE_OWNER(dev);
-    if (!request_mem_region(ioaddr, NE_IO_EXTENT*2, dev->name)) {
+    if (!request_mem_region(ioaddr, NE_IO_EXTENT*2, DRV_NAME)) {
 	free_netdev(dev);
 	return -EBUSY;
     }
@@ -198,7 +200,7 @@
     dev->irq = IRQ_AMIGA_PORTS;
 
     /* Install the Interrupt handler */
-    i = request_irq(IRQ_AMIGA_PORTS, ei_interrupt, SA_SHIRQ, dev->name, dev);
+    i = request_irq(IRQ_AMIGA_PORTS, ei_interrupt, SA_SHIRQ, DRV_NAME, dev);
     if (i) return i;
 
     for(i = 0; i < ETHER_ADDR_LEN; i++) {
--- diff/drivers/parisc/ccio-dma.c	2004-05-19 22:12:02.000000000 +0100
+++ source/drivers/parisc/ccio-dma.c	2004-06-11 19:22:03.000000000 +0100
@@ -44,7 +44,6 @@
 #include <asm/byteorder.h>
 #include <asm/cache.h>		/* for L1_CACHE_BYTES */
 #include <asm/uaccess.h>
-#include <asm/pgalloc.h>
 #include <asm/page.h>
 #include <asm/dma.h>
 #include <asm/io.h>
--- diff/drivers/parisc/ccio-rm-dma.c	2004-05-19 22:12:02.000000000 +0100
+++ source/drivers/parisc/ccio-rm-dma.c	2004-06-11 19:22:03.000000000 +0100
@@ -40,7 +40,6 @@
 #include <linux/pci.h>
 
 #include <asm/uaccess.h>
-#include <asm/pgalloc.h>
 
 #include <asm/io.h>
 #include <asm/hardware.h>
--- diff/drivers/pci/Kconfig	2004-05-19 22:12:02.000000000 +0100
+++ source/drivers/pci/Kconfig	2004-06-11 19:22:03.000000000 +0100
@@ -3,7 +3,7 @@
 #
 config PCI_USE_VECTOR
 	bool "Vector-based interrupt indexing (MSI)"
-	depends on (X86_LOCAL_APIC && X86_IO_APIC && !X86_64) || IA64
+	depends on (X86_LOCAL_APIC && X86_IO_APIC) || IA64
 	default n
 	help
 	   This replaces the current existing IRQ-based index interrupt scheme
--- diff/drivers/pci/hotplug/pciehp_ctrl.c	2004-06-11 19:17:30.000000000 +0100
+++ source/drivers/pci/hotplug/pciehp_ctrl.c	2004-06-11 19:22:03.000000000 +0100
@@ -1058,6 +1058,34 @@
    hotplug controller logic
  */
 
+static void set_slot_off(struct controller *ctrl, struct slot * pslot)
+{
+	/* Wait for exclusive access to hardware */
+	down(&ctrl->crit_sect);
+
+	/* turn off slot, turn on Amber LED, turn off Green LED */
+	if (pslot->hpc_ops->power_off_slot(pslot)) {   
+		err("%s: Issue of Slot Power Off command failed\n", __FUNCTION__);
+		up(&ctrl->crit_sect);
+		return;
+	}
+	wait_for_ctrl_irq (ctrl);
+
+	pslot->hpc_ops->green_led_off(pslot);   
+	
+	wait_for_ctrl_irq (ctrl);
+
+	/* turn on Amber LED */
+	if (pslot->hpc_ops->set_attention_status(pslot, 1)) {   
+		err("%s: Issue of Set Attention Led command failed\n", __FUNCTION__);
+		up(&ctrl->crit_sect);
+		return;
+	}
+	wait_for_ctrl_irq (ctrl);
+
+	/* Done with exclusive hardware access */
+	up(&ctrl->crit_sect);
+}
 
 /**
  * board_added - Called after a board has been added to the system.
@@ -1071,7 +1099,7 @@
 	u8 hp_slot;
 	int index;
 	u32 temp_register = 0xFFFFFFFF;
-	u32 retval, rc = 0;
+	u32 rc = 0;
 	struct pci_func *new_func = NULL;
 	struct slot *p_slot;
 	struct resource_lists res_lists;
@@ -1086,8 +1114,10 @@
 
 	/* Power on slot */
 	rc = p_slot->hpc_ops->power_on_slot(p_slot);
-	if (rc)
+	if (rc) {
+		up(&ctrl->crit_sect);
 		return -1;
+	}
 
 	/* Wait for the command to complete */
 	wait_for_ctrl_irq (ctrl);
@@ -1105,11 +1135,12 @@
 	wait_for_ctrl_irq (ctrl);
 	dbg("%s: afterlong_delay\n", __FUNCTION__);
 
-	/*  Make this to check for link training status */
+	/*  Check link training status */
 	rc = p_slot->hpc_ops->check_lnk_status(ctrl);  
 	if (rc) {
 		err("%s: Failed to check link status\n", __FUNCTION__);
-		return -1;
+		set_slot_off(ctrl, p_slot);
+		return rc;
 	}
 
 	dbg("%s: func status = %x\n", __FUNCTION__, func->status);
@@ -1159,36 +1190,7 @@
 		pciehp_resource_sort_and_combine(&(ctrl->bus_head));
 
 		if (rc) {
-			/* Wait for exclusive access to hardware */
-			down(&ctrl->crit_sect);
-
-			/* turn off slot, turn on Amber LED, turn off Green LED */
-			retval = p_slot->hpc_ops->power_off_slot(p_slot);   
-			/* In PCI Express, just power off slot */
-			if (retval) {
-				err("%s: Issue of Slot Power Off command failed\n", __FUNCTION__);
-				return retval;
-			}
-			/* Wait for the command to complete */
-			wait_for_ctrl_irq (ctrl);
-
-			p_slot->hpc_ops->green_led_off(p_slot);   
-			
-			/* Wait for the command to complete */
-			wait_for_ctrl_irq (ctrl);
-
-			/* turn on Amber LED */
-			retval = p_slot->hpc_ops->set_attention_status(p_slot, 1);   
-			if (retval) {
-				err("%s: Issue of Set Attention Led command failed\n", __FUNCTION__);
-				return retval;
-			}
-			/* Wait for the command to complete */
-			wait_for_ctrl_irq (ctrl);
-
-			/* Done with exclusive hardware access */
-			up(&ctrl->crit_sect);
-
+			set_slot_off(ctrl, p_slot);
 			return rc;
 		}
 		pciehp_save_slot_config(ctrl, func);
@@ -1223,37 +1225,8 @@
 		up(&ctrl->crit_sect);
 
 	} else {
-		/* Wait for exclusive access to hardware */
-		down(&ctrl->crit_sect);
-
-		/* turn off slot, turn on Amber LED, turn off Green LED */
-		retval = p_slot->hpc_ops->power_off_slot(p_slot);   
-		/* In PCI Express, just power off slot */
-		if (retval) {
-			err("%s: Issue of Slot Power Off command failed\n", __FUNCTION__);
-			return retval;
-		}
-		/* Wait for the command to complete */
-		wait_for_ctrl_irq (ctrl);
-
-		p_slot->hpc_ops->green_led_off(p_slot);   
-		
-		/* Wait for the command to complete */
-		wait_for_ctrl_irq (ctrl);
-
-		/* turn on Amber LED */
-		retval = p_slot->hpc_ops->set_attention_status(p_slot, 1);   
-		if (retval) {
-			err("%s: Issue of Set Attention Led command failed\n", __FUNCTION__);
-			return retval;
-		}
-		/* Wait for the command to complete */
-		wait_for_ctrl_irq (ctrl);
-
-		/* Done with exclusive hardware access */
-		up(&ctrl->crit_sect);
-
-		return rc;
+		set_slot_off(ctrl, p_slot);
+		return -1;
 	}
 	return 0;
 }
@@ -1320,6 +1293,7 @@
 	rc = p_slot->hpc_ops->power_off_slot(p_slot);
 	if (rc) {
 		err("%s: Issue of Slot Disable command failed\n", __FUNCTION__);
+		up(&ctrl->crit_sect);
 		return rc;
 	}
 	/* Wait for the command to complete */
@@ -1406,7 +1380,6 @@
 {
 	struct slot *p_slot = (struct slot *) slot;
 	u8 getstatus;
-	int rc;
 	
 	pushbutton_pending = 0;
 
@@ -1420,23 +1393,7 @@
 		p_slot->state = POWEROFF_STATE;
 		dbg("In power_down_board, b:d(%x:%x)\n", p_slot->bus, p_slot->device);
 
-		if (pciehp_disable_slot(p_slot)) {
-			/* Wait for exclusive access to hardware */
-			down(&p_slot->ctrl->crit_sect);
-
-			/* Turn on the Attention LED */
-			rc = p_slot->hpc_ops->set_attention_status(p_slot, 1);
-			if (rc) {
-				err("%s: Issue of Set Atten Indicator On command failed\n", __FUNCTION__);
-				return;
-			}
-	
-			/* Wait for the command to complete */
-			wait_for_ctrl_irq (p_slot->ctrl);
-
-			/* Done with exclusive hardware access */
-			up(&p_slot->ctrl->crit_sect);
-		}
+		pciehp_disable_slot(p_slot);
 		p_slot->state = STATIC_STATE;
 	} else {
 		p_slot->state = POWERON_STATE;
@@ -1446,15 +1403,6 @@
 			/* Wait for exclusive access to hardware */
 			down(&p_slot->ctrl->crit_sect);
 
-			/* Turn off the green LED */
-			rc = p_slot->hpc_ops->set_attention_status(p_slot, 1);
-			if (rc) {
-				err("%s: Issue of Set Atten Indicator On command failed\n", __FUNCTION__);
-				return;
-			}
-			/* Wait for the command to complete */
-			wait_for_ctrl_irq (p_slot->ctrl);
-			
 			p_slot->hpc_ops->green_led_off(p_slot);
 
 			/* Wait for the command to complete */
@@ -1664,7 +1612,10 @@
 					down(&ctrl->crit_sect);
 
 					p_slot->hpc_ops->set_attention_status(p_slot, 1);
+					wait_for_ctrl_irq (ctrl);
+						
 					p_slot->hpc_ops->green_led_off(p_slot);
+					wait_for_ctrl_irq (ctrl);
 
 					/* Done with exclusive hardware access */
 					up(&ctrl->crit_sect);
@@ -1701,21 +1652,21 @@
 	if (rc || !getstatus) {
 		info("%s: no adapter on slot(%x)\n", __FUNCTION__, p_slot->number);
 		up(&p_slot->ctrl->crit_sect);
-		return 0;
+		return 1;
 	}
 	
 	rc = p_slot->hpc_ops->get_latch_status(p_slot, &getstatus);
 	if (rc || getstatus) {
 		info("%s: latch open on slot(%x)\n", __FUNCTION__, p_slot->number);
 		up(&p_slot->ctrl->crit_sect);
-		return 0;
+		return 1;
 	}
 	
 	rc = p_slot->hpc_ops->get_power_status(p_slot, &getstatus);
 	if (rc || getstatus) {
 		info("%s: already enabled on slot(%x)\n", __FUNCTION__, p_slot->number);
 		up(&p_slot->ctrl->crit_sect);
-		return 0;
+		return 1;
 	}
 	up(&p_slot->ctrl->crit_sect);
 
@@ -1788,21 +1739,21 @@
 	if (ret || !getstatus) {
 		info("%s: no adapter on slot(%x)\n", __FUNCTION__, p_slot->number);
 		up(&p_slot->ctrl->crit_sect);
-		return 0;
+		return 1;
 	}
 
 	ret = p_slot->hpc_ops->get_latch_status(p_slot, &getstatus);
 	if (ret || getstatus) {
 		info("%s: latch open on slot(%x)\n", __FUNCTION__, p_slot->number);
 		up(&p_slot->ctrl->crit_sect);
-		return 0;
+		return 1;
 	}
 
 	ret = p_slot->hpc_ops->get_power_status(p_slot, &getstatus);
 	if (ret || !getstatus) {
 		info("%s: already disabled slot(%x)\n", __FUNCTION__, p_slot->number);
 		up(&p_slot->ctrl->crit_sect);
-		return 0;
+		return 1;
 	}
 	up(&p_slot->ctrl->crit_sect);
 
--- diff/drivers/pci/hotplug/pciehp_hpc.c	2004-06-11 19:17:30.000000000 +0100
+++ source/drivers/pci/hotplug/pciehp_hpc.c	2004-06-11 19:22:03.000000000 +0100
@@ -349,7 +349,9 @@
 		return retval;
 	}
 
-	if ( (lnk_status & (LNK_TRN | LNK_TRN_ERR)) == 0x0C00) {
+	dbg("%s: lnk_status = %x\n", __FUNCTION__, lnk_status);
+	if ( (lnk_status & LNK_TRN) || (lnk_status & LNK_TRN_ERR) || 
+		!(lnk_status & NEG_LINK_WD)) {
 		err("%s : Link Training Error occurs \n", __FUNCTION__);
 		retval = -1;
 		return retval;
--- diff/drivers/pci/hotplug/pciehprm_acpi.c	2004-06-11 19:17:30.000000000 +0100
+++ source/drivers/pci/hotplug/pciehprm_acpi.c	2004-06-11 19:22:03.000000000 +0100
@@ -218,6 +218,10 @@
 	}
 
 	ab->_hpp = kmalloc (sizeof (struct acpi__hpp), GFP_KERNEL);
+	if (!ab->_hpp) {
+		err ("acpi_pciehprm:%s alloc for _HPP failed\n", path_name);
+		goto free_and_return;
+	}
 	memset(ab->_hpp, 0, sizeof(struct acpi__hpp));
 
 	ab->_hpp->cache_line_size	= nui[0];
@@ -1393,7 +1397,7 @@
 
 static int bind_pci_resources_to_slots ( struct controller *ctrl)
 {
-	struct pci_func *func;
+	struct pci_func *func, new_func;
 	int busn = ctrl->slot_bus;
 	int devn, funn;
 	u32	vid;
@@ -1411,11 +1415,19 @@
 			if (vid != 0xFFFFFFFF) {
 				dbg("%s: vid = %x\n", __FUNCTION__, vid);
 				func = pciehp_slot_find(busn, devn, funn);
-				if (!func)
-					continue;
-				configure_existing_function(ctrl, func);
+				if (!func) {
+					memset(&new_func, 0, sizeof(struct pci_func));
+					new_func.bus = busn;
+					new_func.device = devn;
+					new_func.function = funn;
+					new_func.is_a_board = 1;
+					configure_existing_function(ctrl, &new_func);
+					pciehprm_dump_func_res(&new_func);
+				} else {
+					configure_existing_function(ctrl, func);
+					pciehprm_dump_func_res(func);
+				}
 				dbg("aCCF:existing PCI 0x%x Func ResourceDump\n", ctrl->bus);
-				pciehprm_dump_func_res(func);
 			}
 		}
 	}
--- diff/drivers/pci/hotplug/pciehprm_nonacpi.c	2004-06-11 19:17:30.000000000 +0100
+++ source/drivers/pci/hotplug/pciehprm_nonacpi.c	2004-06-11 19:22:03.000000000 +0100
@@ -276,7 +276,7 @@
 
 static int bind_pci_resources_to_slots ( struct controller *ctrl)
 {
-	struct pci_func *func;
+	struct pci_func *func, new_func;
 	int busn = ctrl->slot_bus;
 	int devn, funn;
 	u32	vid;
@@ -297,11 +297,19 @@
 				vid, busn, devn, funn);
 				func = pciehp_slot_find(busn, devn, funn);
 				dbg("%s: func = %p\n", __FUNCTION__,func);
-				if (!func)
-					continue;
-				configure_existing_function(ctrl, func);
+				if (!func) {
+					memset(&new_func, 0, sizeof(struct pci_func));
+					new_func.bus = busn;
+					new_func.device = devn;
+					new_func.function = funn;
+					new_func.is_a_board = 1;
+					configure_existing_function(ctrl, &new_func);
+					phprm_dump_func_res(&new_func);
+				} else {
+					configure_existing_function(ctrl, func);
+					phprm_dump_func_res(func);
+				}
 				dbg("aCCF:existing PCI 0x%x Func ResourceDump\n", ctrl->bus);
-				phprm_dump_func_res(func);
 			}
 		}
 	}
--- diff/drivers/pci/hotplug/shpchp.h	2004-06-11 19:17:30.000000000 +0100
+++ source/drivers/pci/hotplug/shpchp.h	2004-06-11 19:22:03.000000000 +0100
@@ -61,6 +61,7 @@
 	u8 configured;
 	u8 switch_save;
 	u8 presence_save;
+	u8 pwr_save;
 	u32 base_length[0x06];
 	u8 base_type[0x06];
 	u16 reserved2;
--- diff/drivers/pci/hotplug/shpchp_ctrl.c	2004-06-11 19:17:30.000000000 +0100
+++ source/drivers/pci/hotplug/shpchp_ctrl.c	2004-06-11 19:22:03.000000000 +0100
@@ -137,6 +137,8 @@
 	p_slot = shpchp_find_slot(ctrl, hp_slot + ctrl->slot_device_offset);
 	p_slot->hpc_ops->get_adapter_status(p_slot, &(func->presence_save));
 	p_slot->hpc_ops->get_latch_status(p_slot, &getstatus);
+	dbg("%s: Card present %x Power status %x\n", __FUNCTION__,
+		func->presence_save, func->pwr_save);
 
 	if (getstatus) {
 		/*
@@ -145,6 +147,10 @@
 		info("Latch open on Slot(%d)\n", ctrl->first_slot + hp_slot);
 		func->switch_save = 0;
 		taskInfo->event_type = INT_SWITCH_OPEN;
+		if (func->pwr_save && func->presence_save) {
+			taskInfo->event_type = INT_POWER_FAULT;
+			err("Surprise Removal of card\n");
+		}
 	} else {
 		/*
 		 *  Switch closed
@@ -1427,6 +1433,7 @@
 					rc = p_slot->hpc_ops->set_bus_speed_mode(p_slot, adapter_speed);
 					if (rc) {
 						err("%s: Issue of set bus speed mode command failed\n", __FUNCTION__);
+						up(&ctrl->crit_sect);
 						return WRONG_BUS_FREQUENCY;
 					}
 				
@@ -1438,6 +1445,7 @@
 						err("%s: Can't set bus speed/mode in the case of adapter & bus mismatch\n",
 								  __FUNCTION__);
 						err("%s: Error code (%d)\n", __FUNCTION__, rc);
+						up(&ctrl->crit_sect);
 						return WRONG_BUS_FREQUENCY;
 					}
 					/* Done with exclusive hardware access */
@@ -1589,8 +1597,9 @@
 		func->status = 0;
 		func->switch_save = 0x10;
 		func->is_a_board = 0x01;
+		func->pwr_save = 1;
 
-		/* next, we will instantiate the linux pci_dev structures 
+		/* Next, we will instantiate the linux pci_dev structures 
 		 * (with appropriate driver notification, if already present) 
 		 */
 		index = 0;
@@ -1781,6 +1790,7 @@
 		func->function = 0;
 		func->configured = 0;
 		func->switch_save = 0x10;
+		func->pwr_save = 0;
 		func->is_a_board = 0;
 	}
 
@@ -1807,7 +1817,6 @@
 {
 	struct slot *p_slot = (struct slot *) slot;
 	u8 getstatus;
-	int rc;
 	
 	pushbutton_pending = 0;
 
@@ -1821,23 +1830,7 @@
 		p_slot->state = POWEROFF_STATE;
 		dbg("In power_down_board, b:d(%x:%x)\n", p_slot->bus, p_slot->device);
 
-		if (shpchp_disable_slot(p_slot)) {
-			/* Wait for exclusive access to hardware */
-			down(&p_slot->ctrl->crit_sect);
-
-			/* Turn on the Attention LED */
-			rc = p_slot->hpc_ops->set_attention_status(p_slot, 1);
-			if (rc) {
-				err("%s: Issue of Set Atten Indicator On command failed\n", __FUNCTION__);
-				return;
-			}
-	
-			/* Wait for the command to complete */
-			wait_for_ctrl_irq (p_slot->ctrl);
-
-			/* Done with exclusive hardware access */
-			up(&p_slot->ctrl->crit_sect);
-		}
+		shpchp_disable_slot(p_slot);
 		p_slot->state = STATIC_STATE;
 	} else {
 		p_slot->state = POWERON_STATE;
@@ -1847,15 +1840,6 @@
 			/* Wait for exclusive access to hardware */
 			down(&p_slot->ctrl->crit_sect);
 
-			/* Turn off the green LED */
-			rc = p_slot->hpc_ops->set_attention_status(p_slot, 1);
-			if (rc) {
-				err("%s: Issue of Set Atten Indicator On command failed\n", __FUNCTION__);
-				return;
-			}
-			/* Wait for the command to complete */
-			wait_for_ctrl_irq (p_slot->ctrl);
-			
 			p_slot->hpc_ops->green_led_off(p_slot);
 
 			/* Wait for the command to complete */
@@ -2096,7 +2080,7 @@
 	func = shpchp_slot_find(p_slot->bus, p_slot->device, 0);
 	if (!func) {
 		dbg("%s: Error! slot NULL\n", __FUNCTION__);
-		return (1);
+		return 1;
 	}
 
 	/* Check to see if (latch closed, card present, power off) */
@@ -2105,19 +2089,19 @@
 	if (rc || !getstatus) {
 		info("%s: no adapter on slot(%x)\n", __FUNCTION__, p_slot->number);
 		up(&p_slot->ctrl->crit_sect);
-		return (0);
+		return 1;
 	}
 	rc = p_slot->hpc_ops->get_latch_status(p_slot, &getstatus);
 	if (rc || getstatus) {
 		info("%s: latch open on slot(%x)\n", __FUNCTION__, p_slot->number);
 		up(&p_slot->ctrl->crit_sect);
-		return (0);
+		return 1;
 	}
 	rc = p_slot->hpc_ops->get_power_status(p_slot, &getstatus);
 	if (rc || getstatus) {
 		info("%s: already enabled on slot(%x)\n", __FUNCTION__, p_slot->number);
 		up(&p_slot->ctrl->crit_sect);
-		return (0);
+		return 1;
 	}
 	up(&p_slot->ctrl->crit_sect);
 
@@ -2125,7 +2109,7 @@
 
 	func = shpchp_slot_create(p_slot->bus);
 	if (func == NULL)
-		return (1);
+		return 1;
 
 	func->bus = p_slot->bus;
 	func->device = p_slot->device;
@@ -2135,6 +2119,8 @@
 
 	/* We have to save the presence info for these slots */
 	p_slot->hpc_ops->get_adapter_status(p_slot, &(func->presence_save));
+	p_slot->hpc_ops->get_power_status(p_slot, &(func->pwr_save));
+	dbg("%s: func->pwr_save %x\n", __FUNCTION__, func->pwr_save);
 	p_slot->hpc_ops->get_latch_status(p_slot, &getstatus);
 	func->switch_save = !getstatus? 0x10:0;
 
@@ -2181,7 +2167,7 @@
 	struct pci_func *func;
 
 	if (!p_slot->ctrl)
-		return (1);
+		return 1;
 
 	/* Check to see if (latch closed, card present, power on) */
 	down(&p_slot->ctrl->crit_sect);
@@ -2190,19 +2176,19 @@
 	if (ret || !getstatus) {
 		info("%s: no adapter on slot(%x)\n", __FUNCTION__, p_slot->number);
 		up(&p_slot->ctrl->crit_sect);
-		return (0);
+		return 1;
 	}
 	ret = p_slot->hpc_ops->get_latch_status(p_slot, &getstatus);
 	if (ret || getstatus) {
 		info("%s: latch open on slot(%x)\n", __FUNCTION__, p_slot->number);
 		up(&p_slot->ctrl->crit_sect);
-		return (0);
+		return 1;
 	}
 	ret = p_slot->hpc_ops->get_power_status(p_slot, &getstatus);
 	if (ret || !getstatus) {
 		info("%s: already disabled slot(%x)\n", __FUNCTION__, p_slot->number);
 		up(&p_slot->ctrl->crit_sect);
-		return (0);
+		return 1;
 	}
 	up(&p_slot->ctrl->crit_sect);
 
--- diff/drivers/pci/hotplug/shpchp_pci.c	2004-06-11 19:17:30.000000000 +0100
+++ source/drivers/pci/hotplug/shpchp_pci.c	2004-06-11 19:22:03.000000000 +0100
@@ -263,6 +263,7 @@
 				new_slot->function = (u8) function;
 				new_slot->is_a_board = 1;
 				new_slot->switch_save = 0x10;
+				new_slot->pwr_save = 1;
 				/* In case of unsupported board */
 				new_slot->status = DevError;
 				new_slot->pci_dev = pci_find_slot(new_slot->bus,
--- diff/drivers/pci/hotplug/shpchprm_acpi.c	2004-06-11 19:17:30.000000000 +0100
+++ source/drivers/pci/hotplug/shpchprm_acpi.c	2004-06-11 19:22:03.000000000 +0100
@@ -218,6 +218,10 @@
 	}
 
 	ab->_hpp = kmalloc (sizeof (struct acpi__hpp), GFP_KERNEL);
+	if (!ab->_hpp) {
+		err ("acpi_shpchprm:%s alloc for _HPP failed\n", path_name);
+		goto free_and_return;
+	}
 	memset(ab->_hpp, 0, sizeof(struct acpi__hpp));
 
 	ab->_hpp->cache_line_size	= nui[0];
@@ -1391,7 +1395,7 @@
 
 static int bind_pci_resources_to_slots ( struct controller *ctrl)
 {
-	struct pci_func *func;
+	struct pci_func *func, new_func;
 	int busn = ctrl->bus;
 	int devn, funn;
 	u32	vid;
@@ -1406,11 +1410,19 @@
 
 			if (vid != 0xFFFFFFFF) {
 				func = shpchp_slot_find(busn, devn, funn);
-				if (!func)
-					continue;
-				configure_existing_function(ctrl, func);
+				if (!func) {
+					memset(&new_func, 0, sizeof(struct pci_func));
+					new_func.bus = busn;
+					new_func.device = devn;
+					new_func.function = funn;
+					new_func.is_a_board = 1;
+					configure_existing_function(ctrl, &new_func);
+					shpchprm_dump_func_res(&new_func);
+				} else {
+					configure_existing_function(ctrl, func);
+					shpchprm_dump_func_res(func);
+				}
 				dbg("aCCF:existing PCI 0x%x Func ResourceDump\n", ctrl->bus);
-				shpchprm_dump_func_res(func);
 			}
 		}
 	}
--- diff/drivers/pci/hotplug/shpchprm_nonacpi.c	2004-06-11 19:17:30.000000000 +0100
+++ source/drivers/pci/hotplug/shpchprm_nonacpi.c	2004-06-11 19:22:03.000000000 +0100
@@ -208,7 +208,7 @@
 
 static int bind_pci_resources_to_slots ( struct controller *ctrl)
 {
-	struct pci_func *func;
+	struct pci_func *func, new_func;
 	int busn = ctrl->slot_bus;
 	int devn, funn;
 	u32	vid;
@@ -226,11 +226,19 @@
 
 			if (vid != 0xFFFFFFFF) {
 				func = shpchp_slot_find(busn, devn, funn);
-				if (!func)
-					continue;
-				configure_existing_function(ctrl, func);
+				if (!func) {
+					memset(&new_func, 0, sizeof(struct pci_func));
+					new_func.bus = busn;
+					new_func.device = devn;
+					new_func.function = funn;
+					new_func.is_a_board = 1;
+					configure_existing_function(ctrl, &new_func);
+					phprm_dump_func_res(&new_func);
+				} else {
+					configure_existing_function(ctrl, func);
+					phprm_dump_func_res(func);
+				}
 				dbg("aCCF:existing PCI 0x%x Func ResourceDump\n", ctrl->bus);
-				phprm_dump_func_res(func);
 			}
 		}
 	}
--- diff/drivers/pci/pci-driver.c	2004-06-11 19:17:30.000000000 +0100
+++ source/drivers/pci/pci-driver.c	2004-06-11 19:22:03.000000000 +0100
@@ -539,6 +539,7 @@
 	.hotplug	= pci_hotplug,
 	.suspend	= pci_device_suspend,
 	.resume		= pci_device_resume,
+	.dev_attrs	= pci_dev_attrs,
 };
 
 static int __init pci_driver_init(void)
--- diff/drivers/pci/pci-sysfs.c	2004-05-19 22:12:02.000000000 +0100
+++ source/drivers/pci/pci-sysfs.c	2004-06-11 19:22:03.000000000 +0100
@@ -23,14 +23,13 @@
 /* show configuration fields */
 #define pci_config_attr(field, format_string)				\
 static ssize_t								\
-show_##field (struct device *dev, char *buf)				\
+field##_show(struct device *dev, char *buf)				\
 {									\
 	struct pci_dev *pdev;						\
 									\
 	pdev = to_pci_dev (dev);					\
 	return sprintf (buf, format_string, pdev->field);		\
-}									\
-static DEVICE_ATTR(field, S_IRUGO, show_##field, NULL);
+}
 
 pci_config_attr(vendor, "0x%04x\n");
 pci_config_attr(device, "0x%04x\n");
@@ -41,7 +40,7 @@
 
 /* show resources */
 static ssize_t
-pci_show_resources(struct device * dev, char * buf)
+resource_show(struct device * dev, char * buf)
 {
 	struct pci_dev * pci_dev = to_pci_dev(dev);
 	char * str = buf;
@@ -60,7 +59,16 @@
 	return (str - buf);
 }
 
-static DEVICE_ATTR(resource,S_IRUGO,pci_show_resources,NULL);
+struct device_attribute pci_dev_attrs[] = {
+	__ATTR_RO(resource),
+	__ATTR_RO(vendor),
+	__ATTR_RO(device),
+	__ATTR_RO(subsystem_vendor),
+	__ATTR_RO(subsystem_device),
+	__ATTR_RO(class),
+	__ATTR_RO(irq),
+	__ATTR_NULL,
+};
 
 static ssize_t
 pci_read_config(struct kobject *kobj, char *buf, loff_t off, size_t count)
@@ -180,21 +188,10 @@
 
 void pci_create_sysfs_dev_files (struct pci_dev *pdev)
 {
-	struct device *dev = &pdev->dev;
-
-	/* current configuration's attributes */
-	device_create_file (dev, &dev_attr_vendor);
-	device_create_file (dev, &dev_attr_device);
-	device_create_file (dev, &dev_attr_subsystem_vendor);
-	device_create_file (dev, &dev_attr_subsystem_device);
-	device_create_file (dev, &dev_attr_class);
-	device_create_file (dev, &dev_attr_irq);
-	device_create_file (dev, &dev_attr_resource);
-
 	if (pdev->cfg_size < 4096)
-		sysfs_create_bin_file(&dev->kobj, &pci_config_attr);
+		sysfs_create_bin_file(&pdev->dev.kobj, &pci_config_attr);
 	else
-		sysfs_create_bin_file(&dev->kobj, &pcie_config_attr);
+		sysfs_create_bin_file(&pdev->dev.kobj, &pcie_config_attr);
 
 	/* add platform-specific attributes */
 	pcibios_add_platform_entries(pdev);
--- diff/drivers/pci/pci.c	2004-06-11 19:17:30.000000000 +0100
+++ source/drivers/pci/pci.c	2004-06-11 19:22:03.000000000 +0100
@@ -247,6 +247,8 @@
 	int pm;
 	u16 pmcsr;
 
+	might_sleep();
+
 	/* bound the state we're entering */
 	if (state > 3) state = 3;
 
--- diff/drivers/pci/pci.h	2004-05-19 22:12:02.000000000 +0100
+++ source/drivers/pci/pci.h	2004-06-11 19:22:03.000000000 +0100
@@ -62,3 +62,4 @@
 extern spinlock_t pci_bus_lock;
 
 extern int pciehp_msi_quirk;
+extern struct device_attribute pci_dev_attrs[];
--- diff/drivers/pcmcia/i82365.c	2004-06-11 19:17:30.000000000 +0100
+++ source/drivers/pcmcia/i82365.c	2004-06-11 19:22:03.000000000 +0100
@@ -65,7 +65,6 @@
 #include "cirrus.h"
 #include "vg468.h"
 #include "ricoh.h"
-#include "o2micro.h"
 
 #ifdef DEBUG
 static const char version[] =
@@ -1372,8 +1371,15 @@
 {
     int i, ret;
 
-    if (driver_register(&i82365_driver))
-	return -1;
+    ret = driver_register(&i82365_driver);
+    if (ret)
+	return ret;
+
+    ret = platform_device_register(&i82365_device);
+    if (ret) {
+	driver_unregister(&i82365_driver);
+	return ret;
+    }
 
     printk(KERN_INFO "Intel ISA PCIC probe: ");
     sockets = 0;
@@ -1382,12 +1388,11 @@
 
     if (sockets == 0) {
 	printk("not found.\n");
+	platform_device_unregister(&i82365_device);
 	driver_unregister(&i82365_driver);
 	return -ENODEV;
     }
 
-    platform_device_register(&i82365_device);
-
     /* Set up interrupt handler(s) */
     if (grab_irq != 0)
 	request_irq(cs_irq, pcic_interrupt, 0, "i82365", pcic_interrupt);
--- diff/drivers/pcmcia/o2micro.h	2004-05-19 22:12:04.000000000 +0100
+++ source/drivers/pcmcia/o2micro.h	2004-06-11 19:22:03.000000000 +0100
@@ -120,4 +120,30 @@
 #define  O2_MODE_E_LED_OUT	0x08
 #define  O2_MODE_E_SKTA_ACTV	0x10
 
+static int o2micro_override(struct yenta_socket *socket)
+{
+	/*
+	 * 'reserved' register at 0x94/D4. chaning it to 0xCA (8 bit) enables
+	 * read prefetching which for example makes the RME Hammerfall DSP
+	 * working. for some bridges it is at 0x94, for others at 0xD4. it's
+	 * ok to write to both registers on all O2 bridges.
+	 * from Eric Still, 02Micro.
+	 */
+	if (PCI_FUNC(socket->dev->devfn) == 0) {
+		config_writeb(socket, 0x94, 0xCA);
+		config_writeb(socket, 0xD4, 0xCA);
+	}
+
+	return 0;
+}
+
+static void o2micro_restore_state(struct yenta_socket *socket)
+{
+	/*
+	 * as long as read prefetch is the only thing in
+	 * o2micro_override, it's safe to call it from here
+	 */
+	o2micro_override(socket);
+}
+
 #endif /* _LINUX_O2MICRO_H */
--- diff/drivers/pcmcia/yenta_socket.c	2004-05-19 22:12:04.000000000 +0100
+++ source/drivers/pcmcia/yenta_socket.c	2004-06-11 19:22:03.000000000 +0100
@@ -668,6 +668,7 @@
 #include "ti113x.h"
 #include "ricoh.h"
 #include "topic.h"
+#include "o2micro.h"
 
 enum {
 	CARDBUS_TYPE_DEFAULT = -1,
@@ -676,7 +677,8 @@
 	CARDBUS_TYPE_TI12XX,
 	CARDBUS_TYPE_TI1250,
 	CARDBUS_TYPE_RICOH,
-	CARDBUS_TYPE_TOPIC97
+	CARDBUS_TYPE_TOPIC97,
+	CARDBUS_TYPE_O2MICRO,
 };
 
 /*
@@ -716,6 +718,10 @@
 	[CARDBUS_TYPE_TOPIC97]	= {
 		.override	= topic97_override,
 	},
+	[CARDBUS_TYPE_O2MICRO]	= {
+		.override	= o2micro_override,
+		.restore_state	= o2micro_restore_state,
+	},
 };
 
 
@@ -1099,6 +1105,8 @@
 	CB_ID(PCI_VENDOR_ID_TOSHIBA, PCI_DEVICE_ID_TOSHIBA_TOPIC97, TOPIC97),
 	CB_ID(PCI_VENDOR_ID_TOSHIBA, PCI_DEVICE_ID_TOSHIBA_TOPIC100, TOPIC97),
 
+	CB_ID(PCI_VENDOR_ID_O2, PCI_ANY_ID, O2MICRO),
+
 	/* match any cardbus bridge */
 	CB_ID(PCI_ANY_ID, PCI_ANY_ID, DEFAULT),
 	{ /* all zeroes */ }
--- diff/drivers/pnp/isapnp/core.c	2004-05-19 22:12:04.000000000 +0100
+++ source/drivers/pnp/isapnp/core.c	2004-06-11 19:22:03.000000000 +0100
@@ -68,13 +68,8 @@
 MODULE_PARM_DESC(isapnp_verbose, "ISA Plug & Play verbose mode");
 MODULE_LICENSE("GPL");
 
-#ifdef CONFIG_X86_PC9800
-#define _PIDXR		0x259
-#define _PNPWRP		0xa59
-#else
 #define _PIDXR		0x279
 #define _PNPWRP		0xa79
-#endif
 
 /* short tags */
 #define _STAG_PNPVERNO		0x01
--- diff/drivers/sbus/char/openprom.c	2004-05-19 22:12:07.000000000 +0100
+++ source/drivers/sbus/char/openprom.c	2004-06-11 19:22:03.000000000 +0100
@@ -149,7 +149,6 @@
 	char buffer[OPROMMAXPARAM+1], *buf;
 	struct openpromio *opp;
 	int bufsize, len, error = 0;
-	extern char saved_command_line[];
 	static int cnt;
 
 	if (cmd == OPROMSETOPT)
--- diff/drivers/scsi/3w-xxxx.c	2004-06-11 19:17:30.000000000 +0100
+++ source/drivers/scsi/3w-xxxx.c	2004-06-11 19:22:03.000000000 +0100
@@ -220,7 +220,7 @@
 #define __3W_C			/* let 3w-xxxx.h know it is use */
 
 #include "scsi.h"
-#include "hosts.h"
+#include <scsi/scsi_host.h>
 
 #include "3w-xxxx.h"
 
--- diff/drivers/scsi/53c700.c	2004-05-19 22:12:07.000000000 +0100
+++ source/drivers/scsi/53c700.c	2004-06-11 19:22:03.000000000 +0100
@@ -125,18 +125,21 @@
 #include <linux/sched.h>
 #include <linux/init.h>
 #include <linux/proc_fs.h>
+#include <linux/blkdev.h>
+#include <linux/module.h>
+#include <linux/interrupt.h>
 #include <asm/dma.h>
 #include <asm/system.h>
 #include <asm/io.h>
 #include <asm/pgtable.h>
 #include <asm/byteorder.h>
-#include <linux/blkdev.h>
-#include <linux/module.h>
-#include <linux/interrupt.h>
-
-#include "scsi.h"
-#include "hosts.h"
 
+#include <scsi/scsi.h>
+#include <scsi/scsi_cmnd.h>
+#include <scsi/scsi_dbg.h>
+#include <scsi/scsi_eh.h>
+#include <scsi/scsi_host.h>
+#include <scsi/scsi_tcq.h>
 #include <scsi/scsi_transport.h>
 #include <scsi/scsi_transport_spi.h>
 
@@ -164,15 +167,15 @@
 #include "53c700_d.h"
 
 
-STATIC int NCR_700_queuecommand(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *));
-STATIC int NCR_700_abort(Scsi_Cmnd * SCpnt);
-STATIC int NCR_700_bus_reset(Scsi_Cmnd * SCpnt);
-STATIC int NCR_700_dev_reset(Scsi_Cmnd * SCpnt);
-STATIC int NCR_700_host_reset(Scsi_Cmnd * SCpnt);
+STATIC int NCR_700_queuecommand(struct scsi_cmnd *, void (*done)(struct scsi_cmnd *));
+STATIC int NCR_700_abort(struct scsi_cmnd * SCpnt);
+STATIC int NCR_700_bus_reset(struct scsi_cmnd * SCpnt);
+STATIC int NCR_700_dev_reset(struct scsi_cmnd * SCpnt);
+STATIC int NCR_700_host_reset(struct scsi_cmnd * SCpnt);
 STATIC void NCR_700_chip_setup(struct Scsi_Host *host);
 STATIC void NCR_700_chip_reset(struct Scsi_Host *host);
-STATIC int NCR_700_slave_configure(Scsi_Device *SDpnt);
-STATIC void NCR_700_slave_destroy(Scsi_Device *SDpnt);
+STATIC int NCR_700_slave_configure(struct scsi_device *SDpnt);
+STATIC void NCR_700_slave_destroy(struct scsi_device *SDpnt);
 
 STATIC struct device_attribute *NCR_700_dev_attrs[];
 
@@ -279,7 +282,7 @@
 }
 
 static inline __u8
-NCR_700_get_SXFER(Scsi_Device *SDp)
+NCR_700_get_SXFER(struct scsi_device *SDp)
 {
 	struct NCR_700_Host_Parameters *hostdata = 
 		(struct NCR_700_Host_Parameters *)SDp->host->hostdata[0];
@@ -289,7 +292,7 @@
 }
 
 struct Scsi_Host *
-NCR_700_detect(Scsi_Host_Template *tpnt,
+NCR_700_detect(struct scsi_host_template *tpnt,
 	       struct NCR_700_Host_Parameters *hostdata)
 {
 	dma_addr_t pScript, pSlots;
@@ -561,7 +564,7 @@
    the ITL and (if tagged) the ITLQ lists in _queuecommand */
 STATIC void
 save_for_reselection(struct NCR_700_Host_Parameters *hostdata,
-		     Scsi_Cmnd *SCp, __u32 dsp)
+		     struct scsi_cmnd *SCp, __u32 dsp)
 {
 	/* Its just possible that this gets executed twice */
 	if(SCp != NULL) {
@@ -575,27 +578,25 @@
 }
 
 STATIC inline void
-NCR_700_unmap(struct NCR_700_Host_Parameters *hostdata, Scsi_Cmnd *SCp,
+NCR_700_unmap(struct NCR_700_Host_Parameters *hostdata, struct scsi_cmnd *SCp,
 	      struct NCR_700_command_slot *slot)
 {
-	if(SCp->sc_data_direction != SCSI_DATA_NONE &&
-	   SCp->sc_data_direction != SCSI_DATA_UNKNOWN) {
-		enum dma_data_direction direction = SCp->sc_data_direction;
+	if(SCp->sc_data_direction != DMA_NONE &&
+	   SCp->sc_data_direction != DMA_BIDIRECTIONAL) {
 		if(SCp->use_sg) {
 			dma_unmap_sg(hostdata->dev, SCp->buffer,
-				     SCp->use_sg, direction);
+				     SCp->use_sg, SCp->sc_data_direction);
 		} else {
-			dma_unmap_single(hostdata->dev,
-					 slot->dma_handle,
+			dma_unmap_single(hostdata->dev, slot->dma_handle,
 					 SCp->request_bufflen,
-					 direction);
+					 SCp->sc_data_direction);
 		}
 	}
 }
 
 STATIC inline void
 NCR_700_scsi_done(struct NCR_700_Host_Parameters *hostdata,
-	       Scsi_Cmnd *SCp, int result)
+	       struct scsi_cmnd *SCp, int result)
 {
 	hostdata->state = NCR_700_HOST_FREE;
 	hostdata->cmd = NULL;
@@ -611,7 +612,7 @@
 #ifdef NCR_700_DEBUG
 			printk(" ORIGINAL CMD %p RETURNED %d, new return is %d sense is\n",
 			       SCp, SCp->cmnd[7], result);
-			print_sense("53c700", SCp);
+			scsi_print_sense("53c700", SCp);
 
 #endif
 			/* restore the old result if the request sense was
@@ -780,7 +781,7 @@
 STATIC __u32
 process_extended_message(struct Scsi_Host *host, 
 			 struct NCR_700_Host_Parameters *hostdata,
-			 Scsi_Cmnd *SCp, __u32 dsp, __u32 dsps)
+			 struct scsi_cmnd *SCp, __u32 dsp, __u32 dsps)
 {
 	__u32 resume_offset = dsp, temp = dsp + 8;
 	__u8 pun = 0xff, lun = 0xff;
@@ -849,7 +850,7 @@
 		printk(KERN_INFO "scsi%d (%d:%d): Unexpected message %s: ",
 		       host->host_no, pun, lun,
 		       NCR_700_phase[(dsps & 0xf00) >> 8]);
-		print_msg(hostdata->msgin);
+		scsi_print_msg(hostdata->msgin);
 		printk("\n");
 		/* just reject it */
 		hostdata->msgout[0] = A_REJECT_MSG;
@@ -865,7 +866,7 @@
 
 STATIC __u32
 process_message(struct Scsi_Host *host,	struct NCR_700_Host_Parameters *hostdata,
-		Scsi_Cmnd *SCp, __u32 dsp, __u32 dsps)
+		struct scsi_cmnd *SCp, __u32 dsp, __u32 dsps)
 {
 	/* work out where to return to */
 	__u32 temp = dsp + 8, resume_offset = dsp;
@@ -879,7 +880,7 @@
 #ifdef NCR_700_DEBUG
 	printk("scsi%d (%d:%d): message %s: ", host->host_no, pun, lun,
 	       NCR_700_phase[(dsps & 0xf00) >> 8]);
-	print_msg(hostdata->msgin);
+	scsi_print_msg(hostdata->msgin);
 	printk("\n");
 #endif
 
@@ -927,7 +928,7 @@
 		       host->host_no, pun, lun,
 		       NCR_700_phase[(dsps & 0xf00) >> 8]);
 
-		print_msg(hostdata->msgin);
+		scsi_print_msg(hostdata->msgin);
 		printk("\n");
 		/* just reject it */
 		hostdata->msgout[0] = A_REJECT_MSG;
@@ -946,7 +947,7 @@
 }
 
 STATIC __u32
-process_script_interrupt(__u32 dsps, __u32 dsp, Scsi_Cmnd *SCp,
+process_script_interrupt(__u32 dsps, __u32 dsp, struct scsi_cmnd *SCp,
 			 struct Scsi_Host *host,
 			 struct NCR_700_Host_Parameters *hostdata)
 {
@@ -975,7 +976,7 @@
 				NCR_700_scsi_done(hostdata, SCp, hostdata->status[0]);
 			} else {
 #ifdef NCR_DEBUG
-				print_command(SCp->cmnd);
+				scsi_print_command(SCp);
 				printk("  cmd %p has status %d, requesting sense\n",
 				       SCp, hostdata->status[0]);
 #endif
@@ -1004,7 +1005,7 @@
 				SCp->cmnd[6] = NCR_700_INTERNAL_SENSE_MAGIC;
 				SCp->cmnd[7] = hostdata->status[0];
 				SCp->use_sg = 0;
-				SCp->sc_data_direction = SCSI_DATA_READ;
+				SCp->sc_data_direction = DMA_FROM_DEVICE;
 				dma_sync_single_for_device(hostdata->dev, slot->pCmd,
 							   SCp->cmd_len, DMA_TO_DEVICE);
 				SCp->request_bufflen = sizeof(SCp->sense_buffer);
@@ -1053,7 +1054,7 @@
 		       NCR_700_phase[i],
 		       sbcl_to_string(NCR_700_readb(host, SBCL_REG)));
 		printk(KERN_ERR "         len = %d, cmd =", SCp->cmd_len);
-		print_command(SCp->cmnd);
+		scsi_print_command(SCp);
 
 		NCR_700_internal_bus_reset(host);
 	} else if((dsps & 0xfffff000) == A_FATAL) {
@@ -1080,7 +1081,7 @@
 		__u8 lun;
 		struct NCR_700_command_slot *slot;
 		__u8 reselection_id = hostdata->reselection_id;
-		Scsi_Device *SDp;
+		struct scsi_device *SDp;
 
 		lun = hostdata->msgin[0] & 0x1f;
 
@@ -1095,7 +1096,7 @@
 			BUG();
 		}
 		if(hostdata->msgin[1] == A_SIMPLE_TAG_MSG) {
-			Scsi_Cmnd *SCp = scsi_find_tag(SDp, hostdata->msgin[2]);
+			struct scsi_cmnd *SCp = scsi_find_tag(SDp, hostdata->msgin[2]);
 			if(unlikely(SCp == NULL)) {
 				printk(KERN_ERR "scsi%d: (%d:%d) no saved request for tag %d\n", 
 				       host->host_no, reselection_id, lun, hostdata->msgin[2]);
@@ -1107,7 +1108,7 @@
 			       host->host_no, SDp->id, SDp->lun,
 			       hostdata->msgin[2], slot, slot->tag));
 		} else {
-			Scsi_Cmnd *SCp = scsi_find_tag(SDp, SCSI_NO_TAG);
+			struct scsi_cmnd *SCp = scsi_find_tag(SDp, SCSI_NO_TAG);
 			if(unlikely(SCp == NULL)) {
 				printk(KERN_ERR "scsi%d: (%d:%d) no saved request for untagged cmd\n", 
 				       host->host_no, reselection_id, lun);
@@ -1234,7 +1235,7 @@
 		       host->host_no, pun, lun, NCR_700_condition[i],
 		       NCR_700_phase[j], dsp - hostdata->pScript);
 		if(SCp != NULL) {
-			print_command(SCp->cmnd);
+			scsi_print_command(SCp);
 
 			if(SCp->use_sg) {
 				for(i = 0; i < SCp->use_sg + 1; i++) {
@@ -1270,7 +1271,7 @@
 	__u32 resume_offset = 0;
 	struct NCR_700_Host_Parameters *hostdata =
 		(struct NCR_700_Host_Parameters *)host->hostdata[0];
-	Scsi_Cmnd *SCp = hostdata->cmd;
+	struct scsi_cmnd *SCp = hostdata->cmd;
 	__u8 sbcl;
 
 	for(count = 0; count < 5; count++) {
@@ -1373,7 +1374,7 @@
 /* The queue lock with interrupts disabled must be held on entry to
  * this function */
 STATIC int
-NCR_700_start_command(Scsi_Cmnd *SCp)
+NCR_700_start_command(struct scsi_cmnd *SCp)
 {
 	struct NCR_700_command_slot *slot =
 		(struct NCR_700_command_slot *)SCp->host_scribble;
@@ -1481,7 +1482,7 @@
 		__u32 dsps;
 		__u8 sstat0 = 0, dstat = 0;
 		__u32 dsp;
-		Scsi_Cmnd *SCp = hostdata->cmd;
+		struct scsi_cmnd *SCp = hostdata->cmd;
 		enum NCR_700_Host_State state;
 
 		handled = 1;
@@ -1514,7 +1515,7 @@
 		}
 
 		if(sstat0 & SCSI_RESET_DETECTED) {
-			Scsi_Device *SDp;
+			struct scsi_device *SDp;
 			int i;
 
 			hostdata->state = NCR_700_HOST_BUSY;
@@ -1530,7 +1531,7 @@
 			
 			/* clear all the slots and their pending commands */
 			for(i = 0; i < NCR_700_COMMAND_SLOTS_PER_HOST; i++) {
-				Scsi_Cmnd *SCp;
+				struct scsi_cmnd *SCp;
 				struct NCR_700_command_slot *slot =
 					&hostdata->slots[i];
 
@@ -1590,7 +1591,7 @@
 				printk("scsi%d: (%d:%d) Expected phase mismatch in slot->SG[%d], transferred 0x%x\n",
 				       host->host_no, pun, lun,
 				       SGcount, data_transfer);
-				print_command(SCp->cmnd);
+				scsi_print_command(SCp);
 				if(residual) {
 					printk("scsi%d: (%d:%d) Expected phase mismatch in slot->SG[%d], transferred 0x%x, residual %d\n",
 				       host->host_no, pun, lun,
@@ -1731,7 +1732,7 @@
 }
 
 STATIC int
-NCR_700_queuecommand(Scsi_Cmnd *SCp, void (*done)(Scsi_Cmnd *))
+NCR_700_queuecommand(struct scsi_cmnd *SCp, void (*done)(struct scsi_cmnd *))
 {
 	struct NCR_700_Host_Parameters *hostdata = 
 		(struct NCR_700_Host_Parameters *)SCp->device->host->hostdata[0];
@@ -1781,7 +1782,7 @@
 
 #ifdef NCR_700_DEBUG
 	printk("53c700: scsi%d, command ", SCp->device->host->host_no);
-	print_command(SCp->cmnd);
+	scsi_print_command(SCp);
 #endif
 	if(SCp->device->tagged_supported && !SCp->device->simple_tags
 	   && (hostdata->tag_negotiated &(1<<SCp->device->id)) == 0
@@ -1827,13 +1828,13 @@
 	/* sanity check: some of the commands generated by the mid-layer
 	 * have an eccentric idea of their sc_data_direction */
 	if(!SCp->use_sg && !SCp->request_bufflen 
-	   && SCp->sc_data_direction != SCSI_DATA_NONE) {
+	   && SCp->sc_data_direction != DMA_NONE) {
 #ifdef NCR_700_DEBUG
 		printk("53c700: Command");
-		print_command(SCp->cmnd);
+		scsi_print_command(SCp);
 		printk("Has wrong data direction %d\n", SCp->sc_data_direction);
 #endif
-		SCp->sc_data_direction = SCSI_DATA_NONE;
+		SCp->sc_data_direction = DMA_NONE;
 	}
 
 	switch (SCp->cmnd[0]) {
@@ -1844,20 +1845,20 @@
 	default:
 		/* OK, get it from the command */
 		switch(SCp->sc_data_direction) {
-		case SCSI_DATA_UNKNOWN:
+		case DMA_BIDIRECTIONAL:
 		default:
 			printk(KERN_ERR "53c700: Unknown command for data direction ");
-			print_command(SCp->cmnd);
+			scsi_print_command(SCp);
 			
 			move_ins = 0;
 			break;
-		case SCSI_DATA_NONE:
+		case DMA_NONE:
 			move_ins = 0;
 			break;
-		case SCSI_DATA_READ:
+		case DMA_FROM_DEVICE:
 			move_ins = SCRIPT_MOVE_DATA_IN;
 			break;
-		case SCSI_DATA_WRITE:
+		case DMA_TO_DEVICE:
 			move_ins = SCRIPT_MOVE_DATA_OUT;
 			break;
 		}
@@ -1914,13 +1915,13 @@
 }
 
 STATIC int
-NCR_700_abort(Scsi_Cmnd * SCp)
+NCR_700_abort(struct scsi_cmnd * SCp)
 {
 	struct NCR_700_command_slot *slot;
 
 	printk(KERN_INFO "scsi%d (%d:%d) New error handler wants to abort command\n\t",
 	       SCp->device->host->host_no, SCp->device->id, SCp->device->lun);
-	print_command(SCp->cmnd);
+	scsi_print_command(SCp);
 
 	slot = (struct NCR_700_command_slot *)SCp->host_scribble;
 
@@ -1946,7 +1947,7 @@
 }
 
 STATIC int
-NCR_700_bus_reset(Scsi_Cmnd * SCp)
+NCR_700_bus_reset(struct scsi_cmnd * SCp)
 {
 	DECLARE_COMPLETION(complete);
 	struct NCR_700_Host_Parameters *hostdata = 
@@ -1954,7 +1955,7 @@
 
 	printk(KERN_INFO "scsi%d (%d:%d) New error handler wants BUS reset, cmd %p\n\t",
 	       SCp->device->host->host_no, SCp->device->id, SCp->device->lun, SCp);
-	print_command(SCp->cmnd);
+	scsi_print_command(SCp);
 	/* In theory, eh_complete should always be null because the
 	 * eh is single threaded, but just in case we're handling a
 	 * reset via sg or something */
@@ -1976,21 +1977,21 @@
 }
 
 STATIC int
-NCR_700_dev_reset(Scsi_Cmnd * SCp)
+NCR_700_dev_reset(struct scsi_cmnd * SCp)
 {
 	printk(KERN_INFO "scsi%d (%d:%d) New error handler wants device reset\n\t",
 	       SCp->device->host->host_no, SCp->device->id, SCp->device->lun);
-	print_command(SCp->cmnd);
+	scsi_print_command(SCp);
 	
 	return FAILED;
 }
 
 STATIC int
-NCR_700_host_reset(Scsi_Cmnd * SCp)
+NCR_700_host_reset(struct scsi_cmnd * SCp)
 {
 	printk(KERN_INFO "scsi%d (%d:%d) New error handler wants HOST reset\n\t",
 	       SCp->device->host->host_no, SCp->device->id, SCp->device->lun);
-	print_command(SCp->cmnd);
+	scsi_print_command(SCp);
 
 	NCR_700_internal_bus_reset(SCp->device->host);
 	NCR_700_chip_reset(SCp->device->host);
@@ -2043,7 +2044,7 @@
 
 
 STATIC int
-NCR_700_slave_configure(Scsi_Device *SDp)
+NCR_700_slave_configure(struct scsi_device *SDp)
 {
 	struct NCR_700_Host_Parameters *hostdata = 
 		(struct NCR_700_Host_Parameters *)SDp->host->hostdata[0];
@@ -2066,7 +2067,7 @@
 }
 
 STATIC void
-NCR_700_slave_destroy(Scsi_Device *SDp)
+NCR_700_slave_destroy(struct scsi_device *SDp)
 {
 	/* to do here: deallocate memory */
 }
--- diff/drivers/scsi/53c700.h	2004-05-19 22:12:07.000000000 +0100
+++ source/drivers/scsi/53c700.h	2004-06-11 19:22:03.000000000 +0100
@@ -9,9 +9,11 @@
 #define _53C700_H
 
 #include <linux/interrupt.h>
-
 #include <asm/io.h>
 
+#include <scsi/scsi_device.h>
+
+
 #if defined(CONFIG_53C700_MEM_MAPPED) && defined(CONFIG_53C700_IO_MAPPED)
 #define CONFIG_53C700_BOTH_MAPPED
 #endif
@@ -57,7 +59,8 @@
 struct NCR_700_Host_Parameters;
 
 /* These are the externally used routines */
-struct Scsi_Host *NCR_700_detect(Scsi_Host_Template *, struct NCR_700_Host_Parameters *);
+struct Scsi_Host *NCR_700_detect(struct scsi_host_template *,
+		struct NCR_700_Host_Parameters *);
 int NCR_700_release(struct Scsi_Host *host);
 irqreturn_t NCR_700_intr(int, void *, struct pt_regs *);
 
@@ -102,7 +105,7 @@
 #define NCR_700_DEV_PRINT_SYNC_NEGOTIATION (1<<19)
 
 static inline void
-NCR_700_set_depth(Scsi_Device *SDp, __u8 depth)
+NCR_700_set_depth(struct scsi_device *SDp, __u8 depth)
 {
 	long l = (long)SDp->hostdata;
 
@@ -111,27 +114,27 @@
 	SDp->hostdata = (void *)l;
 }
 static inline __u8
-NCR_700_get_depth(Scsi_Device *SDp)
+NCR_700_get_depth(struct scsi_device *SDp)
 {
 	return ((((unsigned long)SDp->hostdata) & 0xff00)>>8);
 }
 static inline int
-NCR_700_is_flag_set(Scsi_Device *SDp, __u32 flag)
+NCR_700_is_flag_set(struct scsi_device *SDp, __u32 flag)
 {
 	return (((unsigned long)SDp->hostdata) & flag) == flag;
 }
 static inline int
-NCR_700_is_flag_clear(Scsi_Device *SDp, __u32 flag)
+NCR_700_is_flag_clear(struct scsi_device *SDp, __u32 flag)
 {
 	return (((unsigned long)SDp->hostdata) & flag) == 0;
 }
 static inline void
-NCR_700_set_flag(Scsi_Device *SDp, __u32 flag)
+NCR_700_set_flag(struct scsi_device *SDp, __u32 flag)
 {
 	SDp->hostdata = (void *)((long)SDp->hostdata | (flag & 0xffff0000));
 }
 static inline void
-NCR_700_clear_flag(Scsi_Device *SDp, __u32 flag)
+NCR_700_clear_flag(struct scsi_device *SDp, __u32 flag)
 {
 	SDp->hostdata = (void *)((long)SDp->hostdata & ~(flag & 0xffff0000));
 }
@@ -147,7 +150,7 @@
 	__u8	state;
 	int	tag;
 	__u32	resume_offset;
-	Scsi_Cmnd	*cmnd;
+	struct scsi_cmnd *cmnd;
 	/* The pci_mapped address of the actual command in cmnd */
 	dma_addr_t	pCmd;
 	__u32		temp;
@@ -185,7 +188,7 @@
 	__u32	pScript;		/* physical mem addr of script */
 
 	enum NCR_700_Host_State state; /* protected by state lock */
-	Scsi_Cmnd *cmd;
+	struct scsi_cmnd *cmd;
 	/* Note: pScript contains the single consistent block of
 	 * memory.  All the msgin, msgout and status are allocated in
 	 * this memory too (at separate cache lines).  TOTAL_MEM_SIZE
--- diff/drivers/scsi/53c7xx.c	2004-05-19 22:12:07.000000000 +0100
+++ source/drivers/scsi/53c7xx.c	2004-06-11 19:22:03.000000000 +0100
@@ -280,7 +280,7 @@
 #endif
 
 #include "scsi.h"
-#include "hosts.h"
+#include <scsi/scsi_host.h>
 #include "53c7xx.h"
 #include <linux/stat.h>
 #include <linux/stddef.h>
--- diff/drivers/scsi/BusLogic.c	2004-05-19 22:12:07.000000000 +0100
+++ source/drivers/scsi/BusLogic.c	2004-06-11 19:22:03.000000000 +0100
@@ -48,7 +48,7 @@
 #include <asm/system.h>
 
 #include "scsi.h"
-#include "hosts.h"
+#include <scsi/scsi_host.h>
 #include "BusLogic.h"
 #include "FlashPoint.c"
 
--- diff/drivers/scsi/Kconfig	2004-06-11 19:17:30.000000000 +0100
+++ source/drivers/scsi/Kconfig	2004-06-11 19:22:03.000000000 +0100
@@ -227,7 +227,7 @@
 	depends on DECSTATION && SCSI
 
 config BLK_DEV_3W_XXXX_RAID
-	tristate "3ware Hardware ATA-RAID support"
+	tristate "3ware 5/6/7/8xxx ATA-RAID support"
 	depends on PCI && SCSI
 	help
 	  3ware is the only hardware ATA-Raid product in Linux to date.
@@ -239,6 +239,17 @@
 	  Please read the comments at the top of
 	  <file:drivers/scsi/3w-xxxx.c>.
 
+config SCSI_3W_9XXX
+	tristate "3ware 9xxx SATA-RAID support"
+	depends on PCI && SCSI
+	help
+	  This driver supports the 9000 series 3ware SATA-RAID cards.
+
+	  <http://www.amcc.com>
+
+	  Please read the comments at the top of
+	  <file:drivers/scsi/3w-9xxx.c>.
+
 config SCSI_7000FASST
 	tristate "7000FASST SCSI support"
 	depends on ISA && SCSI
@@ -478,9 +489,7 @@
 	  Adapters. Consult the SCSI-HOWTO, available from
 	  <http://www.tldp.org/docs.html#howto>, and the files
 	  <file:Documentation/scsi/BusLogic.txt> and
-	  <file:Documentation/scsi/FlashPoint.txt> for more information. If this
-	  driver does not work correctly without modification, please contact
-	  the author, Leonard N. Zubkoff, by email to lnz@dandelion.com.
+	  <file:Documentation/scsi/FlashPoint.txt> for more information.
 
 	  To compile this driver as a module, choose M here: the
 	  module will be called BusLogic.
@@ -978,7 +987,7 @@
 
 config SCSI_IPR
 	tristate "IBM Power Linux RAID adapter support"
-	depends on PCI && SCSI
+	depends on PCI && SCSI && PPC
 	select FW_LOADER
 	---help---
 	  This driver supports the IBM Power Linux family RAID adapters.
@@ -1710,18 +1719,6 @@
 	  To compile this driver as a module, choose M here: the
 	  module will be called esp.
 
-config SCSI_PC980155
-	tristate "NEC PC-9801-55 SCSI support"
-	depends on X86_PC9800 && SCSI
-	help
-	  If you have the NEC PC-9801-55 SCSI interface card or compatibles
-	  for NEC PC-9801/PC-9821, say Y.
-
-config WD33C93_PIO
-	bool
-	depends on SCSI_PC980155
-	default y
-
 #      bool 'Cyberstorm Mk III SCSI support (EXPERIMENTAL)' CONFIG_CYBERSTORMIII_SCSI
 
 config ZFCP
--- diff/drivers/scsi/Makefile	2004-06-11 19:17:30.000000000 +0100
+++ source/drivers/scsi/Makefile	2004-06-11 19:22:03.000000000 +0100
@@ -34,7 +34,6 @@
 obj-$(CONFIG_A3000_SCSI)	+= a3000.o	wd33c93.o
 obj-$(CONFIG_A2091_SCSI)	+= a2091.o	wd33c93.o
 obj-$(CONFIG_GVP11_SCSI)	+= gvp11.o	wd33c93.o
-obj-$(CONFIG_SCSI_PC980155)	+= pc980155.o	wd33c93.o
 obj-$(CONFIG_MVME147_SCSI)	+= mvme147.o	wd33c93.o
 obj-$(CONFIG_SGIWD93_SCSI)	+= sgiwd93.o	wd33c93.o
 obj-$(CONFIG_CYBERSTORM_SCSI)	+= NCR53C9x.o	cyberstorm.o
@@ -109,6 +108,7 @@
 obj-$(CONFIG_SCSI_PLUTO)	+= pluto.o
 obj-$(CONFIG_SCSI_DECNCR)	+= NCR53C9x.o	dec_esp.o
 obj-$(CONFIG_BLK_DEV_3W_XXXX_RAID) += 3w-xxxx.o
+obj-$(CONFIG_SCSI_3W_9XXX)	+= 3w-9xxx.o
 obj-$(CONFIG_SCSI_PPA)		+= ppa.o
 obj-$(CONFIG_SCSI_IMM)		+= imm.o
 obj-$(CONFIG_JAZZ_ESP)		+= NCR53C9x.o	jazz_esp.o
@@ -142,7 +142,6 @@
 				   scsi_devinfo.o
 scsi_mod-$(CONFIG_SYSCTL)	+= scsi_sysctl.o
 scsi_mod-$(CONFIG_SCSI_PROC_FS)	+= scsi_proc.o
-scsi_mod-$(CONFIG_X86_PC9800)	+= scsi_pc98.o
 
 sd_mod-objs	:= sd.o
 sr_mod-objs	:= sr.o sr_ioctl.o sr_vendor.o
--- diff/drivers/scsi/NCR53C9x.c	2004-05-19 22:12:08.000000000 +0100
+++ source/drivers/scsi/NCR53C9x.c	2004-06-11 19:22:04.000000000 +0100
@@ -36,7 +36,7 @@
 #include <linux/init.h>
 
 #include "scsi.h"
-#include "hosts.h"
+#include <scsi/scsi_host.h>
 #include "NCR53C9x.h"
 
 #include <asm/system.h>
--- diff/drivers/scsi/NCR53c406a.c	2004-06-11 19:17:30.000000000 +0100
+++ source/drivers/scsi/NCR53c406a.c	2004-06-11 19:22:04.000000000 +0100
@@ -54,7 +54,7 @@
 #include <linux/blkdev.h>
 #include <linux/spinlock.h>
 #include "scsi.h"
-#include "hosts.h"
+#include <scsi/scsi_host.h>
 
 /* ============================================================= */
 
--- diff/drivers/scsi/NCR_D700.c	2004-05-19 22:12:08.000000000 +0100
+++ source/drivers/scsi/NCR_D700.c	2004-06-11 19:22:04.000000000 +0100
@@ -98,9 +98,7 @@
 #include <linux/module.h>
 #include <linux/mca.h>
 #include <asm/io.h>
-
-#include "scsi.h"
-#include "hosts.h"
+#include <scsi/scsi_host.h>
 
 #include "53c700.h"
 #include "NCR_D700.h"
@@ -156,7 +154,7 @@
 
 /* Host template.  The 53c700 routine NCR_700_detect will
  * fill in all of the missing routines */
-static Scsi_Host_Template NCR_D700_driver_template = {
+static struct scsi_host_template NCR_D700_driver_template = {
 	.module			= THIS_MODULE,
 	.name			= "NCR Dual 700 MCA",
 	.proc_name		= "NCR_D700",
--- diff/drivers/scsi/NCR_Q720.c	2004-05-19 22:12:08.000000000 +0100
+++ source/drivers/scsi/NCR_Q720.c	2004-06-11 19:22:04.000000000 +0100
@@ -16,7 +16,7 @@
 #include <asm/io.h>
 
 #include "scsi.h"
-#include "hosts.h"
+#include <scsi/scsi_host.h>
 
 #include "ncr53c8xx.h"
 
--- diff/drivers/scsi/a2091.c	2004-05-19 22:12:08.000000000 +0100
+++ source/drivers/scsi/a2091.c	2004-06-11 19:22:03.000000000 +0100
@@ -16,7 +16,7 @@
 #include <linux/spinlock.h>
 
 #include "scsi.h"
-#include "hosts.h"
+#include <scsi/scsi_host.h>
 #include "wd33c93.h"
 #include "a2091.h"
 
--- diff/drivers/scsi/a3000.c	2004-05-19 22:12:08.000000000 +0100
+++ source/drivers/scsi/a3000.c	2004-06-11 19:22:03.000000000 +0100
@@ -15,7 +15,7 @@
 #include <asm/irq.h>
 
 #include "scsi.h"
-#include "hosts.h"
+#include <scsi/scsi_host.h>
 #include "wd33c93.h"
 #include "a3000.h"
 
--- diff/drivers/scsi/advansys.c	2004-05-19 22:12:08.000000000 +0100
+++ source/drivers/scsi/advansys.c	2004-06-11 19:22:03.000000000 +0100
@@ -756,27 +756,6 @@
 
 */
 
-
-/*
- * --- Linux Version
- */
-
-#ifndef LINUX_VERSION_CODE
-#include <linux/version.h>
-#endif /* LINUX_VERSION_CODE */
-
-/* Convert Linux Version, Patch-level, Sub-level to LINUX_VERSION_CODE. */
-#define ASC_LINUX_VERSION(V, P, S)    (((V) * 65536) + ((P) * 256) + (S))
-#define ASC_LINUX_KERNEL22 (LINUX_VERSION_CODE < ASC_LINUX_VERSION(2,4,0))
-#define ASC_LINUX_KERNEL24 (LINUX_VERSION_CODE >= ASC_LINUX_VERSION(2,4,0))
-
-/* Driver supported only in version 2.2 and version >= 2.4. */
-#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(2,2,0) || \
-    (LINUX_VERSION_CODE > ASC_LINUX_VERSION(2,3,0) && \
-     LINUX_VERSION_CODE < ASC_LINUX_VERSION(2,4,0))
-#error "AdvanSys driver supported only in 2.2 and 2.4 or greater kernels."
-#endif
-
 /*
  * --- Linux Include Files
  */
@@ -801,13 +780,14 @@
 #include <linux/blkdev.h>
 #include <linux/stat.h>
 #include <linux/spinlock.h>
+#include <linux/dma-mapping.h>
 
 #include <asm/io.h>
 #include <asm/system.h>
 #include <asm/dma.h>
 
 #include "scsi.h"
-#include "hosts.h"
+#include <scsi/scsi_host.h>
 #include "advansys.h"
 #ifdef CONFIG_PCI
 #include <linux/pci.h>
@@ -874,9 +854,6 @@
 
 typedef unsigned char uchar;
 
-#ifndef NULL
-#define NULL     (0)
-#endif
 #ifndef TRUE
 #define TRUE     (1)
 #endif
@@ -986,49 +963,6 @@
 #define ASC_MIN_SENSE_LEN   14
 #define ASC_MAX_CDB_LEN     12
 #define ASC_SCSI_RESET_HOLD_TIME_US  60
-#define SCSICMD_TestUnitReady     0x00
-#define SCSICMD_Rewind            0x01
-#define SCSICMD_Rezero            0x01
-#define SCSICMD_RequestSense      0x03
-#define SCSICMD_Format            0x04
-#define SCSICMD_FormatUnit        0x04
-#define SCSICMD_Read6             0x08
-#define SCSICMD_Write6            0x0A
-#define SCSICMD_Seek6             0x0B
-#define SCSICMD_Inquiry           0x12
-#define SCSICMD_Verify6           0x13
-#define SCSICMD_ModeSelect6       0x15
-#define SCSICMD_ModeSense6        0x1A
-#define SCSICMD_StartStopUnit     0x1B
-#define SCSICMD_LoadUnloadTape    0x1B
-#define SCSICMD_ReadCapacity      0x25
-#define SCSICMD_Read10            0x28
-#define SCSICMD_Write10           0x2A
-#define SCSICMD_Seek10            0x2B
-#define SCSICMD_Erase10           0x2C
-#define SCSICMD_WriteAndVerify10  0x2E
-#define SCSICMD_Verify10          0x2F
-#define SCSICMD_WriteBuffer       0x3B
-#define SCSICMD_ReadBuffer        0x3C
-#define SCSICMD_ReadLong          0x3E
-#define SCSICMD_WriteLong         0x3F
-#define SCSICMD_ReadTOC           0x43
-#define SCSICMD_ReadHeader        0x44
-#define SCSICMD_ModeSelect10      0x55
-#define SCSICMD_ModeSense10       0x5A
-
-/* Inquiry Data Peripheral Device Types */
-#define SCSI_TYPE_DASD     0x00
-#define SCSI_TYPE_SASD     0x01
-#define SCSI_TYPE_PRN      0x02
-#define SCSI_TYPE_PROC     0x03
-#define SCSI_TYPE_WORM     0x04
-#define SCSI_TYPE_CDROM    0x05
-#define SCSI_TYPE_SCANNER  0x06
-#define SCSI_TYPE_OPTMEM   0x07
-#define SCSI_TYPE_MED_CHG  0x08
-#define SCSI_TYPE_COMM     0x09
-#define SCSI_TYPE_UNKNOWN  0x1F
 
 #define ADV_INQ_CLOCKING_ST_ONLY    0x0
 #define ADV_INQ_CLOCKING_DT_ONLY    0x1
@@ -1047,36 +981,11 @@
 #define ASC_SCSIDIR_T2H      0x08
 #define ASC_SCSIDIR_H2T      0x10
 #define ASC_SCSIDIR_NODATA   0x18
-#define SCSI_SENKEY_NO_SENSE      0x00
-#define SCSI_SENKEY_UNDEFINED     0x01
-#define SCSI_SENKEY_NOT_READY     0x02
-#define SCSI_SENKEY_MEDIUM_ERR    0x03
-#define SCSI_SENKEY_HW_ERR        0x04
-#define SCSI_SENKEY_ILLEGAL       0x05
-#define SCSI_SENKEY_ATTENTION     0x06
-#define SCSI_SENKEY_PROTECTED     0x07
-#define SCSI_SENKEY_BLANK         0x08
-#define SCSI_SENKEY_V_UNIQUE      0x09
-#define SCSI_SENKEY_CPY_ABORT     0x0A
-#define SCSI_SENKEY_ABORT         0x0B
-#define SCSI_SENKEY_EQUAL         0x0C
-#define SCSI_SENKEY_VOL_OVERFLOW  0x0D
-#define SCSI_SENKEY_MISCOMP       0x0E
-#define SCSI_SENKEY_RESERVED      0x0F
 #define SCSI_ASC_NOMEDIA          0x3A
 #define ASC_SRB_HOST(x)  ((uchar)((uchar)(x) >> 4))
 #define ASC_SRB_TID(x)   ((uchar)((uchar)(x) & (uchar)0x0F))
 #define ASC_SRB_LUN(x)   ((uchar)((uint)(x) >> 13))
 #define PUT_CDB1(x)   ((uchar)((uint)(x) >> 8))
-#define SS_GOOD              0x00
-#define SS_CHK_CONDITION     0x02
-#define SS_CONDITION_MET     0x04
-#define SS_TARGET_BUSY       0x08
-#define SS_INTERMID          0x10
-#define SS_INTERMID_COND_MET 0x14
-#define SS_RSERV_CONFLICT    0x18
-#define SS_CMD_TERMINATED    0x22
-#define SS_QUEUE_FULL        0x28
 #define MS_CMD_DONE    0x00
 #define MS_EXTEND      0x01
 #define MS_SDTR_LEN    0x03
@@ -1085,26 +994,6 @@
 #define MS_WDTR_CODE   0x03
 #define MS_MDP_LEN    0x05
 #define MS_MDP_CODE   0x00
-#define M1_SAVE_DATA_PTR        0x02
-#define M1_RESTORE_PTRS         0x03
-#define M1_DISCONNECT           0x04
-#define M1_INIT_DETECTED_ERR    0x05
-#define M1_ABORT                0x06
-#define M1_MSG_REJECT           0x07
-#define M1_NO_OP                0x08
-#define M1_MSG_PARITY_ERR       0x09
-#define M1_LINK_CMD_DONE        0x0A
-#define M1_LINK_CMD_DONE_WFLAG  0x0B
-#define M1_BUS_DVC_RESET        0x0C
-#define M1_ABORT_TAG            0x0D
-#define M1_CLR_QUEUE            0x0E
-#define M1_INIT_RECOVERY        0x0F
-#define M1_RELEASE_RECOVERY     0x10
-#define M1_KILL_IO_PROC         0x11
-#define M2_QTAG_MSG_SIMPLE      0x20
-#define M2_QTAG_MSG_HEAD        0x21
-#define M2_QTAG_MSG_ORDERED     0x22
-#define M2_IGNORE_WIDE_RESIDUE  0x23
 
 /*
  * Inquiry data structure and bitfield macros
@@ -1576,7 +1465,7 @@
     uchar               sdtr_period_offset[ASC_MAX_TID + 1];
     ushort              pci_slot_info;
     uchar               adapter_info[6];
-    struct pci_dev	*pci_dev;
+    struct device	*dev;
 } ASC_DVC_CFG;
 
 #define ASC_DEF_DVC_CNTL       0xFFFF
@@ -3082,7 +2971,7 @@
   ushort serial1;           /* EEPROM serial number word 1 */
   ushort serial2;           /* EEPROM serial number word 2 */
   ushort serial3;           /* EEPROM serial number word 3 */
-  struct pci_dev *pci_dev;  /* pointer to the pci dev structure for this board */
+  struct device *dev;  /* pointer to the pci dev structure for this board */
 } ADV_DVC_CFG;
 
 struct adv_dvc_var;
@@ -3581,19 +3470,6 @@
 
 #define NO_ISA_DMA              0xff        /* No ISA DMA Channel Used */
 
-/*
- * If the Linux kernel version supports freeing initialization code
- * and data after loading, define macros for this purpose. These macros
- * are not used when the driver is built as a module, cf. linux/init.h.
- */
-#if ASC_LINUX_KERNEL24
-#define ASC_INITFUNC(type, func)        type __init func
-#elif ASC_LINUX_KERNEL22
-#define ASC_INITFUNC(type, func)        __initfunc(type func)
-#endif
-#define ASC_INITDATA                    __initdata
-#define ASC_INIT                        __init
-
 #define ASC_INFO_SIZE           128            /* advansys_info() line size */
 
 #ifdef CONFIG_PROC_FS
@@ -3610,8 +3486,6 @@
         } \
         cp += len; \
     }
-
-#define ASC_MIN(a, b) (((a) < (b)) ? (a) : (b))
 #endif /* CONFIG_PROC_FS */
 
 /* Asc Library return codes */
@@ -3685,53 +3559,6 @@
 /* Return non-zero, if the queue is empty. */
 #define ASC_QUEUE_EMPTY(ascq)    ((ascq)->q_tidmask == 0)
 
-/* PCI configuration declarations */
-
-#define PCI_BASE_CLASS_PREDEFINED               0x00
-#define PCI_BASE_CLASS_MASS_STORAGE             0x01
-#define PCI_BASE_CLASS_NETWORK                  0x02
-#define PCI_BASE_CLASS_DISPLAY                  0x03
-#define PCI_BASE_CLASS_MULTIMEDIA               0x04
-#define PCI_BASE_CLASS_MEMORY_CONTROLLER        0x05
-#define PCI_BASE_CLASS_BRIDGE_DEVICE            0x06
-
-/* MASS STORAGE */
-#define PCI_SUB_CLASS_SCSI_CONTROLLER           0x00
-#define PCI_SUB_CLASS_IDE_CONTROLLER            0x01
-#define PCI_SUB_CLASS_FLOPPY_DISK_CONTROLLER    0x02
-#define PCI_SUB_CLASS_IPI_BUS_CONTROLLER        0x03
-#define PCI_SUB_CLASS_OTHER_MASS_CONTROLLER     0x80
-
-/* NETWORK CONTROLLER */
-#define PCI_SUB_CLASS_ETHERNET_CONTROLLER       0x00
-#define PCI_SUB_CLASS_TOKEN_RING_CONTROLLER     0x01
-#define PCI_SUB_CLASS_FDDI_CONTROLLER           0x02
-#define PCI_SUB_CLASS_OTHER_NETWORK_CONTROLLER  0x80
-
-/* DISPLAY CONTROLLER */
-#define PCI_SUB_CLASS_VGA_CONTROLLER            0x00
-#define PCI_SUB_CLASS_XGA_CONTROLLER            0x01
-#define PCI_SUB_CLASS_OTHER_DISPLAY_CONTROLLER  0x80
-
-/* MULTIMEDIA CONTROLLER */
-#define PCI_SUB_CLASS_VIDEO_DEVICE              0x00
-#define PCI_SUB_CLASS_AUDIO_DEVICE              0x01
-#define PCI_SUB_CLASS_OTHER_MULTIMEDIA_DEVICE   0x80
-
-/* MEMORY CONTROLLER */
-#define PCI_SUB_CLASS_RAM_CONTROLLER            0x00
-#define PCI_SUB_CLASS_FLASH_CONTROLLER          0x01
-#define PCI_SUB_CLASS_OTHER_MEMORY_CONTROLLER   0x80
-
-/* BRIDGE CONTROLLER */
-#define PCI_SUB_CLASS_HOST_BRIDGE_CONTROLLER    0x00
-#define PCI_SUB_CLASS_ISA_BRIDGE_CONTROLLER     0x01
-#define PCI_SUB_CLASS_EISA_BRIDGE_CONTROLLER    0x02
-#define PCI_SUB_CLASS_MC_BRIDGE_CONTROLLER      0x03
-#define PCI_SUB_CLASS_PCI_TO_PCI_BRIDGE_CONTROLLER    0x04
-#define PCI_SUB_CLASS_PCMCIA_BRIDGE_CONTROLLER  0x05
-#define PCI_SUB_CLASS_OTHER_BRIDGE_CONTROLLER   0x80
-
 #define PCI_MAX_SLOT            0x1F
 #define PCI_MAX_BUS             0xFF
 #define PCI_IOADDRESS_MASK      0xFFFE
@@ -3744,25 +3571,6 @@
 #define ASC_PCI_DEVICE_ID_2500  0x2500  /* ASC-38C0800 */
 #define ASC_PCI_DEVICE_ID_2700  0x2700  /* ASC-38C1600 */
 
-/* PCI IO Port Addresses to generate special cycle */
-
-#define PCI_CONFIG_ADDRESS_MECH1          0x0CF8
-#define PCI_CONFIG_DATA_MECH1             0x0CFC
-
-#define PCI_CONFIG_FORWARD_REGISTER       0x0CFA    /* 0=type 0; 1=type 1; */
-
-#define PCI_CONFIG_BUS_NUMBER_MASK        0x00FF0000
-#define PCI_CONFIG_DEVICE_FUNCTION_MASK   0x0000FF00
-#define PCI_CONFIG_REGISTER_NUMBER_MASK   0x000000F8
-
-#define PCI_DEVICE_FOUND                0x0000
-#define PCI_DEVICE_NOT_FOUND            0xffff
-
-#define SUBCLASS_OFFSET         0x0A
-#define CLASSCODE_OFFSET        0x0B
-#define VENDORID_OFFSET         0x00
-#define DEVICEID_OFFSET         0x02
-
 #ifndef ADVANSYS_STATS
 #define ASC_STATS(shp, counter)
 #define ASC_STATS_ADD(shp, counter, count)
@@ -4145,19 +3953,6 @@
 
 /* Note: All driver global data should be initialized. */
 
-#if ASC_LINUX_KERNEL22
-#ifdef CONFIG_PROC_FS
-struct proc_dir_entry proc_scsi_advansys =
-{
-    PROC_SCSI_ADVANSYS,              /* unsigned short low_ino */
-    8,                               /* unsigned short namelen */
-    "advansys",                      /* const char *name */
-    S_IFDIR | S_IRUGO | S_IXUGO,     /* mode_t mode */
-    2                                /* nlink_t nlink */
-};
-#endif /* CONFIG_PROC_FS */
-#endif /* ASC_LINUX_KERNEL22 */
-
 /* Number of boards detected in system. */
 STATIC int asc_board_count = 0;
 STATIC struct Scsi_Host    *asc_host[ASC_NUM_BOARD_SUPPORTED] = { 0 };
@@ -4172,7 +3967,7 @@
 STATIC ASC_SG_HEAD asc_sg_head = { 0 };
 
 /* List of supported bus types. */
-STATIC ushort asc_bus[ASC_NUM_BUS] ASC_INITDATA = {
+STATIC ushort asc_bus[ASC_NUM_BUS] __initdata = {
     ASC_IS_ISA,
     ASC_IS_VL,
     ASC_IS_EISA,
@@ -4210,11 +4005,11 @@
 
 STATIC irqreturn_t advansys_interrupt(int, void *, struct pt_regs *);
 STATIC int	  advansys_slave_configure(Scsi_Device *);
-STATIC void       asc_scsi_done_list(Scsi_Cmnd *, int from_isr);
+STATIC void       asc_scsi_done_list(Scsi_Cmnd *);
 STATIC int        asc_execute_scsi_cmnd(Scsi_Cmnd *);
 STATIC int        asc_build_req(asc_board_t *, Scsi_Cmnd *);
 STATIC int        adv_build_req(asc_board_t *, Scsi_Cmnd *, ADV_SCSI_REQ_Q **);
-STATIC int        adv_get_sglist(asc_board_t *, adv_req_t *, Scsi_Cmnd *);
+STATIC int        adv_get_sglist(asc_board_t *, adv_req_t *, Scsi_Cmnd *, int);
 STATIC void       asc_isr_callback(ASC_DVC_VAR *, ASC_QDONE_INFO *);
 STATIC void       adv_isr_callback(ADV_DVC_VAR *, ADV_SCSI_REQ_Q *);
 STATIC void       adv_async_callback(ADV_DVC_VAR *, uchar);
@@ -4505,10 +4300,8 @@
  * it must not call SCSI mid-level functions including scsi_malloc()
  * and scsi_free().
  */
-ASC_INITFUNC(
-int,
+int __init
 advansys_detect(Scsi_Host_Template *tpnt)
-)
 {
     static int          detect_called = ASC_FALSE;
     int                 iop;
@@ -4526,6 +4319,7 @@
     struct pci_dev      *pci_devicep[ASC_NUM_BOARD_SUPPORTED];
     int                 pci_card_cnt_max = 0;
     int                 pci_card_cnt = 0;
+    struct device	*dev = NULL;
     struct pci_dev      *pci_devp = NULL;
     int                 pci_device_id_cnt = 0;
     unsigned int        pci_device_id[ASC_PCI_DEVICE_ID_CNT] = {
@@ -4550,12 +4344,6 @@
 
     ASC_DBG(1, "advansys_detect: begin\n");
 
-#if ASC_LINUX_KERNEL24
-    tpnt->proc_name = "advansys";
-#elif ASC_LINUX_KERNEL22
-    tpnt->proc_dir = &proc_scsi_advansys;
-#endif
-
     asc_board_count = 0;
 
     /*
@@ -4681,13 +4469,9 @@
                             NULL) {
                             pci_device_id_cnt++;
                         } else {
-#if ASC_LINUX_KERNEL24
                             if (pci_enable_device(pci_devp) == 0) {
                                 pci_devicep[pci_card_cnt_max++] = pci_devp;
                             }
-#elif ASC_LINUX_KERNEL22
-                            pci_devicep[pci_card_cnt_max++] = pci_devp;
-#endif
                         }
                     }
 
@@ -4724,17 +4508,16 @@
                     ASC_DBG2(2,
                         "advansys_detect: devfn %d, bus number %d\n",
                         pci_devp->devfn, pci_devp->bus->number);
-#if ASC_LINUX_KERNEL24
                     iop = pci_resource_start(pci_devp, 0);
-#elif ASC_LINUX_KERNEL22
-                    iop = pci_devp->base_address[0] & PCI_IOADDRESS_MASK;
-#endif
                     ASC_DBG2(1,
                         "advansys_detect: vendorID %X, deviceID %X\n",
                         pci_devp->vendor, pci_devp->device);
                     ASC_DBG2(2, "advansys_detect: iop %X, irqLine %d\n",
                         iop, pci_devp->irq);
                 }
+		if(pci_devp)
+		    dev = &pci_devp->dev;
+
 #endif /* CONFIG_PCI */
                 break;
 
@@ -4765,7 +4548,7 @@
                 continue;
             }
 
-	    scsi_set_device(shp, &pci_devp->dev);
+	    scsi_set_device(shp, dev);
 
             /* Save a pointer to the Scsi_Host of each board found. */
             asc_host[asc_board_count++] = shp;
@@ -4849,11 +4632,7 @@
                     iolen = ADV_38C1600_IOLEN;
                 }
 #ifdef CONFIG_PCI
-#if ASC_LINUX_KERNEL24
                 pci_memory_address = pci_resource_start(pci_devp, 1);
-#elif ASC_LINUX_KERNEL22
-                pci_memory_address = pci_devp->base_address[1];
-#endif
                 ASC_DBG1(1, "advansys_detect: pci_memory_address: 0x%lx\n",
                     (ulong) pci_memory_address);
                 if ((boardp->ioremap_addr =
@@ -4904,7 +4683,8 @@
 #endif /* CONFIG_PROC_FS */
 
             if (ASC_NARROW_BOARD(boardp)) {
-                /*
+		asc_dvc_varp->cfg->dev = dev;
+		/*
                  * Set the board bus type and PCI IRQ before
                  * calling AscInitGetConfig().
                  */
@@ -4926,7 +4706,6 @@
 #ifdef CONFIG_PCI
                 case ASC_IS_PCI:
                     shp->irq = asc_dvc_varp->irq_no = pci_devp->irq;
-                    asc_dvc_varp->cfg->pci_dev = pci_devp;
                     asc_dvc_varp->cfg->pci_slot_info =
                         ASC_PCI_MKID(pci_devp->bus->number,
                             PCI_SLOT(pci_devp->devfn),
@@ -4944,13 +4723,13 @@
                     break;
                 }
             } else {
+                adv_dvc_varp->cfg->dev = dev;
                 /*
                  * For Wide boards set PCI information before calling
                  * AdvInitGetConfig().
                  */
 #ifdef CONFIG_PCI
                 shp->irq = adv_dvc_varp->irq_no = pci_devp->irq;
-                adv_dvc_varp->cfg->pci_dev = pci_devp;
                 adv_dvc_varp->cfg->pci_slot_info =
                     ASC_PCI_MKID(pci_devp->bus->number,
                         PCI_SLOT(pci_devp->devfn),
@@ -5321,11 +5100,7 @@
 
             /* BIOS start address. */
             if (ASC_NARROW_BOARD(boardp)) {
-#if ASC_LINUX_KERNEL24
                 shp->base =
-#elif ASC_LINUX_KERNEL22
-                shp->base = (char *)
-#endif
                         ((ulong) AscGetChipBiosAddress(
                             asc_dvc_varp->iop_base,
                             asc_dvc_varp->bus_type));
@@ -5360,11 +5135,7 @@
                      * Convert x86 realmode code segment to a linear
                      * address by shifting left 4.
                      */
-                    shp->base =
-#if ASC_LINUX_KERNEL22
-                        (char *)
-#endif
-                        ((ulong) boardp->bios_codeseg << 4);
+                    shp->base = ((ulong) boardp->bios_codeseg << 4);
                 } else {
                     shp->base = 0;
                 }
@@ -5385,7 +5156,6 @@
             ASC_DBG2(2,
                 "advansys_detect: request_region port 0x%lx, len 0x%x\n",
                 (ulong) shp->io_port, boardp->asc_n_io_port);
-#if ASC_LINUX_KERNEL24
             if (request_region(shp->io_port, boardp->asc_n_io_port,
                                "advansys") == NULL) {
                 ASC_PRINT3(
@@ -5398,9 +5168,6 @@
                 asc_board_count--;
                 continue;
             }
-#elif ASC_LINUX_KERNEL22
-            request_region(shp->io_port, boardp->asc_n_io_port, "advansys");
-#endif
 
             /* Register DMA Channel for Narrow boards. */
             shp->dma_channel = NO_ISA_DMA; /* Default to no ISA DMA. */
@@ -5880,7 +5647,7 @@
     default:
         done_scp = asc_dequeue_list(&boardp->done, NULL, ASC_TID_ALL);
         /* Interrupts could be enabled here. */
-        asc_scsi_done_list(done_scp, 0);
+        asc_scsi_done_list(done_scp);
         break;
     }
     spin_unlock_irqrestore(&boardp->lock, flags);
@@ -6063,7 +5830,7 @@
      * Complete all the 'done_scp' requests.
      */
     if (done_scp != NULL) {
-        asc_scsi_done_list(done_scp, 0);
+        asc_scsi_done_list(done_scp);
     }
 
     ASC_DBG1(1, "advansys_reset: ret %d\n", ret);
@@ -6149,10 +5916,8 @@
  * ints[2] - second argument
  * ...
  */
-ASC_INITFUNC(
-void,
+void __init
 advansys_setup(char *str, int *ints)
-)
 {
     int    i;
 
@@ -6328,7 +6093,7 @@
      * Complete all requests on the done list.
      */
 
-    asc_scsi_done_list(done_scp, 1);
+    asc_scsi_done_list(done_scp);
 
     ASC_DBG(1, "advansys_interrupt: end\n");
     return IRQ_HANDLED;
@@ -6374,23 +6139,38 @@
  * Interrupts can be enabled on entry.
  */
 STATIC void
-asc_scsi_done_list(Scsi_Cmnd *scp, int from_isr)
+asc_scsi_done_list(Scsi_Cmnd *scp)
 {
     Scsi_Cmnd    *tscp;
-    ulong	  flags = 0;
 
     ASC_DBG(2, "asc_scsi_done_list: begin\n");
     while (scp != NULL) {
+	asc_board_t *boardp;
+	struct device *dev;
+
         ASC_DBG1(3, "asc_scsi_done_list: scp 0x%lx\n", (ulong) scp);
         tscp = REQPNEXT(scp);
         scp->host_scribble = NULL;
+
+	boardp = ASC_BOARDP(scp->device->host);
+
+	if (ASC_NARROW_BOARD(boardp))
+	    dev = boardp->dvc_cfg.asc_dvc_cfg.dev;
+	else
+	    dev = boardp->dvc_cfg.adv_dvc_cfg.dev;
+
+	if (scp->use_sg)
+	    dma_unmap_sg(dev, (struct scatterlist *)scp->request_buffer,
+			 scp->use_sg, scp->sc_data_direction);
+	else if (scp->request_bufflen)
+	    dma_unmap_single(dev, scp->SCp.dma_handle,
+			     scp->request_bufflen, scp->sc_data_direction);
+
         ASC_STATS(scp->device->host, done);
         ASC_ASSERT(scp->scsi_done != NULL);
-	if (from_isr)
-	    spin_lock_irqsave(scp->device->host->host_lock, flags);
+
         scp->scsi_done(scp);
-	if (from_isr)
-	    spin_unlock_irqrestore(scp->device->host->host_lock, flags);
+
         scp = tscp;
     }
     ASC_DBG(2, "asc_scsi_done_list: done\n");
@@ -6619,6 +6399,8 @@
 STATIC int
 asc_build_req(asc_board_t *boardp, Scsi_Cmnd *scp)
 {
+    struct device *dev = boardp->dvc_cfg.asc_dvc_cfg.dev;
+
     /*
      * Mutually exclusive access is required to 'asc_scsi_q' and
      * 'asc_sg_head' until after the request is started.
@@ -6665,9 +6447,9 @@
      */
     if ((boardp->dvc_var.asc_dvc_var.cur_dvc_qng[scp->device->id] > 0) &&
         (boardp->reqcnt[scp->device->id] % 255) == 0) {
-        asc_scsi_q.q2.tag_code = M2_QTAG_MSG_ORDERED;
+        asc_scsi_q.q2.tag_code = MSG_ORDERED_TAG;
     } else {
-        asc_scsi_q.q2.tag_code = M2_QTAG_MSG_SIMPLE;
+        asc_scsi_q.q2.tag_code = MSG_SIMPLE_TAG;
     }
 
     /*
@@ -6679,8 +6461,10 @@
          * CDB request of single contiguous buffer.
          */
         ASC_STATS(scp->device->host, cont_cnt);
-        asc_scsi_q.q1.data_addr =
-            cpu_to_le32(virt_to_bus(scp->request_buffer));
+	scp->SCp.dma_handle = scp->request_bufflen ?
+	    dma_map_single(dev, scp->request_buffer,
+			   scp->request_bufflen, scp->sc_data_direction) : 0;
+	asc_scsi_q.q1.data_addr = cpu_to_le32(scp->SCp.dma_handle);
         asc_scsi_q.q1.data_cnt = cpu_to_le32(scp->request_bufflen);
         ASC_STATS_ADD(scp->device->host, cont_xfer,
                       ASC_CEILING(scp->request_bufflen, 512));
@@ -6691,12 +6475,17 @@
          * CDB scatter-gather request list.
          */
         int                     sgcnt;
+	int			use_sg;
         struct scatterlist      *slp;
 
-        if (scp->use_sg > scp->device->host->sg_tablesize) {
+	slp = (struct scatterlist *)scp->request_buffer;
+	use_sg = dma_map_sg(dev, slp, scp->use_sg, scp->sc_data_direction);
+
+	if (use_sg > scp->device->host->sg_tablesize) {
             ASC_PRINT3(
 "asc_build_req: board %d: use_sg %d > sg_tablesize %d\n",
-                boardp->id, scp->use_sg, scp->device->host->sg_tablesize);
+		boardp->id, use_sg, scp->device->host->sg_tablesize);
+	    dma_unmap_sg(dev, slp, scp->use_sg, scp->sc_data_direction);
             scp->result = HOST_BYTE(DID_ERROR);
             asc_enqueue(&boardp->done, scp, ASC_BACK);
             return ASC_ERROR;
@@ -6715,19 +6504,16 @@
         asc_scsi_q.q1.data_cnt = 0;
         asc_scsi_q.q1.data_addr = 0;
         /* This is a byte value, otherwise it would need to be swapped. */
-        asc_sg_head.entry_cnt = asc_scsi_q.q1.sg_queue_cnt = scp->use_sg;
+	asc_sg_head.entry_cnt = asc_scsi_q.q1.sg_queue_cnt = use_sg;
         ASC_STATS_ADD(scp->device->host, sg_elem, asc_sg_head.entry_cnt);
 
         /*
          * Convert scatter-gather list into ASC_SG_HEAD list.
          */
-        slp = (struct scatterlist *) scp->request_buffer;
-        for (sgcnt = 0; sgcnt < scp->use_sg; sgcnt++, slp++) {
-            asc_sg_head.sg_list[sgcnt].addr =
-                cpu_to_le32(virt_to_bus(
-		(unsigned char *)page_address(slp->page) + slp->offset));
-            asc_sg_head.sg_list[sgcnt].bytes = cpu_to_le32(slp->length);
-            ASC_STATS_ADD(scp->device->host, sg_xfer, ASC_CEILING(slp->length, 512));
+	for (sgcnt = 0; sgcnt < use_sg; sgcnt++, slp++) {
+	    asc_sg_head.sg_list[sgcnt].addr = cpu_to_le32(sg_dma_address(slp));
+	    asc_sg_head.sg_list[sgcnt].bytes = cpu_to_le32(sg_dma_len(slp));
+	    ASC_STATS_ADD(scp->device->host, sg_xfer, ASC_CEILING(sg_dma_len(slp), 512));
         }
     }
 
@@ -6755,6 +6541,7 @@
     ADV_SCSI_REQ_Q      *scsiqp;
     int                 i;
     int                 ret;
+    struct device	*dev = boardp->dvc_cfg.adv_dvc_cfg.dev;
 
     /*
      * Allocate an adv_req_t structure from the board to execute
@@ -6827,15 +6614,23 @@
      * Build ADV_SCSI_REQ_Q for a contiguous buffer or a scatter-gather
      * buffer command.
      */
-    scsiqp->data_cnt = cpu_to_le32(scp->request_bufflen);
-    scsiqp->vdata_addr = scp->request_buffer;
-    scsiqp->data_addr = cpu_to_le32(virt_to_bus(scp->request_buffer));
 
     if (scp->use_sg == 0) {
         /*
          * CDB request of single contiguous buffer.
          */
         reqp->sgblkp = NULL;
+	scsiqp->data_cnt = cpu_to_le32(scp->request_bufflen);
+	if (scp->request_bufflen) {
+	    scsiqp->vdata_addr = scp->request_buffer;
+	    scp->SCp.dma_handle =
+	        dma_map_single(dev, scp->request_buffer,
+			       scp->request_bufflen, scp->sc_data_direction);
+	} else {
+	    scsiqp->vdata_addr = 0;
+	    scp->SCp.dma_handle = 0;
+	}
+	scsiqp->data_addr = cpu_to_le32(scp->SCp.dma_handle);
         scsiqp->sg_list_ptr = NULL;
         scsiqp->sg_real_addr = 0;
         ASC_STATS(scp->device->host, cont_cnt);
@@ -6845,10 +6640,21 @@
         /*
          * CDB scatter-gather request list.
          */
-        if (scp->use_sg > ADV_MAX_SG_LIST) {
+	struct scatterlist *slp;
+	int use_sg;
+
+	scsiqp->data_cnt = 0;
+	scsiqp->vdata_addr = 0;
+	scsiqp->data_addr = 0;
+
+	slp = (struct scatterlist *)scp->request_buffer;
+	use_sg = dma_map_sg(dev, slp, scp->use_sg, scp->sc_data_direction);
+
+	if (use_sg > ADV_MAX_SG_LIST) {
             ASC_PRINT3(
 "adv_build_req: board %d: use_sg %d > ADV_MAX_SG_LIST %d\n",
-                boardp->id, scp->use_sg, scp->device->host->sg_tablesize);
+		boardp->id, use_sg, scp->device->host->sg_tablesize);
+	    dma_unmap_sg(dev, slp, scp->use_sg, scp->sc_data_direction);
             scp->result = HOST_BYTE(DID_ERROR);
             asc_enqueue(&boardp->done, scp, ASC_BACK);
 
@@ -6862,7 +6668,7 @@
             return ASC_ERROR;
         }
 
-        if ((ret = adv_get_sglist(boardp, reqp, scp)) != ADV_SUCCESS) {
+	if ((ret = adv_get_sglist(boardp, reqp, scp, use_sg)) != ADV_SUCCESS) {
             /*
              * Free the adv_req_t structure by adding it back to the
              * board free list.
@@ -6874,7 +6680,7 @@
         }
 
         ASC_STATS(scp->device->host, sg_cnt);
-        ASC_STATS_ADD(scp->device->host, sg_elem, scp->use_sg);
+	ASC_STATS_ADD(scp->device->host, sg_elem, use_sg);
     }
 
     ASC_DBG_PRT_ADV_SCSI_REQ_Q(2, scsiqp);
@@ -6898,7 +6704,7 @@
  *      ADV_ERROR(-1) - SG List creation failed
  */
 STATIC int
-adv_get_sglist(asc_board_t *boardp, adv_req_t *reqp, Scsi_Cmnd *scp)
+adv_get_sglist(asc_board_t *boardp, adv_req_t *reqp, Scsi_Cmnd *scp, int use_sg)
 {
     adv_sgblk_t         *sgblkp;
     ADV_SCSI_REQ_Q      *scsiqp;
@@ -6910,7 +6716,7 @@
 
     scsiqp = (ADV_SCSI_REQ_Q *) ADV_32BALIGN(&reqp->scsi_req_q);
     slp = (struct scatterlist *) scp->request_buffer;
-    sg_elem_cnt = scp->use_sg;
+    sg_elem_cnt = use_sg;
     prev_sg_block = NULL;
     reqp->sgblkp = NULL;
 
@@ -6982,11 +6788,9 @@
 
         for (i = 0; i < NO_OF_SG_PER_BLOCK; i++)
         {
-            sg_block->sg_list[i].sg_addr =
-                cpu_to_le32(virt_to_bus(
-                   (unsigned char *)page_address(slp->page) + slp->offset));
-            sg_block->sg_list[i].sg_count = cpu_to_le32(slp->length);
-            ASC_STATS_ADD(scp->device->host, sg_xfer, ASC_CEILING(slp->length, 512));
+	    sg_block->sg_list[i].sg_addr = cpu_to_le32(sg_dma_address(slp));
+	    sg_block->sg_list[i].sg_count = cpu_to_le32(sg_dma_len(slp));
+	    ASC_STATS_ADD(scp->device->host, sg_xfer, ASC_CEILING(sg_dma_len(slp), 512));
 
             if (--sg_elem_cnt == 0)
             {   /* Last ADV_SG_BLOCK and scatter-gather entry. */
@@ -7079,14 +6883,13 @@
          * If an INQUIRY command completed successfully, then call
          * the AscInquiryHandling() function to set-up the device.
          */
-        if (scp->cmnd[0] == SCSICMD_Inquiry && scp->device->lun == 0 &&
+        if (scp->cmnd[0] == INQUIRY && scp->device->lun == 0 &&
             (scp->request_bufflen - qdonep->remain_bytes) >= 8)
         {
             AscInquiryHandling(asc_dvc_varp, scp->device->id & 0x7,
                 (ASC_SCSI_INQUIRY *) scp->request_buffer);
         }
 
-#if ASC_LINUX_KERNEL24
         /*
          * Check for an underrun condition.
          *
@@ -7099,15 +6902,14 @@
             (unsigned) qdonep->remain_bytes);
             scp->resid = qdonep->remain_bytes;
         }
-#endif
         break;
 
     case QD_WITH_ERROR:
         ASC_DBG(2, "asc_isr_callback: QD_WITH_ERROR\n");
         switch (qdonep->d3.host_stat) {
         case QHSTA_NO_ERROR:
-            if (qdonep->d3.scsi_stat == SS_CHK_CONDITION) {
-                ASC_DBG(2, "asc_isr_callback: SS_CHK_CONDITION\n");
+            if (qdonep->d3.scsi_stat == SAM_STAT_CHECK_CONDITION) {
+                ASC_DBG(2, "asc_isr_callback: SAM_STAT_CHECK_CONDITION\n");
                 ASC_DBG_PRT_SENSE(2, scp->sense_buffer,
                     sizeof(scp->sense_buffer));
                 /*
@@ -7185,9 +6987,7 @@
     Scsi_Cmnd           *scp;
     struct Scsi_Host    *shp;
     int                 i;
-#if ASC_LINUX_KERNEL24
     ADV_DCNT            resid_cnt;
-#endif
 
 
     ASC_DBG2(1, "adv_isr_callback: adv_dvc_varp 0x%lx, scsiqp 0x%lx\n",
@@ -7270,7 +7070,6 @@
         ASC_DBG(2, "adv_isr_callback: QD_NO_ERROR\n");
         scp->result = 0;
 
-#if ASC_LINUX_KERNEL24
         /*
          * Check for an underrun condition.
          *
@@ -7284,15 +7083,14 @@
                 (ulong) resid_cnt);
             scp->resid = resid_cnt;
         }
-#endif
         break;
 
     case QD_WITH_ERROR:
         ASC_DBG(2, "adv_isr_callback: QD_WITH_ERROR\n");
         switch (scsiqp->host_status) {
         case QHSTA_NO_ERROR:
-            if (scsiqp->scsi_status == SS_CHK_CONDITION) {
-                ASC_DBG(2, "adv_isr_callback: SS_CHK_CONDITION\n");
+            if (scsiqp->scsi_status == SAM_STAT_CHECK_CONDITION) {
+                ASC_DBG(2, "adv_isr_callback: SAM_STAT_CHECK_CONDITION\n");
                 ASC_DBG_PRT_SENSE(2, scp->sense_buffer,
                     sizeof(scp->sense_buffer));
                 /*
@@ -8858,7 +8656,7 @@
             (unsigned) offset, (unsigned) advoffset, cplen);
     if (offset <= advoffset) {
         /* Read offset below current offset, copy everything. */
-        cnt = ASC_MIN(cplen, leftlen);
+        cnt = min(cplen, leftlen);
         ASC_DBG3(2, "asc_proc_copy: curbuf 0x%lx, cp 0x%lx, cnt %d\n",
                 (ulong) curbuf, (ulong) cp, cnt);
         memcpy(curbuf, cp, cnt);
@@ -8866,7 +8664,7 @@
         /* Read offset within current range, partial copy. */
         cnt = (advoffset + cplen) - offset;
         cp = (cp + cplen) - cnt;
-        cnt = ASC_MIN(cnt, leftlen);
+        cnt = min(cnt, leftlen);
         ASC_DBG3(2, "asc_proc_copy: curbuf 0x%lx, cp 0x%lx, cnt %d\n",
                 (ulong) curbuf, (ulong) cp, cnt);
         memcpy(curbuf, cp, cnt);
@@ -8899,7 +8697,7 @@
         (void) printk(s);
         ret = 0;
     } else {
-        ret = ASC_MIN(buflen, ret);
+        ret = min(buflen, ret);
         memcpy(buf, s, ret);
     }
     va_end(args);
@@ -9002,16 +8800,14 @@
 /*
  * Read a PCI configuration byte.
  */
-ASC_INITFUNC(
-STATIC uchar,
+STATIC uchar __init
 DvcReadPCIConfigByte(
         ASC_DVC_VAR *asc_dvc,
         ushort offset)
-)
 {
 #ifdef CONFIG_PCI
     uchar byte_data;
-    pci_read_config_byte(asc_dvc->cfg->pci_dev, offset, &byte_data);
+    pci_read_config_byte(to_pci_dev(asc_dvc->cfg->dev), offset, &byte_data);
     return byte_data;
 #else /* !defined(CONFIG_PCI) */
     return 0;
@@ -9021,16 +8817,14 @@
 /*
  * Write a PCI configuration byte.
  */
-ASC_INITFUNC(
-STATIC void,
+STATIC void __init
 DvcWritePCIConfigByte(
         ASC_DVC_VAR *asc_dvc,
         ushort offset,
         uchar  byte_data)
-)
 {
 #ifdef CONFIG_PCI
-    pci_write_config_byte(asc_dvc->cfg->pci_dev, offset, byte_data);
+    pci_write_config_byte(to_pci_dev(asc_dvc->cfg->dev), offset, byte_data);
 #endif /* CONFIG_PCI */
 }
 
@@ -9038,13 +8832,10 @@
  * Return the BIOS address of the adapter at the specified
  * I/O port and with the specified bus type.
  */
-ASC_INITFUNC(
-STATIC ushort,
+STATIC ushort __init
 AscGetChipBiosAddress(
         PortAddr iop_base,
-        ushort bus_type
-)
-)
+        ushort bus_type)
 {
     ushort  cfg_lsw;
     ushort  bios_addr;
@@ -9119,16 +8910,14 @@
 /*
  * Read a PCI configuration byte.
  */
-ASC_INITFUNC(
-STATIC uchar,
+STATIC uchar __init
 DvcAdvReadPCIConfigByte(
         ADV_DVC_VAR *asc_dvc,
         ushort offset)
-)
 {
 #ifdef CONFIG_PCI
     uchar byte_data;
-    pci_read_config_byte(asc_dvc->cfg->pci_dev, offset, &byte_data);
+    pci_read_config_byte(to_pci_dev(asc_dvc->cfg->dev), offset, &byte_data);
     return byte_data;
 #else /* CONFIG_PCI */
     return 0;
@@ -9138,16 +8927,14 @@
 /*
  * Write a PCI configuration byte.
  */
-ASC_INITFUNC(
-STATIC void,
+STATIC void __init
 DvcAdvWritePCIConfigByte(
         ADV_DVC_VAR *asc_dvc,
         ushort offset,
         uchar  byte_data)
-)
 {
 #ifdef CONFIG_PCI
-    pci_write_config_byte(asc_dvc->cfg->pci_dev, offset, byte_data);
+    pci_write_config_byte(to_pci_dev(asc_dvc->cfg->dev), offset, byte_data);
 #else /* CONFIG_PCI */
     return 0;
 #endif /* CONFIG_PCI */
@@ -9358,16 +9145,6 @@
         s->host_busy, s->host_no,
         (unsigned) s->last_reset);
 
-#if ASC_LINUX_KERNEL24
-    printk(
-" hostt 0x%lx\n",
-        (ulong) s->hostt);
-#elif ASC_LINUX_KERNEL22
-    printk(
-" host_queue 0x%lx, hostt 0x%lx, block 0x%lx,\n",
-        (ulong) s->host_queue, (ulong) s->hostt, (ulong) s->block);
-#endif
-
     printk(
 " base 0x%lx, io_port 0x%lx, n_io_port %u, irq 0x%x,\n",
         (ulong) s->base, (ulong) s->io_port, s->n_io_port, s->irq);
@@ -9404,11 +9181,9 @@
 
     asc_prt_hex(" CDB", s->cmnd, s->cmd_len);
 
-#if ASC_LINUX_KERNEL24
     printk (
 "sc_data_direction %u, resid %d\n",
         s->sc_data_direction, s->resid);
-#endif
 
     printk(
 " use_sg %u, sglist_len %u, abort_reason 0x%x\n",
@@ -9423,15 +9198,9 @@
 " timeout_per_command %d, timeout_total %d, timeout %d\n",
         s->timeout_per_command, s->timeout_total, s->timeout);
 
-#if ASC_LINUX_KERNEL24
     printk(
 " internal_timeout %u, flags %u\n",
         s->internal_timeout, s->flags);
-#elif ASC_LINUX_KERNEL22
-    printk(
-" internal_timeout %u, flags %u, this_count %d\n",
-        s->internal_timeout, s->flags,s->this_count);
-#endif
 
     printk(
 " scsi_done 0x%lx, done 0x%lx, host_scribble 0x%lx, result 0x%x\n",
@@ -9507,7 +9276,8 @@
 
     printk(
 " pci_device_id %d, lib_serial_no %u, lib_version %u, mcode_date 0x%x,\n",
-          h->pci_dev->device, h->lib_serial_no, h->lib_version, h->mcode_date);
+	   to_pci_dev(h->dev)->device, h->lib_serial_no, h->lib_version,
+	   h->mcode_date);
 
     printk(
 " mcode_version %d, overrun_buf 0x%lx\n",
@@ -9632,7 +9402,7 @@
 
     printk(
 "  mcode_version 0x%x, pci_device_id 0x%x, lib_version %u\n",
-       h->mcode_version, h->pci_dev->device, h->lib_version);
+       h->mcode_version, to_pci_dev(h->dev)->device, h->lib_version);
 
     printk(
 "  control_flag 0x%x, pci_slot_info 0x%x\n",
@@ -9787,12 +9557,9 @@
  * --- Asc Library Functions
  */
 
-ASC_INITFUNC(
-STATIC ushort,
+STATIC ushort __init
 AscGetEisaChipCfg(
-                     PortAddr iop_base
-)
-)
+                     PortAddr iop_base)
 {
     PortAddr            eisa_cfg_iop;
 
@@ -9801,13 +9568,11 @@
     return (inpw(eisa_cfg_iop));
 }
 
-ASC_INITFUNC(
-STATIC uchar,
+STATIC uchar __init
 AscSetChipScsiID(
                     PortAddr iop_base,
                     uchar new_host_id
 )
-)
 {
     ushort              cfg_lsw;
 
@@ -9821,12 +9586,9 @@
     return (AscGetChipScsiID(iop_base));
 }
 
-ASC_INITFUNC(
-STATIC uchar,
+STATIC uchar __init
 AscGetChipScsiCtrl(
-                      PortAddr iop_base
-)
-)
+		PortAddr iop_base)
 {
     uchar               sc;
 
@@ -9836,13 +9598,11 @@
     return (sc);
 }
 
-ASC_INITFUNC(
-STATIC uchar,
+STATIC uchar __init
 AscGetChipVersion(
                      PortAddr iop_base,
                      ushort bus_type
 )
-)
 {
     if ((bus_type & ASC_IS_EISA) != 0) {
         PortAddr            eisa_iop;
@@ -9855,12 +9615,9 @@
     return (AscGetChipVerNo(iop_base));
 }
 
-ASC_INITFUNC(
-STATIC ushort,
+STATIC ushort __init
 AscGetChipBusType(
-                     PortAddr iop_base
-)
-)
+                     PortAddr iop_base)
 {
     ushort              chip_ver;
 
@@ -9940,22 +9697,19 @@
     return (0);
 }
 
-STATIC PortAddr _asc_def_iop_base[ASC_IOADR_TABLE_MAX_IX] ASC_INITDATA =
+STATIC PortAddr _asc_def_iop_base[ASC_IOADR_TABLE_MAX_IX] __initdata =
 {
     0x100, ASC_IOADR_1, 0x120, ASC_IOADR_2, 0x140, ASC_IOADR_3, ASC_IOADR_4,
     ASC_IOADR_5, ASC_IOADR_6, ASC_IOADR_7, ASC_IOADR_8
 };
 
 #ifdef CONFIG_ISA
-STATIC uchar _isa_pnp_inited ASC_INITDATA = 0;
+STATIC uchar _isa_pnp_inited __initdata = 0;
 
-ASC_INITFUNC(
-STATIC PortAddr,
+STATIC PortAddr __init
 AscSearchIOPortAddr(
                        PortAddr iop_beg,
-                       ushort bus_type
-)
-)
+                       ushort bus_type)
 {
     if (bus_type & ASC_IS_VL) {
         while ((iop_beg = AscSearchIOPortAddr11(iop_beg)) != 0) {
@@ -9986,12 +9740,10 @@
     return (0);
 }
 
-ASC_INITFUNC(
-STATIC PortAddr,
+STATIC PortAddr __init
 AscSearchIOPortAddr11(
                          PortAddr s_addr
 )
-)
 {
     int                 i;
     PortAddr            iop_base;
@@ -10017,11 +9769,8 @@
     return (0);
 }
 
-ASC_INITFUNC(
-STATIC void,
-AscSetISAPNPWaitForKey(
-    void)
-)
+STATIC void __init
+AscSetISAPNPWaitForKey(void)
 {
     outp(ASC_ISA_PNP_PORT_ADDR, 0x02);
     outp(ASC_ISA_PNP_PORT_WRITE, 0x02);
@@ -10029,25 +9778,20 @@
 }
 #endif /* CONFIG_ISA */
 
-ASC_INITFUNC(
-STATIC void,
+STATIC void __init
 AscToggleIRQAct(
                    PortAddr iop_base
 )
-)
 {
     AscSetChipStatus(iop_base, CIW_IRQ_ACT);
     AscSetChipStatus(iop_base, 0);
     return;
 }
 
-ASC_INITFUNC(
-STATIC uchar,
+STATIC uchar __init
 AscGetChipIRQ(
                  PortAddr iop_base,
-                 ushort bus_type
-)
-)
+                 ushort bus_type)
 {
     ushort              cfg_lsw;
     uchar               chip_irq;
@@ -10077,14 +9821,11 @@
     return ((uchar) (chip_irq + ASC_MIN_IRQ_NO));
 }
 
-ASC_INITFUNC(
-STATIC uchar,
+STATIC uchar __init
 AscSetChipIRQ(
                  PortAddr iop_base,
                  uchar irq_no,
-                 ushort bus_type
-)
-)
+                 ushort bus_type)
 {
     ushort              cfg_lsw;
 
@@ -10119,12 +9860,9 @@
 }
 
 #ifdef CONFIG_ISA
-ASC_INITFUNC(
-STATIC void,
+STATIC void __init
 AscEnableIsaDma(
-                   uchar dma_channel
-)
-)
+                   uchar dma_channel)
 {
     if (dma_channel < 4) {
         outp(0x000B, (ushort) (0xC0 | dma_channel));
@@ -10285,7 +10023,7 @@
             return (0);
         } else {
 
-            ext_msg.msg_type = M1_MSG_REJECT;
+            ext_msg.msg_type = MESSAGE_REJECT;
             AscMemWordCopyPtrToLram(iop_base,
                                  ASCV_MSGOUT_BEG,
                                  (uchar *) &ext_msg,
@@ -10385,7 +10123,7 @@
                              (ushort) ASCV_SCSIBUSY_B, scsi_busy);
             asc_dvc->queue_full_or_busy |= target_id;
 
-            if (scsi_status == SS_QUEUE_FULL) {
+            if (scsi_status == SAM_STAT_TASK_SET_FULL) {
                 if (cur_dvc_qng > ASC_MIN_TAGGED_CMD) {
                     cur_dvc_qng -= 1;
                     asc_dvc->max_dvc_qng[tid_no] = cur_dvc_qng;
@@ -10732,7 +10470,7 @@
             } else {
                 if ((AscReadLramByte(iop_base,
                           (ushort) (q_addr + (ushort) ASC_SCSIQ_CDB_BEG)) ==
-                     SCSICMD_StartStopUnit)) {
+                     START_STOP)) {
                     asc_dvc->unit_not_ready &= ~target_id;
                     if (scsiq->d3.done_stat != QD_NO_ERROR) {
                         asc_dvc->start_motor &= ~target_id;
@@ -11005,14 +10743,14 @@
 #define ASC_SYN_OFFSET_ONE_DISABLE_LIST  16
 STATIC uchar _syn_offset_one_disable_cmd[ASC_SYN_OFFSET_ONE_DISABLE_LIST] =
 {
-    SCSICMD_Inquiry,
-    SCSICMD_RequestSense,
-    SCSICMD_ReadCapacity,
-    SCSICMD_ReadTOC,
-    SCSICMD_ModeSelect6,
-    SCSICMD_ModeSense6,
-    SCSICMD_ModeSelect10,
-    SCSICMD_ModeSense10,
+    INQUIRY,
+    REQUEST_SENSE,
+    READ_CAPACITY,
+    READ_TOC,
+    MODE_SELECT,
+    MODE_SENSE,
+    MODE_SELECT_10,
+    MODE_SENSE_10,
     0xFF,
     0xFF,
     0xFF,
@@ -11065,7 +10803,7 @@
     target_ix = scsiq->q2.target_ix;
     tid_no = ASC_TIX_TO_TID(target_ix);
     n_q_required = 1;
-    if (scsiq->cdbptr[0] == SCSICMD_RequestSense) {
+    if (scsiq->cdbptr[0] == REQUEST_SENSE) {
         if ((asc_dvc->init_sdtr & scsiq->q1.target_id) != 0) {
             asc_dvc->sdtr_done &= ~scsiq->q1.target_id;
             sdtr_data = AscGetMCodeInitSDTRAtID(iop_base, tid_no);
@@ -11134,7 +10872,7 @@
         }
     }
     if (disable_syn_offset_one_fix) {
-        scsiq->q2.tag_code &= ~M2_QTAG_MSG_SIMPLE;
+        scsiq->q2.tag_code &= ~MSG_SIMPLE_TAG;
         scsiq->q2.tag_code |= (ASC_TAG_FLAG_DISABLE_ASYN_USE_SYN_FIX |
                                ASC_TAG_FLAG_DISABLE_DISCONNECT);
     } else {
@@ -11143,8 +10881,8 @@
     if ((scsiq->q1.cntl & QC_SG_HEAD) != 0) {
         if (asc_dvc->bug_fix_cntl) {
             if (asc_dvc->bug_fix_cntl & ASC_BUG_FIX_IF_NOT_DWB) {
-                if ((scsi_cmd == SCSICMD_Read6) ||
-                    (scsi_cmd == SCSICMD_Read10)) {
+                if ((scsi_cmd == READ_6) ||
+                    (scsi_cmd == READ_10)) {
                     addr =
                         (ADV_PADDR) le32_to_cpu(
                             sg_head->sg_list[sg_entry_cnt_minus_one].addr) +
@@ -11193,8 +10931,8 @@
     } else {
         if (asc_dvc->bug_fix_cntl) {
             if (asc_dvc->bug_fix_cntl & ASC_BUG_FIX_IF_NOT_DWB) {
-                if ((scsi_cmd == SCSICMD_Read6) ||
-                    (scsi_cmd == SCSICMD_Read10)) {
+                if ((scsi_cmd == READ_6) ||
+                    (scsi_cmd == READ_10)) {
                     addr = le32_to_cpu(scsiq->q1.data_addr) +
                         le32_to_cpu(scsiq->q1.data_cnt);
                     extra_bytes = (uchar) ((ushort) addr & 0x0003);
@@ -11365,7 +11103,7 @@
     }
     q_addr = ASC_QNO_TO_QADDR(q_no);
     if ((scsiq->q1.target_id & asc_dvc->use_tagged_qng) == 0) {
-        scsiq->q2.tag_code &= ~M2_QTAG_MSG_SIMPLE;
+        scsiq->q2.tag_code &= ~MSG_SIMPLE_TAG ;
     }
     scsiq->q1.status = QS_FREE;
     AscMemWordCopyPtrToLram(iop_base,
@@ -11862,12 +11600,9 @@
 }
 
 #ifdef CONFIG_ISA
-ASC_INITFUNC(
-STATIC ASC_DCNT,
+STATIC ASC_DCNT __init
 AscGetEisaProductID(
-                       PortAddr iop_base
-)
-)
+                       PortAddr iop_base)
 {
     PortAddr            eisa_iop;
     ushort              product_id_high, product_id_low;
@@ -11881,12 +11616,9 @@
     return (product_id);
 }
 
-ASC_INITFUNC(
-STATIC PortAddr,
+STATIC PortAddr __init
 AscSearchIOPortAddrEISA(
-                           PortAddr iop_base
-)
-)
+                           PortAddr iop_base)
 {
     ASC_DCNT            eisa_product_id;
 
@@ -12080,12 +11812,9 @@
     return (AscIsChipHalted(iop_base));
 }
 
-ASC_INITFUNC(
-STATIC ASC_DCNT,
+STATIC ASC_DCNT __init
 AscGetMaxDmaCount(
-                     ushort bus_type
-)
-)
+                     ushort bus_type)
 {
     if (bus_type & ASC_IS_ISA)
         return (ASC_MAX_ISA_DMA_COUNT);
@@ -12095,12 +11824,9 @@
 }
 
 #ifdef CONFIG_ISA
-ASC_INITFUNC(
-STATIC ushort,
+STATIC ushort __init
 AscGetIsaDmaChannel(
-                       PortAddr iop_base
-)
-)
+                       PortAddr iop_base)
 {
     ushort              channel;
 
@@ -12112,13 +11838,10 @@
     return (channel + 4);
 }
 
-ASC_INITFUNC(
-STATIC ushort,
+STATIC ushort __init
 AscSetIsaDmaChannel(
                        PortAddr iop_base,
-                       ushort dma_channel
-)
-)
+                       ushort dma_channel)
 {
     ushort              cfg_lsw;
     uchar               value;
@@ -12136,13 +11859,10 @@
     return (0);
 }
 
-ASC_INITFUNC(
-STATIC uchar,
+STATIC uchar __init
 AscSetIsaDmaSpeed(
                      PortAddr iop_base,
-                     uchar speed_value
-)
-)
+                     uchar speed_value)
 {
     speed_value &= 0x07;
     AscSetBank(iop_base, 1);
@@ -12151,12 +11871,10 @@
     return (AscGetIsaDmaSpeed(iop_base));
 }
 
-ASC_INITFUNC(
-STATIC uchar,
+STATIC uchar __init
 AscGetIsaDmaSpeed(
                      PortAddr iop_base
 )
-)
 {
     uchar               speed_value;
 
@@ -12168,12 +11886,10 @@
 }
 #endif /* CONFIG_ISA */
 
-ASC_INITFUNC(
-STATIC ushort,
+STATIC ushort __init
 AscReadPCIConfigWord(
     ASC_DVC_VAR *asc_dvc,
     ushort pci_config_offset)
-)
 {
     uchar       lsb, msb;
 
@@ -12182,12 +11898,10 @@
     return ((ushort) ((msb << 8) | lsb));
 }
 
-ASC_INITFUNC(
-STATIC ushort,
+STATIC ushort __init
 AscInitGetConfig(
         ASC_DVC_VAR *asc_dvc
 )
-)
 {
     ushort              warn_code;
     PortAddr            iop_base;
@@ -12267,12 +11981,10 @@
     return(warn_code);
 }
 
-ASC_INITFUNC(
-STATIC ushort,
+STATIC ushort __init
 AscInitSetConfig(
                     ASC_DVC_VAR *asc_dvc
 )
-)
 {
     ushort              warn_code = 0;
 
@@ -12288,12 +12000,10 @@
     return (warn_code);
 }
 
-ASC_INITFUNC(
-STATIC ushort,
+STATIC ushort __init
 AscInitFromAscDvcVar(
                         ASC_DVC_VAR *asc_dvc
 )
-)
 {
     PortAddr            iop_base;
     ushort              cfg_msw;
@@ -12301,7 +12011,7 @@
     ushort              pci_device_id;
 
     iop_base = asc_dvc->iop_base;
-    pci_device_id = asc_dvc->cfg->pci_dev->device;
+    pci_device_id = to_pci_dev(asc_dvc->cfg->dev)->device;
     warn_code = 0;
     cfg_msw = AscGetChipCfgMsw(iop_base);
     if ((cfg_msw & ASC_CFG_MSW_CLR_MASK) != 0) {
@@ -12393,12 +12103,9 @@
     return (warn_code);
 }
 
-ASC_INITFUNC(
-STATIC ushort,
+STATIC ushort __init
 AscInitAscDvcVar(
-                    ASC_DVC_VAR *asc_dvc
-)
-)
+                    ASC_DVC_VAR *asc_dvc)
 {
     int                 i;
     PortAddr            iop_base;
@@ -12508,12 +12215,8 @@
     return (warn_code);
 }
 
-ASC_INITFUNC(
-STATIC ushort,
-AscInitFromEEP(
-                  ASC_DVC_VAR *asc_dvc
-)
-)
+STATIC ushort __init
+AscInitFromEEP(ASC_DVC_VAR *asc_dvc)
 {
     ASCEEP_CONFIG       eep_config_buf;
     ASCEEP_CONFIG       *eep_config;
@@ -12729,12 +12432,9 @@
     return (warn_code);
 }
 
-ASC_INITFUNC(
-STATIC int,
+STATIC int __init
 AscTestExternalLram(
-                       ASC_DVC_VAR *asc_dvc
-)
-)
+                       ASC_DVC_VAR *asc_dvc)
 {
     PortAddr            iop_base;
     ushort              q_addr;
@@ -12756,13 +12456,11 @@
     return (sta);
 }
 
-ASC_INITFUNC(
-STATIC int,
+STATIC int __init
 AscWriteEEPCmdReg(
                      PortAddr iop_base,
                      uchar cmd_reg
 )
-)
 {
     uchar               read_back;
     int                 retry;
@@ -12781,13 +12479,11 @@
     }
 }
 
-ASC_INITFUNC(
-STATIC int,
+STATIC int __init
 AscWriteEEPDataReg(
                       PortAddr iop_base,
                       ushort data_reg
 )
-)
 {
     ushort              read_back;
     int                 retry;
@@ -12806,35 +12502,24 @@
     }
 }
 
-ASC_INITFUNC(
-STATIC void,
-AscWaitEEPRead(
-                  void
-)
-)
+STATIC void __init
+AscWaitEEPRead(void)
 {
     DvcSleepMilliSecond(1);
     return;
 }
 
-ASC_INITFUNC(
-STATIC void,
-AscWaitEEPWrite(
-                   void
-)
-)
+STATIC void __init
+AscWaitEEPWrite(void)
 {
     DvcSleepMilliSecond(20);
     return;
 }
 
-ASC_INITFUNC(
-STATIC ushort,
+STATIC ushort __init
 AscReadEEPWord(
                   PortAddr iop_base,
-                  uchar addr
-)
-)
+                  uchar addr)
 {
     ushort              read_wval;
     uchar               cmd_reg;
@@ -12849,14 +12534,11 @@
     return (read_wval);
 }
 
-ASC_INITFUNC(
-STATIC ushort,
+STATIC ushort __init
 AscWriteEEPWord(
                    PortAddr iop_base,
                    uchar addr,
-                   ushort word_val
-)
-)
+                   ushort word_val)
 {
     ushort              read_wval;
 
@@ -12876,13 +12558,10 @@
     return (read_wval);
 }
 
-ASC_INITFUNC(
-STATIC ushort,
+STATIC ushort __init
 AscGetEEPConfig(
                    PortAddr iop_base,
-                   ASCEEP_CONFIG * cfg_buf, ushort bus_type
-)
-)
+                   ASCEEP_CONFIG * cfg_buf, ushort bus_type)
 {
     ushort              wval;
     ushort              sum;
@@ -12928,13 +12607,10 @@
     return (sum);
 }
 
-ASC_INITFUNC(
-STATIC int,
+STATIC int __init
 AscSetEEPConfigOnce(
                        PortAddr iop_base,
-                       ASCEEP_CONFIG * cfg_buf, ushort bus_type
-)
-)
+                       ASCEEP_CONFIG * cfg_buf, ushort bus_type)
 {
     int                 n_error;
     ushort              *wbuf;
@@ -13026,13 +12702,11 @@
     return (n_error);
 }
 
-ASC_INITFUNC(
-STATIC int,
+STATIC int __init
 AscSetEEPConfig(
                    PortAddr iop_base,
                    ASCEEP_CONFIG * cfg_buf, ushort bus_type
 )
-)
 {
     int            retry;
     int            n_error;
@@ -13066,17 +12740,17 @@
     {
         if (!(asc_dvc->init_sdtr & tid_bits))
         {
-            if ((dvc_type == SCSI_TYPE_CDROM) &&
+            if ((dvc_type == TYPE_ROM) &&
                 (AscCompareString((uchar *) inq->vendor_id,
                     (uchar *) "HP ", 3) == 0))
             {
                 asc_dvc->pci_fix_asyn_xfer_always |= tid_bits;
             }
             asc_dvc->pci_fix_asyn_xfer |= tid_bits;
-            if ((dvc_type == SCSI_TYPE_PROC) ||
-                (dvc_type == SCSI_TYPE_SCANNER) ||
-                (dvc_type == SCSI_TYPE_CDROM) ||
-                (dvc_type == SCSI_TYPE_SASD))
+            if ((dvc_type == TYPE_PROCESSOR) ||
+                (dvc_type == TYPE_SCANNER) ||
+                (dvc_type == TYPE_ROM) ||
+                (dvc_type == TYPE_TAPE))
             {
                 asc_dvc->pci_fix_asyn_xfer &= ~tid_bits;
             }
@@ -14470,7 +14144,7 @@
  * unswapped on big-endian platforms.
  */
 STATIC ADVEEP_3550_CONFIG
-Default_3550_EEPROM_Config ASC_INITDATA = {
+Default_3550_EEPROM_Config __initdata = {
     ADV_EEPROM_BIOS_ENABLE,     /* cfg_lsw */
     0x0000,                     /* cfg_msw */
     0xFFFF,                     /* disc_enable */
@@ -14508,7 +14182,7 @@
 };
 
 STATIC ADVEEP_3550_CONFIG
-ADVEEP_3550_Config_Field_IsChar ASC_INITDATA = {
+ADVEEP_3550_Config_Field_IsChar __initdata = {
     0,                          /* cfg_lsw */
     0,                          /* cfg_msw */
     0,                          /* -disc_enable */
@@ -14546,7 +14220,7 @@
 };
 
 STATIC ADVEEP_38C0800_CONFIG
-Default_38C0800_EEPROM_Config ASC_INITDATA = {
+Default_38C0800_EEPROM_Config __initdata = {
     ADV_EEPROM_BIOS_ENABLE,     /* 00 cfg_lsw */
     0x0000,                     /* 01 cfg_msw */
     0xFFFF,                     /* 02 disc_enable */
@@ -14611,7 +14285,7 @@
 };
 
 STATIC ADVEEP_38C0800_CONFIG
-ADVEEP_38C0800_Config_Field_IsChar ASC_INITDATA = {
+ADVEEP_38C0800_Config_Field_IsChar __initdata = {
     0,                          /* 00 cfg_lsw */
     0,                          /* 01 cfg_msw */
     0,                          /* 02 disc_enable */
@@ -14676,7 +14350,7 @@
 };
 
 STATIC ADVEEP_38C1600_CONFIG
-Default_38C1600_EEPROM_Config ASC_INITDATA = {
+Default_38C1600_EEPROM_Config __initdata = {
     ADV_EEPROM_BIOS_ENABLE,     /* 00 cfg_lsw */
     0x0000,                     /* 01 cfg_msw */
     0xFFFF,                     /* 02 disc_enable */
@@ -14741,7 +14415,7 @@
 };
 
 STATIC ADVEEP_38C1600_CONFIG
-ADVEEP_38C1600_Config_Field_IsChar ASC_INITDATA = {
+ADVEEP_38C1600_Config_Field_IsChar __initdata = {
     0,                          /* 00 cfg_lsw */
     0,                          /* 01 cfg_msw */
     0,                          /* 02 disc_enable */
@@ -14813,10 +14487,8 @@
  * For a non-fatal error return a warning code. If there are no warnings
  * then 0 is returned.
  */
-ASC_INITFUNC(
-STATIC int,
+STATIC int __init
 AdvInitGetConfig(ADV_DVC_VAR *asc_dvc)
-)
 {
     ushort      warn_code;
     AdvPortAddr iop_base;
@@ -16800,10 +16472,8 @@
  *
  * Note: Chip is stopped on entry.
  */
-ASC_INITFUNC(
-STATIC int,
+STATIC int __init
 AdvInitFrom3550EEP(ADV_DVC_VAR *asc_dvc)
-)
 {
     AdvPortAddr         iop_base;
     ushort              warn_code;
@@ -16974,10 +16644,8 @@
  *
  * Note: Chip is stopped on entry.
  */
-ASC_INITFUNC(
-STATIC int,
+STATIC int __init
 AdvInitFrom38C0800EEP(ADV_DVC_VAR *asc_dvc)
-)
 {
     AdvPortAddr              iop_base;
     ushort                   warn_code;
@@ -17209,10 +16877,8 @@
  *
  * Note: Chip is stopped on entry.
  */
-ASC_INITFUNC(
-STATIC int,
+STATIC int __init
 AdvInitFrom38C1600EEP(ADV_DVC_VAR *asc_dvc)
-)
 {
     AdvPortAddr              iop_base;
     ushort                   warn_code;
@@ -17477,10 +17143,8 @@
  *
  * Return a checksum based on the EEPROM configuration read.
  */
-ASC_INITFUNC(
-STATIC ushort,
+STATIC ushort __init
 AdvGet3550EEPConfig(AdvPortAddr iop_base, ADVEEP_3550_CONFIG *cfg_buf)
-)
 {
     ushort              wval, chksum;
     ushort              *wbuf;
@@ -17525,11 +17189,9 @@
  *
  * Return a checksum based on the EEPROM configuration read.
  */
-ASC_INITFUNC(
-STATIC ushort,
+STATIC ushort __init
 AdvGet38C0800EEPConfig(AdvPortAddr iop_base,
                        ADVEEP_38C0800_CONFIG *cfg_buf)
-)
 {
     ushort              wval, chksum;
     ushort              *wbuf;
@@ -17574,11 +17236,9 @@
  *
  * Return a checksum based on the EEPROM configuration read.
  */
-ASC_INITFUNC(
-STATIC ushort,
+STATIC ushort __init
 AdvGet38C1600EEPConfig(AdvPortAddr iop_base,
                        ADVEEP_38C1600_CONFIG *cfg_buf)
-)
 {
     ushort              wval, chksum;
     ushort              *wbuf;
@@ -17621,10 +17281,8 @@
 /*
  * Read the EEPROM from specified location
  */
-ASC_INITFUNC(
-STATIC ushort,
+STATIC ushort __init
 AdvReadEEPWord(AdvPortAddr iop_base, int eep_word_addr)
-)
 {
     AdvWriteWordRegister(iop_base, IOPW_EE_CMD,
         ASC_EEP_CMD_READ | eep_word_addr);
@@ -17635,10 +17293,8 @@
 /*
  * Wait for EEPROM command to complete
  */
-ASC_INITFUNC(
-STATIC void,
+STATIC void __init
 AdvWaitEEPCmd(AdvPortAddr iop_base)
-)
 {
     int eep_delay_ms;
 
@@ -18290,7 +17946,7 @@
          * the device, otherwise may erroneously set *_able bits.
          */
         if (scsiq->done_status == QD_NO_ERROR &&
-            scsiq->cdb[0] == SCSICMD_Inquiry &&
+            scsiq->cdb[0] == INQUIRY &&
             scsiq->target_lun == 0 &&
             (scsiq->cdb[1] & ADV_INQ_RTN_VPD_AND_CMDDT)
                 == ADV_INQ_RTN_STD_INQUIRY_DATA)
--- diff/drivers/scsi/aha1542.c	2004-05-19 22:12:08.000000000 +0100
+++ source/drivers/scsi/aha1542.c	2004-06-11 19:22:03.000000000 +0100
@@ -47,7 +47,7 @@
 #include <asm/io.h>
 
 #include "scsi.h"
-#include "hosts.h"
+#include <scsi/scsi_host.h>
 #include "aha1542.h"
 
 #define SCSI_BUF_PA(address)	isa_virt_to_bus(address)
--- diff/drivers/scsi/aha1740.c	2004-05-19 22:12:08.000000000 +0100
+++ source/drivers/scsi/aha1740.c	2004-06-11 19:22:03.000000000 +0100
@@ -56,7 +56,7 @@
 #include <asm/io.h>
 
 #include "scsi.h"
-#include "hosts.h"
+#include <scsi/scsi_host.h>
 #include "aha1740.h"
 
 /* IF YOU ARE HAVING PROBLEMS WITH THIS DRIVER, AND WANT TO WATCH
--- diff/drivers/scsi/aic7xxx/aic79xx_osm.h	2004-05-19 22:12:12.000000000 +0100
+++ source/drivers/scsi/aic7xxx/aic79xx_osm.h	2004-06-11 19:22:03.000000000 +0100
@@ -68,7 +68,7 @@
 /* Core SCSI definitions */
 #define AIC_LIB_PREFIX ahd
 #include "scsi.h"
-#include "hosts.h"
+#include <scsi/scsi_host.h>
 
 /* Name space conflict with BSD queue macros */
 #ifdef LIST_HEAD
--- diff/drivers/scsi/aic7xxx/aic7xxx_osm.h	2004-06-11 19:17:30.000000000 +0100
+++ source/drivers/scsi/aic7xxx/aic7xxx_osm.h	2004-06-11 19:22:03.000000000 +0100
@@ -85,7 +85,7 @@
 /* Core SCSI definitions */
 #define AIC_LIB_PREFIX ahc
 #include "scsi.h"
-#include "hosts.h"
+#include <scsi/scsi_host.h>
 
 /* Name space conflict with BSD queue macros */
 #ifdef LIST_HEAD
--- diff/drivers/scsi/aic7xxx/aiclib.c	2004-05-19 22:12:13.000000000 +0100
+++ source/drivers/scsi/aic7xxx/aiclib.c	2004-06-11 19:22:03.000000000 +0100
@@ -36,7 +36,7 @@
 
 /* Core SCSI definitions */
 #include "scsi.h"
-#include "hosts.h"
+#include <scsi/scsi_host.h>
 #include "aiclib.h"
 #include "cam.h"
 
--- diff/drivers/scsi/aic7xxx_old.c	2004-06-11 19:17:30.000000000 +0100
+++ source/drivers/scsi/aic7xxx_old.c	2004-06-11 19:22:03.000000000 +0100
@@ -239,7 +239,7 @@
 #include <linux/smp.h>
 #include <linux/interrupt.h>
 #include "scsi.h"
-#include "hosts.h"
+#include <scsi/scsi_host.h>
 #include "aic7xxx_old/aic7xxx.h"
 
 #include "aic7xxx_old/sequencer.h"
--- diff/drivers/scsi/amiga7xx.c	2004-05-19 22:12:08.000000000 +0100
+++ source/drivers/scsi/amiga7xx.c	2004-06-11 19:22:03.000000000 +0100
@@ -25,7 +25,7 @@
 #include <asm/irq.h>
 
 #include "scsi.h"
-#include "hosts.h"
+#include <scsi/scsi_host.h>
 #include "53c7xx.h"
 #include "amiga7xx.h"
 
--- diff/drivers/scsi/atari_scsi.c	2004-05-19 22:12:08.000000000 +0100
+++ source/drivers/scsi/atari_scsi.c	2004-06-11 19:22:03.000000000 +0100
@@ -102,7 +102,7 @@
 #include <asm/bitops.h>
 
 #include "scsi.h"
-#include "hosts.h"
+#include <scsi/scsi_host.h>
 #include "atari_scsi.h"
 #include "NCR5380.h"
 #include <asm/atari_stdma.h>
--- diff/drivers/scsi/atp870u.c	2004-06-11 19:17:30.000000000 +0100
+++ source/drivers/scsi/atp870u.c	2004-06-11 19:22:03.000000000 +0100
@@ -35,7 +35,7 @@
 #include <asm/io.h>
 
 #include "scsi.h"
-#include "hosts.h"
+#include <scsi/scsi_host.h>
 #include "atp870u.h"
 
 /*
--- diff/drivers/scsi/blz1230.c	2004-05-19 22:12:08.000000000 +0100
+++ source/drivers/scsi/blz1230.c	2004-06-11 19:22:03.000000000 +0100
@@ -28,7 +28,7 @@
 #include <linux/interrupt.h>
 
 #include "scsi.h"
-#include "hosts.h"
+#include <scsi/scsi_host.h>
 #include "NCR53C9x.h"
 
 #include <linux/zorro.h>
--- diff/drivers/scsi/blz2060.c	2004-05-19 22:12:08.000000000 +0100
+++ source/drivers/scsi/blz2060.c	2004-06-11 19:22:03.000000000 +0100
@@ -28,7 +28,7 @@
 #include <linux/interrupt.h>
 
 #include "scsi.h"
-#include "hosts.h"
+#include <scsi/scsi_host.h>
 #include "NCR53C9x.h"
 
 #include <linux/zorro.h>
--- diff/drivers/scsi/bvme6000.c	2004-05-19 22:12:08.000000000 +0100
+++ source/drivers/scsi/bvme6000.c	2004-06-11 19:22:03.000000000 +0100
@@ -17,7 +17,7 @@
 #include <asm/irq.h>
 
 #include "scsi.h"
-#include "hosts.h"
+#include <scsi/scsi_host.h>
 #include "53c7xx.h"
 #include "bvme6000.h"
 
--- diff/drivers/scsi/constants.c	2004-06-11 19:17:30.000000000 +0100
+++ source/drivers/scsi/constants.c	2004-06-11 19:22:03.000000000 +0100
@@ -12,7 +12,7 @@
 #include <linux/blkdev.h>
 #include <linux/kernel.h>
 #include "scsi.h"
-#include "hosts.h"
+#include <scsi/scsi_host.h>
 
 #define CONST_COMMAND   0x01
 #define CONST_STATUS    0x02
@@ -154,7 +154,7 @@
 }
 #endif  
 
-void print_command (unsigned char *command) {
+void __scsi_print_command (unsigned char *command) {
     int i,s;
     print_opcode(command[0]);
     for ( i = 1, s = COMMAND_SIZE(command[0]); i < s; ++i) 
@@ -173,7 +173,7 @@
  *	(e.g. "0x2" for Check Condition).
  **/
 void
-print_status(unsigned char scsi_status) {
+scsi_print_status(unsigned char scsi_status) {
 #if (CONSTANTS & CONST_STATUS)
 	const char * ccp;
 
@@ -1014,12 +1014,12 @@
 #endif
 }
 
-void print_sense(const char *devclass, struct scsi_cmnd *cmd)
+void scsi_print_sense(const char *devclass, struct scsi_cmnd *cmd)
 {
 	print_sense_internal(devclass, cmd->sense_buffer, cmd->request);
 }
 
-void print_req_sense(const char *devclass, struct scsi_request *sreq)
+void scsi_print_req_sense(const char *devclass, struct scsi_request *sreq)
 {
 	print_sense_internal(devclass, sreq->sr_sense_buffer, sreq->sr_request);
 }
@@ -1051,7 +1051,7 @@
 #define NO_EXTENDED_MSGS (sizeof(two_byte_msgs)  / sizeof (const char *))
 #endif /* (CONSTANTS & CONST_MSG) */
 
-int print_msg (const unsigned char *msg) {
+int scsi_print_msg (const unsigned char *msg) {
     int len = 0, i;
     if (msg[0] == EXTENDED_MESSAGE) {
 	len = 3 + msg[1];
@@ -1124,13 +1124,13 @@
     return len;
 }
 
-void print_Scsi_Cmnd(struct scsi_cmnd *cmd) {
+void scsi_print_command(struct scsi_cmnd *cmd) {
     printk("scsi%d : destination target %d, lun %d\n", 
 	   cmd->device->host->host_no, 
 	   cmd->device->id, 
 	   cmd->device->lun);
     printk("        command = ");
-    print_command(cmd->cmnd);
+    __scsi_print_command(cmd->cmnd);
 }
 
 #if (CONSTANTS & CONST_HOST)
@@ -1139,7 +1139,7 @@
 "DID_ABORT", "DID_PARITY", "DID_ERROR", "DID_RESET", "DID_BAD_INTR",
 "DID_PASSTHROUGH", "DID_SOFT_ERROR", "DID_IMM_RETRY", NULL};
 
-void print_hostbyte(int scsiresult)
+void scsi_print_hostbyte(int scsiresult)
 {   static int maxcode=0;
     int i;
    
@@ -1155,7 +1155,7 @@
     printk("(%s) ",hostbyte_table[host_byte(scsiresult)]);
 }
 #else
-void print_hostbyte(int scsiresult)
+void scsi_print_hostbyte(int scsiresult)
 {   printk("Hostbyte=0x%02x ",host_byte(scsiresult));
 }
 #endif
@@ -1170,7 +1170,7 @@
 unknown,unknown,unknown, "SUGGEST_SENSE",NULL};
 
 
-void print_driverbyte(int scsiresult)
+void scsi_print_driverbyte(int scsiresult)
 {   static int driver_max=0,suggest_max=0;
     int i,dr=driver_byte(scsiresult)&DRIVER_MASK, 
 	su=(driver_byte(scsiresult)&SUGGEST_MASK)>>4;
@@ -1187,7 +1187,7 @@
 	su<suggest_max ? driversuggest_table[su]:"invalid");
 }
 #else
-void print_driverbyte(int scsiresult)
+void scsi_print_driverbyte(int scsiresult)
 {   printk("Driverbyte=0x%02x ",driver_byte(scsiresult));
 }
 #endif
--- diff/drivers/scsi/cpqfcTScontrol.c	2004-05-19 22:12:08.000000000 +0100
+++ source/drivers/scsi/cpqfcTScontrol.c	2004-06-11 19:22:03.000000000 +0100
@@ -45,7 +45,7 @@
 #include <linux/spinlock.h>
 
 #include "scsi.h"
-#include "hosts.h"   // Scsi_Host definition for INT handler
+#include <scsi/scsi_host.h>   // Scsi_Host definition for INT handler
 #include "cpqfcTSchip.h"
 #include "cpqfcTSstructs.h"
 
--- diff/drivers/scsi/cpqfcTSinit.c	2004-05-19 22:12:08.000000000 +0100
+++ source/drivers/scsi/cpqfcTSinit.c	2004-06-11 19:22:03.000000000 +0100
@@ -51,7 +51,7 @@
 #include <asm/irq.h>
 #include <linux/spinlock.h>
 #include "scsi.h"
-#include "hosts.h"
+#include <scsi/scsi_host.h>
 #include <scsi/scsi_ioctl.h>
 #include "cpqfcTSchip.h"
 #include "cpqfcTSstructs.h"
@@ -1266,7 +1266,7 @@
 
 
 
-// The file "hosts.h" says not to call scsi_done from
+// The file <scsi/scsi_host.h> says not to call scsi_done from
 // inside _queuecommand, so we'll do it from the heartbeat timer
 // (clarification: Turns out it's ok to call scsi_done from queuecommand 
 // for cases that don't go to the hardware like scsi cmds destined
--- diff/drivers/scsi/cpqfcTSworker.c	2004-05-19 22:12:09.000000000 +0100
+++ source/drivers/scsi/cpqfcTSworker.c	2004-06-11 19:22:03.000000000 +0100
@@ -39,7 +39,7 @@
 #include <asm/dma.h>
 
 #include "scsi.h"
-#include "hosts.h"   // struct Scsi_Host definition for T handler
+#include <scsi/scsi_host.h>   // struct Scsi_Host definition for T handler
 #include "cpqfcTSchip.h"
 #include "cpqfcTSstructs.h"
 #include "cpqfcTStrigger.h"
--- diff/drivers/scsi/cyberstorm.c	2004-05-19 22:12:09.000000000 +0100
+++ source/drivers/scsi/cyberstorm.c	2004-06-11 19:22:03.000000000 +0100
@@ -31,7 +31,7 @@
 #include <linux/interrupt.h>
 
 #include "scsi.h"
-#include "hosts.h"
+#include <scsi/scsi_host.h>
 #include "NCR53C9x.h"
 
 #include <linux/zorro.h>
--- diff/drivers/scsi/cyberstormII.c	2004-05-19 22:12:09.000000000 +0100
+++ source/drivers/scsi/cyberstormII.c	2004-06-11 19:22:03.000000000 +0100
@@ -27,7 +27,7 @@
 #include <linux/interrupt.h>
 
 #include "scsi.h"
-#include "hosts.h"
+#include <scsi/scsi_host.h>
 #include "NCR53C9x.h"
 
 #include <linux/zorro.h>
--- diff/drivers/scsi/dc390.h	2004-06-11 19:17:30.000000000 +0100
+++ source/drivers/scsi/dc390.h	2004-06-11 19:22:03.000000000 +0100
@@ -14,12 +14,9 @@
 #define DC390_H
 
 #include <linux/version.h>
-#ifndef KERNEL_VERSION
-# define KERNEL_VERSION(a,b,c) (((a) << 16) + ((b) << 8) + (c))
-#endif
 
 #define DC390_BANNER "Tekram DC390/AM53C974"
-#define DC390_VERSION "2.1b 2004-04-13"
+#define DC390_VERSION "2.1d 2004-05-27"
 
 /* We don't have eh_abort_handler, eh_device_reset_handler, 
  * eh_bus_reset_handler, eh_host_reset_handler yet! 
@@ -32,14 +29,4 @@
 # define NEW_EH use_new_eh_code: 1,
 # define USE_NEW_EH
 #endif
-
-static int DC390_detect(Scsi_Host_Template *psht);
-static int DC390_queue_command(Scsi_Cmnd *cmd, void (*done)(Scsi_Cmnd *));
-static int DC390_abort(Scsi_Cmnd *cmd);
-static int DC390_reset(Scsi_Cmnd *cmd);
-static int DC390_bios_param(struct scsi_device *sdev, struct block_device *dev,
-		sector_t capacity, int geom[]);
-
-static int DC390_release(struct Scsi_Host *);
-
 #endif /* DC390_H */
--- diff/drivers/scsi/dc395x.c	2004-05-19 22:12:09.000000000 +0100
+++ source/drivers/scsi/dc395x.c	2004-06-11 19:22:03.000000000 +0100
@@ -53,7 +53,7 @@
 #include <linux/blkdev.h>
 #include <asm/io.h>
 #include "scsi.h"
-#include "hosts.h"
+#include <scsi/scsi_host.h>
 #include "dc395x.h"
 #include <scsi/scsicam.h>	/* needed for scsicam_bios_param */
 #include <linux/interrupt.h>
--- diff/drivers/scsi/dec_esp.c	2004-05-19 22:12:09.000000000 +0100
+++ source/drivers/scsi/dec_esp.c	2004-06-11 19:22:03.000000000 +0100
@@ -29,7 +29,7 @@
 #include <linux/stat.h>
 
 #include "scsi.h"
-#include "hosts.h"
+#include <scsi/scsi_host.h>
 #include "NCR53C9x.h"
 
 #include <asm/irq.h>
--- diff/drivers/scsi/dmx3191d.c	2004-05-19 22:12:09.000000000 +0100
+++ source/drivers/scsi/dmx3191d.c	2004-06-11 19:22:03.000000000 +0100
@@ -34,7 +34,7 @@
 #include <linux/delay.h>
 
 #include "scsi.h"
-#include "hosts.h"
+#include <scsi/scsi_host.h>
 
 #include "dmx3191d.h"
 
--- diff/drivers/scsi/dpt_i2o.c	2004-06-11 19:17:30.000000000 +0100
+++ source/drivers/scsi/dpt_i2o.c	2004-06-11 19:22:03.000000000 +0100
@@ -68,8 +68,11 @@
 #include <asm/pgtable.h>
 #include <asm/io.h>		/* for virt_to_bus, etc. */
 
-#include "scsi.h"
-#include "hosts.h"
+#include <scsi/scsi.h>
+#include <scsi/scsi_cmnd.h>
+#include <scsi/scsi_device.h>
+#include <scsi/scsi_host.h>
+#include <scsi/scsi_tcq.h>
 
 #include "dpt/dptsig.h"
 #include "dpti.h"
@@ -86,9 +89,9 @@
 #elif defined(__ia64__)
 	PROC_INTEL, PROC_IA64,
 #elif defined(__sparc__)
-	PROC_ULTRASPARC,
+	PROC_ULTRASPARC, PROC_ULTRASPARC,
 #elif defined(__alpha__)
-	PROC_ALPHA ,
+	PROC_ALPHA, PROC_ALPHA,
 #else
 	(-1),(-1),
 #endif
@@ -173,7 +176,7 @@
 };
 MODULE_DEVICE_TABLE(pci,dptids);
 
-static int adpt_detect(Scsi_Host_Template* sht)
+static int adpt_detect(struct scsi_host_template* sht)
 {
 	struct pci_dev *pDev = NULL;
 	adpt_hba* pHba;
@@ -362,7 +365,7 @@
 }
 
 
-static int adpt_slave_configure(Scsi_Device * device)
+static int adpt_slave_configure(struct scsi_device * device)
 {
 	struct Scsi_Host *host = device->host;
 	adpt_hba* pHba;
@@ -378,7 +381,7 @@
 	return 0;
 }
 
-static int adpt_queue(Scsi_Cmnd * cmd, void (*done) (Scsi_Cmnd *))
+static int adpt_queue(struct scsi_cmnd * cmd, void (*done) (struct scsi_cmnd *))
 {
 	adpt_hba* pHba = NULL;
 	struct adpt_device* pDev = NULL;	/* dpt per device information */
@@ -643,7 +646,7 @@
  *===========================================================================
  */
 
-static int adpt_abort(Scsi_Cmnd * cmd)
+static int adpt_abort(struct scsi_cmnd * cmd)
 {
 	adpt_hba* pHba = NULL;	/* host bus adapter structure */
 	struct adpt_device* dptdevice;	/* dpt per device information */
@@ -683,7 +686,7 @@
 // This is the same for BLK and SCSI devices
 // NOTE this is wrong in the i2o.h definitions
 // This is not currently supported by our adapter but we issue it anyway
-static int adpt_device_reset(Scsi_Cmnd* cmd)
+static int adpt_device_reset(struct scsi_cmnd* cmd)
 {
 	adpt_hba* pHba;
 	u32 msg[4];
@@ -723,7 +726,7 @@
 
 #define I2O_HBA_BUS_RESET 0x87
 // This version of bus reset is called by the eh_error handler
-static int adpt_bus_reset(Scsi_Cmnd* cmd)
+static int adpt_bus_reset(struct scsi_cmnd* cmd)
 {
 	adpt_hba* pHba;
 	u32 msg[4];
@@ -745,7 +748,7 @@
 }
 
 // This version of reset is called by the eh_error_handler
-static int adpt_reset(Scsi_Cmnd* cmd)
+static int adpt_reset(struct scsi_cmnd* cmd)
 {
 	adpt_hba* pHba;
 	int rcode;
@@ -860,7 +863,7 @@
 #endif
 
 
-static int adpt_install_hba(Scsi_Host_Template* sht, struct pci_dev* pDev) 
+static int adpt_install_hba(struct scsi_host_template* sht, struct pci_dev* pDev) 
 {
 
 	adpt_hba* pHba = NULL;
@@ -1997,7 +2000,7 @@
 
 static irqreturn_t adpt_isr(int irq, void *dev_id, struct pt_regs *regs)
 {
-	Scsi_Cmnd* cmd;
+	struct scsi_cmnd* cmd;
 	adpt_hba* pHba = dev_id;
 	u32 m;
 	ulong reply;
@@ -2059,14 +2062,14 @@
 				status = I2O_POST_WAIT_OK;
 			}
 			if(!(context & 0x40000000)) {
-				cmd = (Scsi_Cmnd*) readl(reply+12); 
+				cmd = (struct scsi_cmnd*) readl(reply+12); 
 				if(cmd != NULL) {
 					printk(KERN_WARNING"%s: Apparent SCSI cmd in Post Wait Context - cmd=%p context=%x\n", pHba->name, cmd, context);
 				}
 			}
 			adpt_i2o_post_wait_complete(context, status);
 		} else { // SCSI message
-			cmd = (Scsi_Cmnd*) readl(reply+12); 
+			cmd = (struct scsi_cmnd*) readl(reply+12); 
 			if(cmd != NULL){
 				if(cmd->serial_number != 0) { // If not timedout
 					adpt_i2o_to_scsi(reply, cmd);
@@ -2083,7 +2086,7 @@
 	return IRQ_RETVAL(handled);
 }
 
-static s32 adpt_scsi_to_i2o(adpt_hba* pHba, Scsi_Cmnd* cmd, struct adpt_device* d)
+static s32 adpt_scsi_to_i2o(adpt_hba* pHba, struct scsi_cmnd* cmd, struct adpt_device* d)
 {
 	int i;
 	u32 msg[MAX_MESSAGE_SIZE];
@@ -2108,16 +2111,16 @@
 		 * cmd->cmnd[0] is an unsigned char
 		 */
 		switch(cmd->sc_data_direction){
-		case SCSI_DATA_READ:
+		case DMA_FROM_DEVICE:
 			scsidir  =0x40000000;	// DATA IN  (iop<--dev)
 			break;
-		case SCSI_DATA_WRITE:
+		case DMA_TO_DEVICE:
 			direction=0x04000000;	// SGL OUT
 			scsidir  =0x80000000;	// DATA OUT (iop-->dev)
 			break;
-		case SCSI_DATA_NONE:
+		case DMA_NONE:
 			break;
-		case SCSI_DATA_UNKNOWN:
+		case DMA_BIDIRECTIONAL:
 			scsidir  =0x40000000;	// DATA IN  (iop<--dev)
 			// Assume In - and continue;
 			break;
@@ -2156,7 +2159,7 @@
 	if(cmd->use_sg) {
 		struct scatterlist *sg = (struct scatterlist *)cmd->request_buffer;
 		int sg_count = pci_map_sg(pHba->pDev, sg, cmd->use_sg,
-                        scsi_to_pci_dma_dir(cmd->sc_data_direction));
+				cmd->sc_data_direction);
 
 
 		len = 0;
@@ -2184,7 +2187,7 @@
 			*mptr++ = pci_map_single(pHba->pDev,
 				cmd->request_buffer,
 				cmd->request_bufflen,
-				scsi_to_pci_dma_dir(cmd->sc_data_direction));
+				cmd->sc_data_direction);
 		}
 	}
 	
@@ -2200,7 +2203,7 @@
 }
 
 
-static s32 adpt_scsi_register(adpt_hba* pHba,Scsi_Host_Template * sht)
+static s32 adpt_scsi_register(adpt_hba* pHba,struct scsi_host_template * sht)
 {
 	struct Scsi_Host *host = NULL;
 
@@ -2231,7 +2234,7 @@
 }
 
 
-static s32 adpt_i2o_to_scsi(ulong reply, Scsi_Cmnd* cmd)
+static s32 adpt_i2o_to_scsi(ulong reply, struct scsi_cmnd* cmd)
 {
 	adpt_hba* pHba;
 	u32 hba_status;
@@ -2533,8 +2536,8 @@
 
 static void adpt_fail_posted_scbs(adpt_hba* pHba)
 {
-	Scsi_Cmnd* 	cmd = NULL;
-	Scsi_Device* 	d = NULL;
+	struct scsi_cmnd* 	cmd = NULL;
+	struct scsi_device* 	d = NULL;
 
 	shost_for_each_device(d, pHba->host) {
 		unsigned long flags;
@@ -3358,7 +3361,7 @@
 
 #endif
 
-static Scsi_Host_Template driver_template = {
+static struct scsi_host_template driver_template = {
 	.name			= "dpt_i2o",
 	.proc_name		= "dpt_i2o",
 	.proc_info		= adpt_proc_info,
--- diff/drivers/scsi/dpti.h	2004-06-11 19:17:30.000000000 +0100
+++ source/drivers/scsi/dpti.h	2004-06-11 19:22:03.000000000 +0100
@@ -37,19 +37,19 @@
  * SCSI interface function Prototypes
  */
 
-static int adpt_detect(Scsi_Host_Template * sht);
-static int adpt_queue(Scsi_Cmnd * cmd, void (*cmdcomplete) (Scsi_Cmnd *));
-static int adpt_abort(Scsi_Cmnd * cmd);
-static int adpt_reset(Scsi_Cmnd* cmd);
+static int adpt_detect(struct scsi_host_template * sht);
+static int adpt_queue(struct scsi_cmnd * cmd, void (*cmdcomplete) (struct scsi_cmnd *));
+static int adpt_abort(struct scsi_cmnd * cmd);
+static int adpt_reset(struct scsi_cmnd* cmd);
 static int adpt_release(struct Scsi_Host *host);
-static int adpt_slave_configure(Scsi_Device *);
+static int adpt_slave_configure(struct scsi_device *);
 
 static const char *adpt_info(struct Scsi_Host *pSHost);
 static int adpt_bios_param(struct scsi_device * sdev, struct block_device *dev,
 		sector_t, int geom[]);
 
-static int adpt_bus_reset(Scsi_Cmnd* cmd);
-static int adpt_device_reset(Scsi_Cmnd* cmd);
+static int adpt_bus_reset(struct scsi_cmnd* cmd);
+static int adpt_device_reset(struct scsi_cmnd* cmd);
 
 
 /*
@@ -198,7 +198,7 @@
 	u8	state;
 	u16	tid;
 	struct i2o_device* pI2o_dev;
-	Scsi_Device *pScsi_dev;
+	struct scsi_device *pScsi_dev;
 };
 
 struct adpt_channel {
@@ -296,9 +296,9 @@
 static s32 adpt_i2o_status_get(adpt_hba* pHba);
 static s32 adpt_i2o_init_outbound_q(adpt_hba* pHba);
 static s32 adpt_i2o_hrt_get(adpt_hba* pHba);
-static s32 adpt_scsi_to_i2o(adpt_hba* pHba, Scsi_Cmnd* cmd, struct adpt_device* dptdevice);
-static s32 adpt_i2o_to_scsi(ulong reply, Scsi_Cmnd* cmd);
-static s32 adpt_scsi_register(adpt_hba* pHba,Scsi_Host_Template * sht);
+static s32 adpt_scsi_to_i2o(adpt_hba* pHba, struct scsi_cmnd* cmd, struct adpt_device* dptdevice);
+static s32 adpt_i2o_to_scsi(ulong reply, struct scsi_cmnd* cmd);
+static s32 adpt_scsi_register(adpt_hba* pHba,struct scsi_host_template * sht);
 static s32 adpt_hba_reset(adpt_hba* pHba);
 static s32 adpt_i2o_reset_hba(adpt_hba* pHba);
 static s32 adpt_rescan(adpt_hba* pHba);
@@ -308,7 +308,7 @@
 static void adpt_inquiry(adpt_hba* pHba);
 static void adpt_fail_posted_scbs(adpt_hba* pHba);
 static struct adpt_device* adpt_find_device(adpt_hba* pHba, u32 chan, u32 id, u32 lun);
-static int adpt_install_hba(Scsi_Host_Template* sht, struct pci_dev* pDev) ;
+static int adpt_install_hba(struct scsi_host_template* sht, struct pci_dev* pDev) ;
 static int adpt_i2o_online_hba(adpt_hba* pHba);
 static void adpt_i2o_post_wait_complete(u32, int);
 static int adpt_i2o_systab_send(adpt_hba* pHba);
--- diff/drivers/scsi/dtc.c	2004-05-19 22:12:09.000000000 +0100
+++ source/drivers/scsi/dtc.c	2004-06-11 19:22:03.000000000 +0100
@@ -84,7 +84,7 @@
 #include <linux/interrupt.h>
 #include <asm/io.h>
 #include "scsi.h"
-#include "hosts.h"
+#include <scsi/scsi_host.h>
 #include "dtc.h"
 #define AUTOPROBE_IRQ
 #include "NCR5380.h"
--- diff/drivers/scsi/eata.c	2004-05-19 22:12:09.000000000 +0100
+++ source/drivers/scsi/eata.c	2004-06-11 19:22:03.000000000 +0100
@@ -495,7 +495,7 @@
 #include <linux/spinlock.h>
 #include <scsi/scsicam.h>
 #include "scsi.h"
-#include "hosts.h"
+#include <scsi/scsi_host.h>
 #include <asm/dma.h>
 #include <asm/irq.h>
 
--- diff/drivers/scsi/eata_pio.c	2004-05-19 22:12:09.000000000 +0100
+++ source/drivers/scsi/eata_pio.c	2004-06-11 19:22:03.000000000 +0100
@@ -63,7 +63,7 @@
 #include <asm/io.h>
 
 #include "scsi.h"
-#include "hosts.h"
+#include <scsi/scsi_host.h>
 #include <scsi/scsicam.h>
 
 #include "eata_generic.h"
@@ -593,14 +593,14 @@
 	int z;
 	unsigned short *p;
 
-	if (check_region(base, 9))
-		return (FALSE);
+	if (!request_region(base, 9, "eata_pio"))
+		return 0;
 
 	memset(buf, 0, sizeof(struct get_conf));
 
 	while (inb(base + HA_RSTATUS) & HA_SBUSY)
 		if (--loop == 0)
-			return (FALSE);
+			goto fail;
 
 	DBG(DBG_PIO && DBG_PROBE, printk(KERN_DEBUG "Issuing PIO READ CONFIG to HBA at %#x\n", base));
 	eata_pio_send_command(base, EATA_CMD_PIO_READ_CONFIG);
@@ -609,30 +609,40 @@
 	for (p = (unsigned short *) buf; (long) p <= ((long) buf + (sizeof(struct get_conf) / 2)); p++) {
 		while (!(inb(base + HA_RSTATUS) & HA_SDRQ))
 			if (--loop == 0)
-				return (FALSE);
+				goto fail;
 
 		loop = HZ / 2;
 		*p = inw(base + HA_RDATA);
 	}
-	if (!(inb(base + HA_RSTATUS) & HA_SERROR)) {	/* Error ? */
-		if (htonl(EATA_SIGNATURE) == buf->signature) {
-			DBG(DBG_PIO && DBG_PROBE, printk(KERN_NOTICE "EATA Controller found " "at %#4x EATA Level: %x\n", base, (uint) (buf->version)));
-
-			while (inb(base + HA_RSTATUS) & HA_SDRQ)
-				inw(base + HA_RDATA);
-			if (ALLOW_DMA_BOARDS == FALSE) {
-				for (z = 0; z < MAXISA; z++)
-					if (base == ISAbases[z]) {
-						buf->IRQ = ISAirqs[z];
-						break;
-					}
+	if (inb(base + HA_RSTATUS) & HA_SERROR) {
+		DBG(DBG_PROBE, printk("eata_dma: get_conf_PIO, error during "
+					"transfer for HBA at %x\n", base));
+		goto fail;
+	}
+
+	if (htonl(EATA_SIGNATURE) != buf->signature)
+		goto fail;
+
+	DBG(DBG_PIO && DBG_PROBE, printk(KERN_NOTICE "EATA Controller found "
+				"at %#4x EATA Level: %x\n",
+				base, (uint) (buf->version)));
+
+	while (inb(base + HA_RSTATUS) & HA_SDRQ)
+		inw(base + HA_RDATA);
+
+	if (ALLOW_DMA_BOARDS == FALSE) {
+		for (z = 0; z < MAXISA; z++)
+			if (base == ISAbases[z]) {
+				buf->IRQ = ISAirqs[z];
+				break;
 			}
-			return (TRUE);
-		}
-	} else {
-		DBG(DBG_PROBE, printk("eata_dma: get_conf_PIO, error during transfer " "for HBA at %x\n", base));
 	}
-	return (FALSE);
+
+	return 1;
+
+ fail:
+	release_region(base, 9);
+	return 0;
 }
 
 static void print_pio_config(struct get_conf *gc)
@@ -689,23 +699,19 @@
 
 	if ((buff = get_pio_board_data((uint) base, gc->IRQ, gc->scsi_id[3], cplen = (htonl(gc->cplen) + 1) / 2, cppadlen = (htons(gc->cppadlen) + 1) / 2)) == NULL) {
 		printk("HBA at %#lx didn't react on INQUIRY. Sorry.\n", (unsigned long) base);
-		return (FALSE);
+		return 0;
 	}
 
 	if (print_selftest(base) == FALSE && ALLOW_DMA_BOARDS == FALSE) {
 		printk("HBA at %#lx failed while performing self test & setup.\n", (unsigned long) base);
-		return (FALSE);
+		return 0;
 	}
 
-	request_region(base, 8, "eata_pio");
-
 	size = sizeof(hostdata) + (sizeof(struct eata_ccb) * ntohs(gc->queuesiz));
 
 	sh = scsi_register(tpnt, size);
-	if (sh == NULL) {
-		release_region(base, 8);
-		return FALSE;
-	}
+	if (sh == NULL)
+		return 0;
 
 	if (!reg_IRQ[gc->IRQ]) {	/* Interrupt already registered ? */
 		if (!request_irq(gc->IRQ, do_eata_pio_int_handler, SA_INTERRUPT, "EATA-PIO", sh)) {
@@ -714,14 +720,12 @@
 				reg_IRQL[gc->IRQ] = TRUE;	/* IRQ is edge triggered */
 		} else {
 			printk("Couldn't allocate IRQ %d, Sorry.\n", gc->IRQ);
-			release_region(base, 8);
-			return (FALSE);
+			return 0;
 		}
 	} else {		/* More than one HBA on this IRQ */
 		if (reg_IRQL[gc->IRQ] == TRUE) {
 			printk("Can't support more than one HBA on this IRQ,\n" "  if the IRQ is edge triggered. Sorry.\n");
-			release_region(base, 8);
-			return (FALSE);
+			return 0;
 		} else
 			reg_IRQ[gc->IRQ]++;
 	}
@@ -780,7 +784,7 @@
 	sh->unique_id = base;
 	sh->base = base;
 	sh->io_port = base;
-	sh->n_io_port = 8;
+	sh->n_io_port = 9;
 	sh->irq = gc->IRQ;
 	sh->dma_channel = PIO;
 	sh->this_id = gc->scsi_id[3];
@@ -816,12 +820,14 @@
 	int i;
 
 	for (i = 0; i < MAXISA; i++) {
-		if (ISAbases[i]) {
-			if (get_pio_conf_PIO(ISAbases[i], buf) == TRUE) {
-				register_pio_HBA(ISAbases[i], buf, tpnt);
-			}
+		if (!ISAbases[i])
+			continue;
+		if (!get_pio_conf_PIO(ISAbases[i], buf))
+			continue;
+		if (!register_pio_HBA(ISAbases[i], buf, tpnt))
+			release_region(ISAbases[i], 9);
+		else
 			ISAbases[i] = 0;
-		}
 	}
 	return;
 }
@@ -847,12 +853,15 @@
 			if (((pal1 == 0x12) && (pal2 == 0x14)) || ((pal1 == 0x38) && (pal2 == 0xa3) && (pal3 == 0x82)) || ((pal1 == 0x06) && (pal2 == 0x94) && (pal3 == 0x24))) {
 				DBG(DBG_PROBE, printk(KERN_NOTICE "EISA EATA id tags found: " "%x %x %x \n", (int) pal1, (int) pal2, (int) pal3));
 #endif
-				if (get_pio_conf_PIO(base, buf) == TRUE) {
+				if (get_pio_conf_PIO(base, buf)) {
 					DBG(DBG_PROBE && DBG_EISA, print_pio_config(buf));
 					if (buf->IRQ) {
-						register_pio_HBA(base, buf, tpnt);
-					} else
+						if (!register_pio_HBA(base, buf, tpnt))
+							release_region(base, 9);
+					} else {
 						printk(KERN_NOTICE "eata_dma: No valid IRQ. HBA " "removed from list\n");
+						release_region(base, 9);
+					}
 				}
 				/* Nothing found here so we take it from the list */
 				EISAbases[i] = 0;
@@ -889,16 +898,21 @@
 		base += 0x10;	/* Now, THIS is the real address */
 		if (base != 0x1f8) {
 			/* We didn't find it in the primary search */
-			if (get_pio_conf_PIO(base, buf) == TRUE) {
-				if (buf->FORCADR)	/* If the address is forced */
+			if (get_pio_conf_PIO(base, buf)) {
+				if (buf->FORCADR) {	/* If the address is forced */
+					release_region(base, 9);
 					continue;	/* we'll find it later      */
+				}
 
 				/* OK. We made it till here, so we can go now  
 				 * and register it. We  only have to check and 
 				 * eventually remove it from the EISA and ISA list 
 				 */
 
-				register_pio_HBA(base, buf, tpnt);
+				if (!register_pio_HBA(base, buf, tpnt)) {
+					release_region(base, 9);
+					continue;
+				}
 
 				if (base < 0x1000) {
 					for (x = 0; x < MAXISA; ++x) {
--- diff/drivers/scsi/esp.c	2004-06-11 19:17:30.000000000 +0100
+++ source/drivers/scsi/esp.c	2004-06-11 19:22:03.000000000 +0100
@@ -27,6 +27,8 @@
 #include <linux/interrupt.h>
 #include <linux/module.h>
 
+#include "scsi.h"
+#include <scsi/scsi_host.h>
 #include "esp.h"
 
 #include <asm/sbus.h>
--- diff/drivers/scsi/fastlane.c	2004-05-19 22:12:09.000000000 +0100
+++ source/drivers/scsi/fastlane.c	2004-06-11 19:22:03.000000000 +0100
@@ -36,7 +36,7 @@
 #include <linux/interrupt.h>
 
 #include "scsi.h"
-#include "hosts.h"
+#include <scsi/scsi_host.h>
 #include "NCR53C9x.h"
 
 #include <linux/zorro.h>
--- diff/drivers/scsi/fcal.c	2004-05-19 22:12:09.000000000 +0100
+++ source/drivers/scsi/fcal.c	2004-06-11 19:22:03.000000000 +0100
@@ -21,7 +21,7 @@
 #include <asm/irq.h>
 
 #include "scsi.h"
-#include "hosts.h"
+#include <scsi/scsi_host.h>
 #include "../fc4/fcp_impl.h"
 #include "fcal.h"
 
--- diff/drivers/scsi/fd_mcs.c	2004-05-19 22:12:09.000000000 +0100
+++ source/drivers/scsi/fd_mcs.c	2004-06-11 19:22:03.000000000 +0100
@@ -93,7 +93,7 @@
 #include <asm/system.h>
 
 #include "scsi.h"
-#include "hosts.h"
+#include <scsi/scsi_host.h>
 #include "fd_mcs.h"
 
 #define DRIVER_VERSION "v0.2 by ZP Gu<zpg@castle.net>"
--- diff/drivers/scsi/fdomain.c	2004-05-19 22:12:09.000000000 +0100
+++ source/drivers/scsi/fdomain.c	2004-06-11 19:22:03.000000000 +0100
@@ -284,7 +284,7 @@
 #include <asm/system.h>
 
 #include "scsi.h"
-#include "hosts.h"
+#include <scsi/scsi_host.h>
 
 MODULE_AUTHOR("Rickard E. Faith");
 MODULE_DESCRIPTION("Future domain SCSI driver");
--- diff/drivers/scsi/g_NCR5380.c	2004-05-19 22:12:09.000000000 +0100
+++ source/drivers/scsi/g_NCR5380.c	2004-06-11 19:22:03.000000000 +0100
@@ -107,7 +107,7 @@
 #include <linux/sched.h>
 #include <linux/blkdev.h>
 #include "scsi.h"
-#include "hosts.h"
+#include <scsi/scsi_host.h>
 #include "g_NCR5380.h"
 #include "NCR5380.h"
 #include <linux/stat.h>
--- diff/drivers/scsi/gvp11.c	2004-05-19 22:12:09.000000000 +0100
+++ source/drivers/scsi/gvp11.c	2004-06-11 19:22:03.000000000 +0100
@@ -16,7 +16,7 @@
 #include <linux/spinlock.h>
 
 #include "scsi.h"
-#include "hosts.h"
+#include <scsi/scsi_host.h>
 #include "wd33c93.h"
 #include "gvp11.h"
 
--- diff/drivers/scsi/i60uscsi.c	2004-05-19 22:12:09.000000000 +0100
+++ source/drivers/scsi/i60uscsi.c	2004-06-11 19:22:03.000000000 +0100
@@ -81,7 +81,7 @@
 #include <asm/io.h>
 #include <linux/blkdev.h>
 #include "scsi.h"
-#include "hosts.h"
+#include <scsi/scsi_host.h>
 #include "inia100.h"
 
 #define JIFFIES_TO_MS(t) ((t) * 1000 / HZ)
--- diff/drivers/scsi/ibmmca.c	2004-05-19 22:12:09.000000000 +0100
+++ source/drivers/scsi/ibmmca.c	2004-06-11 19:22:03.000000000 +0100
@@ -45,7 +45,7 @@
 #include <asm/io.h>
 
 #include "scsi.h"
-#include "hosts.h"
+#include <scsi/scsi_host.h>
 #include "ibmmca.h"
 
 /* current version of this driver-source: */
--- diff/drivers/scsi/ide-scsi.c	2004-06-11 19:17:30.000000000 +0100
+++ source/drivers/scsi/ide-scsi.c	2004-06-11 19:22:03.000000000 +0100
@@ -51,7 +51,7 @@
 #include <asm/uaccess.h>
 
 #include "scsi.h"
-#include "hosts.h"
+#include <scsi/scsi_host.h>
 #include <scsi/sg.h>
 
 #define IDESCSI_DEBUG_LOG		0
--- diff/drivers/scsi/imm.h	2004-06-11 19:17:30.000000000 +0100
+++ source/drivers/scsi/imm.h	2004-06-11 19:22:03.000000000 +0100
@@ -79,7 +79,7 @@
 #include  <linux/interrupt.h>
 
 #include  <asm/io.h>
-#include  "hosts.h"
+#include  <scsi/scsi_host.h>
 /* batteries not included :-) */
 
 /*
--- diff/drivers/scsi/in2000.c	2004-05-19 22:12:09.000000000 +0100
+++ source/drivers/scsi/in2000.c	2004-06-11 19:22:03.000000000 +0100
@@ -126,7 +126,7 @@
 #include <asm/system.h>
 
 #include "scsi.h"
-#include "hosts.h"
+#include <scsi/scsi_host.h>
 
 #define IN2000_VERSION    "1.33-2.5"
 #define IN2000_DATE       "2002/11/03"
--- diff/drivers/scsi/ini9100u.c	2004-06-11 19:17:30.000000000 +0100
+++ source/drivers/scsi/ini9100u.c	2004-06-11 19:22:03.000000000 +0100
@@ -136,7 +136,7 @@
 #include <asm/io.h>
 
 #include "scsi.h"
-#include "hosts.h"
+#include <scsi/scsi_host.h>
 #include "ini9100u.h"
 
 #ifdef DEBUG_i91u
--- diff/drivers/scsi/ipr.c	2004-06-11 19:17:30.000000000 +0100
+++ source/drivers/scsi/ipr.c	2004-06-11 19:22:03.000000000 +0100
@@ -2884,6 +2884,7 @@
 		    (res->cfgte.res_addr.lun == sdev->lun)) {
 			res->sdev = sdev;
 			res->add_to_ml = 0;
+			res->in_erp = 0;
 			sdev->hostdata = res;
 			res->needs_sync_complete = 1;
 			break;
@@ -3435,8 +3436,10 @@
 		       SCSI_SENSE_BUFFERSIZE);
 	}
 
-	if (res)
+	if (res) {
 		res->needs_sync_complete = 1;
+		res->in_erp = 0;
+	}
 	ipr_unmap_sglist(ioa_cfg, ipr_cmd);
 	list_add_tail(&ipr_cmd->queue, &ioa_cfg->free_q);
 	scsi_cmd->scsi_done(scsi_cmd);
@@ -3479,6 +3482,12 @@
 static void ipr_erp_request_sense(struct ipr_cmnd *ipr_cmd)
 {
 	struct ipr_cmd_pkt *cmd_pkt = &ipr_cmd->ioarcb.cmd_pkt;
+	u32 ioasc = be32_to_cpu(ipr_cmd->ioasa.ioasc);
+
+	if (IPR_IOASC_SENSE_KEY(ioasc) > 0) {
+		ipr_erp_done(ipr_cmd);
+		return;
+	}
 
 	ipr_reinit_ipr_cmnd_for_erp(ipr_cmd);
 
@@ -3756,6 +3765,7 @@
 			ipr_erp_cancel_all(ipr_cmd);
 			return;
 		}
+		res->needs_sync_complete = 1;
 		break;
 	case IPR_IOASC_NR_INIT_CMD_REQUIRED:
 		break;
@@ -4808,6 +4818,7 @@
 	ipr_cmd->timer.data = (unsigned long) ipr_cmd;
 	ipr_cmd->timer.expires = jiffies + IPR_OPERATIONAL_TIMEOUT;
 	ipr_cmd->timer.function = (void (*)(unsigned long))ipr_timeout;
+	ipr_cmd->done = ipr_reset_ioa_job;
 	add_timer(&ipr_cmd->timer);
 	list_add_tail(&ipr_cmd->queue, &ioa_cfg->pending_q);
 
--- diff/drivers/scsi/ipr.h	2004-06-11 19:17:30.000000000 +0100
+++ source/drivers/scsi/ipr.h	2004-06-11 19:22:03.000000000 +0100
@@ -36,8 +36,8 @@
 /*
  * Literals
  */
-#define IPR_DRIVER_VERSION "2.0.7"
-#define IPR_DRIVER_DATE "(May 21, 2004)"
+#define IPR_DRIVER_VERSION "2.0.9"
+#define IPR_DRIVER_DATE "(May 26, 2004)"
 
 /*
  * IPR_DBG_TRACE: Setting this to 1 will turn on some general function tracing
--- diff/drivers/scsi/ips.c	2004-05-19 22:12:09.000000000 +0100
+++ source/drivers/scsi/ips.c	2004-06-11 19:22:03.000000000 +0100
@@ -176,7 +176,7 @@
 #include <scsi/sg.h>
 
 #include "scsi.h"
-#include "hosts.h"
+#include <scsi/scsi_host.h>
 #include "ips.h"
 
 #include <linux/module.h>
--- diff/drivers/scsi/jazz_esp.c	2004-05-19 22:12:09.000000000 +0100
+++ source/drivers/scsi/jazz_esp.c	2004-06-11 19:22:03.000000000 +0100
@@ -16,7 +16,7 @@
 #include <linux/stat.h>
 
 #include "scsi.h"
-#include "hosts.h"
+#include <scsi/scsi_host.h>
 #include "NCR53C9x.h"
 
 #include <asm/irq.h>
--- diff/drivers/scsi/lasi700.c	2004-05-19 22:12:09.000000000 +0100
+++ source/drivers/scsi/lasi700.c	2004-06-11 19:22:03.000000000 +0100
@@ -49,8 +49,7 @@
 #include <asm/parisc-device.h>
 #include <asm/delay.h>
 
-#include "scsi.h"
-#include "hosts.h"
+#include <scsi/scsi_host.h>
 
 #include "lasi700.h"
 #include "53c700.h"
@@ -65,7 +64,7 @@
 	{ 0 }
 };
 
-static Scsi_Host_Template lasi700_template = {
+static struct scsi_host_template lasi700_template = {
 	.name		= "LASI SCSI 53c700",
 	.proc_name	= "lasi700",
 	.this_id	= 7,
--- diff/drivers/scsi/mac_esp.c	2004-05-19 22:12:10.000000000 +0100
+++ source/drivers/scsi/mac_esp.c	2004-06-11 19:22:03.000000000 +0100
@@ -26,7 +26,7 @@
 #include <linux/interrupt.h>
 
 #include "scsi.h"
-#include "hosts.h"
+#include <scsi/scsi_host.h>
 #include "NCR53C9x.h"
 
 #include <asm/io.h>
--- diff/drivers/scsi/mac_scsi.c	2004-05-19 22:12:10.000000000 +0100
+++ source/drivers/scsi/mac_scsi.c	2004-06-11 19:22:03.000000000 +0100
@@ -52,7 +52,7 @@
 #include <asm/mac_via.h>
 
 #include "scsi.h"
-#include "hosts.h"
+#include <scsi/scsi_host.h>
 #include "mac_scsi.h"
 #include "NCR5380.h"
 
--- diff/drivers/scsi/mca_53c9x.c	2004-05-19 22:12:10.000000000 +0100
+++ source/drivers/scsi/mca_53c9x.c	2004-06-11 19:22:03.000000000 +0100
@@ -43,7 +43,7 @@
 #include <linux/mca-legacy.h>
 
 #include "scsi.h"
-#include "hosts.h"
+#include <scsi/scsi_host.h>
 #include "NCR53C9x.h"
 
 #include <asm/dma.h>
--- diff/drivers/scsi/megaraid.c	2004-06-11 19:17:30.000000000 +0100
+++ source/drivers/scsi/megaraid.c	2004-06-11 19:22:03.000000000 +0100
@@ -49,7 +49,7 @@
 #include <scsi/scsicam.h>
 
 #include "scsi.h"
-#include "hosts.h"
+#include <scsi/scsi_host.h>
 
 #include "megaraid.h"
 
@@ -4068,7 +4068,6 @@
 static int
 mega_del_logdrv(adapter_t *adapter, int logdrv)
 {
-	DECLARE_WAIT_QUEUE_HEAD(wq);
 	unsigned long flags;
 	scb_t *scb;
 	int rval;
@@ -4083,11 +4082,9 @@
 	 * Wait till all the issued commands are complete and there are no
 	 * commands in the pending queue
 	 */
-	while( atomic_read(&adapter->pend_cmds) > 0 ||
-			!list_empty(&adapter->pending_list) ) {
-
-		sleep_on_timeout( &wq, 1*HZ );	/* sleep for 1s */
-	}
+	while (atomic_read(&adapter->pend_cmds) > 0 ||
+	       !list_empty(&adapter->pending_list))
+		msleep(1000);	/* sleep for 1s */
 
 	rval = mega_do_del_logdrv(adapter, logdrv);
 
@@ -4612,6 +4609,26 @@
 	pci_dev_func = pdev->devfn;
 
 	/*
+	 * The megaraid3 stuff reports the ID of the Intel part which is not
+	 * remotely specific to the megaraid
+	 */
+	if (pdev->vendor == PCI_VENDOR_ID_INTEL) {
+		u16 magic;
+		/*
+		 * Don't fall over the Compaq management cards using the same
+		 * PCI identifier
+		 */
+		if (pdev->subsystem_vendor == PCI_VENDOR_ID_COMPAQ &&
+		    pdev->subsystem_device == 0xC000)
+		   	return -ENODEV;
+		/* Now check the magic signature byte */
+		pci_read_config_word(pdev, PCI_CONF_AMISIG, &magic);
+		if (magic != HBA_SIGNATURE_471 && magic != HBA_SIGNATURE)
+			return -ENODEV;
+		/* Ok it is probably a megaraid */
+	}
+
+	/*
 	 * For these vendor and device ids, signature offsets are not
 	 * valid and 64 bit is implicit
 	 */
--- diff/drivers/scsi/mvme147.c	2004-05-19 22:12:10.000000000 +0100
+++ source/drivers/scsi/mvme147.c	2004-06-11 19:22:03.000000000 +0100
@@ -11,7 +11,7 @@
 #include <asm/irq.h>
 
 #include "scsi.h"
-#include "hosts.h"
+#include <scsi/scsi_host.h>
 #include "wd33c93.h"
 #include "mvme147.h"
 
--- diff/drivers/scsi/mvme16x.c	2004-05-19 22:12:10.000000000 +0100
+++ source/drivers/scsi/mvme16x.c	2004-06-11 19:22:03.000000000 +0100
@@ -15,7 +15,7 @@
 #include <asm/irq.h>
 
 #include "scsi.h"
-#include "hosts.h"
+#include <scsi/scsi_host.h>
 #include "53c7xx.h"
 #include "mvme16x.h"
 
--- diff/drivers/scsi/ncr53c8xx.c	2004-06-11 19:17:30.000000000 +0100
+++ source/drivers/scsi/ncr53c8xx.c	2004-06-11 19:22:04.000000000 +0100
@@ -138,7 +138,7 @@
 #include <asm/system.h>
 
 #include "scsi.h"
-#include "hosts.h"
+#include <scsi/scsi_host.h>
 
 #include "ncr53c8xx.h"
 
--- diff/drivers/scsi/nsp32.c	2004-06-11 19:17:30.000000000 +0100
+++ source/drivers/scsi/nsp32.c	2004-06-11 19:22:04.000000000 +0100
@@ -44,7 +44,7 @@
 #include <asm/io.h>
 
 #include "scsi.h"
-#include "hosts.h"
+#include <scsi/scsi_host.h>
 #include <scsi/scsi_ioctl.h>
 #include <scsi/scsi.h>
 
--- diff/drivers/scsi/oktagon_esp.c	2004-05-19 22:12:10.000000000 +0100
+++ source/drivers/scsi/oktagon_esp.c	2004-06-11 19:22:04.000000000 +0100
@@ -29,7 +29,7 @@
 
 
 #include "scsi.h"
-#include "hosts.h"
+#include <scsi/scsi_host.h>
 #include "NCR53C9x.h"
 
 #include <linux/zorro.h>
--- diff/drivers/scsi/osst.c	2004-06-11 19:17:30.000000000 +0100
+++ source/drivers/scsi/osst.c	2004-06-11 19:22:04.000000000 +0100
@@ -61,7 +61,7 @@
 #define OSST_DEB_MSG  KERN_NOTICE
 
 #include "scsi.h"
-#include "hosts.h"
+#include <scsi/scsi_host.h>
 #include <scsi/scsi_driver.h>
 #include <scsi/scsi_ioctl.h>
 
--- diff/drivers/scsi/pas16.c	2004-05-19 22:12:10.000000000 +0100
+++ source/drivers/scsi/pas16.c	2004-06-11 19:22:04.000000000 +0100
@@ -125,7 +125,7 @@
 #include <linux/init.h>
 
 #include "scsi.h"
-#include "hosts.h"
+#include <scsi/scsi_host.h>
 #include "pas16.h"
 #define AUTOPROBE_IRQ
 #include "NCR5380.h"
--- diff/drivers/scsi/pc980155.c	2004-05-19 22:12:10.000000000 +0100
+++ source/drivers/scsi/pc980155.c	2004-06-11 19:22:04.000000000 +0100
@@ -20,7 +20,7 @@
 #include <asm/dma.h>
 
 #include "scsi.h"
-#include "hosts.h"
+#include <scsi/scsi_host.h>
 #include "wd33c93.h"
 #include "pc980155.h"
 
--- diff/drivers/scsi/pci2000.c	2004-06-11 19:17:30.000000000 +0100
+++ source/drivers/scsi/pci2000.c	2004-06-11 19:22:04.000000000 +0100
@@ -54,7 +54,7 @@
 #include <asm/io.h>
 
 #include "scsi.h"
-#include "hosts.h"
+#include <scsi/scsi_host.h>
 #include "pci2000.h"
 #include "psi_roy.h"
 
--- diff/drivers/scsi/pci2220i.c	2004-05-19 22:12:10.000000000 +0100
+++ source/drivers/scsi/pci2220i.c	2004-06-11 19:22:04.000000000 +0100
@@ -59,7 +59,7 @@
 #include <asm/io.h>
 
 #include "scsi.h"
-#include "hosts.h"
+#include <scsi/scsi_host.h>
 #include "pci2220i.h"
 #include "psi_dale.h"
 
--- diff/drivers/scsi/pcmcia/aha152x_stub.c	2004-05-19 22:12:13.000000000 +0100
+++ source/drivers/scsi/pcmcia/aha152x_stub.c	2004-06-11 19:22:04.000000000 +0100
@@ -47,7 +47,7 @@
 #include <scsi/scsi_ioctl.h>
 
 #include "scsi.h"
-#include "hosts.h"
+#include <scsi/scsi_host.h>
 #include "aha152x.h"
 
 #include <pcmcia/version.h>
--- diff/drivers/scsi/pcmcia/fdomain_stub.c	2004-05-19 22:12:13.000000000 +0100
+++ source/drivers/scsi/pcmcia/fdomain_stub.c	2004-06-11 19:22:04.000000000 +0100
@@ -44,7 +44,7 @@
 #include <scsi/scsi_ioctl.h>
 
 #include "scsi.h"
-#include "hosts.h"
+#include <scsi/scsi_host.h>
 
 #include <pcmcia/version.h>
 #include <pcmcia/cs_types.h>
--- diff/drivers/scsi/pcmcia/qlogic_stub.c	2004-06-11 19:17:30.000000000 +0100
+++ source/drivers/scsi/pcmcia/qlogic_stub.c	2004-06-11 19:22:04.000000000 +0100
@@ -46,7 +46,7 @@
 #include <linux/interrupt.h>
 
 #include "scsi.h"
-#include "hosts.h"
+#include <scsi/scsi_host.h>
 #include "../qlogicfas408.h"
 
 #include <pcmcia/version.h>
--- diff/drivers/scsi/pluto.c	2004-05-19 22:12:10.000000000 +0100
+++ source/drivers/scsi/pluto.c	2004-06-11 19:22:04.000000000 +0100
@@ -21,7 +21,7 @@
 #include <asm/irq.h>
 
 #include "scsi.h"
-#include "hosts.h"
+#include <scsi/scsi_host.h>
 #include "../fc4/fcp_impl.h"
 #include "pluto.h"
 
--- diff/drivers/scsi/ppa.h	2004-06-11 19:17:30.000000000 +0100
+++ source/drivers/scsi/ppa.h	2004-06-11 19:22:04.000000000 +0100
@@ -86,7 +86,7 @@
 #include  <linux/interrupt.h>
 
 #include  <asm/io.h>
-#include  "hosts.h"
+#include  <scsi/scsi_host.h>
 /* batteries not included :-) */
 
 /*
--- diff/drivers/scsi/psi240i.c	2004-05-19 22:12:10.000000000 +0100
+++ source/drivers/scsi/psi240i.c	2004-06-11 19:22:04.000000000 +0100
@@ -41,7 +41,7 @@
 #include <asm/system.h>
 #include <asm/io.h>
 #include "scsi.h"
-#include "hosts.h"
+#include <scsi/scsi_host.h>
 
 #include "psi240i.h"
 #include "psi_chip.h"
--- diff/drivers/scsi/qla1280.c	2004-06-11 19:17:30.000000000 +0100
+++ source/drivers/scsi/qla1280.c	2004-06-11 19:22:04.000000000 +0100
@@ -357,7 +357,7 @@
 #else
 #include <linux/blk.h>
 #include "scsi.h"
-#include "hosts.h"
+#include <scsi/scsi_host.h>
 #include "sd.h"
 #endif
 
@@ -3119,6 +3119,7 @@
  * Returns:
  *      0 = success, was able to issue command.
  */
+#ifdef QLA_64BIT_PTR
 static int
 qla1280_64bit_start_scsi(struct scsi_qla_host *ha, struct srb * sp)
 {
@@ -3381,9 +3382,8 @@
 
 	return status;
 }
+#else /* !QLA_64BIT_PTR */
 
-
-#ifndef QLA_64BIT_PTR
 /*
  * qla1280_32bit_start_scsi
  *      The start SCSI is responsible for building request packets on
--- diff/drivers/scsi/qla2xxx/qla_os.h	2004-05-19 22:12:14.000000000 +0100
+++ source/drivers/scsi/qla2xxx/qla_os.h	2004-06-11 19:22:04.000000000 +0100
@@ -59,7 +59,7 @@
 #include <asm/uaccess.h>
 
 #include "scsi.h"
-#include "hosts.h"
+#include <scsi/scsi_host.h>
 
 #include <scsi/scsicam.h>
 #include <scsi/scsi_ioctl.h>
--- diff/drivers/scsi/qlogicfas.c	2004-06-11 19:17:31.000000000 +0100
+++ source/drivers/scsi/qlogicfas.c	2004-06-11 19:22:04.000000000 +0100
@@ -32,7 +32,7 @@
 #include <asm/dma.h>
 
 #include "scsi.h"
-#include "hosts.h"
+#include <scsi/scsi_host.h>
 #include "qlogicfas408.h"
 
 /* Set the following to 2 to use normal interrupt (active high/totempole-
--- diff/drivers/scsi/qlogicfas408.c	2004-06-11 19:17:31.000000000 +0100
+++ source/drivers/scsi/qlogicfas408.c	2004-06-11 19:22:04.000000000 +0100
@@ -56,7 +56,7 @@
 #include <asm/dma.h>
 
 #include "scsi.h"
-#include "hosts.h"
+#include <scsi/scsi_host.h>
 #include "qlogicfas408.h"
 
 /*----------------------------------------------------------------*/
--- diff/drivers/scsi/qlogicfc.c	2004-05-19 22:12:11.000000000 +0100
+++ source/drivers/scsi/qlogicfc.c	2004-06-11 19:22:04.000000000 +0100
@@ -64,7 +64,7 @@
 #include <asm/io.h>
 #include <asm/irq.h>
 #include "scsi.h"
-#include "hosts.h"
+#include <scsi/scsi_host.h>
 
 #define pci64_dma_hi32(a) ((u32) (0xffffffff & (((u64)(a))>>32)))
 #define pci64_dma_lo32(a) ((u32) (0xffffffff & (((u64)(a)))))
--- diff/drivers/scsi/qlogicisp.c	2004-05-19 22:12:11.000000000 +0100
+++ source/drivers/scsi/qlogicisp.c	2004-06-11 19:22:04.000000000 +0100
@@ -36,7 +36,7 @@
 #include <asm/irq.h>
 #include <asm/byteorder.h>
 #include "scsi.h"
-#include "hosts.h"
+#include <scsi/scsi_host.h>
 #include "qlogicisp.h"
 
 /* Configuration section *****************************************************/
--- diff/drivers/scsi/qlogicpti.c	2004-06-11 19:17:31.000000000 +0100
+++ source/drivers/scsi/qlogicpti.c	2004-06-11 19:22:04.000000000 +0100
@@ -27,6 +27,8 @@
 
 #include <asm/byteorder.h>
 
+#include "scsi.h"
+#include <scsi/scsi_host.h>
 #include "qlogicpti.h"
 
 #include <asm/sbus.h>
--- diff/drivers/scsi/scsi.h	2004-05-19 22:12:11.000000000 +0100
+++ source/drivers/scsi/scsi.h	2004-06-11 19:22:04.000000000 +0100
@@ -11,6 +11,11 @@
  *       add scatter-gather, multiple outstanding request, and other
  *       enhancements.
  */
+/*
+ * NOTE:  this file only contains compatibility glue for old drivers.  All
+ * these wrappers will be removed sooner or later.  For new code please use
+ * the interfaces declared in the headers in include/scsi/
+ */
 
 #ifndef _SCSI_H
 #define _SCSI_H
@@ -18,6 +23,7 @@
 #include <linux/config.h>	    /* for CONFIG_SCSI_LOGGING */
 
 #include <scsi/scsi_cmnd.h>
+#include <scsi/scsi_dbg.h>
 #include <scsi/scsi_device.h>
 #include <scsi/scsi_eh.h>
 #include <scsi/scsi_request.h>
@@ -47,21 +53,6 @@
 struct scatterlist;
 
 /*
- * Prototypes for functions in constants.c
- * Some of these used to live in constants.h
- */
-extern void print_Scsi_Cmnd(struct scsi_cmnd *);
-extern void print_command(unsigned char *);
-extern void print_sense(const char *, struct scsi_cmnd *);
-extern void print_req_sense(const char *, struct scsi_request *);
-extern void print_driverbyte(int scsiresult);
-extern void print_hostbyte(int scsiresult);
-extern void print_status(unsigned char status);
-extern int print_msg(const unsigned char *);
-extern const char *scsi_sense_key_string(unsigned char);
-extern const char *scsi_extd_sense_format(unsigned char, unsigned char);
-
-/*
  * Legacy dma direction interfaces.
  *
  * This assumes the pci/sbus dma mapping flags have the same numercial
@@ -77,6 +68,42 @@
 #define scsi_to_sbus_dma_dir(scsi_dir)	((int)(scsi_dir))
 
 /*
+ * Old names for debug prettyprinting functions.
+ */
+static inline void print_Scsi_Cmnd(struct scsi_cmnd *cmd)
+{
+	return scsi_print_command(cmd);
+}
+static inline void print_command(unsigned char *cdb)
+{
+	return __scsi_print_command(cdb);
+}
+static inline void print_sense(const char *devclass, struct scsi_cmnd *cmd)
+{
+	return scsi_print_sense(devclass, cmd);
+}
+static inline void print_req_sense(const char *devclass, struct scsi_request *req)
+{
+	return scsi_print_req_sense(devclass, req);
+}
+static inline void print_driverbyte(int scsiresult)
+{
+	return scsi_print_driverbyte(scsiresult);
+}
+static inline void print_hostbyte(int scsiresult)
+{
+	return scsi_print_hostbyte(scsiresult);
+}
+static inline void print_status(unsigned char status)
+{
+	return scsi_print_status(status);
+}
+static inline int print_msg(const unsigned char *msg)
+{
+	return scsi_print_msg(msg);
+}
+
+/*
  * This is the crap from the old error handling code.  We have it in a special
  * place so that we can more easily delete it later on.
  */
--- diff/drivers/scsi/scsi_debug.c	2004-06-11 19:17:31.000000000 +0100
+++ source/drivers/scsi/scsi_debug.c	2004-06-11 19:22:04.000000000 +0100
@@ -43,7 +43,7 @@
 
 #include <linux/blkdev.h>
 #include "scsi.h"
-#include "hosts.h"
+#include <scsi/scsi_host.h>
 #include <scsi/scsicam.h>
 
 #include <linux/stat.h>
@@ -1326,7 +1326,7 @@
 	return -EINVAL;
 }
 DRIVER_ATTR(delay, S_IRUGO | S_IWUSR, sdebug_delay_show, 
-	    sdebug_delay_store)
+	    sdebug_delay_store);
 
 static ssize_t sdebug_opts_show(struct device_driver * ddp, char * buf) 
 {
@@ -1355,7 +1355,7 @@
 	return count;
 }
 DRIVER_ATTR(opts, S_IRUGO | S_IWUSR, sdebug_opts_show, 
-	    sdebug_opts_store)
+	    sdebug_opts_store);
 
 static ssize_t sdebug_num_tgts_show(struct device_driver * ddp, char * buf) 
 {
@@ -1373,13 +1373,13 @@
 	return -EINVAL;
 }
 DRIVER_ATTR(num_tgts, S_IRUGO | S_IWUSR, sdebug_num_tgts_show, 
-	    sdebug_num_tgts_store) 
+	    sdebug_num_tgts_store);
 
 static ssize_t sdebug_dev_size_mb_show(struct device_driver * ddp, char * buf) 
 {
         return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_dev_size_mb);
 }
-DRIVER_ATTR(dev_size_mb, S_IRUGO, sdebug_dev_size_mb_show, NULL) 
+DRIVER_ATTR(dev_size_mb, S_IRUGO, sdebug_dev_size_mb_show, NULL);
 
 static ssize_t sdebug_every_nth_show(struct device_driver * ddp, char * buf) 
 {
@@ -1398,7 +1398,7 @@
 	return -EINVAL;
 }
 DRIVER_ATTR(every_nth, S_IRUGO | S_IWUSR, sdebug_every_nth_show,
-	    sdebug_every_nth_store) 
+	    sdebug_every_nth_store);
 
 static ssize_t sdebug_max_luns_show(struct device_driver * ddp, char * buf) 
 {
@@ -1416,13 +1416,13 @@
 	return -EINVAL;
 }
 DRIVER_ATTR(max_luns, S_IRUGO | S_IWUSR, sdebug_max_luns_show, 
-	    sdebug_max_luns_store) 
+	    sdebug_max_luns_store);
 
 static ssize_t sdebug_scsi_level_show(struct device_driver * ddp, char * buf) 
 {
         return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_scsi_level);
 }
-DRIVER_ATTR(scsi_level, S_IRUGO, sdebug_scsi_level_show, NULL) 
+DRIVER_ATTR(scsi_level, S_IRUGO, sdebug_scsi_level_show, NULL);
 
 static ssize_t sdebug_add_host_show(struct device_driver * ddp, char * buf) 
 {
@@ -1459,7 +1459,7 @@
 	return count;
 }
 DRIVER_ATTR(add_host, S_IRUGO | S_IWUSR, sdebug_add_host_show, 
-	    sdebug_add_host_store)
+	    sdebug_add_host_store);
 
 static void do_create_driverfs_files(void)
 {
--- diff/drivers/scsi/scsi_devinfo.c	2004-06-11 19:17:31.000000000 +0100
+++ source/drivers/scsi/scsi_devinfo.c	2004-06-11 19:22:04.000000000 +0100
@@ -9,7 +9,7 @@
 #include <scsi/scsi_devinfo.h>
 
 #include "scsi.h"
-#include "hosts.h"
+#include <scsi/scsi_host.h>
 #include "scsi_priv.h"
 
 /*
@@ -27,7 +27,7 @@
 static const char spaces[] = "                "; /* 16 of them */
 static unsigned scsi_default_dev_flags;
 static LIST_HEAD(scsi_dev_info_list);
-static __init char scsi_dev_flags[256];
+static __initdata char scsi_dev_flags[256];
 
 /*
  * scsi_static_device_list: deprecated list of devices that require
@@ -117,8 +117,10 @@
 	 */
 	{"ADAPTEC", "AACRAID", NULL, BLIST_FORCELUN},
 	{"ADAPTEC", "Adaptec 5400S", NULL, BLIST_FORCELUN},
-	{"BELKIN", "USB 2 HS-CF", "1.95",  BLIST_SPARSELUN},
+	{"AFT PRO", "-IX CF", "0.0>", BLIST_FORCELUN},
+	{"BELKIN", "USB 2 HS-CF", "1.95",  BLIST_FORCELUN},
 	{"CANON", "IPUBJD", NULL, BLIST_SPARSELUN},
+	{"CBOX3", "USB Storage-SMC", "300A", BLIST_FORCELUN},
 	{"CMD", "CRA-7280", NULL, BLIST_SPARSELUN},	/* CMD RAID Controller */
 	{"CNSI", "G7324", NULL, BLIST_SPARSELUN},	/* Chaparral G7324 RAID */
 	{"CNSi", "G8324", NULL, BLIST_SPARSELUN},	/* Chaparral G8324 RAID */
@@ -139,6 +141,7 @@
 	{"EMC", "SYMMETRIX", NULL, BLIST_SPARSELUN | BLIST_LARGELUN | BLIST_FORCELUN},
 	{"EMULEX", "MD21/S2     ESDI", NULL, BLIST_SINGLELUN},
 	{"FSC", "CentricStor", "*", BLIST_SPARSELUN | BLIST_LARGELUN},
+	{"Generic", "USB SD Reader", "1.00", BLIST_FORCELUN},
 	{"Generic", "USB Storage-SMC", "0180", BLIST_FORCELUN},
 	{"Generic", "USB Storage-SMC", "0207", BLIST_FORCELUN},
 	{"HITACHI", "DF400", "*", BLIST_SPARSELUN},
@@ -171,6 +174,7 @@
 	{"PIONEER", "CD-ROM DRM-602X", NULL, BLIST_FORCELUN | BLIST_SINGLELUN},
 	{"PIONEER", "CD-ROM DRM-604X", NULL, BLIST_FORCELUN | BLIST_SINGLELUN},
 	{"REGAL", "CDC-4X", NULL, BLIST_MAX5LUN | BLIST_SINGLELUN},
+	{"SanDisk", "ImageMate CF-SD1", NULL, BLIST_FORCELUN},
 	{"SGI", "RAID3", "*", BLIST_SPARSELUN},
 	{"SGI", "RAID5", "*", BLIST_SPARSELUN},
 	{"SGI", "TP9100", "*", BLIST_SPARSELUN | BLIST_LARGELUN},
@@ -182,6 +186,7 @@
 	{"TEXEL", "CD-ROM", "1.06", BLIST_BORKEN},
 	{"TOSHIBA", "CDROM", NULL, BLIST_ISROM},
 	{"TOSHIBA", "CD-ROM", NULL, BLIST_ISROM},
+	{"USB2.0", "SMARTMEDIA/XD", NULL, BLIST_FORCELUN},
 	{"XYRATEX", "RS", "*", BLIST_SPARSELUN | BLIST_LARGELUN},
 	{"Zzyzx", "RocketStor 500S", NULL, BLIST_SPARSELUN},
 	{"Zzyzx", "RocketStor 2000", NULL, BLIST_SPARSELUN},
--- diff/drivers/scsi/scsi_error.c	2004-05-19 22:12:11.000000000 +0100
+++ source/drivers/scsi/scsi_error.c	2004-06-11 19:22:04.000000000 +0100
@@ -26,7 +26,7 @@
 #include <scsi/scsi_ioctl.h>
 
 #include "scsi.h"
-#include "hosts.h"
+#include <scsi/scsi_host.h>
 
 #include "scsi_priv.h"
 #include "scsi_logging.h"
@@ -1026,7 +1026,8 @@
 	spin_unlock_irqrestore(scmd->device->host->host_lock, flags);
 
 	if (rtn == SUCCESS) {
-		scsi_sleep(BUS_RESET_SETTLE_TIME);
+		if (!scmd->device->host->hostt->skip_settle_delay)
+			scsi_sleep(BUS_RESET_SETTLE_TIME);
 		spin_lock_irqsave(scmd->device->host->host_lock, flags);
 		scsi_report_bus_reset(scmd->device->host, scmd->device->channel);
 		spin_unlock_irqrestore(scmd->device->host->host_lock, flags);
@@ -1057,7 +1058,8 @@
 	spin_unlock_irqrestore(scmd->device->host->host_lock, flags);
 
 	if (rtn == SUCCESS) {
-		scsi_sleep(HOST_RESET_SETTLE_TIME);
+		if (!scmd->device->host->hostt->skip_settle_delay)
+			scsi_sleep(HOST_RESET_SETTLE_TIME);
 		spin_lock_irqsave(scmd->device->host->host_lock, flags);
 		scsi_report_bus_reset(scmd->device->host, scmd->device->channel);
 		spin_unlock_irqrestore(scmd->device->host->host_lock, flags);
--- diff/drivers/scsi/scsi_ioctl.c	2004-06-11 19:17:31.000000000 +0100
+++ source/drivers/scsi/scsi_ioctl.c	2004-06-11 19:22:04.000000000 +0100
@@ -20,7 +20,7 @@
 
 #include <linux/blkdev.h>
 #include "scsi.h"
-#include "hosts.h"
+#include <scsi/scsi_host.h>
 #include <scsi/scsi_ioctl.h>
 
 #include "scsi_logging.h"
--- diff/drivers/scsi/scsi_lib.c	2004-06-11 19:17:31.000000000 +0100
+++ source/drivers/scsi/scsi_lib.c	2004-06-11 19:22:04.000000000 +0100
@@ -255,7 +255,6 @@
 	sreq->sr_request->rq_status = RQ_SCSI_BUSY;
 	scsi_do_req(sreq, cmnd, buffer, bufflen, scsi_wait_done,
 			timeout, retries);
-	generic_unplug_device(sreq->sr_device->request_queue);
 	wait_for_completion(&wait);
 	sreq->sr_request->waiting = NULL;
 	if (sreq->sr_request->rq_status != RQ_SCSI_DONE)
@@ -951,6 +950,22 @@
 	return BLKPREP_KILL;
 }
 
+static int scsi_issue_flush_fn(request_queue_t *q, struct gendisk *disk,
+			       sector_t *error_sector)
+{
+	struct scsi_device *sdev = q->queuedata;
+	struct scsi_driver *drv;
+
+	if (sdev->sdev_state != SDEV_RUNNING)
+		return -ENXIO;
+
+	drv = *(struct scsi_driver **) disk->private_data;
+	if (drv->issue_flush)
+		return drv->issue_flush(&sdev->sdev_gendev, error_sector);
+
+	return -EOPNOTSUPP;
+}
+
 static int scsi_prep_fn(struct request_queue *q, struct request *req)
 {
 	struct scsi_device *sdev = q->queuedata;
@@ -1332,7 +1347,8 @@
 	blk_queue_max_sectors(q, shost->max_sectors);
 	blk_queue_bounce_limit(q, scsi_calculate_bounce_limit(shost));
 	blk_queue_segment_boundary(q, shost->dma_boundary);
- 
+	blk_queue_issue_flush_fn(q, scsi_issue_flush_fn);
+
 	if (!shost->use_clustering)
 		clear_bit(QUEUE_FLAG_CLUSTER, &q->queue_flags);
 	return q;
--- diff/drivers/scsi/scsi_module.c	2004-05-19 22:12:11.000000000 +0100
+++ source/drivers/scsi/scsi_module.c	2004-06-11 19:22:04.000000000 +0100
@@ -12,7 +12,7 @@
 #include <linux/module.h>
 
 #include "scsi.h"
-#include "hosts.h"
+#include <scsi/scsi_host.h>
 
 
 static int __init init_this_scsi_driver(void)
--- diff/drivers/scsi/scsi_pc98.c	2004-05-19 22:12:11.000000000 +0100
+++ source/drivers/scsi/scsi_pc98.c	2004-06-11 19:22:04.000000000 +0100
@@ -12,7 +12,7 @@
 #include <asm/pc9800.h>
 
 #include "scsi.h"
-#include "hosts.h"
+#include <scsi/scsi_host.h>
 
 
 static int pc98_first_bios_param(struct scsi_device *sdev, int *ip)
--- diff/drivers/scsi/scsi_syms.c	2004-05-19 22:12:11.000000000 +0100
+++ source/drivers/scsi/scsi_syms.c	2004-06-11 19:22:04.000000000 +0100
@@ -46,15 +46,15 @@
 EXPORT_SYMBOL(scsi_partsize);
 EXPORT_SYMBOL(scsi_bios_ptable);
 EXPORT_SYMBOL(scsi_ioctl);
-EXPORT_SYMBOL(print_command);
-EXPORT_SYMBOL(print_sense);
-EXPORT_SYMBOL(print_req_sense);
-EXPORT_SYMBOL(print_msg);
-EXPORT_SYMBOL(print_status);
+EXPORT_SYMBOL(scsi_print_command);
+EXPORT_SYMBOL(__scsi_print_command);
+EXPORT_SYMBOL(scsi_print_sense);
+EXPORT_SYMBOL(scsi_print_req_sense);
+EXPORT_SYMBOL(scsi_print_msg);
+EXPORT_SYMBOL(scsi_print_status);
 EXPORT_SYMBOL(scsi_sense_key_string);
 EXPORT_SYMBOL(scsi_extd_sense_format);
 EXPORT_SYMBOL(kernel_scsi_ioctl);
-EXPORT_SYMBOL(print_Scsi_Cmnd);
 EXPORT_SYMBOL(scsi_block_when_processing_errors);
 EXPORT_SYMBOL(scsi_ioctl_send_command);
 EXPORT_SYMBOL(scsi_set_medium_removal);
--- diff/drivers/scsi/scsi_sysfs.c	2004-06-11 19:17:31.000000000 +0100
+++ source/drivers/scsi/scsi_sysfs.c	2004-06-11 19:22:04.000000000 +0100
@@ -99,7 +99,7 @@
  */
 #define shost_rd_attr2(name, field, format_string)			\
 	shost_show_function(name, field, format_string)			\
-static CLASS_DEVICE_ATTR(name, S_IRUGO, show_##name, NULL)
+static CLASS_DEVICE_ATTR(name, S_IRUGO, show_##name, NULL);
 
 #define shost_rd_attr(field, format_string) \
 shost_rd_attr2(field, field, format_string)
@@ -228,8 +228,8 @@
  * read only field.
  */
 #define sdev_rd_attr(field, format_string)				\
-	sdev_show_function(field, format_string)				\
-static DEVICE_ATTR(field, S_IRUGO, sdev_show_##field, NULL)
+	sdev_show_function(field, format_string)			\
+static DEVICE_ATTR(field, S_IRUGO, sdev_show_##field, NULL);
 
 
 /*
@@ -247,7 +247,7 @@
 	snscanf (buf, 20, format_string, &sdev->field);			\
 	return count;							\
 }									\
-static DEVICE_ATTR(field, S_IRUGO | S_IWUSR, sdev_show_##field, sdev_store_##field)
+static DEVICE_ATTR(field, S_IRUGO | S_IWUSR, sdev_show_##field, sdev_store_##field);
 
 /* Currently we don't export bit fields, but we might in future,
  * so leave this code in */
@@ -272,7 +272,7 @@
 	}								\
 	return ret;							\
 }									\
-static DEVICE_ATTR(field, S_IRUGO | S_IWUSR, sdev_show_##field, sdev_store_##field)
+static DEVICE_ATTR(field, S_IRUGO | S_IWUSR, sdev_show_##field, sdev_store_##field);
 
 /*
  * scsi_sdev_check_buf_bit: return 0 if buf is "0", return 1 if buf is "1",
@@ -320,7 +320,7 @@
 	sdev->timeout = timeout * HZ;
 	return count;
 }
-static DEVICE_ATTR(timeout, S_IRUGO | S_IWUSR, sdev_show_timeout, sdev_store_timeout)
+static DEVICE_ATTR(timeout, S_IRUGO | S_IWUSR, sdev_show_timeout, sdev_store_timeout);
 
 static ssize_t
 store_rescan_field (struct device *dev, const char *buf, size_t count) 
@@ -328,7 +328,7 @@
 	scsi_rescan_device(dev);
 	return count;
 }
-static DEVICE_ATTR(rescan, S_IWUSR, NULL, store_rescan_field)
+static DEVICE_ATTR(rescan, S_IWUSR, NULL, store_rescan_field);
 
 static ssize_t sdev_store_delete(struct device *dev, const char *buf,
 				 size_t count)
--- diff/drivers/scsi/scsi_transport_spi.c	2004-05-19 22:12:11.000000000 +0100
+++ source/drivers/scsi/scsi_transport_spi.c	2004-06-11 19:22:04.000000000 +0100
@@ -152,7 +152,7 @@
 	spi_transport_store_function(field, format_string)		\
 static CLASS_DEVICE_ATTR(field, S_IRUGO | S_IWUSR,			\
 			 show_spi_transport_##field,			\
-			 store_spi_transport_##field)
+			 store_spi_transport_##field);
 
 /* The Parallel SCSI Tranport Attributes: */
 spi_transport_rd_attr(offset, "%d\n");
@@ -173,7 +173,7 @@
 	spi_dv_device(sdev);
 	return count;
 }
-static CLASS_DEVICE_ATTR(revalidate, S_IWUSR, NULL, store_spi_revalidate)
+static CLASS_DEVICE_ATTR(revalidate, S_IWUSR, NULL, store_spi_revalidate);
 
 /* Translate the period into ns according to the current spec
  * for SDTR/PPR messages */
--- diff/drivers/scsi/scsicam.c	2004-05-19 22:12:11.000000000 +0100
+++ source/drivers/scsi/scsicam.c	2004-06-11 19:22:04.000000000 +0100
@@ -19,7 +19,7 @@
 #include <linux/buffer_head.h>
 #include <asm/unaligned.h>
 #include "scsi.h"
-#include "hosts.h"
+#include <scsi/scsi_host.h>
 #include <scsi/scsicam.h>
 
 static int setsize(unsigned long capacity, unsigned int *cyls, unsigned int *hds,
--- diff/drivers/scsi/scsiiom.c	2004-06-11 19:17:31.000000000 +0100
+++ source/drivers/scsi/scsiiom.c	2004-06-11 19:22:04.000000000 +0100
@@ -12,7 +12,7 @@
 		pDCB->TagMask &= ~(1 << pSRB->TagNumber);   /* free tag mask */
 		pSRB->TagNumber = 255;
 	}
-};
+}
 
 
 static UCHAR
@@ -75,7 +75,7 @@
 		printk (KERN_WARNING "DC390: Out of tags for Dev. %02x %02x\n", pDCB->TargetID, pDCB->TargetLUN); 
 		return 1;
 		//goto no_tag;
-	};
+	}
 	DC390_write8 (ScsiFifo, SIMPLE_QUEUE_TAG);
 	pDCB->TagMask |= (1 << tag_no); pSRB->TagNumber = tag_no;
 	DC390_write8 (ScsiFifo, tag_no);
@@ -86,7 +86,7 @@
       {
 //      no_tag:
 	DEBUG1(printk (KERN_DEBUG "DC390: Select w%s/DisCn for Cmd %li (SRB %p), No TagQ\n", (disc_allowed?"":"o"), pSRB->pcmd->pid, pSRB));
-      };
+      }
 
     pSRB->SRBState = SRB_START_;
 
@@ -104,7 +104,7 @@
 	//pSRB->SRBState = SRB_MSGOUT_;
 	pSRB->SRBState |= DO_SYNC_NEGO;
 	cmd = SEL_W_ATN_STOP;
-      };
+      }
 
     /* Command is written in CommandPhase, if SEL_W_ATN_STOP ... */
     if (cmd != SEL_W_ATN_STOP)
@@ -125,7 +125,7 @@
 	    ptr = (PUCHAR) pSRB->pcmd->cmnd;
 	    for (i=0; i<pSRB->pcmd->cmd_len; i++)
 	      DC390_write8 (ScsiFifo, *(ptr++));
-	  };
+	  }
       }
     DEBUG0(if (pACB->pActiveDCB)	\
 	   printk (KERN_WARNING "DC390: ActiveDCB != 0\n"));
@@ -141,7 +141,7 @@
 	//DC390_write8 (ScsiCmd, CLEAR_FIFO_CMD);
 	pACB->SelLost++;
 	return 1;
-    };
+    }
     DC390_write8 (ScsiCmd, cmd);
     pACB->pActiveDCB = pDCB; pDCB->pActiveSRB = pSRB;
     pACB->Connected = 1;
@@ -176,7 +176,7 @@
     {
 	printk (KERN_ERR "DC390: DMA error (%02x)!\n", dstate);
 	return dstate;
-    };
+    }
   if (dstate & DMA_XFER_DONE)
     {
 	UINT residual, xferCnt; int ctr = 6000000;
@@ -253,7 +253,7 @@
       {
 	DEBUG0(printk (KERN_WARNING "DC390 Int w/o SCSI actions (only DMA?)\n"));
 	return IRQ_NONE;
-      };
+      }
 #else
     //DC390_write32 (DMA_ScsiBusCtrl, WRT_ERASE_DMA_STAT | EN_INT_ON_PCI_ABORT);
     //dstatus = DC390_read8 (DMA_Status);
@@ -313,7 +313,7 @@
 	{
 		printk (KERN_ERR "DC390: Suc. op/ Serv. req: pActiveDCB = 0!\n");
 		goto unlock;
-	};
+	}
 	pSRB = pDCB->pActiveSRB;
 	if( pDCB->DCBFlag & ABORT_DEV_ )
 	  dc390_EnableMsgOut_Abort (pACB, pSRB);
@@ -549,7 +549,7 @@
   DC390_write8 (CtrlReg3, pDCB->CtrlR3);
   DC390_write8 (CtrlReg4, pDCB->CtrlR4);
   dc390_SetXferRate (pACB, pDCB);
-};
+}
 
 
 #ifdef DC390_DEBUG0
@@ -561,7 +561,7 @@
   for (i = 1; i < len; i++)
     printk (" %02x", MsgBuf[i]);
   printk ("\n");
-};
+}
 #endif
 
 #define DC390_ENABLE_MSGOUT DC390_write8 (ScsiCmd, SET_ATN_CMD)
@@ -671,11 +671,11 @@
 	{
 	  printk (KERN_INFO "DC390: Set sync nego period to %ins\n", pDCB->NegoPeriod << 2);
 	  pSRB->MsgInBuf[3] = pDCB->NegoPeriod;
-	};
+	}
       memcpy (pSRB->MsgOutBuf, pSRB->MsgInBuf, 5);
       pSRB->MsgCnt = 5;
       DC390_ENABLE_MSGOUT;
-    };
+    }
 
   pSRB->SRBState &= ~DO_SYNC_NEGO;
   pDCB->SyncMode |= SYNC_ENABLE+SYNC_NEGO_DONE;
@@ -713,7 +713,7 @@
     }
   
   dc390_reprog (pACB, pDCB);
-};
+}
 
 
 /* handle RESTORE_PTR */
@@ -761,7 +761,7 @@
     }
 
   pSRB->TotalXferredLen = pSRB->Saved_Ptr;
-};
+}
 
 
 /* According to the docs, the AM53C974 reads the message and 
@@ -789,7 +789,7 @@
 
 
 /* read and eval received messages */
-void
+static void
 dc390_MsgIn_0( PACB pACB, PSRB pSRB, PUCHAR psstatus)
 {
     PDCB   pDCB = pACB->pActiveDCB;
@@ -832,7 +832,7 @@
 		  dc390_MsgIn_set_async (pACB, pSRB);
 		else
 		  dc390_MsgIn_set_sync (pACB, pSRB);
-	      };
+	      }
 	    
 	    // nothing has to be done
 	  case COMMAND_COMPLETE: break;
@@ -948,7 +948,7 @@
     dc390_DataIO_Comm (pACB, pSRB, READ_DIRECTION);
 }
 
-void
+static void
 dc390_CommandPhase( PACB pACB, PSRB pSRB, PUCHAR psstatus)
 {
     PDCB   pDCB;
@@ -989,7 +989,7 @@
     //DC390_write8 (DMA_Cmd, DMA_IDLE_CMD);
 }
 
-void
+static void
 dc390_MsgOutPhase( PACB pACB, PSRB pSRB, PUCHAR psstatus)
 {
     UCHAR   bval, i, cnt;
@@ -1097,7 +1097,7 @@
 }
 
 
-void
+static void
 dc390_Disconnect( PACB pACB )
 {
     PDCB   pDCB;
@@ -1179,7 +1179,7 @@
 }
 
 
-void
+static void
 dc390_Reselect( PACB pACB )
 {
     PDCB   pDCB;
@@ -1276,7 +1276,7 @@
 	DCBDEBUG(printk (KERN_INFO "DC390: Driver won't free DCB (ID %i, LUN %i): 0x%08x because of SRBCnt %i\n",\
 		pDCB->TargetID, pDCB->TargetLUN, (int)pDCB, pDCB->GoingSRBCnt));
 	return;
-     };
+     }
    pACB->DCBmap[pDCB->TargetID] &= ~(1 << pDCB->TargetLUN);
    
    // The first one
@@ -1302,8 +1302,7 @@
    if (pDCB == pACB->pDCBRunRobin) pACB->pDCBRunRobin = pDCB->pNextDCB;
    kfree (pDCB); 
    pACB->DCBCnt--;
-   /* pACB->DeviceCnt--; */
-};
+}
 
 
 static UCHAR __inline__
@@ -1314,7 +1313,7 @@
      if (memcmp (name, dc390_baddevname1[i], 28) == 0)
 	return 1;
    return 0;
-};
+}
    
 
 static void 
@@ -1336,7 +1335,7 @@
 	else
 	     pDCB->MaxCommand = 1;
      }
-};
+}
 
 
 static void 
@@ -1346,13 +1345,13 @@
    pDCB->DevType = bval1;
    /* if (bval1 == TYPE_DISK || bval1 == TYPE_MOD) */
 	dc390_disc_tagq_set (pDCB, ptr);
-};
+}
 
 
-void
+static void
 dc390_SRBdone( PACB pACB, PDCB pDCB, PSRB pSRB )
 {
-    UCHAR  bval, status, i, DCB_removed;
+    UCHAR  bval, status, i;
     PSCSICMD pcmd;
     PSCSI_INQDATA  ptr;
     PSGL   ptr2;
@@ -1362,7 +1361,6 @@
     /* KG: Moved pci_unmap here */
     dc390_pci_unmap(pSRB);
 
-    DCB_removed = 0;
     status = pSRB->TargetStatus;
     ptr = (PSCSI_INQDATA) (pcmd->request_buffer);
     if( pcmd->use_sg )
@@ -1564,55 +1562,22 @@
 				   pcmd->sense_buffer[2], pcmd->sense_buffer[3]);
 	    else printk ("\n");
 #endif
-	    if( (host_byte(pcmd->result) != DID_OK && !(status_byte(pcmd->result) & CHECK_CONDITION) && !(status_byte(pcmd->result) & BUSY)) ||
-	       ((driver_byte(pcmd->result) & DRIVER_SENSE) && (pcmd->sense_buffer[0] & 0x70) == 0x70 &&
-		(pcmd->sense_buffer[2] & 0xf) == ILLEGAL_REQUEST) || host_byte(pcmd->result) & DID_ERROR )
-	    {
-	       /* device not present: remove */ 
-	       //dc390_Going_remove (pDCB, pSRB);
-	       dc390_remove_dev (pACB, pDCB); DCB_removed = 1;
-	       
-	       if( (pcmd->device->id == pACB->pScsiHost->max_id - 1) &&
-		  ((pcmd->device->lun == 0) || (pcmd->device->lun == pACB->pScsiHost->max_lun - 1)) )
-		 pACB->scan_devices = 0;
-	    }
-	    else
-	    {
-	        /* device present: add */
-		if( (pcmd->device->id == pACB->pScsiHost->max_id - 1) && 
-		    (pcmd->device->lun == pACB->pScsiHost->max_lun - 1) )
-		    pACB->scan_devices = END_SCAN ;
-	        /* pACB->DeviceCnt++; */ /* Dev is added on INQUIRY */
-	    }
 	}
     }
-   
-    //if( pSRB->pcmd->cmnd[0] == INQUIRY && 
-    //  (host_byte(pcmd->result) == DID_OK || status_byte(pcmd->result) & CHECK_CONDITION) )
+
     if( pcmd->cmnd[0] == INQUIRY && 
 	(pcmd->result == (DID_OK << 16) || status_byte(pcmd->result) & CHECK_CONDITION) )
      {
-	if ((ptr->DevType & SCSI_DEVTYPE) == TYPE_NODEV && !DCB_removed)
-	  {
-	     //printk ("DC390: Type = nodev! (%02i-%i)\n", pcmd->target, pcmd->lun);
-	     /* device not present: remove */
-	     //dc390_Going_remove (pDCB, pSRB);
-	     dc390_remove_dev (pACB, pDCB); DCB_removed = 1;
-	  }
-	else
+	if ((ptr->DevType & SCSI_DEVTYPE) != TYPE_NODEV)
 	  {
 	     /* device found: add */ 
 	     dc390_add_dev (pACB, pDCB, ptr);
-	     if (pACB->scan_devices) pACB->DeviceCnt++;
 	  }
-	if( (pcmd->device->id == pACB->pScsiHost->max_id - 1) &&
-	    (pcmd->device->lun == pACB->pScsiHost->max_lun - 1) )
-	  pACB->scan_devices = 0;
-     };
+     }
 
     pcmd->resid = pcmd->request_bufflen - pSRB->TotalXferredLen;
 
-    if (!DCB_removed) dc390_Going_remove (pDCB, pSRB);
+    dc390_Going_remove (pDCB, pSRB);
     /* Add to free list */
     dc390_Free_insert (pACB, pSRB);
 
@@ -1625,7 +1590,7 @@
 
 
 /* Remove all SRBs from Going list and inform midlevel */
-void
+static void
 dc390_DoingSRB_Done( PACB pACB, PSCSICMD cmd )
 {
     PDCB   pDCB, pdcb;
@@ -1760,4 +1725,3 @@
     if( pACB->pActiveDCB->pActiveSRB->SRBState & (SRB_START_+SRB_MSGOUT) )
 	DC390_write8 (ScsiCmd, CLEAR_FIFO_CMD);
 }
-
--- diff/drivers/scsi/sd.c	2004-06-11 19:17:31.000000000 +0100
+++ source/drivers/scsi/sd.c	2004-06-11 19:22:04.000000000 +0100
@@ -52,7 +52,7 @@
 #include <asm/uaccess.h>
 
 #include "scsi.h"
-#include "hosts.h"
+#include <scsi/scsi_host.h>
 
 #include <scsi/scsi_driver.h>
 #include <scsi/scsi_ioctl.h>
@@ -111,6 +111,7 @@
 static void sd_shutdown(struct device *dev);
 static void sd_rescan(struct device *);
 static int sd_init_command(struct scsi_cmnd *);
+static int sd_issue_flush(struct device *, sector_t *);
 static void sd_read_capacity(struct scsi_disk *sdkp, char *diskname,
 		 struct scsi_request *SRpnt, unsigned char *buffer);
 
@@ -124,6 +125,7 @@
 	},
 	.rescan			= sd_rescan,
 	.init_command		= sd_init_command,
+	.issue_flush		= sd_issue_flush,
 };
 
 /* Device no to disk mapping:
@@ -674,6 +676,62 @@
 	return 1;
 }
 
+static int sd_sync_cache(struct scsi_device *sdp)
+{
+	struct scsi_request *sreq;
+	int retries, res;
+
+	if (!scsi_device_online(sdp))
+		return -ENODEV;
+
+	sreq = scsi_allocate_request(sdp, GFP_KERNEL);
+	if (!sreq) {
+		printk("FAILED\n  No memory for request\n");
+		return -ENOMEM;
+	}
+
+	sreq->sr_data_direction = DMA_NONE;
+	for (retries = 3; retries > 0; --retries) {
+		unsigned char cmd[10] = { 0 };
+
+		cmd[0] = SYNCHRONIZE_CACHE;
+		/*
+		 * Leave the rest of the command zero to indicate
+		 * flush everything.
+		 */
+		scsi_wait_req(sreq, cmd, NULL, 0, SD_TIMEOUT, SD_MAX_RETRIES);
+		if (sreq->sr_result == 0)
+			break;
+	}
+
+	res = sreq->sr_result;
+	if (res) {
+		printk(KERN_WARNING "FAILED\n  status = %x, message = %02x, "
+				    "host = %d, driver = %02x\n  ",
+				    status_byte(res), msg_byte(res),
+				    host_byte(res), driver_byte(res));
+			if (driver_byte(res) & DRIVER_SENSE)
+				print_req_sense("sd", sreq);
+	}
+
+	scsi_release_request(sreq);
+	return res;
+}
+
+static int sd_issue_flush(struct device *dev, sector_t *error_sector)
+{
+	struct scsi_device *sdp = to_scsi_device(dev);
+	struct scsi_disk *sdkp = dev_get_drvdata(dev);
+
+	if (!sdkp)
+               return -ENODEV;
+
+	if (!sdkp->WCE)
+		return 0;
+
+	return sd_sync_cache(sdp);
+}
+
 static void sd_rescan(struct device *dev)
 {
 	struct scsi_disk *sdkp = dev_get_drvdata(dev);
@@ -763,11 +821,11 @@
 				good_bytes = 0;
 			break;
 
-		case RECOVERED_ERROR:
+		case RECOVERED_ERROR: /* an error occurred, but it recovered */
+		case NO_SENSE: /* LLDD got sense data */
 			/*
-			 * An error occurred, but it recovered.  Inform the
-			 * user, but make sure that it's not treated as a
-			 * hard error.
+			 * Inform the user, but make sure that it's not treated
+			 * as a hard error.
 			 */
 			print_sense("sd", SCpnt);
 			SCpnt->result = 0;
@@ -1501,52 +1559,17 @@
 static void sd_shutdown(struct device *dev)
 {
 	struct scsi_device *sdp = to_scsi_device(dev);
-	struct scsi_disk *sdkp;
-	struct scsi_request *sreq;
-	int retries, res;
+	struct scsi_disk *sdkp = dev_get_drvdata(dev);
 
-	sdkp = dev_get_drvdata(dev);
 	if (!sdkp)
                return;         /* this can happen */
 
-	if (!scsi_device_online(sdp) || !sdkp->WCE)
+	if (!sdkp->WCE)
 		return;
 
-	printk(KERN_NOTICE "Synchronizing SCSI cache for disk %s: ",
+	printk(KERN_NOTICE "Synchronizing SCSI cache for disk %s: \n",
 			sdkp->disk->disk_name);
-
-	sreq = scsi_allocate_request(sdp, GFP_KERNEL);
-	if (!sreq) {
-		printk("FAILED\n  No memory for request\n");
-		return;
-	}
-
-	sreq->sr_data_direction = DMA_NONE;
-	for (retries = 3; retries > 0; --retries) {
-		unsigned char cmd[10] = { 0 };
-
-		cmd[0] = SYNCHRONIZE_CACHE;
-		/*
-		 * Leave the rest of the command zero to indicate
-		 * flush everything.
-		 */
-		scsi_wait_req(sreq, cmd, NULL, 0, SD_TIMEOUT, SD_MAX_RETRIES);
-		if (sreq->sr_result == 0)
-			break;
-	}
-
-	res = sreq->sr_result;
-	if (res) {
-		printk(KERN_WARNING "FAILED\n  status = %x, message = %02x, "
-				    "host = %d, driver = %02x\n  ",
-				    status_byte(res), msg_byte(res),
-				    host_byte(res), driver_byte(res));
-			if (driver_byte(res) & DRIVER_SENSE)
-				print_req_sense("sd", sreq);
-	}
-	
-	scsi_release_request(sreq);
-	printk("\n");
+	sd_sync_cache(sdp);
 }	
 
 /**
--- diff/drivers/scsi/seagate.c	2004-05-19 22:12:11.000000000 +0100
+++ source/drivers/scsi/seagate.c	2004-06-11 19:22:04.000000000 +0100
@@ -103,7 +103,7 @@
 #include <asm/uaccess.h>
 
 #include "scsi.h"
-#include "hosts.h"
+#include <scsi/scsi_host.h>
 #include "seagate.h"
 
 #include <scsi/scsi_ioctl.h>
--- diff/drivers/scsi/sg.c	2004-06-11 19:17:31.000000000 +0100
+++ source/drivers/scsi/sg.c	2004-06-11 19:22:04.000000000 +0100
@@ -42,7 +42,6 @@
 #include <linux/fcntl.h>
 #include <linux/init.h>
 #include <linux/poll.h>
-#include <linux/vmalloc.h>
 #include <linux/smp_lock.h>
 #include <linux/moduleparam.h>
 #include <linux/devfs_fs_kernel.h>
@@ -51,7 +50,7 @@
 
 #include <linux/blkdev.h>
 #include "scsi.h"
-#include "hosts.h"
+#include <scsi/scsi_host.h>
 #include <scsi/scsi_driver.h>
 #include <scsi/scsi_ioctl.h>
 #include <scsi/sg.h>
@@ -60,7 +59,7 @@
 
 #ifdef CONFIG_SCSI_PROC_FS
 #include <linux/proc_fs.h>
-static char *sg_version_date = "20040513";
+static char *sg_version_date = "20040516";
 
 static int sg_proc_init(void);
 static void sg_proc_cleanup(void);
@@ -73,7 +72,7 @@
 #define SG_ALLOW_DIO_DEF 0
 #define SG_ALLOW_DIO_CODE /* compile out by commenting this define */
 
-#define SG_MAX_DEVS 8192
+#define SG_MAX_DEVS 32768
 
 /*
  * Suppose you want to calculate the formula muldiv(x,m,d)=int(x * m / d)
@@ -718,7 +717,6 @@
 		    (void *) SRpnt->sr_buffer, hp->dxfer_len,
 		    sg_cmd_done, timeout, SG_DEFAULT_RETRIES);
 	/* dxfer_len overwrites SRpnt->sr_bufflen, hence need for b_malloc_len */
-	generic_unplug_device(q);
 	return 0;
 }
 
@@ -1331,9 +1329,11 @@
 	void *old_sg_dev_arr = NULL;
 	int k, error;
 
-	sdp = vmalloc(sizeof(Sg_device));
-	if (!sdp)
+	sdp = kmalloc(sizeof(Sg_device), GFP_KERNEL);
+	if (!sdp) {
+		printk(KERN_WARNING "kmalloc Sg_device failure\n");
 		return -ENOMEM;
+	}
 
 	write_lock_irqsave(&sg_dev_arr_lock, iflags);
 	if (unlikely(sg_nr_dev >= sg_dev_max)) {	/* try to resize */
@@ -1341,7 +1341,7 @@
 		int tmp_dev_max = sg_nr_dev + SG_DEV_ARR_LUMP;
 		write_unlock_irqrestore(&sg_dev_arr_lock, iflags);
 
-		tmp_da = vmalloc(tmp_dev_max * sizeof(Sg_device *));
+		tmp_da = kmalloc(tmp_dev_max * sizeof(Sg_device *), GFP_KERNEL);
 		if (unlikely(!tmp_da))
 			goto expand_failed;
 
@@ -1375,12 +1375,12 @@
 
  out:
 	if (error < 0)
-		vfree(sdp);
-	vfree(old_sg_dev_arr);
+		kfree(sdp);
+	kfree(old_sg_dev_arr);
 	return error;
 
  expand_failed:
-	printk(KERN_ERR "sg_alloc: device array cannot be resized\n");
+	printk(KERN_WARNING "sg_alloc: device array cannot be resized\n");
 	error = -ENOMEM;
 	goto out;
 
@@ -1404,20 +1404,26 @@
 	int error, k;
 
 	disk = alloc_disk(1);
-	if (!disk)
+	if (!disk) {
+		printk(KERN_WARNING "alloc_disk failed\n");
 		return -ENOMEM;
+	}
 	disk->major = SCSI_GENERIC_MAJOR;
 
 	error = -ENOMEM;
 	cdev = cdev_alloc();
-	if (!cdev)
+	if (!cdev) {
+		printk(KERN_WARNING "cdev_alloc failed\n");
 		goto out;
+	}
 	cdev->owner = THIS_MODULE;
 	cdev->ops = &sg_fops;
 
 	error = sg_alloc(disk, scsidp);
-	if (error < 0)
+	if (error < 0) {
+		printk(KERN_WARNING "sg_alloc failed\n");
 		goto out;
+	}
 	k = error;
 	sdp = sg_dev_arr[k];
 
@@ -1525,7 +1531,7 @@
 		put_disk(sdp->disk);
 		sdp->disk = NULL;
 		if (NULL == sdp->headfp)
-			vfree((char *) sdp);
+			kfree((char *) sdp);
 	}
 
 	if (delay)
@@ -1590,7 +1596,7 @@
 	unregister_chrdev_region(MKDEV(SCSI_GENERIC_MAJOR, 0),
 				 SG_MAX_DEVS);
 	if (sg_dev_arr != NULL) {
-		vfree((char *) sg_dev_arr);
+		kfree((char *) sg_dev_arr);
 		sg_dev_arr = NULL;
 	}
 	sg_dev_max = 0;
@@ -2492,7 +2498,7 @@
 			}
 			if (k < maxd)
 				sg_dev_arr[k] = NULL;
-			vfree((char *) sdp);
+			kfree((char *) sdp);
 			res = 1;
 		}
 		write_unlock_irqrestore(&sg_dev_arr_lock, iflags);
--- diff/drivers/scsi/sgiwd93.c	2004-06-11 19:17:31.000000000 +0100
+++ source/drivers/scsi/sgiwd93.c	2004-06-11 19:22:04.000000000 +0100
@@ -31,7 +31,7 @@
 #include <asm/io.h>
 
 #include "scsi.h"
-#include "hosts.h"
+#include <scsi/scsi_host.h>
 #include "wd33c93.h"
 #include "sgiwd93.h"
 
--- diff/drivers/scsi/sim710.c	2004-05-19 22:12:12.000000000 +0100
+++ source/drivers/scsi/sim710.c	2004-06-11 19:22:04.000000000 +0100
@@ -35,9 +35,8 @@
 #include <linux/mca.h>
 #include <linux/eisa.h>
 #include <linux/interrupt.h>
+#include <scsi/scsi_host.h>
 
-#include "scsi.h"
-#include "hosts.h"
 #include "53c700.h"
 
 
@@ -86,7 +85,7 @@
 }
 __setup("sim710=", param_setup);
 
-static Scsi_Host_Template sim710_driver_template = {
+static struct scsi_host_template sim710_driver_template = {
 	.name			= "LSI (Symbios) 710 MCA/EISA",
 	.proc_name		= "sim710",
 	.this_id		= 7,
--- diff/drivers/scsi/sr.c	2004-06-11 19:17:31.000000000 +0100
+++ source/drivers/scsi/sr.c	2004-06-11 19:22:04.000000000 +0100
@@ -47,7 +47,7 @@
 #include <asm/uaccess.h>
 
 #include "scsi.h"
-#include "hosts.h"
+#include <scsi/scsi_host.h>
 
 #include <scsi/scsi_driver.h>
 #include <scsi/scsi_ioctl.h>	/* For the door lock/unlock commands */
--- diff/drivers/scsi/sr_ioctl.c	2004-06-11 19:17:31.000000000 +0100
+++ source/drivers/scsi/sr_ioctl.c	2004-06-11 19:22:04.000000000 +0100
@@ -11,7 +11,7 @@
 #include <asm/uaccess.h>
 
 #include "scsi.h"
-#include "hosts.h"
+#include <scsi/scsi_host.h>
 #include <scsi/scsi_ioctl.h>
 
 #include "sr.h"
@@ -331,6 +331,9 @@
 	int result;
 	unsigned char *buffer = kmalloc(32, GFP_KERNEL | SR_GFP_DMA(cd));
 
+	if (!buffer)
+		return -ENOMEM;
+
 	memset(&cgc, 0, sizeof(struct packet_command));
 	cgc.timeout = IOCTL_TIMEOUT;
 
--- diff/drivers/scsi/sr_vendor.c	2004-06-11 19:17:31.000000000 +0100
+++ source/drivers/scsi/sr_vendor.c	2004-06-11 19:22:04.000000000 +0100
@@ -41,7 +41,7 @@
 
 #include <linux/blkdev.h>
 #include "scsi.h"
-#include "hosts.h"
+#include <scsi/scsi_host.h>
 #include <scsi/scsi_ioctl.h>
 
 #include <linux/cdrom.h>
--- diff/drivers/scsi/st.c	2004-06-11 19:17:31.000000000 +0100
+++ source/drivers/scsi/st.c	2004-06-11 19:22:04.000000000 +0100
@@ -58,7 +58,7 @@
 
 
 #include "scsi.h"
-#include "hosts.h"
+#include <scsi/scsi_host.h>
 
 #include <scsi/scsi_driver.h>
 #include <scsi/scsi_ioctl.h>
--- diff/drivers/scsi/sun3_scsi.c	2004-05-19 22:12:12.000000000 +0100
+++ source/drivers/scsi/sun3_scsi.c	2004-06-11 19:22:04.000000000 +0100
@@ -75,7 +75,7 @@
 #define REAL_DMA
 
 #include "scsi.h"
-#include "hosts.h"
+#include <scsi/scsi_host.h>
 #include "sun3_scsi.h"
 #include "NCR5380.h"
 
--- diff/drivers/scsi/sun3_scsi_vme.c	2004-05-19 22:12:12.000000000 +0100
+++ source/drivers/scsi/sun3_scsi_vme.c	2004-06-11 19:22:04.000000000 +0100
@@ -41,7 +41,7 @@
 #define REAL_DMA
 
 #include "scsi.h"
-#include "hosts.h"
+#include <scsi/scsi_host.h>
 #include "sun3_scsi.h"
 #include "NCR5380.h"
 
--- diff/drivers/scsi/sun3x_esp.c	2004-05-19 22:12:12.000000000 +0100
+++ source/drivers/scsi/sun3x_esp.c	2004-06-11 19:22:04.000000000 +0100
@@ -16,7 +16,7 @@
 #include <linux/interrupt.h>
 
 #include "scsi.h"
-#include "hosts.h"
+#include <scsi/scsi_host.h>
 #include "NCR53C9x.h"
 
 #include <asm/sun3x.h>
--- diff/drivers/scsi/sym53c416.c	2004-05-19 22:12:12.000000000 +0100
+++ source/drivers/scsi/sym53c416.c	2004-06-11 19:22:04.000000000 +0100
@@ -43,7 +43,7 @@
 #include <linux/blkdev.h>
 #include <linux/isapnp.h>
 #include "scsi.h"
-#include "hosts.h"
+#include <scsi/scsi_host.h>
 #include "sym53c416.h"
 
 #define VERSION_STRING        "Version 1.0.0-ac"
@@ -622,12 +622,13 @@
 	int ints[2];
 
 	ints[0] = 1;
-	for(; *base; base++)
-	{
-		if(!check_region(*base, IO_RANGE) && sym53c416_test(*base))
-		{
-			ints[1] = *base;
-			sym53c416_setup(NULL, ints);
+	for(; *base; base++) {
+		if (request_region(*base, IO_RANGE, ID)) {
+			if (sym53c416_test(*base)) {
+				ints[1] = *base;
+				sym53c416_setup(NULL, ints);
+			}
+			release_region(*base, IO_RANGE);
 		}
 	}
 }
@@ -702,44 +703,42 @@
 	sym53c416_probe();
 
 	/* Now we register and set up each host adapter found... */
-	for(count = 0, i = 0; i < host_index; i++)
-	{
-		if(!sym53c416_test(hosts[i].base))
+	for(count = 0, i = 0; i < host_index; i++) {
+		if (!request_region(hosts[i].base, IO_RANGE, ID))
+			continue;
+		if (!sym53c416_test(hosts[i].base)) {
 			printk(KERN_WARNING "No sym53c416 found at address 0x%03x\n", hosts[i].base);
-		else
-		{
-			if(hosts[i].irq == 0)
-			/* We don't have an irq yet, so we should probe for one */
-				if((hosts[i].irq = sym53c416_probeirq(hosts[i].base, hosts[i].scsi_id)) == 0)
-					printk(KERN_WARNING "IRQ autoprobing failed for sym53c416 at address 0x%03x\n", hosts[i].base);
-			if(hosts[i].irq && !check_region(hosts[i].base, IO_RANGE))
-			{
-				shpnt = scsi_register(tpnt, 0);
-				if(shpnt==NULL)
-					continue;
-				spin_lock_irqsave(&sym53c416_lock, flags);
-				/* Request for specified IRQ */
-				if(request_irq(hosts[i].irq, sym53c416_intr_handle, 0, ID, shpnt))
-				{
-					spin_unlock_irqrestore(&sym53c416_lock, flags);
-					printk(KERN_ERR "sym53c416: Unable to assign IRQ %d\n", hosts[i].irq);
-					scsi_unregister(shpnt);
-				}
-				else
-				{
-					/* Inform the kernel of our IO range */
-					request_region(hosts[i].base, IO_RANGE, ID);
-					shpnt->unique_id = hosts[i].base;
-					shpnt->io_port = hosts[i].base;
-					shpnt->n_io_port = IO_RANGE;
-					shpnt->irq = hosts[i].irq;
-					shpnt->this_id = hosts[i].scsi_id;
-					sym53c416_init(hosts[i].base, hosts[i].scsi_id);
-					count++;
-					spin_unlock_irqrestore(&sym53c416_lock, flags);
-				}
-			}
+			goto fail_release_region;
 		}
+
+		/* We don't have an irq yet, so we should probe for one */
+		if (!hosts[i].irq)
+			hosts[i].irq = sym53c416_probeirq(hosts[i].base, hosts[i].scsi_id);
+		if (!hosts[i].irq)
+			goto fail_release_region;
+	
+		shpnt = scsi_register(tpnt, 0);
+		if (!shpnt)
+			goto fail_release_region;
+		/* Request for specified IRQ */
+		if (request_irq(hosts[i].irq, sym53c416_intr_handle, 0, ID, shpnt))
+			goto fail_free_host;
+
+		spin_lock_irqsave(&sym53c416_lock, flags);
+		shpnt->unique_id = hosts[i].base;
+		shpnt->io_port = hosts[i].base;
+		shpnt->n_io_port = IO_RANGE;
+		shpnt->irq = hosts[i].irq;
+		shpnt->this_id = hosts[i].scsi_id;
+		sym53c416_init(hosts[i].base, hosts[i].scsi_id);
+		count++;
+		spin_unlock_irqrestore(&sym53c416_lock, flags);
+		continue;
+
+ fail_free_host:
+		scsi_unregister(shpnt);
+ fail_release_region:
+		release_region(hosts[i].base, IO_RANGE);
 	}
 	return count;
 }
--- diff/drivers/scsi/t128.c	2004-05-19 22:12:12.000000000 +0100
+++ source/drivers/scsi/t128.c	2004-06-11 19:22:04.000000000 +0100
@@ -118,7 +118,7 @@
 #include <linux/delay.h>
 
 #include "scsi.h"
-#include "hosts.h"
+#include <scsi/scsi_host.h>
 #include "t128.h"
 #define AUTOPROBE_IRQ
 #include "NCR5380.h"
--- diff/drivers/scsi/tmscsim.c	2004-06-11 19:17:31.000000000 +0100
+++ source/drivers/scsi/tmscsim.c	2004-06-11 19:22:04.000000000 +0100
@@ -172,6 +172,11 @@
  *	2.1b1 04/01/31	GL	(applied 05.04) Remove internal		*
  *				command-queuing.			*
  *	2.1b2 04/02/01	CH	(applied 05.04) Fix error-handling	*
+ *	2.1c  04/05/23  GL	Update to use the new pci_driver API,	*
+ *				some scsi EH updates, more cleanup.	*
+ *	2.1d  04/05/27	GL	Moved setting of scan_devices to	*
+ *				slave_alloc/_configure/_destroy, as	*
+ *				suggested by CH.			*
  ***********************************************************************/
 
 /* Uncomment SA_INTERRUPT, if the driver refuses to share its IRQ with other devices */
@@ -239,7 +244,7 @@
 #include <linux/interrupt.h>
 
 #include "scsi.h"
-#include "hosts.h"
+#include <scsi/scsi_host.h>
 #include <linux/stat.h>
 #include <scsi/scsicam.h>
 
@@ -267,7 +272,6 @@
 #include <linux/init.h>
 #include <linux/spinlock.h>
 
-#if defined(MODULE)
 static struct pci_device_id tmscsim_pci_tbl[] = {
 	{
 		.vendor		= PCI_VENDOR_ID_AMD,
@@ -278,8 +282,7 @@
 	{ }		/* Terminating entry */
 };
 MODULE_DEVICE_TABLE(pci, tmscsim_pci_tbl);
-#endif
-	
+
 #define USE_SPINLOCKS 1
 
 #define DC390_IFLAGS unsigned long iflags
@@ -342,6 +345,8 @@
 
 static int DC390_release(struct Scsi_Host *host);
 static int dc390_shutdown (struct Scsi_Host *host);
+static int DC390_proc_info (struct Scsi_Host *shpnt, char *buffer, char **start,
+			    off_t offset, int length, int inout);
 
 static PACB	dc390_pACB_start= NULL;
 static PACB	dc390_pACB_current = NULL;
@@ -351,16 +356,14 @@
 
 /* Startup values, to be overriden on the commandline */
 static int tmscsim[] = {-2, -2, -2, -2, -2, -2};
+static int tmscsim_paramnum = ARRAY_SIZE(tmscsim);
 
-#if defined(MODULE)
-MODULE_PARM(tmscsim, "1-6i");
+module_param_array(tmscsim, int, tmscsim_paramnum, 0);
 MODULE_PARM_DESC(tmscsim, "Host SCSI ID, Speed (0=10MHz), Device Flags, Adapter Flags, Max Tags (log2(tags)-1), DelayReset (s)");
 MODULE_AUTHOR("C.L. Huang / Kurt Garloff");
 MODULE_DESCRIPTION("SCSI host adapter driver for Tekram DC390 and other AMD53C974A based PCI SCSI adapters");
 MODULE_LICENSE("GPL");
-
 MODULE_SUPPORTED_DEVICE("sd,sr,sg,st");
-#endif
 
 static PVOID dc390_phase0[]={
        dc390_DataOut_0,
@@ -1031,15 +1034,15 @@
  * 2.0.x: always return 0
  * 2.1.x: old model: (use_new_eh_code == 0): like 2.0.x
  *	  TO BE DONE:
- *	  new model: return 0 if successful
- *	  	     return 1 if command cannot be queued (queue full)
+ *	  new model: return 0 if successful, or must not be re-queued
+ *		     return 1 if command cannot be queued (queue full)
  *		     command will be inserted in midlevel queue then ...
  *
  ***********************************************************************/
 
 static int DC390_queue_command (Scsi_Cmnd *cmd, void (* done)(Scsi_Cmnd *))
 {
-    PDCB   pDCB;
+    PDCB   pDCB = (PDCB) cmd->device->hostdata;
     PSRB   pSRB;
     PACB   pACB = (PACB) cmd->device->host->hostdata;
 
@@ -1050,42 +1053,19 @@
     /* TODO: Change the policy: Always accept TEST_UNIT_READY or INQUIRY 
      * commands and alloc a DCB for the device if not yet there. DCB will
      * be removed in dc390_SRBdone if SEL_TIMEOUT */
-
-    if( (pACB->scan_devices == END_SCAN) && (cmd->cmnd[0] != INQUIRY) )
-	pACB->scan_devices = 0;
-
-    else if( (pACB->scan_devices) && (cmd->cmnd[0] == READ_6) )
-	pACB->scan_devices = 0;
-
-    if( (pACB->scan_devices || cmd->cmnd[0] == TEST_UNIT_READY || cmd->cmnd[0] == INQUIRY) && 
-       !(pACB->DCBmap[cmd->device->id] & (1 << cmd->device->lun)) )
-    {
-        pACB->scan_devices = 1;
-
-	dc390_initDCB( pACB, &pDCB, cmd->device->id, cmd->device->lun );
-	if (!pDCB)
-	  {
-	    printk (KERN_ERR "DC390: kmalloc for DCB failed, target %02x lun %02x\n", 
-		    cmd->device->id, cmd->device->lun);
-	    goto fail;
-	  }
-            
-    }
-    else if( !(pACB->scan_devices) && !(pACB->DCBmap[cmd->device->id] & (1 << cmd->device->lun)) )
-    {
+    if (!(pACB->scan_devices) && !(pACB->DCBmap[cmd->device->id] & (1 << cmd->device->lun))) {
 	printk(KERN_INFO "DC390: Ignore target %02x lun %02x\n",
 		cmd->device->id, cmd->device->lun); 
 	goto fail;
     }
-    else
-    {
-	pDCB = dc390_findDCB (pACB, cmd->device->id, cmd->device->lun);
-	if (!pDCB)
-	 {  /* should never happen */
-	    printk (KERN_ERR "DC390: no DCB failed, target %02x lun %02x\n", 
-		    cmd->device->id, cmd->device->lun);
-	    goto fail;
-	 }
+
+    /* Should it be: BUG_ON(!pDCB); ? */
+
+    if (!pDCB)
+    {  /* should never happen */
+	printk (KERN_ERR "DC390: no DCB found, target %02x lun %02x\n", 
+		cmd->device->id, cmd->device->lun);
+	goto fail;
     }
 
     pACB->Cmds++;
@@ -1304,7 +1284,7 @@
 
 static int DC390_abort (Scsi_Cmnd *cmd)
 {
-    PDCB  pDCB;
+    PDCB  pDCB = (PDCB) cmd->device->hostdata;
     PSRB  pSRB, psrb;
     UINT  count, i;
     int   status;
@@ -1314,7 +1294,6 @@
     printk ("DC390: Abort command (pid %li, Device %02i-%02i)\n",
 	    cmd->pid, cmd->device->id, cmd->device->lun);
 
-    pDCB = dc390_findDCB (pACB, cmd->device->id, cmd->device->lun);
     if( !pDCB ) goto  NOT_RUN;
 
     /* Added 98/07/02 KG */
@@ -1746,7 +1725,6 @@
     pACB->AdapterIndex = index;
     pACB->status = 0;
     psh->this_id = dc390_eepromBuf[index][EE_ADAPT_SCSI_ID];
-    pACB->DeviceCnt = 0;
     pACB->DCBCnt = 0;
     pACB->TagMaxNum = 2 << dc390_eepromBuf[index][EE_TAG_CMD_NUM];
     pACB->ACBFlag = 0;
@@ -1856,7 +1834,7 @@
  *
  * Inputs : host - pointer to this host adapter's structure
  *	    io_port - IO ports mapped to this adapter
- *	    Irq - IRQ assigned to this adpater
+ *	    irq - IRQ assigned to this adpater
  *	    struct pci_dev - PCI access handle
  *	    index - Adapter index
  *
@@ -1865,10 +1843,8 @@
  * Note: written in capitals, because the locking is only done here,
  *	not in DC390_detect, called from outside 
  ***********************************************************************/
-
-static int __init DC390_init (PSHT psht, ULONG io_port, UCHAR Irq, struct pci_dev *pdev, UCHAR index)
+static int __init dc390_init (PSH psh, unsigned long io_port, u8 irq, struct pci_dev *pdev, UCHAR index)
 {
-    PSH   psh;
     PACB  pACB;
 
     if (dc390_CheckEEpromCheckSum (PDEV, index))
@@ -1890,25 +1866,16 @@
 	dc390_check_for_safe_settings ();
 	dc390_EEprom_Override (index);
     }
-   
-    psh = scsi_register( psht, sizeof(DC390_ACB) );
-    if( !psh ) return( -1 );
-	
-    scsi_set_device(psh, &pdev->dev);
     pACB = (PACB) psh->hostdata;
 
     DEBUG0(printk(KERN_INFO "DC390: pSH = %8x, Index %02i\n", (UINT) psh, index));
 
-    dc390_initACB( psh, io_port, Irq, index );
+    dc390_initACB( psh, io_port, irq, index );
         
     PDEVSET;
 
-    if( !dc390_initAdapter( psh, io_port, Irq, index ) )
+    if( !dc390_initAdapter( psh, io_port, irq, index ) )
     {
-	DEBUG0(printk("DC390: pACB = %8x, pDCBmap = %8x, pSRB_array = %8x\n",\
-		      (UINT) pACB, (UINT) pACB->DCBmap, (UINT) pACB->SRB_array));
-	DEBUG0(printk("DC390: ACB size= %4x, DCB size= %4x, SRB size= %4x\n",\
-		      sizeof(DC390_ACB), sizeof(DC390_DCB), sizeof(DC390_SRB) ));
         return (0);
     }
     else
@@ -1927,42 +1894,131 @@
 	PCI_WRITE_CONFIG_WORD (PDEV, PCI_STATUS, (PCI_STATUS_SIG_SYSTEM_ERROR | PCI_STATUS_DETECTED_PARITY));
 }
 
-int __init DC390_detect (Scsi_Host_Template *psht)
+/**
+ * dc390_slave_alloc - Called by the scsi mid layer to tell us about a new
+ * scsi device that we need to deal with.
+ *
+ * @scsi_device: The new scsi device that we need to handle.
+ */
+static int dc390_slave_alloc(struct scsi_device *scsi_device)
+{
+	PDCB pDCB;
+	PACB pACB = (PACB) scsi_device->host->hostdata;
+	dc390_initDCB(pACB, &pDCB, scsi_device->id, scsi_device->lun);
+	if (pDCB != NULL) {
+		scsi_device->hostdata = pDCB;
+		pACB->scan_devices = 1;
+		return 0;
+	}
+	return -ENOMEM;
+}
+
+/**
+ * dc390_slave_destroy - Called by the scsi mid layer to tell us about a
+ * device that is going away.
+ *
+ * @scsi_device: The scsi device that we need to remove.
+ */
+static void dc390_slave_destroy(struct scsi_device *scsi_device)
 {
-    struct pci_dev *pdev = NULL;
-    UCHAR   irq;
-    ULONG   io_port;
+	PACB pACB = (PACB) scsi_device->host->hostdata;
+	PDCB pDCB = (PDCB) scsi_device->hostdata;
+	pACB->scan_devices = 0;
+	if (pDCB != NULL)
+		dc390_remove_dev(pACB, pDCB);
+	else
+		printk(KERN_ERR"%s() called for non-existing device!\n", __FUNCTION__);
+}
 
-    dc390_pACB_start = NULL;
+static int dc390_slave_configure(struct scsi_device *scsi_device)
+{
+	PACB pACB = (PACB) scsi_device->host->hostdata;
+	pACB->scan_devices = 0;
+	return 0;
+}
 
-    if ( PCI_PRESENT )
-	    while ((pdev = pci_find_device(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD53C974, pdev)))
-	{
-	    if (pci_enable_device (pdev))
-		continue;
+static Scsi_Host_Template driver_template = {
+	.module			= THIS_MODULE,
+	.proc_name		= "tmscsim", 
+	.proc_info		= DC390_proc_info,
+	.name			= DC390_BANNER " V" DC390_VERSION,
+	.slave_alloc		= dc390_slave_alloc,
+	.slave_configure	= dc390_slave_configure,
+	.slave_destroy		= dc390_slave_destroy,
+	.queuecommand		= DC390_queue_command,
+	.eh_abort_handler	= DC390_abort,
+	.eh_bus_reset_handler	= DC390_reset,
+	.bios_param		= DC390_bios_param,
+	.can_queue		= 42,
+	.this_id		= 7,
+	.sg_tablesize		= SG_ALL,
+	.cmd_per_lun		= 16,
+	.use_clustering		= DISABLE_CLUSTERING,
+};
 
-	    if (pci_set_dma_mask(pdev, 0xffffffff)) {
-		    printk(KERN_ERR "DC390(%i): No suitable DMA available.\n", dc390_adapterCnt);
-		    continue;
-	    }
-	    PCI_GET_IO_AND_IRQ;
-	    DEBUG0(printk(KERN_INFO "DC390(%i): IO_PORT=%04x,IRQ=%x\n", dc390_adapterCnt, (UINT) io_port, irq));
+static int __devinit dc390_init_one(struct pci_dev *dev,
+				    const struct pci_device_id *id)
+{
+	struct Scsi_Host *scsi_host;
+	unsigned long io_port;
+	u8 irq;
+	PACB  pACB;
+	int ret = -ENOMEM;
+
+	if (pci_enable_device(dev))
+		return -ENODEV;
+
+	io_port = pci_resource_start(dev, 0);
+	irq = dev->irq;
+
+	/* allocate scsi host information (includes out adapter) */
+	scsi_host = scsi_host_alloc(&driver_template, sizeof(struct _ACB));
+	if (!scsi_host)
+		goto nomem;
+
+	pACB = (PACB) scsi_host->hostdata;
+
+	if (dc390_init(scsi_host, io_port, irq, dev, dc390_adapterCnt)) {
+		ret = -EBUSY;
+		goto busy;
+	}
 
-	    if( !DC390_init(psht, io_port, irq, PDEV, dc390_adapterCnt))
-	    {
-		pci_set_master(pdev);
-		dc390_set_pci_cfg (PDEV);
-		dc390_adapterCnt++;
-	    }
+	pci_set_master(dev);
+	dc390_set_pci_cfg(dev);
+	dc390_adapterCnt++;
+
+	/* get the scsi mid level to scan for new devices on the bus */
+	if (scsi_add_host(scsi_host, &dev->dev)) {
+		ret = -ENODEV;
+		goto nodev;
 	}
-    else
-	printk (KERN_ERR "DC390: No PCI BIOS found!\n");
-   
-    if (dc390_adapterCnt)
-	psht->proc_name = "tmscsim";
+	pci_set_drvdata(dev, scsi_host);
+	scsi_scan_host(scsi_host);
+
+	return 0;
+
+nodev:
+busy:
+	scsi_host_put(scsi_host);
+nomem:
+	pci_disable_device(dev);
+	return ret;
+}
+
+/**
+ * dc390_remove_one - Called to remove a single instance of the adapter.
+ *
+ * @dev: The PCI device to remove.
+ */
+static void __devexit dc390_remove_one(struct pci_dev *dev)
+{
+	struct Scsi_Host *scsi_host = pci_get_drvdata(dev);
 
-    printk(KERN_INFO "DC390: %i adapters found\n", dc390_adapterCnt);
-    return( dc390_adapterCnt );
+	scsi_remove_host(scsi_host);
+	DC390_release(scsi_host);
+	pci_disable_device(dev);
+	scsi_host_put(scsi_host);
+	pci_set_drvdata(dev, NULL);
 }
 
 /********************************************************************
@@ -2035,7 +2091,7 @@
   SPRINTF("            Lost arbitrations %i, Sel. connected %i, Connected: %s\n", 
 	  pACB->SelLost, pACB->SelConn, pACB->Connected? "Yes": "No");
    
-  SPRINTF("Nr of attached devices: %i, Nr of DCBs: %i\n", pACB->DeviceCnt, pACB->DCBCnt);
+  SPRINTF("Nr of DCBs: %i\n", pACB->DCBCnt);
   SPRINTF("Map of attached LUNs: %02x %02x %02x %02x %02x %02x %02x %02x\n",
 	  pACB->DCBmap[0], pACB->DCBmap[1], pACB->DCBmap[2], pACB->DCBmap[3], 
 	  pACB->DCBmap[4], pACB->DCBmap[5], pACB->DCBmap[6], pACB->DCBmap[7]);
@@ -2122,7 +2178,7 @@
 static int dc390_shutdown (struct Scsi_Host *host)
 {
     UCHAR    bval;
-    PACB pACB = (PACB)(host->hostdata);
+    PACB pACB = (PACB) host->hostdata;
    
 /*  pACB->soft_reset(host); */
 
@@ -2142,7 +2198,7 @@
 static void dc390_freeDCBs (struct Scsi_Host *host)
 {
     PDCB pDCB, nDCB;
-    PACB pACB = (PACB)(host->hostdata);
+    PACB pACB = (PACB) host->hostdata;
     
     pDCB = pACB->pLinkDCB;
     if (!pDCB) return;
@@ -2161,7 +2217,7 @@
 static int DC390_release (struct Scsi_Host *host)
 {
     DC390_IFLAGS;
-    PACB pACB = (PACB)(host->hostdata);
+    PACB pACB = (PACB) host->hostdata;
 
     DC390_LOCK_IO(host);
 
@@ -2177,24 +2233,25 @@
     release_region(host->io_port,host->n_io_port);
     dc390_freeDCBs (host);
     DC390_UNLOCK_IO(host);
-    scsi_unregister(host);
     return( 1 );
 }
 
-static Scsi_Host_Template driver_template = {
-   .proc_name      = "tmscsim", 
-   .proc_info      = DC390_proc_info,
-   .name           = DC390_BANNER " V" DC390_VERSION,
-   .detect         = DC390_detect,
-   .release        = DC390_release,
-   .queuecommand   = DC390_queue_command,
-   .eh_abort_handler		= DC390_abort,
-   .eh_bus_reset_handler	= DC390_reset,
-   .bios_param     = DC390_bios_param,
-   .can_queue      = 42,
-   .this_id        = 7,
-   .sg_tablesize   = SG_ALL,
-   .cmd_per_lun    = 16,
-   .use_clustering = DISABLE_CLUSTERING,
+static struct pci_driver dc390_driver = {
+	.name           = "tmscsim",
+	.id_table       = tmscsim_pci_tbl,
+	.probe          = dc390_init_one,
+	.remove         = __devexit_p(dc390_remove_one),
 };
-#include "scsi_module.c"
+
+static int __init dc390_module_init(void)
+{
+	return pci_module_init(&dc390_driver);
+}
+
+static void __exit dc390_module_exit(void)
+{
+	pci_unregister_driver(&dc390_driver);
+}
+
+module_init(dc390_module_init);
+module_exit(dc390_module_exit);
--- diff/drivers/scsi/tmscsim.h	2004-06-11 19:17:31.000000000 +0100
+++ source/drivers/scsi/tmscsim.h	2004-06-11 19:22:04.000000000 +0100
@@ -22,8 +22,6 @@
 
 #define SEL_TIMEOUT		153	/* 250 ms selection timeout (@ 40 MHz) */
 
-#define END_SCAN		2
-
 #define pci_dma_lo32(a)			(a & 0xffffffff)
 
 typedef u8		UCHAR;	/*  8 bits */
@@ -196,10 +194,8 @@
 
 UCHAR		SRBCount;
 UCHAR		AdapterIndex;	/*; nth Adapter this driver */
-UCHAR		DeviceCnt;
 UCHAR		DCBCnt;
 
-/* 0x10: */
 UCHAR		TagMaxNum;
 UCHAR		ACBFlag;
 UCHAR		Gmode2;
@@ -213,13 +209,11 @@
 PSRB		pFreeSRB;
 PSRB		pTmpSRB;
 
-/* 0x2c: */
 UCHAR		msgin123[4];
 UCHAR		DCBmap[MAX_SCSI_ID];
 UCHAR		Connected;
 UCHAR		pad;
 
-/* 0x30: */
 #if defined(USE_SPINLOCKS) && USE_SPINLOCKS > 1 && (defined(CONFIG_SMP) || DEBUG_SPINLOCKS > 0)
 spinlock_t	lock;
 #endif
@@ -230,20 +224,17 @@
 UCHAR		Ignore_IRQ;	/* Not used */
 
 PDEVDECL1;			/* Pointer to PCI cfg. space */
-/* 0x40/0x3c: */
+
 ULONG		Cmds;
 UINT		SelLost;
 UINT		SelConn;
 UINT		CmdInQ;
 UINT		CmdOutOfSRB;
 	
-/* 0x54/0x50: */
 struct timer_list	Waiting_Timer;
-/* 0x68/0x64: */
+
 DC390_SRB	TmpSRB;
-/* 0xcc/0xc8: */
 DC390_SRB	SRB_array[MAX_SRB_CNT]; 	/* 50 SRBs */
-/* 0xfa4/0xfa0: */
 };
 
 typedef  struct  _ACB	 DC390_ACB, *PACB;
--- diff/drivers/scsi/u14-34f.c	2004-05-19 22:12:12.000000000 +0100
+++ source/drivers/scsi/u14-34f.c	2004-06-11 19:22:04.000000000 +0100
@@ -423,7 +423,7 @@
 #include <linux/spinlock.h>
 #include <scsi/scsicam.h>
 #include "scsi.h"
-#include "hosts.h"
+#include <scsi/scsi_host.h>
 #include <asm/dma.h>
 #include <asm/irq.h>
 
--- diff/drivers/scsi/ultrastor.c	2004-05-19 22:12:12.000000000 +0100
+++ source/drivers/scsi/ultrastor.c	2004-06-11 19:22:04.000000000 +0100
@@ -145,7 +145,7 @@
 
 #define ULTRASTOR_PRIVATE	/* Get the private stuff from ultrastor.h */
 #include "scsi.h"
-#include "hosts.h"
+#include <scsi/scsi_host.h>
 #include "ultrastor.h"
 
 #define FALSE 0
--- diff/drivers/scsi/wd33c93.c	2004-05-19 22:12:12.000000000 +0100
+++ source/drivers/scsi/wd33c93.c	2004-06-11 19:22:04.000000000 +0100
@@ -83,7 +83,7 @@
 #include <asm/irq.h>
 
 #include "scsi.h"
-#include "hosts.h"
+#include <scsi/scsi_host.h>
 
 #include "wd33c93.h"
 
--- diff/drivers/scsi/wd7000.c	2004-06-11 19:17:31.000000000 +0100
+++ source/drivers/scsi/wd7000.c	2004-06-11 19:22:04.000000000 +0100
@@ -184,7 +184,7 @@
 #include <asm/io.h>
 
 #include "scsi.h"
-#include "hosts.h"
+#include <scsi/scsi_host.h>
 #include <scsi/scsicam.h>
 
 
--- diff/drivers/scsi/zalon.c	2004-05-19 22:12:12.000000000 +0100
+++ source/drivers/scsi/zalon.c	2004-06-11 19:22:04.000000000 +0100
@@ -24,7 +24,7 @@
 
 #include "../parisc/gsc.h"
 #include "scsi.h"
-#include "hosts.h"
+#include <scsi/scsi_host.h>
 
 #include "ncr53c8xx.h"
 
--- diff/drivers/serial/8250.c	2004-05-19 22:12:15.000000000 +0100
+++ source/drivers/serial/8250.c	2004-06-11 19:22:04.000000000 +0100
@@ -832,7 +832,7 @@
 		if (unlikely(tty->flip.count >= TTY_FLIPBUF_SIZE)) {
 			tty->flip.work.func((void *)tty);
 			if (tty->flip.count >= TTY_FLIPBUF_SIZE)
-				return; // if TTY_DONT_FLIP is set
+				return;	/* if TTY_DONT_FLIP is set */
 		}
 		ch = serial_inp(up, UART_RX);
 		*tty->flip.char_buf_ptr = ch;
@@ -1193,12 +1193,21 @@
 	spin_unlock_irqrestore(&up->port.lock, flags);
 }
 
+#ifdef CONFIG_KGDB
+static int kgdb_irq = -1;
+#endif
+
 static int serial8250_startup(struct uart_port *port)
 {
 	struct uart_8250_port *up = (struct uart_8250_port *)port;
 	unsigned long flags;
 	int retval;
 
+#ifdef CONFIG_KGDB
+	if (up->port.irq == kgdb_irq)
+		return -EBUSY;
+#endif
+
 	up->capabilities = uart_config[up->port.type].flags;
 	up->mcr = 0;
 
@@ -1888,6 +1897,10 @@
 	for (i = 0; i < UART_NR; i++) {
 		struct uart_8250_port *up = &serial8250_ports[i];
 
+#ifdef CONFIG_KGDB
+		if (up->port.irq == kgdb_irq)
+			up->port.kgdb = 1;
+#endif
 		up->port.line = i;
 		up->port.ops = &serial8250_pops;
 		init_timer(&up->timer);
@@ -2171,6 +2184,31 @@
 	uart_resume_port(&serial8250_reg, &serial8250_ports[line].port);
 }
 
+#ifdef CONFIG_KGDB
+/*
+ * Find all the ports using the given irq and shut them down.
+ * Result should be that the irq will be released.
+ */
+void shutdown_for_kgdb(struct async_struct * info)
+{
+        int irq = info->state->irq;
+        struct uart_8250_port *up;
+	int ttyS;
+
+	kgdb_irq = irq;			/* save for later init */
+	for (ttyS = 0; ttyS < UART_NR; ttyS++){
+		up =  &serial8250_ports[ttyS];
+		if (up->port.irq == irq && (irq_lists + irq)->head) {
+#ifdef CONFIG_DEBUG_SPINLOCK   /* ugly business... */
+			if(up->port.lock.magic != SPINLOCK_MAGIC)
+				spin_lock_init(&up->port.lock);
+#endif
+			serial8250_shutdown(&up->port);
+		}
+        }
+}
+#endif	/* CONFIG_KGDB */
+
 static int __init serial8250_init(void)
 {
 	int ret, i;
--- diff/drivers/serial/8250_acpi.c	2004-06-11 19:17:31.000000000 +0100
+++ source/drivers/serial/8250_acpi.c	2004-06-11 19:22:04.000000000 +0100
@@ -57,28 +57,18 @@
 static acpi_status acpi_serial_ext_irq(struct serial_struct *req,
 				       struct acpi_resource_ext_irq *ext_irq)
 {
-	if (ext_irq->number_of_interrupts > 0) {
-#ifdef CONFIG_IA64
-		req->irq = acpi_register_irq(ext_irq->interrupts[0],
-	                  ext_irq->active_high_low, ext_irq->edge_level);
-#else
-		req->irq = ext_irq->interrupts[0];
-#endif
-	}
+	if (ext_irq->number_of_interrupts > 0)
+		req->irq = acpi_register_gsi(ext_irq->interrupts[0],
+	                  ext_irq->edge_level, ext_irq->active_high_low);
 	return AE_OK;
 }
 
 static acpi_status acpi_serial_irq(struct serial_struct *req,
 				   struct acpi_resource_irq *irq)
 {
-	if (irq->number_of_interrupts > 0) {
-#ifdef CONFIG_IA64
-		req->irq = acpi_register_irq(irq->interrupts[0],
-	                  irq->active_high_low, irq->edge_level);
-#else
-		req->irq = irq->interrupts[0];
-#endif
-	}
+	if (irq->number_of_interrupts > 0)
+		req->irq = acpi_register_gsi(irq->interrupts[0],
+	                  irq->edge_level, irq->active_high_low);
 	return AE_OK;
 }
 
--- diff/drivers/serial/8250_hcdp.c	2004-05-19 22:12:15.000000000 +0100
+++ source/drivers/serial/8250_hcdp.c	2004-06-11 19:22:04.000000000 +0100
@@ -96,7 +96,11 @@
 		 * of the entries for the same type device that has already
 		 * been parsed and initialized
 		 */
+#ifndef	CONFIG_KGDB_EARLY
 		if (hcdp_dev->type != HCDP_DEV_CONSOLE)
+#else
+		if (hcdp_dev->type != HCDP_DEV_CONSOLE && hcdp_dev->type != HCDP_DEV_DEBUG)
+#endif
 			continue;
 
 		iobase = ((u64) hcdp_dev->base_addr.addrhi << 32) |
@@ -183,16 +187,12 @@
 		}
 
 		if (HCDP_IRQ_SUPPORTED(hcdp_dev)) {
-#ifdef CONFIG_IA64
 			if (HCDP_PCI_UART(hcdp_dev))
-				port.irq = acpi_register_irq(gsi,
-					ACPI_ACTIVE_LOW, ACPI_LEVEL_SENSITIVE);
+				port.irq = acpi_register_gsi(gsi,
+					ACPI_LEVEL_SENSITIVE, ACPI_ACTIVE_LOW);
 			else
-				port.irq = acpi_register_irq(gsi,
-					ACPI_ACTIVE_HIGH, ACPI_EDGE_SENSITIVE);
-#else
-			port.irq = gsi;
-#endif
+				port.irq = acpi_register_gsi(gsi,
+					ACPI_EDGE_SENSITIVE, ACPI_ACTIVE_HIGH);
 			port.flags |= UPF_AUTO_IRQ;
 
 			if (HCDP_PCI_UART(hcdp_dev))
@@ -205,6 +205,7 @@
 		 * Note: the above memset() initializes port.line to 0,
 		 * so we register this port as ttyS0.
 		 */
+		port.line = (hcdp_dev->type == HCDP_DEV_CONSOLE) ? 0 : 1;
 		if (early_serial_setup(&port) < 0) {
 			printk("setup_serial_hcdp(): early_serial_setup() "
 				"for HCDP serial console port failed. "
@@ -218,7 +219,9 @@
 				hcdp_dev->baud, hcdp_dev->bits);
 			add_preferred_console("ttyS", port.line, options);
 		}
+#ifndef	CONFIG_KGDB_EARLY
 		break;
+#endif
 	}
 
 #ifdef SERIAL_DEBUG_HCDP
--- diff/drivers/serial/8250_pnp.c	2004-05-19 22:12:15.000000000 +0100
+++ source/drivers/serial/8250_pnp.c	2004-06-11 19:22:04.000000000 +0100
@@ -361,9 +361,6 @@
 			    ((port->min == 0x2f8) ||
 			     (port->min == 0x3f8) ||
 			     (port->min == 0x2e8) ||
-#ifdef CONFIG_X86_PC9800
-			     (port->min == 0x8b0) ||
-#endif
 			     (port->min == 0x3e8)))
 				return 1;
 	}
--- diff/drivers/serial/Kconfig	2004-05-19 22:12:15.000000000 +0100
+++ source/drivers/serial/Kconfig	2004-06-11 19:22:04.000000000 +0100
@@ -517,19 +517,6 @@
 	depends on V850E_UART
 	select SERIAL_CORE_CONSOLE
 
-config SERIAL98
-	tristate "PC-9800 8251-based primary serial port support"
-	depends on X86_PC9800
-	select SERIAL_CORE
-	help
-	  If you want to use standard primary serial ports on PC-9800, 
-	  say Y.  Otherwise, say N.
-
-config SERIAL98_CONSOLE
-        bool "Support for console on PC-9800 standard serial port"
-        depends on SERIAL98=y
-	select SERIAL_CORE_CONSOLE
-
 config SERIAL_SH_SCI
 	tristate "SH SCI(F) serial port support"
 	depends on SUPERH || H8300
--- diff/drivers/serial/Makefile	2004-05-19 22:12:15.000000000 +0100
+++ source/drivers/serial/Makefile	2004-06-11 19:22:04.000000000 +0100
@@ -33,7 +33,6 @@
 obj-$(CONFIG_SERIAL_68360) += 68360serial.o
 obj-$(CONFIG_SERIAL_COLDFIRE) += mcfserial.o
 obj-$(CONFIG_V850E_UART) += v850e_uart.o
-obj-$(CONFIG_SERIAL98) += serial98.o
 obj-$(CONFIG_SERIAL_PMACZILOG) += pmac_zilog.o
 obj-$(CONFIG_SERIAL_AU1X00) += au1x00_uart.o
 obj-$(CONFIG_SERIAL_DZ) += dz.o
--- diff/drivers/serial/serial_core.c	2004-06-11 19:17:31.000000000 +0100
+++ source/drivers/serial/serial_core.c	2004-06-11 19:22:04.000000000 +0100
@@ -1990,6 +1990,11 @@
 {
 	unsigned int flags;
 
+#ifdef CONFIG_KGDB
+	if (port->kgdb)
+		return;
+#endif
+
 	/*
 	 * If there isn't a port here, don't do anything further.
 	 */
--- diff/drivers/usb/Kconfig	2004-05-19 22:12:16.000000000 +0100
+++ source/drivers/usb/Kconfig	2004-06-11 19:22:05.000000000 +0100
@@ -7,7 +7,7 @@
 # ARM SA1111 chips have a non-PCI based "OHCI-compatible" USB host interface.
 config USB
 	tristate "Support for Host-side USB"
-	depends on PCI || SA1111 || ARCH_OMAP1510 || ARCH_OMAP1610
+	depends on PCI || SA1111 || ARCH_OMAP1510 || ARCH_OMAP1610 || ARCH_LH7A404
 	---help---
 	  Universal Serial Bus (USB) is a specification for a serial bus
 	  subsystem which offers higher speeds and more features than the
--- diff/drivers/usb/class/audio.c	2004-05-19 22:12:16.000000000 +0100
+++ source/drivers/usb/class/audio.c	2004-06-11 19:22:04.000000000 +0100
@@ -212,9 +212,6 @@
 
 #define dprintk(x)
 
-#undef abs
-extern int abs(int __x) __attribute_const__; /* Shut up warning */
-
 /* --------------------------------------------------------------------- */
 
 /*
@@ -398,17 +395,6 @@
 
 /* --------------------------------------------------------------------- */
 
-/* prevent picking up a bogus abs macro */
-#undef abs
-static inline int abs(int x)
-{
-        if (x < 0)
-		return -x;
-	return x;
-}
-                                
-/* --------------------------------------------------------------------- */
-
 static inline unsigned ld2(unsigned int x)
 {
 	unsigned r = 0;
--- diff/drivers/usb/class/cdc-acm.c	2004-06-11 19:17:31.000000000 +0100
+++ source/drivers/usb/class/cdc-acm.c	2004-06-11 19:22:04.000000000 +0100
@@ -27,6 +27,7 @@
  *	v0.22 - probe only the control interface. if usbcore doesn't choose the
  *		config we want, sysadmin changes bConfigurationValue in sysfs.
  *	v0.23 - use softirq for rx processing, as needed by tty layer
+ *	v0.24 - change probe method to evaluate CDC union descriptor
  */
 
 /*
@@ -60,6 +61,8 @@
 #include <linux/usb.h>
 #include <asm/byteorder.h>
 
+#include "cdc-acm.h"
+
 /*
  * Version Information
  */
@@ -67,102 +70,12 @@
 #define DRIVER_AUTHOR "Armin Fuerst, Pavel Machek, Johannes Erdfelt, Vojtech Pavlik"
 #define DRIVER_DESC "USB Abstract Control Model driver for USB modems and ISDN adapters"
 
-/*
- * CMSPAR, some architectures can't have space and mark parity.
- */
-
-#ifndef CMSPAR
-#define CMSPAR			0
-#endif
-
-/*
- * Major and minor numbers.
- */
-
-#define ACM_TTY_MAJOR		166
-#define ACM_TTY_MINORS		32
-
-/*
- * Requests.
- */
-
-#define USB_RT_ACM		(USB_TYPE_CLASS | USB_RECIP_INTERFACE)
-
-#define ACM_REQ_COMMAND		0x00
-#define ACM_REQ_RESPONSE	0x01
-#define ACM_REQ_SET_FEATURE	0x02
-#define ACM_REQ_GET_FEATURE	0x03
-#define ACM_REQ_CLEAR_FEATURE	0x04
-
-#define ACM_REQ_SET_LINE	0x20
-#define ACM_REQ_GET_LINE	0x21
-#define ACM_REQ_SET_CONTROL	0x22
-#define ACM_REQ_SEND_BREAK	0x23
-
-/*
- * IRQs.
- */
-
-#define ACM_IRQ_NETWORK		0x00
-#define ACM_IRQ_LINE_STATE	0x20
-
-/*
- * Output control lines.
- */
-
-#define ACM_CTRL_DTR		0x01
-#define ACM_CTRL_RTS		0x02
-
-/*
- * Input control lines and line errors.
- */
-
-#define ACM_CTRL_DCD		0x01
-#define ACM_CTRL_DSR		0x02
-#define ACM_CTRL_BRK		0x04
-#define ACM_CTRL_RI		0x08
-
-#define ACM_CTRL_FRAMING	0x10
-#define ACM_CTRL_PARITY		0x20
-#define ACM_CTRL_OVERRUN	0x40
-
-/*
- * Line speed and caracter encoding.
- */
-
-struct acm_line {
-	__u32 speed;
-	__u8 stopbits;
-	__u8 parity;
-	__u8 databits;
-} __attribute__ ((packed));
-
-/*
- * Internal driver structures.
- */
-
-struct acm {
-	struct usb_device *dev;				/* the corresponding usb device */
-	struct usb_interface *control;			/* control interface */
-	struct usb_interface *data;			/* data interface */
-	struct tty_struct *tty;				/* the corresponding tty */
-	struct urb *ctrlurb, *readurb, *writeurb;	/* urbs */
-	struct acm_line line;				/* line coding (bits, stop, parity) */
-	struct work_struct work;			/* work queue entry for line discipline waking up */
-	struct tasklet_struct bh;			/* rx processing */
-	unsigned int ctrlin;				/* input control lines (DCD, DSR, RI, break, overruns) */
-	unsigned int ctrlout;				/* output control lines (DTR, RTS) */
-	unsigned int writesize;				/* max packet size for the output bulk endpoint */
-	unsigned int used;				/* someone has this acm's device open */
-	unsigned int minor;				/* acm minor number */
-	unsigned char throttle;				/* throttled by tty layer */
-	unsigned char clocal;				/* termios CLOCAL */
-};
-
 static struct usb_driver acm_driver;
 static struct tty_driver *acm_tty_driver;
 static struct acm *acm_table[ACM_TTY_MINORS];
 
+static DECLARE_MUTEX(open_sem);
+
 #define ACM_READY(acm)	(acm && acm->dev && acm->used)
 
 /*
@@ -310,12 +223,14 @@
 	struct acm *acm = (struct acm *)urb->context;
 
 	if (!ACM_READY(acm))
-		return;
+		goto out;
 
 	if (urb->status)
 		dbg("nonzero write bulk status received: %d", urb->status);
 
 	schedule_work(&acm->work);
+out:
+	acm->ready_for_write = 1;
 }
 
 static void acm_softint(void *private)
@@ -346,22 +261,23 @@
 	tty->driver_data = acm;
 	acm->tty = tty;
 
-        lock_kernel();
+        down(&open_sem);
 
-	if (acm->used++) {
-                unlock_kernel();
-                return 0;
+	if (acm->used) {
+		goto done;
         }
 
-        unlock_kernel();
-
 	acm->ctrlurb->dev = acm->dev;
-	if (usb_submit_urb(acm->ctrlurb, GFP_KERNEL))
+	if (usb_submit_urb(acm->ctrlurb, GFP_KERNEL)) {
 		dbg("usb_submit_urb(ctrl irq) failed");
+		goto bail_out;
+	}
 
 	acm->readurb->dev = acm->dev;
-	if (usb_submit_urb(acm->readurb, GFP_KERNEL))
+	if (usb_submit_urb(acm->readurb, GFP_KERNEL)) {
 		dbg("usb_submit_urb(read bulk) failed");
+		goto bail_out_and_unlink;
+	}
 
 	acm_set_control(acm, acm->ctrlout = ACM_CTRL_DTR | ACM_CTRL_RTS);
 
@@ -369,7 +285,16 @@
 	   otherwise it is scheduled, and with high data rates data can get lost. */
 	tty->low_latency = 1;
 
+done:
+	acm->used++;
+	up(&open_sem);
 	return 0;
+
+bail_out_and_unlink:
+	usb_unlink_urb(acm->ctrlurb);
+bail_out:
+	up(&open_sem);
+	return -EIO;
 }
 
 static void acm_tty_close(struct tty_struct *tty, struct file *filp)
@@ -379,6 +304,7 @@
 	if (!acm || !acm->used)
 		return;
 
+	down(&open_sem);
 	if (!--acm->used) {
 		if (acm->dev) {
 			acm_set_control(acm, acm->ctrlout = 0);
@@ -394,6 +320,7 @@
 			kfree(acm);
 		}
 	}
+	up(&open_sem);
 }
 
 static int acm_tty_write(struct tty_struct *tty, int from_user, const unsigned char *buf, int count)
@@ -403,7 +330,7 @@
 
 	if (!ACM_READY(acm))
 		return -EINVAL;
-	if (acm->writeurb->status == -EINPROGRESS)
+	if (!acm->ready_for_write)
 		return 0;
 	if (!count)
 		return 0;
@@ -419,10 +346,11 @@
 	acm->writeurb->transfer_buffer_length = count;
 	acm->writeurb->dev = acm->dev;
 
-	/* GFP_KERNEL probably works if from_user */
-	stat = usb_submit_urb(acm->writeurb, GFP_ATOMIC);
+	acm->ready_for_write = 0;
+	stat = usb_submit_urb(acm->writeurb, GFP_NOIO);
 	if (stat < 0) {
 		dbg("usb_submit_urb(write bulk) failed");
+		acm->ready_for_write = 1;
 		return stat;
 	}
 
@@ -434,7 +362,7 @@
 	struct acm *acm = tty->driver_data;
 	if (!ACM_READY(acm))
 		return -EINVAL;
-	return acm->writeurb->status == -EINPROGRESS ? 0 : acm->writesize;
+	return !acm->ready_for_write ? 0 : acm->writesize;
 }
 
 static int acm_tty_chars_in_buffer(struct tty_struct *tty)
@@ -442,7 +370,7 @@
 	struct acm *acm = tty->driver_data;
 	if (!ACM_READY(acm))
 		return -EINVAL;
-	return acm->writeurb->status == -EINPROGRESS ? acm->writeurb->transfer_buffer_length : 0;
+	return !acm->ready_for_write ? acm->writeurb->transfer_buffer_length : 0;
 }
 
 static void acm_tty_throttle(struct tty_struct *tty)
@@ -567,77 +495,102 @@
  * USB probe and disconnect routines.
  */
 
-#define CHECK_XFERTYPE(descr, xfer_type) (((descr)->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) == xfer_type)
-			
 static int acm_probe (struct usb_interface *intf,
 		      const struct usb_device_id *id)
 {
-	struct usb_device *dev;
+	struct union_desc *union_header = NULL;
+	char *buffer = intf->altsetting->extra;
+	int buflen = intf->altsetting->extralen;
+	struct usb_interface *control_interface;
+	struct usb_interface *data_interface;
+	struct usb_endpoint_descriptor *epctrl;
+	struct usb_endpoint_descriptor *epread;
+	struct usb_endpoint_descriptor *epwrite;
+	struct usb_device *usb_dev = interface_to_usbdev(intf);
 	struct acm *acm;
-	struct usb_host_config *cfacm;
-	struct usb_interface *data = NULL;
-	struct usb_host_interface *ifcom, *ifdata = NULL;
-	struct usb_endpoint_descriptor *epctrl = NULL;
-	struct usb_endpoint_descriptor *epread = NULL;
-	struct usb_endpoint_descriptor *epwrite = NULL;
-	int readsize, ctrlsize, minor, j;
-	unsigned char *buf;
-
-	dev = interface_to_usbdev (intf);
-
-	cfacm = dev->actconfig;
-
-	/* We know we're probe()d with the control interface. */
-	ifcom = intf->cur_altsetting;
-
-	/* ACM doesn't guarantee the data interface is
-	 * adjacent to the control interface, or that if one
-	 * is there it's not for call management ... so find
-	 * it
-	 */
-	for (j = 0; j < cfacm->desc.bNumInterfaces; j++) {
-		ifdata = cfacm->interface[j]->cur_altsetting;
-		data = cfacm->interface[j];
-
-		if (ifdata->desc.bInterfaceClass == USB_CLASS_CDC_DATA
-		    && ifdata->desc.bNumEndpoints == 2) {
-			
-			epctrl = &ifcom->endpoint[0].desc;
-			epread = &ifdata->endpoint[0].desc;
-			epwrite = &ifdata->endpoint[1].desc;
-
-			if ((epctrl->bEndpointAddress & USB_DIR_IN) != USB_DIR_IN
-			    || !CHECK_XFERTYPE(epctrl,  USB_ENDPOINT_XFER_INT)
-			    || !CHECK_XFERTYPE(epread,  USB_ENDPOINT_XFER_BULK)
-			    || !CHECK_XFERTYPE(epwrite, USB_ENDPOINT_XFER_BULK)
-			    || ((epread->bEndpointAddress & USB_DIR_IN)
-			        ^ (epwrite->bEndpointAddress & USB_DIR_IN)) != USB_DIR_IN) {
-				/* not suitable */
-				goto next_interface;
-			}
-			
-			if ((epread->bEndpointAddress & USB_DIR_IN) != USB_DIR_IN) {
-				/* descriptors are swapped */
-				epread = &ifdata->endpoint[1].desc;
-				epwrite = &ifdata->endpoint[0].desc;
-			}
-			dev_dbg(&intf->dev, "found data interface at %d\n", j);
-			break;
-		} else {
-next_interface:
-			ifdata = NULL;
-			data = NULL;
+	int minor;
+	int ctrlsize,readsize;
+	char *buf;
+
+	if (!buffer) {
+		err("Wierd descriptor references");
+		return -EINVAL;
+	}
+
+	while (buflen > 0) {
+		if (buffer [1] != USB_DT_CS_INTERFACE) {
+			err("skipping garbage");
+			goto next_desc;
 		}
+
+		switch (buffer [2]) {
+			case CDC_UNION_TYPE: /* we've found it */
+				if (union_header) {
+					err("More than one union descriptor, skipping ...");
+					goto next_desc;
+				}
+				union_header = (struct union_desc *)buffer;
+				break;
+			default:
+				err("Ignoring extra header");
+				break;
+			}
+next_desc:
+		buflen -= buffer[0];
+		buffer += buffer[0];
 	}
 
-	/* there's been a problem */
-	if (!ifdata) {
-		dev_dbg(&intf->dev, "data interface not found\n");
+	if (!union_header) {
+		dev_dbg(&intf->dev,"No union descriptor, giving up\n");
 		return -ENODEV;
+	}
 
+	control_interface = usb_ifnum_to_if(usb_dev, union_header->bMasterInterface0);
+	data_interface = usb_ifnum_to_if(usb_dev, union_header->bSlaveInterface0);
+	if (!control_interface || !data_interface) {
+		dev_dbg(&intf->dev,"no interfaces\n");
+		return -ENODEV;
 	}
 
+	if (usb_interface_claimed(data_interface)) { /* valid in this context */
+		dev_dbg(&intf->dev,"The data interface isn't available\n");
+		return -EBUSY;
+	}
+
+	/*workaround for switched interfaces */
+	if (data_interface->cur_altsetting->desc.bInterfaceClass != CDC_DATA_INTERFACE_TYPE) {
+		if (control_interface->cur_altsetting->desc.bInterfaceClass == CDC_DATA_INTERFACE_TYPE) {
+			struct usb_interface *t;
+			dev_dbg(&intf->dev,"Your device has switched interfaces.\n");
+
+			t = control_interface;
+			control_interface = data_interface;
+			data_interface = t;
+		} else {
+			return -EINVAL;
+		}
+	}
+	if (data_interface->cur_altsetting->desc.bNumEndpoints < 2)
+		return -EINVAL;
+
+	epctrl = &control_interface->cur_altsetting->endpoint[0].desc;
+	epread = &data_interface->cur_altsetting->endpoint[0].desc;
+	epwrite = &data_interface->cur_altsetting->endpoint[1].desc;
+
+
+	/* workaround for switched endpoints */
+	if ((epread->bEndpointAddress & USB_DIR_IN) != USB_DIR_IN) {
+		/* descriptors are swapped */
+		struct usb_endpoint_descriptor *t;
+		dev_dbg(&intf->dev,"The data interface has switched endpoints\n");
+		
+		t = epread;
+		epread = epwrite;
+		epwrite = t;
+	}
+	dbg("interfaces are valid");
 	for (minor = 0; minor < ACM_TTY_MINORS && acm_table[minor]; minor++);
+
 	if (acm_table[minor]) {
 		err("no more free acm devices");
 		return -ENODEV;
@@ -647,20 +600,21 @@
 		dev_dbg(&intf->dev, "out of memory (acm kmalloc)\n");
 		return -ENOMEM;
 	}
-	
 	memset(acm, 0, sizeof(struct acm));
 
 	ctrlsize = epctrl->wMaxPacketSize;
 	readsize = epread->wMaxPacketSize;
 	acm->writesize = epwrite->wMaxPacketSize;
-	acm->control = intf;
-	acm->data = data;
+	acm->control = control_interface;
+	acm->data = data_interface;
 	acm->minor = minor;
-	acm->dev = dev;
+	acm->dev = usb_dev;
 
 	acm->bh.func = acm_rx_tasklet;
 	acm->bh.data = (unsigned long) acm;
 	INIT_WORK(&acm->work, acm_softint, acm);
+	acm->ready_for_write = 1;
+
 
 	if (!(buf = kmalloc(ctrlsize + readsize + acm->writesize, GFP_KERNEL))) {
 		dev_dbg(&intf->dev, "out of memory (buf kmalloc)\n");
@@ -693,29 +647,17 @@
 		return -ENOMEM;
 	}
 
-	usb_fill_int_urb(acm->ctrlurb, dev, usb_rcvintpipe(dev, epctrl->bEndpointAddress),
-		buf, ctrlsize, acm_ctrl_irq, acm, epctrl->bInterval);
+	usb_fill_int_urb(acm->ctrlurb, usb_dev, usb_rcvintpipe(usb_dev, epctrl->bEndpointAddress),
+			 buf, ctrlsize, acm_ctrl_irq, acm, epctrl->bInterval);
 
-	usb_fill_bulk_urb(acm->readurb, dev, usb_rcvbulkpipe(dev, epread->bEndpointAddress),
-		buf += ctrlsize, readsize, acm_read_bulk, acm);
+	usb_fill_bulk_urb(acm->readurb, usb_dev, usb_rcvbulkpipe(usb_dev, epread->bEndpointAddress),
+			  buf += ctrlsize, readsize, acm_read_bulk, acm);
 	acm->readurb->transfer_flags |= URB_NO_FSBR;
 
-	usb_fill_bulk_urb(acm->writeurb, dev, usb_sndbulkpipe(dev, epwrite->bEndpointAddress),
-		buf += readsize, acm->writesize, acm_write_bulk, acm);
+	usb_fill_bulk_urb(acm->writeurb, usb_dev, usb_sndbulkpipe(usb_dev, epwrite->bEndpointAddress),
+			  buf += readsize, acm->writesize, acm_write_bulk, acm);
 	acm->writeurb->transfer_flags |= URB_NO_FSBR;
 
-	if ( (j = usb_driver_claim_interface(&acm_driver, data, acm)) != 0) {
-		err("claim failed");
-		usb_free_urb(acm->ctrlurb);
-		usb_free_urb(acm->readurb);
-		usb_free_urb(acm->writeurb);
-		kfree(acm);
-		kfree(buf);
-		return j;
-	} 
-
-	tty_register_device(acm_tty_driver, minor, &intf->dev);
-
 	dev_info(&intf->dev, "ttyACM%d: USB ACM device\n", minor);
 
 	acm_set_control(acm, acm->ctrlout);
@@ -724,11 +666,14 @@
 	acm->line.databits = 8;
 	acm_set_line(acm, &acm->line);
 
+	usb_driver_claim_interface(&acm_driver, data_interface, acm);
+
+	tty_register_device(acm_tty_driver, minor, &intf->dev);
+
 	acm_table[minor] = acm;
 	usb_set_intfdata (intf, acm);
 	return 0;
 }
-#undef CHECK_XFERTYPE
 
 static void acm_disconnect(struct usb_interface *intf)
 {
@@ -746,6 +691,8 @@
 	usb_unlink_urb(acm->readurb);
 	usb_unlink_urb(acm->writeurb);
 
+	flush_scheduled_work(); /* wait for acm_softint */
+
 	kfree(acm->ctrlurb->transfer_buffer);
 
 	usb_driver_release_interface(&acm_driver, acm->data);
--- diff/drivers/usb/class/usblp.c	2004-06-11 19:17:31.000000000 +0100
+++ source/drivers/usb/class/usblp.c	2004-06-11 19:22:04.000000000 +0100
@@ -761,6 +761,7 @@
 			usblp->minor, usblp->readurb->status);
 		usblp->readurb->dev = usblp->dev;
  		usblp->readcount = 0;
+		usblp->rcomplete = 0;
 		if (usb_submit_urb(usblp->readurb, GFP_KERNEL) < 0)
 			dbg("error submitting urb");
 		count = -EIO;
--- diff/drivers/usb/core/devio.c	2004-06-11 19:17:31.000000000 +0100
+++ source/drivers/usb/core/devio.c	2004-06-11 19:22:05.000000000 +0100
@@ -719,7 +719,7 @@
 
 static int proc_resetdevice(struct dev_state *ps)
 {
-	return usb_reset_device(ps->dev);
+	return __usb_reset_device(ps->dev);
 
 }
 
--- diff/drivers/usb/core/hcd.c	2004-06-11 19:17:31.000000000 +0100
+++ source/drivers/usb/core/hcd.c	2004-06-11 19:22:05.000000000 +0100
@@ -787,14 +787,12 @@
 		return (retval < 0) ? retval : -EMSGSIZE;
 	}
 
-	(void) usb_get_dev (usb_dev);
 	down (&usb_dev->serialize);
 	retval = usb_new_device (usb_dev);
+	up (&usb_dev->serialize);
 	if (retval)
 		dev_err (parent_dev, "can't register root hub for %s, %d\n",
 				usb_dev->dev.bus_id, retval);
-	up (&usb_dev->serialize);
-	usb_put_dev (usb_dev);
 	return retval;
 }
 EXPORT_SYMBOL (usb_register_root_hub);
--- diff/drivers/usb/core/hcd.h	2004-06-11 19:17:31.000000000 +0100
+++ source/drivers/usb/core/hcd.h	2004-06-11 19:22:05.000000000 +0100
@@ -244,17 +244,10 @@
 					struct usb_bus *, unsigned port);
 extern int usb_new_device(struct usb_device *dev);
 extern void usb_disconnect(struct usb_device **);
-extern void usb_choose_address(struct usb_device *dev);
-extern void usb_release_address(struct usb_device *dev);
 
-/* exported to hub driver ONLY to support usb_reset_device () */
 extern int usb_get_configuration(struct usb_device *dev);
 extern void usb_destroy_configuration(struct usb_device *dev);
 
-/* use these only before the device's address has been set */
-#define usb_snddefctrl(dev)		((PIPE_CONTROL << 30))
-#define usb_rcvdefctrl(dev)		((PIPE_CONTROL << 30) | USB_DIR_IN)
-
 /*-------------------------------------------------------------------------*/
 
 /*
--- diff/drivers/usb/core/hub.c	2004-06-11 19:17:31.000000000 +0100
+++ source/drivers/usb/core/hub.c	2004-06-11 19:22:05.000000000 +0100
@@ -9,6 +9,11 @@
  */
 
 #include <linux/config.h>
+#ifdef CONFIG_USB_DEBUG
+	#define DEBUG
+#else
+	#undef DEBUG
+#endif
 #include <linux/kernel.h>
 #include <linux/errno.h>
 #include <linux/module.h>
@@ -19,11 +24,6 @@
 #include <linux/slab.h>
 #include <linux/smp_lock.h>
 #include <linux/ioctl.h>
-#ifdef CONFIG_USB_DEBUG
-	#define DEBUG
-#else
-	#undef DEBUG
-#endif
 #include <linux/usb.h>
 #include <linux/usbdevice_fs.h>
 #include <linux/suspend.h>
@@ -40,7 +40,6 @@
 static spinlock_t hub_event_lock = SPIN_LOCK_UNLOCKED;
 
 static LIST_HEAD(hub_event_list);	/* List of hubs needing servicing */
-static LIST_HEAD(hub_list);		/* List of all hubs (for cleanup) */
 
 static DECLARE_WAIT_QUEUE_HEAD(khubd_wait);
 static pid_t khubd_pid = 0;			/* PID of khubd */
@@ -268,7 +267,7 @@
 	if ((status = usb_submit_urb (hub->urb, GFP_ATOMIC)) != 0
 			/* ENODEV means we raced disconnect() */
 			&& status != -ENODEV)
-		dev_err (&hub->intf->dev, "resubmit --> %d\n", urb->status);
+		dev_err (&hub->intf->dev, "resubmit --> %d\n", status);
 	if (status == 0)
 		hub->urb_active = 1;
 done:
@@ -646,7 +645,6 @@
 
 	/* Delete it and then reset it */
 	list_del_init(&hub->event_list);
-	list_del_init(&hub->hub_list);
 
 	spin_unlock_irqrestore(&hub_event_lock, flags);
 
@@ -695,7 +693,6 @@
 	struct usb_device *hdev;
 	struct usb_hub *hub;
 	struct device *hub_dev;
-	unsigned long flags;
 
 	desc = intf->cur_altsetting;
 	hdev = interface_to_usbdev(intf);
@@ -711,23 +708,19 @@
 	}
 
 	/* Multiple endpoints? What kind of mutant ninja-hub is this? */
-	if (desc->desc.bNumEndpoints != 1) {
+	if (desc->desc.bNumEndpoints != 1)
 		goto descriptor_error;
-	}
 
 	endpoint = &desc->endpoint[0].desc;
 
 	/* Output endpoint? Curiouser and curiouser.. */
-	if (!(endpoint->bEndpointAddress & USB_DIR_IN)) {
+	if (!(endpoint->bEndpointAddress & USB_DIR_IN))
 		goto descriptor_error;
-	}
 
 	/* If it's not an interrupt endpoint, we'd better punt! */
 	if ((endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK)
-			!= USB_ENDPOINT_XFER_INT) {
+			!= USB_ENDPOINT_XFER_INT)
 		goto descriptor_error;
-		return -EIO;
-	}
 
 	/* We found a hub */
 	dev_info (hub_dev, "USB hub found\n");
@@ -745,12 +738,6 @@
 	init_MUTEX(&hub->khubd_sem);
 	INIT_WORK(&hub->leds, led_work, hub);
 
-	/* Record the new hub's existence */
-	spin_lock_irqsave(&hub_event_lock, flags);
-	INIT_LIST_HEAD(&hub->hub_list);
-	list_add(&hub->hub_list, &hub_list);
-	spin_unlock_irqrestore(&hub_event_lock, flags);
-
 	usb_set_intfdata (intf, hub);
 
 	if (hdev->speed == USB_SPEED_HIGH)
@@ -845,6 +832,233 @@
 	dev_err(&hdev->dev, "cannot disconnect hub!\n");
 }
 
+
+static void choose_address(struct usb_device *udev)
+{
+	int		devnum;
+	struct usb_bus	*bus = udev->bus;
+
+	/* If khubd ever becomes multithreaded, this will need a lock */
+
+	/* Try to allocate the next devnum beginning at bus->devnum_next. */
+	devnum = find_next_zero_bit(bus->devmap.devicemap, 128,
+			bus->devnum_next);
+	if (devnum >= 128)
+		devnum = find_next_zero_bit(bus->devmap.devicemap, 128, 1);
+
+	bus->devnum_next = ( devnum >= 127 ? 1 : devnum + 1);
+
+	if (devnum < 128) {
+		set_bit(devnum, bus->devmap.devicemap);
+		udev->devnum = devnum;
+	}
+}
+
+static void release_address(struct usb_device *udev)
+{
+	if (udev->devnum > 0) {
+		clear_bit(udev->devnum, udev->bus->devmap.devicemap);
+		udev->devnum = -1;
+	}
+}
+
+/**
+ * usb_disconnect - disconnect a device (usbcore-internal)
+ * @pdev: pointer to device being disconnected
+ * Context: !in_interrupt ()
+ *
+ * Something got disconnected. Get rid of it, and all of its children.
+ *
+ * Only hub drivers (including virtual root hub drivers for host
+ * controllers) should ever call this.
+ *
+ * This call is synchronous, and may not be used in an interrupt context.
+ */
+void usb_disconnect(struct usb_device **pdev)
+{
+	struct usb_device	*udev = *pdev;
+	struct usb_bus		*bus;
+	struct usb_operations	*ops;
+	int			i;
+
+	if (!udev) {
+		pr_debug ("%s nodev\n", __FUNCTION__);
+		return;
+	}
+	bus = udev->bus;
+	if (!bus) {
+		pr_debug ("%s nobus\n", __FUNCTION__);
+		return;
+	}
+	ops = bus->op;
+
+	*pdev = NULL;
+
+	/* mark the device as inactive, so any further urb submissions for
+	 * this device will fail.
+	 */
+	udev->state = USB_STATE_NOTATTACHED;
+	down(&udev->serialize);
+
+	dev_info (&udev->dev, "USB disconnect, address %d\n", udev->devnum);
+
+	/* Free up all the children before we remove this device */
+	for (i = 0; i < USB_MAXCHILDREN; i++) {
+		struct usb_device **child = udev->children + i;
+		if (*child)
+			usb_disconnect(child);
+	}
+
+	/* deallocate hcd/hardware state ... nuking all pending urbs and
+	 * cleaning up all state associated with the current configuration
+	 */
+	usb_disable_device(udev, 0);
+
+	/* Free the device number and remove the /proc/bus/usb entry */
+	dev_dbg (&udev->dev, "unregistering device\n");
+	release_address(udev);
+	usbfs_remove_device(udev);
+	up(&udev->serialize);
+	usb_remove_sysfs_dev_files(udev);
+	device_unregister(&udev->dev);
+}
+
+static int choose_configuration(struct usb_device *udev)
+{
+	int c, i;
+
+	/* NOTE: this should interact with hub power budgeting */
+
+	c = udev->config[0].desc.bConfigurationValue;
+	if (udev->descriptor.bNumConfigurations != 1) {
+		for (i = 0; i < udev->descriptor.bNumConfigurations; i++) {
+			struct usb_interface_descriptor	*desc;
+
+			/* heuristic:  Linux is more likely to have class
+			 * drivers, so avoid vendor-specific interfaces.
+			 */
+			desc = &udev->config[i].intf_cache[0]
+					->altsetting->desc;
+			if (desc->bInterfaceClass == USB_CLASS_VENDOR_SPEC)
+				continue;
+			/* COMM/2/all is CDC ACM, except 0xff is MSFT RNDIS */
+			if (desc->bInterfaceClass == USB_CLASS_COMM
+					&& desc->bInterfaceSubClass == 2
+					&& desc->bInterfaceProtocol == 0xff)
+				continue;
+			c = udev->config[i].desc.bConfigurationValue;
+			break;
+		}
+		dev_info(&udev->dev,
+			"configuration #%d chosen from %d choices\n",
+			c, udev->descriptor.bNumConfigurations);
+	}
+	return c;
+}
+
+#ifdef DEBUG
+static void show_string(struct usb_device *udev, char *id, int index)
+{
+	char *buf;
+
+	if (!index)
+		return;
+	if (!(buf = kmalloc(256, GFP_KERNEL)))
+		return;
+	if (usb_string(udev, index, buf, 256) > 0)
+		dev_printk(KERN_INFO, &udev->dev, "%s: %s\n", id, buf);
+	kfree(buf);
+}
+
+#else
+static inline void show_string(struct usb_device *udev, char *id, int index)
+{}
+#endif
+
+/*
+ * usb_new_device - perform initial device setup (usbcore-internal)
+ * @dev: newly addressed device (in ADDRESS state)
+ *
+ * This is called with devices which have been enumerated, but not yet
+ * configured.  The device descriptor is available, but not descriptors
+ * for any device configuration.  The caller owns dev->serialize, and
+ * the device is not visible through sysfs or other filesystem code.
+ *
+ * Returns 0 for success (device is configured and listed, with its
+ * interfaces, in sysfs); else a negative errno value.  On error, one
+ * reference count to the device has been dropped.
+ *
+ * This call is synchronous, and may not be used in an interrupt context.
+ *
+ * Only the hub driver should ever call this; root hub registration
+ * uses it only indirectly.
+ */
+int usb_new_device(struct usb_device *udev)
+{
+	int err;
+	int c;
+
+	err = usb_get_configuration(udev);
+	if (err < 0) {
+		dev_err(&udev->dev, "can't read configurations, error %d\n",
+			err);
+		goto fail;
+	}
+
+	/* Tell the world! */
+	dev_dbg(&udev->dev, "new device strings: Mfr=%d, Product=%d, "
+			"SerialNumber=%d\n",
+			udev->descriptor.iManufacturer,
+			udev->descriptor.iProduct,
+			udev->descriptor.iSerialNumber);
+
+	if (udev->descriptor.iProduct)
+		show_string(udev, "Product",
+				udev->descriptor.iProduct);
+	if (udev->descriptor.iManufacturer)
+		show_string(udev, "Manufacturer",
+				udev->descriptor.iManufacturer);
+	if (udev->descriptor.iSerialNumber)
+		show_string(udev, "SerialNumber",
+				udev->descriptor.iSerialNumber);
+
+	/* put device-specific files into sysfs */
+	err = device_add (&udev->dev);
+	if (err) {
+		dev_err(&udev->dev, "can't device_add, error %d\n", err);
+		goto fail;
+	}
+	usb_create_sysfs_dev_files (udev);
+
+	/* choose and set the configuration. that registers the interfaces
+	 * with the driver core, and lets usb device drivers bind to them.
+	 */
+	c = choose_configuration(udev);
+	if (c < 0)
+		dev_warn(&udev->dev,
+				"can't choose an initial configuration\n");
+	else {
+		err = usb_set_configuration(udev, c);
+		if (err) {
+			dev_err(&udev->dev, "can't set config #%d, error %d\n",
+					c, err);
+			device_del(&udev->dev);
+			goto fail;
+		}
+	}
+
+	/* USB device state == configured ... usable */
+
+	/* add a /proc/bus/usb entry */
+	usbfs_add_device(udev);
+	return 0;
+
+fail:
+	udev->state = USB_STATE_NOTATTACHED;
+	return err;
+}
+
+
 static int hub_port_status(struct usb_device *hdev, int port,
 			       u16 *status, u16 *change)
 {
@@ -934,10 +1148,14 @@
 
 	/* Reset the port */
 	for (i = 0; i < PORT_RESET_TRIES; i++) {
-		set_port_feature(hdev, port + 1, USB_PORT_FEAT_RESET);
+		status = set_port_feature(hdev, port + 1, USB_PORT_FEAT_RESET);
+		if (status)
+			dev_err(hub_dev, "cannot reset port %d (err = %d)\n",
+					port + 1, status);
+		else
+			status = hub_port_wait_reset(hdev, port, udev, delay);
 
 		/* return on disconnect or reset */
-		status = hub_port_wait_reset(hdev, port, udev, delay);
 		if (status == -ENOTCONN || status == 0) {
 			clear_port_feature(hdev,
 				port + 1, USB_PORT_FEAT_C_RESET);
@@ -975,57 +1193,62 @@
 /* USB 2.0 spec, 7.1.7.3 / fig 7-29:
  *
  * Between connect detection and reset signaling there must be a delay
- * of 100ms at least for debounce and power-settling. The corresponding
+ * of 100ms at least for debounce and power-settling.  The corresponding
  * timer shall restart whenever the downstream port detects a disconnect.
  * 
- * Apparently there are some bluetooth and irda-dongles and a number
- * of low-speed devices which require longer delays of about 200-400ms.
+ * Apparently there are some bluetooth and irda-dongles and a number of
+ * low-speed devices for which this debounce period may last over a second.
  * Not covered by the spec - but easy to deal with.
  *
- * This implementation uses 400ms minimum debounce timeout and checks
- * every 25ms for transient disconnects to restart the delay.
+ * This implementation uses a 1500ms total debounce timeout; if the
+ * connection isn't stable by then it returns -ETIMEDOUT.  It checks
+ * every 25ms for transient disconnects.  When the port status has been
+ * unchanged for 100ms it returns the port status.
  */
 
-#define HUB_DEBOUNCE_TIMEOUT	400
-#define HUB_DEBOUNCE_STEP	 25
-#define HUB_DEBOUNCE_STABLE	  4
+#define HUB_DEBOUNCE_TIMEOUT	1500
+#define HUB_DEBOUNCE_STEP	  25
+#define HUB_DEBOUNCE_STABLE	 100
 
 static int hub_port_debounce(struct usb_device *hdev, int port)
 {
 	int ret;
-	int delay_time, stable_count;
+	int total_time, stable_time = 0;
 	u16 portchange, portstatus;
-	unsigned connection;
-
-	connection = 0;
-	stable_count = 0;
-	for (delay_time = 0; delay_time < HUB_DEBOUNCE_TIMEOUT; delay_time += HUB_DEBOUNCE_STEP) {
-		msleep(HUB_DEBOUNCE_STEP);
+	unsigned connection = 0xffff;
 
+	for (total_time = 0; ; total_time += HUB_DEBOUNCE_STEP) {
 		ret = hub_port_status(hdev, port, &portstatus, &portchange);
 		if (ret < 0)
 			return ret;
 
-		if ((portstatus & USB_PORT_STAT_CONNECTION) == connection) {
-			if (connection) {
-				if (++stable_count == HUB_DEBOUNCE_STABLE)
-					break;
-			}
+		if (!(portchange & USB_PORT_STAT_C_CONNECTION) &&
+		     (portstatus & USB_PORT_STAT_CONNECTION) == connection) {
+			stable_time += HUB_DEBOUNCE_STEP;
+			if (stable_time >= HUB_DEBOUNCE_STABLE)
+				break;
 		} else {
-			stable_count = 0;
+			stable_time = 0;
+			connection = portstatus & USB_PORT_STAT_CONNECTION;
 		}
-		connection = portstatus & USB_PORT_STAT_CONNECTION;
 
-		if ((portchange & USB_PORT_STAT_C_CONNECTION)) {
-			clear_port_feature(hdev, port+1, USB_PORT_FEAT_C_CONNECTION);
+		if (portchange & USB_PORT_STAT_C_CONNECTION) {
+			clear_port_feature(hdev, port+1,
+					USB_PORT_FEAT_C_CONNECTION);
 		}
+
+		if (total_time >= HUB_DEBOUNCE_TIMEOUT)
+			break;
+		msleep(HUB_DEBOUNCE_STEP);
 	}
 
 	dev_dbg (hubdev (hdev),
-		"debounce: port %d: delay %dms stable %d status 0x%x\n",
-		port + 1, delay_time, stable_count, portstatus);
+		"debounce: port %d: total %dms stable %dms status 0x%x\n",
+		port + 1, total_time, stable_time, portstatus);
 
-	return (portstatus & USB_PORT_STAT_CONNECTION) ? 0 : -ENOTCONN;
+	if (stable_time < HUB_DEBOUNCE_STABLE)
+		return -ETIMEDOUT;
+	return portstatus;
 }
 
 static int hub_set_address(struct usb_device *udev)
@@ -1037,7 +1260,7 @@
 	if (udev->state != USB_STATE_DEFAULT &&
 			udev->state != USB_STATE_ADDRESS)
 		return -EINVAL;
-	retval = usb_control_msg(udev, usb_snddefctrl(udev),
+	retval = usb_control_msg(udev, (PIPE_CONTROL << 30) /* Address 0 */,
 		USB_REQ_SET_ADDRESS, 0, udev->devnum, 0,
 		NULL, 0, HZ * USB_CTRL_SET_TIMEOUT);
 	if (retval == 0)
@@ -1109,33 +1332,9 @@
 	udev->epmaxpacketin [0] = i;
 	udev->epmaxpacketout[0] = i;
  
-	/* set the address */
-	if (udev->devnum <= 0) {
-		usb_choose_address(udev);
-		if (udev->devnum <= 0)
-			goto fail;
-
-		/* Set up TT records, if needed  */
-		if (hdev->tt) {
-			udev->tt = hdev->tt;
-			udev->ttport = hdev->ttport;
-		} else if (udev->speed != USB_SPEED_HIGH
-				&& hdev->speed == USB_SPEED_HIGH) {
-			struct usb_hub	*hub;
- 
-			hub = usb_get_intfdata (hdev->actconfig
-							->interface[0]);
-			udev->tt = &hub->tt;
-			udev->ttport = port + 1;
-		}
-
-		/* force the right log message (below) at low speed */
-		oldspeed = USB_SPEED_UNKNOWN;
-	}
- 
 	dev_info (&udev->dev,
 			"%s %s speed USB device using address %d\n",
-			(oldspeed == USB_SPEED_UNKNOWN) ? "new" : "reset",
+			(udev->config) ? "reset" : "new",
 			({ char *speed; switch (udev->speed) {
 			case USB_SPEED_LOW:	speed = "low";	break;
 			case USB_SPEED_FULL:	speed = "full";	break;
@@ -1164,12 +1363,7 @@
 			dev_err(&udev->dev,
 				"device not accepting address %d, error %d\n",
 				udev->devnum, retval);
- fail:
-			hub_port_disable(hdev, port);
-			usb_release_address(udev);
-			usb_put_dev(udev);
-			up(&usb_address0_sem);
-			return retval;
+			goto fail;
 		}
  
 		/* cope with hardware quirkiness:
@@ -1192,7 +1386,8 @@
 	if (udev->speed == USB_SPEED_FULL
 			&& (udev->epmaxpacketin [0]
 				!= udev->descriptor.bMaxPacketSize0)) {
-		usb_disable_endpoint(udev, 0);
+		usb_disable_endpoint(udev, 0 + USB_DIR_IN);
+		usb_disable_endpoint(udev, 0 + USB_DIR_OUT);
 		usb_endpoint_running(udev, 0, 1);
 		usb_endpoint_running(udev, 0, 0);
 		udev->epmaxpacketin [0] = udev->descriptor.bMaxPacketSize0;
@@ -1210,9 +1405,11 @@
 
 	/* now dev is visible to other tasks */
 	hdev->children[port] = udev;
+	retval = 0;
 
+fail:
 	up(&usb_address0_sem);
-	return 0;
+	return retval;
 }
 
 static void
@@ -1271,7 +1468,14 @@
 	}
 	return remaining;
 }
- 
+
+/* Handle physical or logical connection change events.
+ * This routine is called when:
+ * 	a port connection-change occurs;
+ *	a port enable-change occurs (often caused by EMI);
+ *	usb_reset_device() encounters changed descriptors (as from
+ *		a firmware download)
+ */
 static void hub_port_connect_change(struct usb_hub *hub, int port,
 					u16 portstatus, u16 portchange)
 {
@@ -1282,9 +1486,6 @@
 	dev_dbg (hub_dev,
 		"port %d, status %04x, change %04x, %s\n",
 		port + 1, portstatus, portchange, portspeed (portstatus));
- 
-	/* Clear the connection change status */
-	clear_port_feature(hdev, port + 1, USB_PORT_FEAT_C_CONNECTION);
 
 	if (hub->has_indicators) {
 		set_port_led(hdev, port + 1, HUB_LED_AUTO);
@@ -1295,6 +1496,17 @@
 	if (hdev->children[port])
 		usb_disconnect(&hdev->children[port]);
 
+	if (portchange & USB_PORT_STAT_C_CONNECTION) {
+		status = hub_port_debounce(hdev, port);
+		if (status < 0) {
+			dev_err (hub_dev,
+				"connect-debounce failed, port %d disabled\n",
+				port+1);
+			goto done;
+		}
+		portstatus = status;
+	}
+
 	/* Return now if nothing is connected */
 	if (!(portstatus & USB_PORT_STAT_CONNECTION)) {
 
@@ -1308,13 +1520,6 @@
   			goto done;
 		return;
 	}
-  
-	if (hub_port_debounce(hdev, port)) {
-		dev_err (hub_dev,
-			"connect-debounce failed, port %d disabled\n",
-			port+1);
-		goto done;
-	}
 
 	for (i = 0; i < SET_CONFIG_TRIES; i++) {
 		struct usb_device *udev;
@@ -1329,20 +1534,36 @@
 			goto done;
 		}
 		udev->state = USB_STATE_POWERED;
-	  
+
 		/* hub can tell if it's lowspeed already:  D- pullup (not D+) */
 		if (portstatus & USB_PORT_STAT_LOW_SPEED)
 			udev->speed = USB_SPEED_LOW;
 		else
 			udev->speed = USB_SPEED_UNKNOWN;
 
-		/* reset, set address, get descriptor, add to hub's children */
 		down (&udev->serialize);
+ 
+		/* set the address */
+		choose_address(udev);
+		if (udev->devnum <= 0) {
+			status = -ENOTCONN;	/* Don't retry */
+			goto loop;
+		}
+
+		/* reset, get descriptor, add to hub's children */
 		status = hub_port_init(hdev, udev, port);
-		if (status == -ENOTCONN)
-			break;
 		if (status < 0)
-			continue;
+			goto loop;
+
+		/* Set up TT records, if needed  */
+		if (hdev->tt) {
+			udev->tt = hdev->tt;
+			udev->ttport = hdev->ttport;
+		} else if (udev->speed != USB_SPEED_HIGH
+				&& hdev->speed == USB_SPEED_HIGH) {
+			udev->tt = &hub->tt;
+			udev->ttport = port + 1;
+		}
 
 		/* consecutive bus-powered hubs aren't reliable; they can
 		 * violate the voltage drop budget.  if the new child has
@@ -1358,7 +1579,7 @@
 					&devstat);
 			if (status < 0) {
 				dev_dbg(&udev->dev, "get status %d ?\n", status);
-				continue;
+				goto loop;
 			}
 			cpu_to_le16s(&devstat);
 			if ((devstat & (1 << USB_DEVICE_SELF_POWERED)) == 0) {
@@ -1370,10 +1591,8 @@
 						INDICATOR_AMBER_BLINK;
 					schedule_work (&hub->leds);
 				}
-				hdev->children[port] = NULL;
-				usb_put_dev(udev);
-				hub_port_disable(hdev, port);
-				return;
+				status = -ENOTCONN;	/* Don't retry */
+				goto loop;
 			}
 		}
  
@@ -1385,11 +1604,8 @@
 
 		/* Run it through the hoops (find a driver, etc) */
 		status = usb_new_device(udev);
-		if (status != 0) {
-			hdev->children[port] = NULL;
-			continue;
-		}
-		up (&udev->serialize);
+		if (status)
+			goto loop;
 
 		status = hub_power_remaining(hub, hdev);
 		if (status)
@@ -1397,7 +1613,19 @@
 				"%dmA power budget left\n",
 				2 * status);
 
+		up (&udev->serialize);
 		return;
+
+loop:
+		hdev->children[port] = NULL;
+		hub_port_disable(hdev, port);
+		usb_disable_endpoint(udev, 0 + USB_DIR_IN);
+		usb_disable_endpoint(udev, 0 + USB_DIR_OUT);
+		release_address(udev);
+		up (&udev->serialize);
+		usb_put_dev(udev);
+		if (status == -ENOTCONN)
+			break;
 	}
  
 done:
@@ -1416,6 +1644,7 @@
 	u16 portstatus;
 	u16 portchange;
 	int i, ret;
+	int connect_change;
 
 	/*
 	 *  We restart the list every time to avoid a deadlock with
@@ -1461,16 +1690,22 @@
 
 		for (i = 0; i < hub->descriptor->bNbrPorts; i++) {
 			ret = hub_port_status(hdev, i, &portstatus, &portchange);
-			if (ret < 0) {
+			if (ret < 0)
 				continue;
-			}
+			connect_change = 0;
 
 			if (portchange & USB_PORT_STAT_C_CONNECTION) {
-				hub_port_connect_change(hub, i, portstatus, portchange);
-			} else if (portchange & USB_PORT_STAT_C_ENABLE) {
-				dev_dbg (hub_dev,
-					"port %d enable change, status %08x\n",
-					i + 1, portstatus);
+				clear_port_feature(hdev,
+					i + 1, USB_PORT_FEAT_C_CONNECTION);
+				connect_change = 1;
+			}
+
+			if (portchange & USB_PORT_STAT_C_ENABLE) {
+				if (!connect_change)
+					dev_dbg (hub_dev,
+						"port %d enable change, "
+						"status %08x\n",
+						i + 1, portstatus);
 				clear_port_feature(hdev,
 					i + 1, USB_PORT_FEAT_C_ENABLE);
 
@@ -1481,15 +1716,14 @@
 				 * Works at least with mouse driver. 
 				 */
 				if (!(portstatus & USB_PORT_STAT_ENABLE)
-				    && (portstatus & USB_PORT_STAT_CONNECTION)
-				    && (hdev->children[i])) {
+				    && !connect_change
+				    && hdev->children[i]) {
 					dev_err (hub_dev,
 					    "port %i "
 					    "disabled by hub (EMI?), "
 					    "re-enabling...",
 						i + 1);
-					hub_port_connect_change(hub,
-						i, portstatus, portchange);
+					connect_change = 1;
 				}
 			}
 
@@ -1517,6 +1751,10 @@
 				clear_port_feature(hdev,
 					i + 1, USB_PORT_FEAT_C_RESET);
 			}
+
+			if (connect_change)
+				hub_port_connect_change(hub, i,
+						portstatus, portchange);
 		} /* end for i */
 
 		/* deal with hub status changes */
@@ -1581,9 +1819,6 @@
 	.id_table =	hub_id_table,
 };
 
-/*
- * This should be a separate module.
- */
 int usb_hub_init(void)
 {
 	pid_t pid;
--- diff/drivers/usb/core/hub.h	2004-06-11 19:17:31.000000000 +0100
+++ source/drivers/usb/core/hub.h	2004-06-11 19:22:05.000000000 +0100
@@ -202,7 +202,6 @@
 	int			error;		/* last reported error */
 	int			nerrors;	/* track consecutive errors */
 
-	struct list_head	hub_list;	/* all hubs */
 	struct list_head	event_list;	/* hubs w/data or errs ready */
 
 	struct usb_hub_descriptor *descriptor;	/* class descriptor */
@@ -216,4 +215,15 @@
 	struct work_struct	leds;
 };
 
+/* use this for low-powered root hubs */
+static inline void
+hub_set_power_budget (struct usb_device *hubdev, unsigned mA)
+{
+	struct usb_hub	*hub;
+
+	hub = (struct usb_hub *)
+		usb_get_intfdata (hubdev->actconfig->interface[0]);
+	hub->power_budget = min(mA,(unsigned)500)/2;
+}
+
 #endif /* __LINUX_HUB_H */
--- diff/drivers/usb/core/message.c	2004-06-11 19:17:31.000000000 +0100
+++ source/drivers/usb/core/message.c	2004-06-11 19:22:05.000000000 +0100
@@ -566,22 +566,19 @@
  */
 int usb_get_descriptor(struct usb_device *dev, unsigned char type, unsigned char index, void *buf, int size)
 {
-	int i = 5;
+	int i;
 	int result;
 	
 	memset(buf,0,size);	// Make sure we parse really received data
 
-	while (i--) {
+	for (i = 0; i < 3; ++i) {
 		/* retry on length 0 or stall; some devices are flakey */
-		if ((result = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
-				    USB_REQ_GET_DESCRIPTOR, USB_DIR_IN,
-				    (type << 8) + index, 0, buf, size,
-				    HZ * USB_CTRL_GET_TIMEOUT)) > 0
-				|| result != -EPIPE)
+		result = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
+				USB_REQ_GET_DESCRIPTOR, USB_DIR_IN,
+				(type << 8) + index, 0, buf, size,
+				HZ * USB_CTRL_GET_TIMEOUT);
+		if (!(result == 0 || result == -EPIPE))
 			break;
-
-		dev_dbg (&dev->dev, "RETRY descriptor, result %d\n", result);
-		result = -ENOMSG;
 	}
 	return result;
 }
@@ -830,6 +827,7 @@
 			interface = dev->actconfig->interface[i];
 			dev_dbg (&dev->dev, "unregistering interface %s\n",
 				interface->dev.bus_id);
+			usb_remove_sysfs_intf_files(interface);
 			device_del (&interface->dev);
 		}
 
--- diff/drivers/usb/core/sysfs.c	2004-06-11 19:17:31.000000000 +0100
+++ source/drivers/usb/core/sysfs.c	2004-06-11 19:22:05.000000000 +0100
@@ -2,8 +2,8 @@
  * drivers/usb/core/sysfs.c
  *
  * (C) Copyright 2002 David Brownell
- * (C) Copyright 2002 Greg Kroah-Hartman
- * (C) Copyright 2002 IBM Corp.
+ * (C) Copyright 2002,2004 Greg Kroah-Hartman
+ * (C) Copyright 2002,2004 IBM Corp.
  *
  * All of the sysfs file attributes for usb devices and interfaces.
  *
@@ -162,29 +162,35 @@
 usb_descriptor_attr (bDeviceProtocol, "%02x\n")
 usb_descriptor_attr (bNumConfigurations, "%d\n")
 
+static struct attribute *dev_attrs[] = {
+	/* current configuration's attributes */
+	&dev_attr_bNumInterfaces.attr,
+	&dev_attr_bConfigurationValue.attr,
+	&dev_attr_bmAttributes.attr,
+	&dev_attr_bMaxPower.attr,
+	/* device attributes */
+	&dev_attr_idVendor.attr,
+	&dev_attr_idProduct.attr,
+	&dev_attr_bcdDevice.attr,
+	&dev_attr_bDeviceClass.attr,
+	&dev_attr_bDeviceSubClass.attr,
+	&dev_attr_bDeviceProtocol.attr,
+	&dev_attr_bNumConfigurations.attr,
+	&dev_attr_speed.attr,
+	&dev_attr_devnum.attr,
+	&dev_attr_version.attr,
+	&dev_attr_maxchild.attr,
+	NULL,
+};
+static struct attribute_group dev_attr_grp = {
+	.attrs = dev_attrs,
+};
 
 void usb_create_sysfs_dev_files (struct usb_device *udev)
 {
 	struct device *dev = &udev->dev;
 
-	/* current configuration's attributes */
-	device_create_file (dev, &dev_attr_bNumInterfaces);
-	device_create_file (dev, &dev_attr_bConfigurationValue);
-	device_create_file (dev, &dev_attr_bmAttributes);
-	device_create_file (dev, &dev_attr_bMaxPower);
-
-	/* device attributes */
-	device_create_file (dev, &dev_attr_idVendor);
-	device_create_file (dev, &dev_attr_idProduct);
-	device_create_file (dev, &dev_attr_bcdDevice);
-	device_create_file (dev, &dev_attr_bDeviceClass);
-	device_create_file (dev, &dev_attr_bDeviceSubClass);
-	device_create_file (dev, &dev_attr_bDeviceProtocol);
-	device_create_file (dev, &dev_attr_bNumConfigurations);
-
-	/* speed varies depending on how you connect the device */
-	device_create_file (dev, &dev_attr_speed);
-	// FIXME iff there are other speed configs, show how many
+	sysfs_create_group(&dev->kobj, &dev_attr_grp);
 
 	if (udev->descriptor.iManufacturer)
 		device_create_file (dev, &dev_attr_manufacturer);
@@ -192,10 +198,20 @@
 		device_create_file (dev, &dev_attr_product);
 	if (udev->descriptor.iSerialNumber)
 		device_create_file (dev, &dev_attr_serial);
+}
+
+void usb_remove_sysfs_dev_files (struct usb_device *udev)
+{
+	struct device *dev = &udev->dev;
 
-	device_create_file (dev, &dev_attr_devnum);
-	device_create_file (dev, &dev_attr_version);
-	device_create_file (dev, &dev_attr_maxchild);
+	sysfs_remove_group(&dev->kobj, &dev_attr_grp);
+
+	if (udev->descriptor.iManufacturer)
+		device_remove_file(dev, &dev_attr_manufacturer);
+	if (udev->descriptor.iProduct)
+		device_remove_file(dev, &dev_attr_product);
+	if (udev->descriptor.iSerialNumber)
+		device_remove_file(dev, &dev_attr_serial);
 }
 
 /* Interface fields */
@@ -217,13 +233,26 @@
 usb_intf_attr (bInterfaceProtocol, "%02x\n")
 usb_intf_attr (iInterface, "%02x\n")
 
+static struct attribute *intf_attrs[] = {
+	&dev_attr_bInterfaceNumber.attr,
+	&dev_attr_bAlternateSetting.attr,
+	&dev_attr_bNumEndpoints.attr,
+	&dev_attr_bInterfaceClass.attr,
+	&dev_attr_bInterfaceSubClass.attr,
+	&dev_attr_bInterfaceProtocol.attr,
+	&dev_attr_iInterface.attr,
+	NULL,
+};
+static struct attribute_group intf_attr_grp = {
+	.attrs = intf_attrs,
+};
+
 void usb_create_sysfs_intf_files (struct usb_interface *intf)
 {
-	device_create_file (&intf->dev, &dev_attr_bInterfaceNumber);
-	device_create_file (&intf->dev, &dev_attr_bAlternateSetting);
-	device_create_file (&intf->dev, &dev_attr_bNumEndpoints);
-	device_create_file (&intf->dev, &dev_attr_bInterfaceClass);
-	device_create_file (&intf->dev, &dev_attr_bInterfaceSubClass);
-	device_create_file (&intf->dev, &dev_attr_bInterfaceProtocol);
-	device_create_file (&intf->dev, &dev_attr_iInterface);
+	sysfs_create_group(&intf->dev.kobj, &intf_attr_grp);
+}
+
+void usb_remove_sysfs_intf_files (struct usb_interface *intf)
+{
+	sysfs_remove_group(&intf->dev.kobj, &intf_attr_grp);
 }
--- diff/drivers/usb/core/usb.c	2004-06-11 19:17:31.000000000 +0100
+++ source/drivers/usb/core/usb.c	2004-06-11 19:22:05.000000000 +0100
@@ -945,235 +945,6 @@
 }
 
 /**
- * usb_disconnect - disconnect a device (usbcore-internal)
- * @pdev: pointer to device being disconnected
- * Context: !in_interrupt ()
- *
- * Something got disconnected. Get rid of it, and all of its children.
- *
- * Only hub drivers (including virtual root hub drivers for host
- * controllers) should ever call this.
- *
- * This call is synchronous, and may not be used in an interrupt context.
- */
-void usb_disconnect(struct usb_device **pdev)
-{
-	struct usb_device	*dev = *pdev;
-	struct usb_bus		*bus;
-	struct usb_operations	*ops;
-	int			i;
-
-	might_sleep ();
-
-	if (!dev) {
-		pr_debug ("%s nodev\n", __FUNCTION__);
-		return;
-	}
-	bus = dev->bus;
-	if (!bus) {
-		pr_debug ("%s nobus\n", __FUNCTION__);
-		return;
-	}
-	ops = bus->op;
-
-	*pdev = NULL;
-
-	/* mark the device as inactive, so any further urb submissions for
-	 * this device will fail.
-	 */
-	dev->state = USB_STATE_NOTATTACHED;
-	down(&dev->serialize);
-
-	dev_info (&dev->dev, "USB disconnect, address %d\n", dev->devnum);
-
-	/* Free up all the children before we remove this device */
-	for (i = 0; i < USB_MAXCHILDREN; i++) {
-		struct usb_device **child = dev->children + i;
-		if (*child)
-			usb_disconnect(child);
-	}
-
-	/* deallocate hcd/hardware state ... nuking all pending urbs and
-	 * cleaning up all state associated with the current configuration
-	 */
-	usb_disable_device(dev, 0);
-
-	/* Free the device number and remove the /proc/bus/usb entry */
-	dev_dbg (&dev->dev, "unregistering device\n");
-	usb_release_address(dev);
-	usbfs_remove_device(dev);
-	up(&dev->serialize);
-	device_unregister(&dev->dev);
-}
-
-/**
- * usb_choose_address - pick device address (usbcore-internal)
- * @dev: newly detected device (in DEFAULT state)
- *
- * Picks a device address.  It's up to the hub (or root hub) driver
- * to handle and manage enumeration, starting from the DEFAULT state.
- * Only hub drivers (but not virtual root hub drivers for host
- * controllers) should ever call this.
- */
-void usb_choose_address(struct usb_device *dev)
-{
-	int devnum;
-	// FIXME needs locking for SMP!!
-	/* why? this is called only from the hub thread, 
-	 * which hopefully doesn't run on multiple CPU's simultaneously 8-)
-	 */
-
-	/* Try to allocate the next devnum beginning at bus->devnum_next. */
-	devnum = find_next_zero_bit(dev->bus->devmap.devicemap, 128, dev->bus->devnum_next);
-	if (devnum >= 128)
-		devnum = find_next_zero_bit(dev->bus->devmap.devicemap, 128, 1);
-
-	dev->bus->devnum_next = ( devnum >= 127 ? 1 : devnum + 1);
-
-	if (devnum < 128) {
-		set_bit(devnum, dev->bus->devmap.devicemap);
-		dev->devnum = devnum;
-	}
-}
-
-/**
- * usb_release_address - deallocate device address (usbcore-internal)
- * @dev: newly removed device
- *
- * Removes and deallocates the address assigned to a device.
- * Only hub drivers (but not virtual root hub drivers for host
- * controllers) should ever call this.
- */
-void usb_release_address(struct usb_device *dev)
-{
-	if (dev->devnum > 0) {
-		clear_bit(dev->devnum, dev->bus->devmap.devicemap);
-		dev->devnum = -1;
-	}
-}
-
-
-static inline void usb_show_string(struct usb_device *dev, char *id, int index)
-{
-	char *buf;
-
-	if (!index)
-		return;
-	if (!(buf = kmalloc(256, GFP_KERNEL)))
-		return;
-	if (usb_string(dev, index, buf, 256) > 0)
-		dev_printk(KERN_INFO, &dev->dev, "%s: %s\n", id, buf);
-	kfree(buf);
-}
-
-static int usb_choose_configuration(struct usb_device *dev)
-{
-	int c, i;
-
-	c = dev->config[0].desc.bConfigurationValue;
-	if (dev->descriptor.bNumConfigurations != 1) {
-		for (i = 0; i < dev->descriptor.bNumConfigurations; i++) {
-			struct usb_interface_descriptor	*desc;
-
-			/* heuristic:  Linux is more likely to have class
-			 * drivers, so avoid vendor-specific interfaces.
-			 */
-			desc = &dev->config[i].intf_cache[0]
-					->altsetting->desc;
-			if (desc->bInterfaceClass == USB_CLASS_VENDOR_SPEC)
-				continue;
-			/* COMM/2/all is CDC ACM, except 0xff is MSFT RNDIS */
-			if (desc->bInterfaceClass == USB_CLASS_COMM
-					&& desc->bInterfaceSubClass == 2
-					&& desc->bInterfaceProtocol == 0xff)
-				continue;
-			c = dev->config[i].desc.bConfigurationValue;
-			break;
-		}
-		dev_info(&dev->dev,
-			"configuration #%d chosen from %d choices\n",
-			c, dev->descriptor.bNumConfigurations);
-	}
-	return c;
-}
-
-/*
- * usb_new_device - perform initial device setup (usbcore-internal)
- * @dev: newly addressed device (in ADDRESS state)
- *
- * This is called with devices which have been enumerated, but not yet
- * configured.  The device descriptor is available, but not descriptors
- * for any device configuration.  The caller owns dev->serialize, and
- * the device is not visible through sysfs or other filesystem code.
- *
- * Returns 0 for success (device is configured and listed, with its
- * interfaces, in sysfs); else a negative errno value.  On error, one
- * reference count to the device has been dropped.
- *
- * This call is synchronous, and may not be used in an interrupt context.
- *
- * Only the hub driver should ever call this; root hub registration
- * uses it only indirectly.
- */
-int usb_new_device(struct usb_device *dev)
-{
-	int err;
-	int c;
-
-	err = usb_get_configuration(dev);
-	if (err < 0) {
-		dev_err(&dev->dev, "can't read configurations, error %d\n",
-			err);
-		goto fail;
-	}
-
-	/* Tell the world! */
-	dev_dbg(&dev->dev, "new device strings: Mfr=%d, Product=%d, SerialNumber=%d\n",
-		dev->descriptor.iManufacturer, dev->descriptor.iProduct, dev->descriptor.iSerialNumber);
-
-#ifdef DEBUG
-	if (dev->descriptor.iProduct)
-		usb_show_string(dev, "Product", dev->descriptor.iProduct);
-	if (dev->descriptor.iManufacturer)
-		usb_show_string(dev, "Manufacturer", dev->descriptor.iManufacturer);
-	if (dev->descriptor.iSerialNumber)
-		usb_show_string(dev, "SerialNumber", dev->descriptor.iSerialNumber);
-#endif
-
-	/* put device-specific files into sysfs */
-	err = device_add (&dev->dev);
-	if (err) {
-		dev_err(&dev->dev, "can't device_add, error %d\n", err);
-		goto fail;
-	}
-	usb_create_sysfs_dev_files (dev);
-
-	/* choose and set the configuration. that registers the interfaces
-	 * with the driver core, and lets usb device drivers bind to them.
-	 * NOTE:  should interact with hub power budgeting.
-	 */
-	c = usb_choose_configuration(dev);
-	err = usb_set_configuration(dev, c);
-	if (err) {
-		dev_err(&dev->dev, "can't set config #%d, error %d\n", c, err);
-		device_del(&dev->dev);
-		goto fail;
-	}
-
-	/* USB device state == configured ... usable */
-
-	/* add a /proc/bus/usb entry */
-	usbfs_add_device(dev);
-
-	return 0;
-fail:
-	dev->state = USB_STATE_NOTATTACHED;
-	usb_release_address(dev);
-	usb_put_dev(dev);
-	return err;
-}
-
-/**
  * usb_buffer_alloc - allocate dma-consistent buffer for URB_NO_xxx_DMA_MAP
  * @dev: device the buffer will be used with
  * @size: requested buffer size
--- diff/drivers/usb/core/usb.h	2004-06-11 19:17:31.000000000 +0100
+++ source/drivers/usb/core/usb.h	2004-06-11 19:22:05.000000000 +0100
@@ -1,7 +1,9 @@
 /* Functions local to drivers/usb/core/ */
 
 extern void usb_create_sysfs_dev_files (struct usb_device *dev);
+extern void usb_remove_sysfs_dev_files (struct usb_device *dev);
 extern void usb_create_sysfs_intf_files (struct usb_interface *intf);
+extern void usb_remove_sysfs_intf_files (struct usb_interface *intf);
 extern int usb_probe_interface (struct device *dev);
 extern int usb_unbind_interface (struct device *dev);
 
--- diff/drivers/usb/gadget/dummy_hcd.c	2004-06-11 19:17:31.000000000 +0100
+++ source/drivers/usb/gadget/dummy_hcd.c	2004-06-11 19:22:05.000000000 +0100
@@ -825,8 +825,7 @@
 	dum = container_of (hcd, struct dummy, hcd);
 	spin_lock_irqsave (&dum->lock, flags);
 
-	if (!dum->hdev)
-		dum->hdev = urb->dev->hcpriv;
+	dum->hdev = urb->dev->hcpriv;
 	urb->hcpriv = dum;
 	if (usb_pipetype (urb->pipe) == PIPE_CONTROL)
 		urb->error_count = 1;		/* mark as a new urb */
@@ -994,10 +993,17 @@
 	return limit;
 }
 
+#define is_active(dum)	((dum->port_status & \
+		(USB_PORT_STAT_CONNECTION | USB_PORT_STAT_ENABLE | \
+			USB_PORT_STAT_SUSPEND)) \
+		== (USB_PORT_STAT_CONNECTION | USB_PORT_STAT_ENABLE))
+
 static struct dummy_ep *find_endpoint (struct dummy *dum, u8 address)
 {
 	int		i;
 
+	if (!is_active (dum))
+		return NULL;
 	if ((address & ~USB_DIR_IN) == 0)
 		return &dum->ep [0];
 	for (i = 1; i < DUMMY_ENDPOINTS; i++) {
@@ -1011,6 +1017,8 @@
 	return NULL;
 }
 
+#undef is_active
+
 #define Dev_Request	(USB_TYPE_STANDARD | USB_RECIP_DEVICE)
 #define Dev_InRequest	(Dev_Request | USB_DIR_IN)
 #define Intf_Request	(USB_TYPE_STANDARD | USB_RECIP_INTERFACE)
@@ -1404,9 +1412,8 @@
 			break;
 		case USB_PORT_FEAT_POWER:
 			dum->port_status = 0;
-			dum->address = 0;
-			dum->hdev = 0;
 			dum->resuming = 0;
+			stop_activity(dum, dum->driver);
 			break;
 		default:
 			dum->port_status &= ~(1 << wValue);
@@ -1679,6 +1686,9 @@
 		goto clean1;
 	}
 
+	/* only show a low-power port: just 8mA */
+	hub_set_power_budget (root, 8);
+
 	dum->started = 1;
 
 	if ((retval = dummy_register_udc (dum)) != 0) {
--- diff/drivers/usb/gadget/ether.c	2004-06-11 19:17:31.000000000 +0100
+++ source/drivers/usb/gadget/ether.c	2004-06-11 19:22:05.000000000 +0100
@@ -118,6 +118,7 @@
 	unsigned		zlp:1;
 	unsigned		cdc:1;
 	unsigned		rndis:1;
+	unsigned		suspended:1;
 	u16			cdc_filter;
 	unsigned long		todo;
 #define	WORK_RX_MEMORY		0
@@ -1345,24 +1346,23 @@
 
 static void rndis_response_complete (struct usb_ep *ep, struct usb_request *req)
 {
-	struct eth_dev          *dev = ep->driver_data;
-	
 	if (req->status || req->actual != req->length)
 		DEBUG (dev, "rndis response complete --> %d, %d/%d\n",
 		       req->status, req->actual, req->length);
 
 	/* done sending after CDC_GET_ENCAPSULATED_RESPONSE */
-	rndis_free_response (dev->rndis_config, req->buf);
 }
 
 static void rndis_command_complete (struct usb_ep *ep, struct usb_request *req)
 {
 	struct eth_dev          *dev = ep->driver_data;
+	int			status;
 	
 	/* received RNDIS command from CDC_SEND_ENCAPSULATED_COMMAND */
 	spin_lock(&dev->lock);
-	if (rndis_msg_parser (dev->rndis_config, (u8 *) req->buf))
-		ERROR(dev, "%s: rndis parse error\n", __FUNCTION__ );
+	status = rndis_msg_parser (dev->rndis_config, (u8 *) req->buf);
+	if (status < 0)
+		ERROR(dev, "%s: rndis parse error %d\n", __FUNCTION__, status);
 	spin_unlock(&dev->lock);
 }
 
@@ -1580,6 +1580,7 @@
 			if (buf) {
 				memcpy (req->buf, buf, value);
 				req->complete = rndis_response_complete;
+				rndis_free_response(dev->rndis_config, buf);
 			}
 			/* else stalls ... spec says to avoid that */
 		}
@@ -2064,6 +2065,16 @@
 	}
 }
 
+static void rndis_control_ack_complete (struct usb_ep *ep, struct usb_request *req)
+{
+	if (req->status || req->actual != req->length)
+		DEBUG (dev, "rndis control ack complete --> %d, %d/%d\n",
+		       req->status, req->actual, req->length);
+
+	usb_ep_free_buffer(ep, req->buf, req->dma, 8);
+	usb_ep_free_request(ep, req);
+}
+
 static int rndis_control_ack (struct net_device *net)
 {
 	struct eth_dev          *dev = (struct eth_dev *) net->priv;
@@ -2095,7 +2106,7 @@
 	 * CDC_NOTIFY_RESPONSE_AVAILABLE should work too
 	 */
 	resp->length = 8;
-	resp->complete = rndis_response_complete;
+	resp->complete = rndis_control_ack_complete;
 	
 	*((u32 *) resp->buf) = __constant_cpu_to_le32 (1);
 	*((u32 *) resp->buf + 1) = __constant_cpu_to_le32 (0);
@@ -2103,7 +2114,7 @@
 	length = usb_ep_queue (dev->status_ep, resp, GFP_ATOMIC);
 	if (length < 0) {
 		resp->status = 0;
-		rndis_response_complete (dev->status_ep, resp);
+		rndis_control_ack_complete (dev->status_ep, resp);
 	}
 	
 	return 0;
@@ -2302,17 +2313,6 @@
 		UTS_SYSNAME " " UTS_RELEASE "/%s",
 		gadget->name);
 
-	/* CDC subset ... recognized by Linux since 2.4.10, but Windows
-	 * drivers aren't widely available.
-	 */
-	if (!cdc) {
-		device_desc.bDeviceClass = USB_CLASS_VENDOR_SPEC;
-		device_desc.idVendor =
-			__constant_cpu_to_le16(SIMPLE_VENDOR_NUM);
-		device_desc.idProduct =
-			__constant_cpu_to_le16(SIMPLE_PRODUCT_NUM);
-	}
-
 	/* If there's an RNDIS configuration, that's what Windows wants to
 	 * be using ... so use these product IDs here and in the "linux.inf"
 	 * needed to install MSFT drivers.  Current Linux kernels will use
@@ -2326,6 +2326,16 @@
 			__constant_cpu_to_le16(RNDIS_PRODUCT_NUM);
 		snprintf (product_desc, sizeof product_desc,
 			"RNDIS/%s", driver_desc);
+
+	/* CDC subset ... recognized by Linux since 2.4.10, but Windows
+	 * drivers aren't widely available.
+	 */
+	} else if (!cdc) {
+		device_desc.bDeviceClass = USB_CLASS_VENDOR_SPEC;
+		device_desc.idVendor =
+			__constant_cpu_to_le16(SIMPLE_VENDOR_NUM);
+		device_desc.idProduct =
+			__constant_cpu_to_le16(SIMPLE_PRODUCT_NUM);
 	}
 
 	/* support optional vendor/distro customization */
@@ -2554,6 +2564,26 @@
 
 /*-------------------------------------------------------------------------*/
 
+static void
+eth_suspend (struct usb_gadget *gadget)
+{
+	struct eth_dev		*dev = get_gadget_data (gadget);
+
+	DEBUG (dev, "suspend\n");
+	dev->suspended = 1;
+}
+
+static void
+eth_resume (struct usb_gadget *gadget)
+{
+	struct eth_dev		*dev = get_gadget_data (gadget);
+
+	DEBUG (dev, "resume\n");
+	dev->suspended = 0;
+}
+
+/*-------------------------------------------------------------------------*/
+
 static struct usb_gadget_driver eth_driver = {
 #ifdef CONFIG_USB_GADGET_DUALSPEED
 	.speed		= USB_SPEED_HIGH,
@@ -2567,6 +2597,9 @@
 	.setup		= eth_setup,
 	.disconnect	= eth_disconnect,
 
+	.suspend	= eth_suspend,
+	.resume		= eth_resume,
+
 	.driver 	= {
 		.name		= (char *) shortname,
 		// .shutdown = ...
--- diff/drivers/usb/gadget/file_storage.c	2004-06-11 19:17:31.000000000 +0100
+++ source/drivers/usb/gadget/file_storage.c	2004-06-11 19:22:05.000000000 +0100
@@ -3834,6 +3834,7 @@
 	}
 
 	/* Find all the endpoints we will use */
+	usb_ep_autoconfig_reset(gadget);
 	ep = usb_ep_autoconfig(gadget, &fs_bulk_in_desc);
 	if (!ep)
 		goto autoconf_fail;
--- diff/drivers/usb/gadget/ndis.h	2004-05-19 22:12:17.000000000 +0100
+++ source/drivers/usb/gadget/ndis.h	2004-06-11 19:22:05.000000000 +0100
@@ -26,11 +26,41 @@
 #define NDIS_STATUS_MULTICAST_EXISTS      0xC001000A
 #define NDIS_STATUS_MULTICAST_NOT_FOUND   0xC001000B
 
+enum NDIS_DEVICE_POWER_STATE {
+	NdisDeviceStateUnspecified = 0,
+	NdisDeviceStateD0,
+	NdisDeviceStateD1,
+	NdisDeviceStateD2,
+	NdisDeviceStateD3,
+	NdisDeviceStateMaximum
+};
+
+struct NDIS_PM_WAKE_UP_CAPABILITIES {
+	enum NDIS_DEVICE_POWER_STATE  MinMagicPacketWakeUp;
+	enum NDIS_DEVICE_POWER_STATE  MinPatternWakeUp;
+	enum NDIS_DEVICE_POWER_STATE  MinLinkChangeWakeUp;
+};
+
 /* NDIS_PNP_CAPABILITIES.Flags constants */
 #define NDIS_DEVICE_WAKE_UP_ENABLE                0x00000001
 #define NDIS_DEVICE_WAKE_ON_PATTERN_MATCH_ENABLE  0x00000002
 #define NDIS_DEVICE_WAKE_ON_MAGIC_PACKET_ENABLE   0x00000004
 
+struct NDIS_PNP_CAPABILITIES {
+	u32					Flags;
+	struct NDIS_PM_WAKE_UP_CAPABILITIES	WakeUpCapabilities;
+};
+
+struct NDIS_PM_PACKET_PATTERN {
+	u32	Priority;
+	u32	Reserved;
+	u32	MaskSize;
+	u32	PatternOffset;
+	u32	PatternSize;
+	u32	PatternFlags;
+};
+
+
 /* Required Object IDs (OIDs) */
 #define OID_GEN_SUPPORTED_LIST            0x00010101
 #define OID_GEN_HARDWARE_STATUS           0x00010102
--- diff/drivers/usb/gadget/net2280.c	2004-05-19 22:12:17.000000000 +0100
+++ source/drivers/usb/gadget/net2280.c	2004-06-11 19:22:05.000000000 +0100
@@ -1902,6 +1902,8 @@
 		, &dev->usb->stdrsp);
 	writel (  (1 << USB_ROOT_PORT_WAKEUP_ENABLE)
 		| (1 << SELF_POWERED_USB_DEVICE)
+		/* erratum 0102 workaround */
+		| ((dev->chiprev == 0100) ? 0 : 1) << SUSPEND_IMMEDIATELY
 		| (1 << REMOTE_WAKEUP_SUPPORT)
 		| (1 << USB_DETECT_ENABLE)
 		| (1 << SELF_POWERED_STATUS)
@@ -1917,6 +1919,7 @@
 		| (1 << PCI_RETRY_ABORT_INTERRUPT_ENABLE)
 		| (1 << VBUS_INTERRUPT_ENABLE)
 		| (1 << ROOT_PORT_RESET_INTERRUPT_ENABLE)
+		| (1 << SUSPEND_REQUEST_CHANGE_INTERRUPT_ENABLE)
 		, &dev->regs->pciirqenb1);
 
 	/* don't leave any writes posted */
@@ -2513,19 +2516,24 @@
 			return;
 	}
 
-	/* NOTE: we don't actually suspend the hardware; that starts to
-	 * interact with PCI power management, and needs something like a
-	 * controller->suspend() call to clear SUSPEND_REQUEST_INTERRUPT.
-	 * we shouldn't see resume interrupts.
-	 * for rev 0100, this also avoids erratum 0102.
+	/* NOTE: chip stays in PCI D0 state for now, but it could
+	 * enter D1 to save more power
 	 */
 	tmp = (1 << SUSPEND_REQUEST_CHANGE_INTERRUPT);
 	if (stat & tmp) {
-		if (dev->driver->suspend)
-			dev->driver->suspend (&dev->gadget);
+		writel (tmp, &dev->regs->irqstat1);
+		if (stat & (1 << SUSPEND_REQUEST_INTERRUPT)) {
+			if (dev->driver->suspend)
+				dev->driver->suspend (&dev->gadget);
+			/* we use SUSPEND_IMMEDIATELY */
+			stat &= ~(1 << SUSPEND_REQUEST_INTERRUPT);
+		} else {
+			if (dev->driver->resume)
+				dev->driver->resume (&dev->gadget);
+			/* at high speed, note erratum 0133 */
+		}
 		stat &= ~tmp;
 	}
-	stat &= ~(1 << SUSPEND_REQUEST_INTERRUPT);
 
 	/* clear any other status/irqs */
 	if (stat)
@@ -2533,6 +2541,7 @@
 
 	/* some status we can just ignore */
 	stat &= ~((1 << CONTROL_STATUS_INTERRUPT)
+			| (1 << SUSPEND_REQUEST_INTERRUPT)
 			| (1 << RESUME_INTERRUPT)
 			| (1 << SOF_INTERRUPT));
 	if (!stat)
--- diff/drivers/usb/gadget/rndis.c	2004-06-11 19:17:31.000000000 +0100
+++ source/drivers/usb/gadget/rndis.c	2004-06-11 19:22:05.000000000 +0100
@@ -18,6 +18,9 @@
  * 
  * 03/25/2004 Kai-Uwe Bloem <linux-development@auerswald.de>
  * 		Fixed rndis_rm_hdr length bug.
+ *
+ * Copyright (C) 2004 by David Brownell
+ *		updates to merge with Linux 2.6, better match RNDIS spec
  */
 
 #include <linux/config.h>
@@ -35,28 +38,34 @@
 #include <asm/byteorder.h>
 #include <asm/system.h>
 
+
+#undef	RNDIS_PM
+#undef	VERBOSE
+
 #include "rndis.h"
 
 
 /* The driver for your USB chip needs to support ep0 OUT to work with
- * RNDIS, plus the same three descriptors as CDC Ethernet.
+ * RNDIS, plus all three CDC Ethernet endpoints (interrupt not optional).
  *
  * Windows hosts need an INF file like Documentation/usb/linux.inf
+ * and will be happier if you provide the host_addr module parameter.
  */
 
-#ifndef	__LITTLE_ENDIAN
-#warning this code is missing all cpu_to_leXX() calls ...
-#endif
-
 #if 0
-#define DEBUG if (rndis_debug) printk 
+#define DEBUG(str,args...) do { \
+	if (rndis_debug) \
+		printk(KERN_DEBUG str , ## args ); \
+	} while (0)
 static int rndis_debug = 0;
 
 module_param (rndis_debug, bool, 0);
 MODULE_PARM_DESC (rndis_debug, "enable debugging");
 
 #else
-#define DEBUG(str,args...) do{}while(0)
+
+#define rndis_debug		0
+#define DEBUG(str,args...)	do{}while(0)
 #endif
 
 #define RNDIS_MAX_CONFIGS	1
@@ -79,16 +88,14 @@
 
 static rndis_resp_t *rndis_add_response (int configNr, u32 length);
 
-/* FIXME OMITTED OIDs, that RNDIS-on-USB "must" support, include
- *  - power management (OID_PNP_CAPABILITIES, ...)
- *  - network wakeup (OID_PNP_ENABLE_WAKE_UP, ...)
- */
 
 /* NDIS Functions */
 static int gen_ndis_query_resp (int configNr, u32 OID, rndis_resp_t *r)
 {
 	int 			retval = -ENOTSUPP;
 	u32 			length = 0;
+	u32			*tmp;
+	int			i, count;
 	rndis_query_cmplt_type	*resp;
 
 	if (!r) return -ENOMEM;
@@ -97,11 +104,17 @@
 	if (!resp) return -ENOMEM;
 	
 	switch (OID) {
+
+	/* general oids (table 4-1) */
+
 	/* mandatory */
 	case OID_GEN_SUPPORTED_LIST:
 		DEBUG ("%s: OID_GEN_SUPPORTED_LIST\n", __FUNCTION__);
 		length = sizeof (oid_supported_list);
-		memcpy ((u8 *) resp + 24, oid_supported_list, length); 
+		count  = length / sizeof (u32);
+		tmp = (u32 *) ((u8 *)resp + 24);
+		for (i = 0; i < count; i++)
+			tmp[i] = cpu_to_le32 (oid_supported_list[i]);
 		retval = 0;
 		break;
 		
@@ -115,7 +128,7 @@
 		 * reddite ergo quae sunt Caesaris Caesari
 		 * et quae sunt Dei Deo!
 		 */
-		*((u32 *) resp + 6) = 0;
+		*((u32 *) resp + 6) = __constant_cpu_to_le32 (0);
 		retval = 0;
 		break;
 		
@@ -123,7 +136,8 @@
 	case OID_GEN_MEDIA_SUPPORTED:
 		DEBUG("%s: OID_GEN_MEDIA_SUPPORTED\n", __FUNCTION__);
 		length = 4;
-		*((u32 *) resp + 6) = rndis_per_dev_params [configNr].medium;
+		*((u32 *) resp + 6) = cpu_to_le32 (
+					rndis_per_dev_params [configNr].medium);
 		retval = 0;
 		break;
 		
@@ -132,24 +146,21 @@
 		DEBUG("%s: OID_GEN_MEDIA_IN_USE\n", __FUNCTION__);
 		length = 4;
 		/* one medium, one transport... (maybe you do it better) */
-		*((u32 *) resp + 6) = rndis_per_dev_params [configNr].medium;
+		*((u32 *) resp + 6) = cpu_to_le32 (
+					rndis_per_dev_params [configNr].medium);
 		retval = 0;
 		break;
 		
-	case OID_GEN_MAXIMUM_LOOKAHEAD:
-		DEBUG("%s: OID_GEN_MAXIMUM_LOOKAHEAD\n", __FUNCTION__);
-		break;
-		
 	/* mandatory */
 	case OID_GEN_MAXIMUM_FRAME_SIZE:
 		DEBUG("%s: OID_GEN_MAXIMUM_FRAME_SIZE\n", __FUNCTION__);
 		if (rndis_per_dev_params [configNr].dev) {
 			length = 4;
-			*((u32 *) resp + 6) = rndis_per_dev_params [configNr]
-						.dev->mtu;
+			*((u32 *) resp + 6) = cpu_to_le32 (
+				rndis_per_dev_params [configNr].dev->mtu);
 			retval = 0;
 		} else {
-			*((u32 *) resp + 6) = 0;
+			*((u32 *) resp + 6) = __constant_cpu_to_le32 (0);
 			retval = 0;
 		}
 		break;
@@ -160,30 +171,20 @@
 		length = 4;
 		if (rndis_per_dev_params [configNr].media_state
 			== NDIS_MEDIA_STATE_DISCONNECTED)
-		    *((u32 *) resp + 6) = 0;
+		    *((u32 *) resp + 6) = __constant_cpu_to_le32 (0);
 		else
-		    *((u32 *) resp + 6) = rndis_per_dev_params [configNr].speed;
+		    *((u32 *) resp + 6) = cpu_to_le32 (
+				rndis_per_dev_params [configNr].speed);
 		retval = 0;
 		break;
-		
-	case OID_GEN_TRANSMIT_BUFFER_SPACE:
-		DEBUG("%s: OID_GEN_TRANSMIT_BUFFER_SPACE\n", __FUNCTION__);
-		length = 4;
-		*((u32 *) resp + 6) = 0;
-		retval = 0;
-		break;
-		
-	case OID_GEN_RECEIVE_BUFFER_SPACE:
-		DEBUG("%s: OID_GEN_RECEIVE_BUFFER_SPACE\n", __FUNCTION__);
-		break;
-		
+
 	/* mandatory */
 	case OID_GEN_TRANSMIT_BLOCK_SIZE:
 		DEBUG("%s: OID_GEN_TRANSMIT_BLOCK_SIZE\n", __FUNCTION__);
 		if (rndis_per_dev_params [configNr].dev) {
 			length = 4;
-			*((u32 *) resp + 6) = rndis_per_dev_params [configNr]
-						.dev->mtu;
+			*((u32 *) resp + 6) = cpu_to_le32 (
+				rndis_per_dev_params [configNr].dev->mtu);
 			retval = 0;
 		}
 		break;
@@ -193,8 +194,8 @@
 		DEBUG("%s: OID_GEN_RECEIVE_BLOCK_SIZE\n", __FUNCTION__);
 		if (rndis_per_dev_params [configNr].dev) {
 			length = 4;
-			*((u32 *) resp + 6) = rndis_per_dev_params [configNr]
-						.dev->mtu;
+			*((u32 *) resp + 6) = cpu_to_le32 (
+				rndis_per_dev_params [configNr].dev->mtu);
 			retval = 0;
 		}
 		break;
@@ -203,7 +204,8 @@
 	case OID_GEN_VENDOR_ID:
 		DEBUG("%s: OID_GEN_VENDOR_ID\n", __FUNCTION__);
 		length = 4;
-		*((u32 *) resp + 6) = rndis_per_dev_params [configNr].vendorID;
+		*((u32 *) resp + 6) = cpu_to_le32 (
+			rndis_per_dev_params [configNr].vendorID);
 		retval = 0;
 		break;
 		
@@ -216,129 +218,92 @@
 		retval = 0;
 		break;
 
+	case OID_GEN_VENDOR_DRIVER_VERSION:
+		DEBUG("%s: OID_GEN_VENDOR_DRIVER_VERSION\n", __FUNCTION__);
+		length = 4;
+		/* Created as LE */
+		*((u32 *) resp + 6) = rndis_driver_version;
+		retval = 0;
+		break;
+
 	/* mandatory */
 	case OID_GEN_CURRENT_PACKET_FILTER:
 		DEBUG("%s: OID_GEN_CURRENT_PACKET_FILTER\n", __FUNCTION__);
 		length = 4;
-		*((u32 *) resp + 6) = rndis_per_dev_params[configNr].filter;
+		*((u32 *) resp + 6) = cpu_to_le32 (
+					rndis_per_dev_params[configNr].filter);
 		retval = 0;
 		break;
-		
-	case OID_GEN_CURRENT_LOOKAHEAD:
-		DEBUG("%s: OID_GEN_CURRENT_LOOKAHEAD\n", __FUNCTION__);
-		break;
-		
-	case OID_GEN_DRIVER_VERSION:
-		DEBUG("%s: OID_GEN_DRIVER_VERSION\n", __FUNCTION__);
-		break;
-		
+
 	/* mandatory */
 	case OID_GEN_MAXIMUM_TOTAL_SIZE:
 		DEBUG("%s: OID_GEN_MAXIMUM_TOTAL_SIZE\n", __FUNCTION__);
 		length = 4;
-		*((u32 *) resp + 6) = RNDIS_MAX_TOTAL_SIZE;
-		retval = 0;
-		break;
-		
-	case OID_GEN_PROTOCOL_OPTIONS:
-		DEBUG("%s: OID_GEN_PROTOCOL_OPTIONS\n", __FUNCTION__);
-		break;
-		
-	case OID_GEN_MAC_OPTIONS:
-		DEBUG("%s: OID_GEN_MAC_OPTIONS\n", __FUNCTION__);
-		length = 4;
-		*((u32 *) resp + 6) = NDIS_MAC_OPTION_RECEIVE_SERIALIZED | 
-		    NDIS_MAC_OPTION_FULL_DUPLEX;
+		*((u32 *) resp + 6) = __constant_cpu_to_le32(
+					RNDIS_MAX_TOTAL_SIZE);
 		retval = 0;
 		break;
-		
+
 	/* mandatory */
 	case OID_GEN_MEDIA_CONNECT_STATUS:
 		DEBUG("%s: OID_GEN_MEDIA_CONNECT_STATUS\n", __FUNCTION__);
 		length = 4;
-		*((u32 *) resp + 6) = rndis_per_dev_params [configNr]
-						.media_state;
+		*((u32 *) resp + 6) = cpu_to_le32 (
+					rndis_per_dev_params [configNr]
+						.media_state);
 		retval = 0;
 		break;
-		
-	case OID_GEN_MAXIMUM_SEND_PACKETS:
-		DEBUG("%s: OID_GEN_MAXIMUM_SEND_PACKETS\n", __FUNCTION__);
-		break;
-		
-	/* mandatory */
-	case OID_GEN_VENDOR_DRIVER_VERSION:
-		DEBUG("%s: OID_GEN_VENDOR_DRIVER_VERSION\n", __FUNCTION__);
-		length = 4;
-		*((u32 *) resp + 6) = rndis_driver_version;
-		retval = 0;
-		break;
-		
-	case OID_GEN_SUPPORTED_GUIDS:
-		DEBUG("%s: OID_GEN_SUPPORTED_GUIDS\n", __FUNCTION__);
-		break;
-		
-	case OID_GEN_NETWORK_LAYER_ADDRESSES:
-		DEBUG("%s: OID_GEN_NETWORK_LAYER_ADDRESSES\n", __FUNCTION__);
-		break;
-		
-	case OID_GEN_TRANSPORT_HEADER_OFFSET:
-		DEBUG("%s: OID_GEN_TRANSPORT_HEADER_OFFSET\n", __FUNCTION__);
-		break;
-		
-	case OID_GEN_MACHINE_NAME:
-		DEBUG("%s: OID_GEN_MACHINE_NAME\n", __FUNCTION__);
-		break;
-		
-	case OID_GEN_RNDIS_CONFIG_PARAMETER:
-		DEBUG("%s: OID_GEN_RNDIS_CONFIG_PARAMETER\n", __FUNCTION__);
+
+	case OID_GEN_PHYSICAL_MEDIUM:
+		DEBUG("%s: OID_GEN_PHYSICAL_MEDIUM\n", __FUNCTION__);
 		length = 4;
-		*((u32 *) resp + 6) = 0;
+		*((u32 *) resp + 6) = __constant_cpu_to_le32 (0);
 		retval = 0;
 		break;
-		
-	case OID_GEN_VLAN_ID:
-		DEBUG("%s: OID_GEN_VLAN_ID\n", __FUNCTION__);
-		break;
-		
-	case OID_GEN_MEDIA_CAPABILITIES:
-		DEBUG("%s: OID_GEN_MEDIA_CAPABILITIES\n", __FUNCTION__);
-		break;
-		
-	case OID_GEN_PHYSICAL_MEDIUM:
-		DEBUG("%s: OID_GEN_PHYSICAL_MEDIUM\n", __FUNCTION__);
+
+	/* The RNDIS specification is incomplete/wrong.   Some versions
+	 * of MS-Windows expect OIDs that aren't specified there.  Other
+	 * versions emit undefined RNDIS messages. DOCUMENT ALL THESE!
+	 */
+	case OID_GEN_MAC_OPTIONS:		/* from WinME */
+		DEBUG("%s: OID_GEN_MAC_OPTIONS\n", __FUNCTION__);
 		length = 4;
-		*((u32 *) resp + 6) = 0;
+		*((u32 *) resp + 6) = __constant_cpu_to_le32(
+			  NDIS_MAC_OPTION_RECEIVE_SERIALIZED
+			| NDIS_MAC_OPTION_FULL_DUPLEX);
 		retval = 0;
 		break;
-		
+
+	/* statistics OIDs (table 4-2) */
+
 	/* mandatory */
 	case OID_GEN_XMIT_OK:
 		DEBUG("%s: OID_GEN_XMIT_OK\n", __FUNCTION__);
 		if (rndis_per_dev_params [configNr].stats) {
 			length = 4;
-			*((u32 *) resp + 6) = rndis_per_dev_params [configNr]
-					.stats->tx_packets - 
+			*((u32 *) resp + 6) = cpu_to_le32 (
+			    rndis_per_dev_params [configNr].stats->tx_packets - 
 			    rndis_per_dev_params [configNr].stats->tx_errors -
-			    rndis_per_dev_params [configNr].stats->tx_dropped;
+			    rndis_per_dev_params [configNr].stats->tx_dropped);
 			retval = 0;
 		} else {
-			*((u32 *) resp + 6) = 0;
+			*((u32 *) resp + 6) = __constant_cpu_to_le32 (0);
 			retval = 0;
 		}
 		break;
-		
+
 	/* mandatory */
 	case OID_GEN_RCV_OK:
 		DEBUG("%s: OID_GEN_RCV_OK\n", __FUNCTION__);
 		if (rndis_per_dev_params [configNr].stats) {
 			length = 4;
-			*((u32 *) resp + 6) = rndis_per_dev_params [configNr].
-					stats->rx_packets - 
+			*((u32 *) resp + 6) = cpu_to_le32 (
+			    rndis_per_dev_params [configNr].stats->rx_packets - 
 			    rndis_per_dev_params [configNr].stats->rx_errors -
-			    rndis_per_dev_params [configNr].stats->rx_dropped;
+			    rndis_per_dev_params [configNr].stats->rx_dropped);
 			retval = 0;
 		} else {
-			*((u32 *) resp + 6) = 0;
+			*((u32 *) resp + 6) = __constant_cpu_to_le32 (0);
 			retval = 0;
 		}
 		break;
@@ -348,11 +313,12 @@
 		DEBUG("%s: OID_GEN_XMIT_ERROR\n", __FUNCTION__);
 		if (rndis_per_dev_params [configNr].stats) {
 			length = 4;
-			*((u32 *) resp + 6) = rndis_per_dev_params [configNr].
-					stats->tx_errors;
+			*((u32 *) resp + 6) = cpu_to_le32 (
+				rndis_per_dev_params [configNr]
+					.stats->tx_errors);
 			retval = 0;
 		} else {
-			*((u32 *) resp + 6) = 0;
+			*((u32 *) resp + 6) = __constant_cpu_to_le32 (0);
 			retval = 0;
 		}
 		break;
@@ -361,11 +327,12 @@
 	case OID_GEN_RCV_ERROR:
 		DEBUG("%s: OID_GEN_RCV_ERROR\n", __FUNCTION__);
 		if (rndis_per_dev_params [configNr].stats) {
-			*((u32 *) resp + 6) = rndis_per_dev_params [configNr].
-					stats->rx_errors;
+			*((u32 *) resp + 6) = cpu_to_le32 (
+				rndis_per_dev_params [configNr]
+					.stats->rx_errors);
 			retval = 0;
 		} else {
-			*((u32 *) resp + 6) = 0;
+			*((u32 *) resp + 6) = __constant_cpu_to_le32 (0);
 			retval = 0;
 		}
 		break;
@@ -374,15 +341,17 @@
 	case OID_GEN_RCV_NO_BUFFER:
 		DEBUG("%s: OID_GEN_RCV_NO_BUFFER\n", __FUNCTION__);
 		if (rndis_per_dev_params [configNr].stats) {
-			*((u32 *) resp + 6) = rndis_per_dev_params [configNr].
-					stats->rx_dropped;
+			*((u32 *) resp + 6) = cpu_to_le32 (
+				rndis_per_dev_params [configNr]
+					.stats->rx_dropped);
 			retval = 0;
 		} else {
-			*((u32 *) resp + 6) = 0;
+			*((u32 *) resp + 6) = __constant_cpu_to_le32 (0);
 			retval = 0;
 		}
 		break;
-		
+
+#ifdef	RNDIS_OPTIONAL_STATS
 	case OID_GEN_DIRECTED_BYTES_XMIT:
 		DEBUG("%s: OID_GEN_DIRECTED_BYTES_XMIT\n", __FUNCTION__);
 		/* 
@@ -392,14 +361,17 @@
 		 */
 		if (rndis_per_dev_params [configNr].stats) {
 			length = 4;
-			*((u32 *) resp + 6) = (rndis_per_dev_params [configNr].
-					stats->tx_packets - 
-			    rndis_per_dev_params [configNr].stats->tx_errors -
-			    rndis_per_dev_params [configNr].stats->tx_dropped)
-					*123;
+			*((u32 *) resp + 6) = cpu_to_le32 (
+				(rndis_per_dev_params [configNr]
+					.stats->tx_packets - 
+				 rndis_per_dev_params [configNr]
+					 .stats->tx_errors -
+				 rndis_per_dev_params [configNr]
+					 .stats->tx_dropped)
+				* 123);
 			retval = 0;
 		} else {
-			*((u32 *) resp + 6) = 0;
+			*((u32 *) resp + 6) = __constant_cpu_to_le32 (0);
 			retval = 0;
 		}
 		break;
@@ -409,14 +381,17 @@
 		/* dito */
 		if (rndis_per_dev_params [configNr].stats) {
 			length = 4;
-			*((u32 *) resp + 6) = (rndis_per_dev_params [configNr].
-					stats->tx_packets - 
-			    rndis_per_dev_params [configNr].stats->tx_errors -
-			    rndis_per_dev_params [configNr].stats->tx_dropped)
-			    		/123;
+			*((u32 *) resp + 6) = cpu_to_le32 (
+				(rndis_per_dev_params [configNr]
+					.stats->tx_packets - 
+				 rndis_per_dev_params [configNr]
+					 .stats->tx_errors -
+				 rndis_per_dev_params [configNr]
+					 .stats->tx_dropped)
+				/ 123);
 			retval = 0;
 		} else {
-			*((u32 *) resp + 6) = 0;
+			*((u32 *) resp + 6) = __constant_cpu_to_le32 (0);
 			retval = 0;
 		}
 		break;
@@ -424,11 +399,12 @@
 	case OID_GEN_MULTICAST_BYTES_XMIT:
 		DEBUG("%s: OID_GEN_MULTICAST_BYTES_XMIT\n", __FUNCTION__);
 		if (rndis_per_dev_params [configNr].stats) {
-			*((u32 *) resp + 6) = rndis_per_dev_params [configNr].
-					stats->multicast*1234;
+			*((u32 *) resp + 6) = cpu_to_le32 (
+				rndis_per_dev_params [configNr]
+					.stats->multicast*1234);
 			retval = 0;
 		} else {
-			*((u32 *) resp + 6) = 0;
+			*((u32 *) resp + 6) = __constant_cpu_to_le32 (0);
 			retval = 0;
 		}
 		break;
@@ -436,11 +412,12 @@
 	case OID_GEN_MULTICAST_FRAMES_XMIT:
 		DEBUG("%s: OID_GEN_MULTICAST_FRAMES_XMIT\n", __FUNCTION__);
 		if (rndis_per_dev_params [configNr].stats) {
-			*((u32 *) resp + 6) = rndis_per_dev_params [configNr].
-					stats->multicast;
+			*((u32 *) resp + 6) = cpu_to_le32 (
+				rndis_per_dev_params [configNr]
+					.stats->multicast);
 			retval = 0;
 		} else {
-			*((u32 *) resp + 6) = 0;
+			*((u32 *) resp + 6) = __constant_cpu_to_le32 (0);
 			retval = 0;
 		}
 		break;
@@ -448,11 +425,12 @@
 	case OID_GEN_BROADCAST_BYTES_XMIT:
 		DEBUG("%s: OID_GEN_BROADCAST_BYTES_XMIT\n", __FUNCTION__);
 		if (rndis_per_dev_params [configNr].stats) {
-			*((u32 *) resp + 6) = rndis_per_dev_params [configNr].
-					stats->tx_packets/42*255;
+			*((u32 *) resp + 6) = cpu_to_le32 (
+				rndis_per_dev_params [configNr]
+					.stats->tx_packets/42*255);
 			retval = 0;
 		} else {
-			*((u32 *) resp + 6) = 0;
+			*((u32 *) resp + 6) = __constant_cpu_to_le32 (0);
 			retval = 0;
 		}
 		break;
@@ -460,35 +438,37 @@
 	case OID_GEN_BROADCAST_FRAMES_XMIT:
 		DEBUG("%s: OID_GEN_BROADCAST_FRAMES_XMIT\n", __FUNCTION__);
 		if (rndis_per_dev_params [configNr].stats) {
-			*((u32 *) resp + 6) = rndis_per_dev_params [configNr].
-					stats->tx_packets/42;
+			*((u32 *) resp + 6) = cpu_to_le32 (
+				rndis_per_dev_params [configNr]
+					.stats->tx_packets/42);
 			retval = 0;
 		} else {
-			*((u32 *) resp + 6) = 0;
+			*((u32 *) resp + 6) = __constant_cpu_to_le32 (0);
 			retval = 0;
 		}
 		break;
 		
 	case OID_GEN_DIRECTED_BYTES_RCV:
 		DEBUG("%s: OID_GEN_DIRECTED_BYTES_RCV\n", __FUNCTION__);
-		*((u32 *) resp + 6) = 0;
+		*((u32 *) resp + 6) = __constant_cpu_to_le32 (0);
 		retval = 0;
 		break;
 		
 	case OID_GEN_DIRECTED_FRAMES_RCV:
 		DEBUG("%s: OID_GEN_DIRECTED_FRAMES_RCV\n", __FUNCTION__);
-		*((u32 *) resp + 6) = 0;
+		*((u32 *) resp + 6) = __constant_cpu_to_le32 (0);
 		retval = 0;
 		break;
 		
 	case OID_GEN_MULTICAST_BYTES_RCV:
 		DEBUG("%s: OID_GEN_MULTICAST_BYTES_RCV\n", __FUNCTION__);
 		if (rndis_per_dev_params [configNr].stats) {
-			*((u32 *) resp + 6) = rndis_per_dev_params [configNr].
-					stats->multicast*1111;
+			*((u32 *) resp + 6) = cpu_to_le32 (
+				rndis_per_dev_params [configNr]
+					.stats->multicast * 1111);
 			retval = 0;
 		} else {
-			*((u32 *) resp + 6) = 0;
+			*((u32 *) resp + 6) = __constant_cpu_to_le32 (0);
 			retval = 0;
 		}
 		break;
@@ -496,11 +476,12 @@
 	case OID_GEN_MULTICAST_FRAMES_RCV:
 		DEBUG("%s: OID_GEN_MULTICAST_FRAMES_RCV\n", __FUNCTION__);
 		if (rndis_per_dev_params [configNr].stats) {
-			*((u32 *) resp + 6) = rndis_per_dev_params [configNr].
-					stats->multicast;
+			*((u32 *) resp + 6) = cpu_to_le32 (
+				rndis_per_dev_params [configNr]
+					.stats->multicast);
 			retval = 0;
 		} else {
-			*((u32 *) resp + 6) = 0;
+			*((u32 *) resp + 6) = __constant_cpu_to_le32 (0);
 			retval = 0;
 		}
 		break;
@@ -508,11 +489,12 @@
 	case OID_GEN_BROADCAST_BYTES_RCV:
 		DEBUG("%s: OID_GEN_BROADCAST_BYTES_RCV\n", __FUNCTION__);
 		if (rndis_per_dev_params [configNr].stats) {
-			*((u32 *) resp + 6) = rndis_per_dev_params [configNr].
-					stats->rx_packets/42*255;
+			*((u32 *) resp + 6) = cpu_to_le32 (
+				rndis_per_dev_params [configNr]
+					.stats->rx_packets/42*255);
 			retval = 0;
 		} else {
-			*((u32 *) resp + 6) = 0;
+			*((u32 *) resp + 6) = __constant_cpu_to_le32 (0);
 			retval = 0;
 		}
 		break;
@@ -520,11 +502,12 @@
 	case OID_GEN_BROADCAST_FRAMES_RCV:
 		DEBUG("%s: OID_GEN_BROADCAST_FRAMES_RCV\n", __FUNCTION__);
 		if (rndis_per_dev_params [configNr].stats) {
-			*((u32 *) resp + 6) = rndis_per_dev_params [configNr].
-					stats->rx_packets/42;
+			*((u32 *) resp + 6) = cpu_to_le32 (
+				rndis_per_dev_params [configNr]
+					.stats->rx_packets/42);
 			retval = 0;
 		} else {
-			*((u32 *) resp + 6) = 0;
+			*((u32 *) resp + 6) = __constant_cpu_to_le32 (0);
 			retval = 0;
 		}
 		break;
@@ -532,61 +515,25 @@
 	case OID_GEN_RCV_CRC_ERROR:
 		DEBUG("%s: OID_GEN_RCV_CRC_ERROR\n", __FUNCTION__);
 		if (rndis_per_dev_params [configNr].stats) {
-			*((u32 *) resp + 6) = rndis_per_dev_params [configNr].
-					stats->rx_crc_errors;
+			*((u32 *) resp + 6) = cpu_to_le32 (
+				rndis_per_dev_params [configNr]
+					.stats->rx_crc_errors);
 			retval = 0;
 		} else {
-			*((u32 *) resp + 6) = 0;
+			*((u32 *) resp + 6) = __constant_cpu_to_le32 (0);
 			retval = 0;
 		}
 		break;
 		
 	case OID_GEN_TRANSMIT_QUEUE_LENGTH:
 		DEBUG("%s: OID_GEN_TRANSMIT_QUEUE_LENGTH\n", __FUNCTION__);
-		*((u32 *) resp + 6) = 0;
+		*((u32 *) resp + 6) = __constant_cpu_to_le32 (0);
 		retval = 0;
 		break;
-		
-	case OID_GEN_GET_TIME_CAPS:
-		DEBUG("%s: OID_GEN_GET_TIME_CAPS\n", __FUNCTION__);
-		break;
-		
-	case OID_GEN_GET_NETCARD_TIME:
-		DEBUG("%s: OID_GEN_GET_NETCARD_TIME\n", __FUNCTION__);
-		break;
-		
-	case OID_GEN_NETCARD_LOAD:
-		DEBUG("%s: OID_GEN_NETCARD_LOAD\n", __FUNCTION__);
-		break;
-		
-	case OID_GEN_DEVICE_PROFILE:
-		DEBUG("%s: OID_GEN_DEVICE_PROFILE\n", __FUNCTION__);
-		break;
-		
-	case OID_GEN_INIT_TIME_MS:
-		DEBUG("%s: OID_GEN_INIT_TIME_MS\n", __FUNCTION__);
-		break;
-		
-	case OID_GEN_RESET_COUNTS:
-		DEBUG("%s: OID_GEN_RESET_COUNTS\n", __FUNCTION__);
-		break;
-		
-	case OID_GEN_MEDIA_SENSE_COUNTS:
-		DEBUG("%s: OID_GEN_MEDIA_SENSE_COUNTS\n", __FUNCTION__);
-		break;
-		
-	case OID_GEN_FRIENDLY_NAME:
-		DEBUG("%s: OID_GEN_FRIENDLY_NAME\n", __FUNCTION__);
-		break;
-		
-	case OID_GEN_MINIPORT_INFO:
-		DEBUG("%s: OID_GEN_MINIPORT_INFO\n", __FUNCTION__);
-		break;
-		
-	case OID_GEN_RESET_VERIFY_PARAMETERS:
-		DEBUG("%s: OID_GEN_RESET_VERIFY_PARAMETERS\n", __FUNCTION__);
-		break;
-		
+#endif	/* RNDIS_OPTIONAL_STATS */
+
+	/* ieee802.3 OIDs (table 4-3) */
+
 	/* mandatory */
 	case OID_802_3_PERMANENT_ADDRESS:
 		DEBUG("%s: OID_802_3_PERMANENT_ADDRESS\n", __FUNCTION__);
@@ -597,7 +544,7 @@
 				length);
 			retval = 0;
 		} else {
-			*((u32 *) resp + 6) = 0;
+			*((u32 *) resp + 6) = __constant_cpu_to_le32 (0);
 			retval = 0;
 		}
 		break;
@@ -619,7 +566,7 @@
 		DEBUG("%s: OID_802_3_MULTICAST_LIST\n", __FUNCTION__);
 		length = 4;
 		/* Multicast base address only */
-		*((u32 *) resp + 6) = 0xE0000000;
+		*((u32 *) resp + 6) = __constant_cpu_to_le32 (0xE0000000);
 		retval = 0;
 		break;
 		
@@ -628,22 +575,25 @@
 		DEBUG("%s: OID_802_3_MAXIMUM_LIST_SIZE\n", __FUNCTION__);
 		 length = 4;
 		/* Multicast base address only */
-		*((u32 *) resp + 6) = 1;
+		*((u32 *) resp + 6) = __constant_cpu_to_le32 (1);
 		retval = 0;
 		break;
 		
 	case OID_802_3_MAC_OPTIONS:
 		DEBUG("%s: OID_802_3_MAC_OPTIONS\n", __FUNCTION__);
 		break;
-		
+
+	/* ieee802.3 statistics OIDs (table 4-4) */
+
 	/* mandatory */
 	case OID_802_3_RCV_ERROR_ALIGNMENT:
 		DEBUG("%s: OID_802_3_RCV_ERROR_ALIGNMENT\n", __FUNCTION__);
 		if (rndis_per_dev_params [configNr].stats)
 		{
 			length = 4;
-			*((u32 *) resp + 6) = rndis_per_dev_params [configNr]
-					.stats->rx_frame_errors;
+			*((u32 *) resp + 6) = cpu_to_le32 (
+				rndis_per_dev_params [configNr]
+					.stats->rx_frame_errors);
 			retval = 0;
 		}
 		break;
@@ -652,7 +602,7 @@
 	case OID_802_3_XMIT_ONE_COLLISION:
 		DEBUG("%s: OID_802_3_XMIT_ONE_COLLISION\n", __FUNCTION__);
 		length = 4;
-		*((u32 *) resp + 6) = 0;
+		*((u32 *) resp + 6) = __constant_cpu_to_le32 (0);
 		retval = 0;
 		break;
 		
@@ -660,10 +610,11 @@
 	case OID_802_3_XMIT_MORE_COLLISIONS:
 		DEBUG("%s: OID_802_3_XMIT_MORE_COLLISIONS\n", __FUNCTION__);
 		length = 4;
-		*((u32 *) resp + 6) = 0;
+		*((u32 *) resp + 6) = __constant_cpu_to_le32 (0);
 		retval = 0;
 		break;
 		
+#ifdef	RNDIS_OPTIONAL_STATS
 	case OID_802_3_XMIT_DEFERRED:
 		DEBUG("%s: OID_802_3_XMIT_DEFERRED\n", __FUNCTION__);
 		/* TODO */
@@ -698,14 +649,46 @@
 		DEBUG("%s: OID_802_3_XMIT_LATE_COLLISIONS\n", __FUNCTION__);
 		/* TODO */
 		break;		
-		
-	default: printk (KERN_ERR "%s: unknown OID 0x%08X\n", 
+#endif	/* RNDIS_OPTIONAL_STATS */
+
+#ifdef	RNDIS_PM
+	/* power management OIDs (table 4-5) */
+	case OID_PNP_CAPABILITIES:
+		DEBUG("%s: OID_PNP_CAPABILITIES\n", __FUNCTION__);
+
+		/* just PM, and remote wakeup on link status change
+		 * (not magic packet or pattern match)
+		 */
+		length = sizeof (struct NDIS_PNP_CAPABILITIES);
+		memset (resp, 0, length);
+		{
+			struct NDIS_PNP_CAPABILITIES *caps = (void *) resp;
+
+			caps->Flags = NDIS_DEVICE_WAKE_UP_ENABLE;
+			caps->WakeUpCapabilities.MinLinkChangeWakeUp 
+				 = NdisDeviceStateD3;
+
+			/* FIXME then use usb_gadget_wakeup(), and
+			 * set USB_CONFIG_ATT_WAKEUP in config desc
+			 */
+		}
+		retval = 0;
+		break;
+	case OID_PNP_QUERY_POWER:
+		DEBUG("%s: OID_PNP_QUERY_POWER\n", __FUNCTION__);
+		/* sure, handle any power state that maps to USB suspend */
+		retval = 0;
+		break;
+#endif
+
+	default:
+		printk (KERN_WARNING "%s: query unknown OID 0x%08X\n", 
 			 __FUNCTION__, OID);
 	}
 	
-	resp->InformationBufferOffset = 16;
-	resp->InformationBufferLength = length;
-	resp->MessageLength = 24 + length;
+	resp->InformationBufferOffset = __constant_cpu_to_le32 (16);
+	resp->InformationBufferLength = cpu_to_le32 (length);
+	resp->MessageLength = cpu_to_le32 (24 + length);
 	r->length = 24 + length;
 	return retval;
 }
@@ -715,9 +698,7 @@
 {
 	rndis_set_cmplt_type		*resp;
 	int 				i, retval = -ENOTSUPP;
-	struct rndis_config_parameter	*param;
 	struct rndis_params		*params;
-	u8 *cp;
 
 	if (!r)
 		return -ENOMEM;
@@ -725,20 +706,37 @@
 	if (!resp)
 		return -ENOMEM;
 
-	cp = (u8 *)resp;
+	DEBUG("set OID %08x value, len %d:\n", OID, buf_len);
+	for (i = 0; i < buf_len; i += 16) {
+		DEBUG ("%03d: "
+			" %02x %02x %02x %02x"
+			" %02x %02x %02x %02x"
+			" %02x %02x %02x %02x"
+			" %02x %02x %02x %02x"
+			"\n",
+			i,
+			buf[i], buf [i+1],
+				buf[i+2], buf[i+3],
+			buf[i+4], buf [i+5],
+				buf[i+6], buf[i+7],
+			buf[i+8], buf [i+9],
+				buf[i+10], buf[i+11],
+			buf[i+12], buf [i+13],
+				buf[i+14], buf[i+15]);
+	}
 
 	switch (OID) {
 	case OID_GEN_CURRENT_PACKET_FILTER:
 		params = &rndis_per_dev_params [configNr];
 		retval = 0;
 
-		/* FIXME use this NDIS_PACKET_TYPE_* bitflags to
+		/* FIXME use these NDIS_PACKET_TYPE_* bitflags to
 		 * filter packets in hard_start_xmit()
 		 * NDIS_PACKET_TYPE_x == CDC_PACKET_TYPE_x for x in:
 		 *	PROMISCUOUS, DIRECTED,
 		 *	MULTICAST, ALL_MULTICAST, BROADCAST
 		 */
-		params->filter = *(u32 *)buf;
+		params->filter = cpu_to_le32p((u32 *)buf);
 		DEBUG("%s: OID_GEN_CURRENT_PACKET_FILTER %08x\n",
 			__FUNCTION__, params->filter);
 
@@ -763,23 +761,40 @@
 		DEBUG("%s: OID_802_3_MULTICAST_LIST\n", __FUNCTION__);
 		retval = 0;
 		break;
-		
+#if 0
 	case OID_GEN_RNDIS_CONFIG_PARAMETER:
-		DEBUG("%s: OID_GEN_RNDIS_CONFIG_PARAMETER\n", __FUNCTION__);
+		{
+		struct rndis_config_parameter	*param;
 		param = (struct rndis_config_parameter *) buf;
-		if (param) {
-			for (i = 0; i < param->ParameterNameLength; i++) {
-				DEBUG ("%c", 
-				       *(buf + param->ParameterNameOffset + i));
-			}
-			DEBUG ("\n");
+		DEBUG("%s: OID_GEN_RNDIS_CONFIG_PARAMETER '%*s'\n",
+			__FUNCTION__,
+			min(cpu_to_le32(param->ParameterNameLength),80),
+			buf + param->ParameterNameOffset);
+		retval = 0;
 		}
-		
+		break;
+#endif
+
+#ifdef	RNDIS_PM
+	case OID_PNP_SET_POWER:
+		DEBUG ("OID_PNP_SET_POWER\n");
+		/* sure, handle any power state that maps to USB suspend */
 		retval = 0;
 		break;
-		
-	default: printk (KERN_ERR "%s: unknown OID 0x%08X\n", 
-			 __FUNCTION__, OID);
+
+	case OID_PNP_ENABLE_WAKE_UP:
+		/* always-connected ... */
+		DEBUG ("OID_PNP_ENABLE_WAKE_UP\n");
+		retval = 0;
+		break;
+
+	// no PM resume patterns supported (specified where?)
+	// so OID_PNP_{ADD,REMOVE}_WAKE_UP_PATTERN always fails
+#endif
+
+	default:
+		printk (KERN_WARNING "%s: set unknown OID 0x%08X, size %d\n", 
+			 __FUNCTION__, OID, buf_len);
 	}
 	
 	return retval;
@@ -804,22 +819,24 @@
 	
 	if (!resp) return -ENOMEM;
 	
-	resp->MessageType = REMOTE_NDIS_INITIALIZE_CMPLT;
-	resp->MessageLength = 52;
-	resp->RequestID = buf->RequestID;
-	resp->Status = RNDIS_STATUS_SUCCESS;
-	resp->MajorVersion = RNDIS_MAJOR_VERSION;
-	resp->MinorVersion = RNDIS_MINOR_VERSION;
-	resp->DeviceFlags = RNDIS_DF_CONNECTIONLESS;
-	resp->Medium = RNDIS_MEDIUM_802_3;
-	resp->MaxPacketsPerTransfer = 1;
-	resp->MaxTransferSize = rndis_per_dev_params [configNr].dev->mtu
+	resp->MessageType = __constant_cpu_to_le32 (
+			REMOTE_NDIS_INITIALIZE_CMPLT);
+	resp->MessageLength = __constant_cpu_to_le32 (52);
+	resp->RequestID = buf->RequestID; /* Still LE in msg buffer */
+	resp->Status = __constant_cpu_to_le32 (RNDIS_STATUS_SUCCESS);
+	resp->MajorVersion = __constant_cpu_to_le32 (RNDIS_MAJOR_VERSION);
+	resp->MinorVersion = __constant_cpu_to_le32 (RNDIS_MINOR_VERSION);
+	resp->DeviceFlags = __constant_cpu_to_le32 (RNDIS_DF_CONNECTIONLESS);
+	resp->Medium = __constant_cpu_to_le32 (RNDIS_MEDIUM_802_3);
+	resp->MaxPacketsPerTransfer = __constant_cpu_to_le32 (1);
+	resp->MaxTransferSize = cpu_to_le32 (
+		  rndis_per_dev_params [configNr].dev->mtu
 		+ sizeof (struct ethhdr)
 		+ sizeof (struct rndis_packet_msg_type)
-		+ 22;
-	resp->PacketAlignmentFactor = 0;
-	resp->AFListOffset = 0;
-	resp->AFListSize = 0;
+		+ 22);
+	resp->PacketAlignmentFactor = __constant_cpu_to_le32 (0);
+	resp->AFListOffset = __constant_cpu_to_le32 (0);
+	resp->AFListSize = __constant_cpu_to_le32 (0);
 	
 	if (rndis_per_dev_params [configNr].ack)
 	    rndis_per_dev_params [configNr].ack (
@@ -833,7 +850,7 @@
 	rndis_query_cmplt_type *resp;
 	rndis_resp_t            *r;
 	
-	DEBUG("%s: OID = %08X\n", __FUNCTION__, buf->OID);
+	// DEBUG("%s: OID = %08X\n", __FUNCTION__, cpu_to_le32(buf->OID));
 	if (!rndis_per_dev_params [configNr].dev) return -ENOTSUPP;
 	
 	/* 
@@ -847,17 +864,18 @@
 	
 	if (!resp) return -ENOMEM;
 	
-	resp->MessageType = REMOTE_NDIS_QUERY_CMPLT;
-	resp->MessageLength = 24;
-	resp->RequestID = buf->RequestID;
+	resp->MessageType = __constant_cpu_to_le32 (REMOTE_NDIS_QUERY_CMPLT);
+	resp->MessageLength = __constant_cpu_to_le32 (24);
+	resp->RequestID = buf->RequestID; /* Still LE in msg buffer */
 	
-	if (gen_ndis_query_resp (configNr, buf->OID, r)) {
+	if (gen_ndis_query_resp (configNr, cpu_to_le32 (buf->OID), r)) {
 		/* OID not supported */
-		resp->Status = RNDIS_STATUS_NOT_SUPPORTED;
-		resp->InformationBufferLength = 0;
-		resp->InformationBufferOffset = 0;
+		resp->Status = __constant_cpu_to_le32 (
+				RNDIS_STATUS_NOT_SUPPORTED);
+		resp->InformationBufferLength = __constant_cpu_to_le32 (0);
+		resp->InformationBufferOffset = __constant_cpu_to_le32 (0);
 	} else
-		resp->Status = RNDIS_STATUS_SUCCESS;
+		resp->Status = __constant_cpu_to_le32 (RNDIS_STATUS_SUCCESS);
 	
 	if (rndis_per_dev_params [configNr].ack)
 	    rndis_per_dev_params [configNr].ack (
@@ -867,38 +885,42 @@
 
 static int rndis_set_response (int configNr, rndis_set_msg_type *buf)
 {
+	u32			BufLength, BufOffset;
 	rndis_set_cmplt_type	*resp;
 	rndis_resp_t		*r;
-	int			i;
 	
 	r = rndis_add_response (configNr, sizeof (rndis_set_cmplt_type));
 	
 	if (!r) return -ENOMEM;
 	resp = (rndis_set_cmplt_type *) r->buf;
 	if (!resp) return -ENOMEM;
-	
-	DEBUG("%s: Length: %d\n", __FUNCTION__, buf->InformationBufferLength);
-	DEBUG("%s: Offset: %d\n", __FUNCTION__, buf->InformationBufferOffset);
+
+	BufLength = cpu_to_le32 (buf->InformationBufferLength);
+	BufOffset = cpu_to_le32 (buf->InformationBufferOffset);
+
+#ifdef	VERBOSE
+	DEBUG("%s: Length: %d\n", __FUNCTION__, BufLength);
+	DEBUG("%s: Offset: %d\n", __FUNCTION__, BufOffset);
 	DEBUG("%s: InfoBuffer: ", __FUNCTION__);
 	
-	for (i = 0; i < buf->InformationBufferLength; i++) {
-		DEBUG ("%02x ", *(((u8 *) buf) + i + 12 +
-		       buf->InformationBufferOffset));
+	for (i = 0; i < BufLength; i++) {
+		DEBUG ("%02x ", *(((u8 *) buf) + i + 8 + BufOffset));
 	}
 	
 	DEBUG ("\n");
+#endif
 	
-	resp->MessageType = REMOTE_NDIS_SET_CMPLT;
-	resp->MessageLength = 16;
-	resp->RequestID = buf->RequestID;
-	if (gen_ndis_set_resp (configNr, buf->OID, 
-			       ((u8 *) buf) + 28, 
-			       buf->InformationBufferLength, r))
-	    resp->Status = RNDIS_STATUS_NOT_SUPPORTED;
-	else resp->Status = RNDIS_STATUS_SUCCESS;
+	resp->MessageType = __constant_cpu_to_le32 (REMOTE_NDIS_SET_CMPLT);
+	resp->MessageLength = __constant_cpu_to_le32 (16);
+	resp->RequestID = buf->RequestID; /* Still LE in msg buffer */
+	if (gen_ndis_set_resp (configNr, cpu_to_le32 (buf->OID), 
+			       ((u8 *) buf) + 8 + BufOffset, BufLength, r))
+	    resp->Status = __constant_cpu_to_le32 (RNDIS_STATUS_NOT_SUPPORTED);
+	else resp->Status = __constant_cpu_to_le32 (RNDIS_STATUS_SUCCESS);
 	
 	if (rndis_per_dev_params [configNr].ack)
-	    rndis_per_dev_params [configNr].ack (rndis_per_dev_params [configNr].dev);
+	    rndis_per_dev_params [configNr].ack (
+	    		rndis_per_dev_params [configNr].dev);
 	
 	return 0;
 }
@@ -914,10 +936,11 @@
 	resp = (rndis_reset_cmplt_type *) r->buf;
 	if (!resp) return -ENOMEM;
 	
-	resp->MessageType = REMOTE_NDIS_RESET_CMPLT;
-	resp->MessageLength = 16;
-	resp->Status = RNDIS_STATUS_SUCCESS;
-	resp->AddressingReset = 1; /* resent information */
+	resp->MessageType = __constant_cpu_to_le32 (REMOTE_NDIS_RESET_CMPLT);
+	resp->MessageLength = __constant_cpu_to_le32 (16);
+	resp->Status = __constant_cpu_to_le32 (RNDIS_STATUS_SUCCESS);
+	/* resent information */
+	resp->AddressingReset = __constant_cpu_to_le32 (1);
 	
 	if (rndis_per_dev_params [configNr].ack)
 	    rndis_per_dev_params [configNr].ack (
@@ -938,10 +961,11 @@
 	resp = (rndis_keepalive_cmplt_type *) r->buf;
 	if (!resp) return -ENOMEM;
 		
-	resp->MessageType = REMOTE_NDIS_KEEPALIVE_CMPLT;
-	resp->MessageLength = 16;
-	resp->RequestID = buf->RequestID;
-	resp->Status = RNDIS_STATUS_SUCCESS;
+	resp->MessageType = __constant_cpu_to_le32 (
+			REMOTE_NDIS_KEEPALIVE_CMPLT);
+	resp->MessageLength = __constant_cpu_to_le32 (16);
+	resp->RequestID = buf->RequestID; /* Still LE in msg buffer */
+	resp->Status = __constant_cpu_to_le32 (RNDIS_STATUS_SUCCESS);
 	
 	if (rndis_per_dev_params [configNr].ack)
 	    rndis_per_dev_params [configNr].ack (
@@ -969,11 +993,12 @@
 	resp = (rndis_indicate_status_msg_type *) r->buf;
 	if (!resp) return -ENOMEM;
 	
-	resp->MessageType = REMOTE_NDIS_INDICATE_STATUS_MSG;
-	resp->MessageLength = 20;
-	resp->Status = status;
-	resp->StatusBufferLength = 0;
-	resp->StatusBufferOffset = 0;
+	resp->MessageType = __constant_cpu_to_le32 (
+			REMOTE_NDIS_INDICATE_STATUS_MSG);
+	resp->MessageLength = __constant_cpu_to_le32 (20);
+	resp->Status = cpu_to_le32 (status);
+	resp->StatusBufferLength = __constant_cpu_to_le32 (0);
+	resp->StatusBufferOffset = __constant_cpu_to_le32 (0);
 	
 	if (rndis_per_dev_params [configNr].ack) 
 	    rndis_per_dev_params [configNr].ack (
@@ -1014,8 +1039,8 @@
 		return -ENOMEM;
 	
 	tmp = (u32 *) buf; 
-	MsgType = *tmp;
-	MsgLength = *(tmp + 1);
+	MsgType   = cpu_to_le32p(tmp++);
+	MsgLength = cpu_to_le32p(tmp++);
 	
 	if (configNr >= RNDIS_MAX_CONFIGS)
 		return -ENOTSUPP;
@@ -1025,14 +1050,14 @@
 	switch (MsgType)
 	{
 	case REMOTE_NDIS_INITIALIZE_MSG:
-		DEBUG(KERN_INFO "%s: REMOTE_NDIS_INITIALIZE_MSG\n", 
+		DEBUG("%s: REMOTE_NDIS_INITIALIZE_MSG\n", 
 			__FUNCTION__ );
 		params->state = RNDIS_INITIALIZED;
 		return  rndis_init_response (configNr,
 					     (rndis_init_msg_type *) buf);
 		
 	case REMOTE_NDIS_HALT_MSG:
-		DEBUG(KERN_INFO "%s: REMOTE_NDIS_HALT_MSG\n",
+		DEBUG("%s: REMOTE_NDIS_HALT_MSG\n",
 			__FUNCTION__ );
 		params->state = RNDIS_UNINITIALIZED;
 		if (params->dev) {
@@ -1042,34 +1067,57 @@
 		return 0;
 		
 	case REMOTE_NDIS_QUERY_MSG:
-		DEBUG(KERN_INFO "%s: REMOTE_NDIS_QUERY_MSG\n", 
-			__FUNCTION__ );
 		return rndis_query_response (configNr, 
 					     (rndis_query_msg_type *) buf);
 		
 	case REMOTE_NDIS_SET_MSG:
-		DEBUG(KERN_INFO "%s: REMOTE_NDIS_SET_MSG\n", 
-			__FUNCTION__ );
 		return rndis_set_response (configNr, 
 					   (rndis_set_msg_type *) buf);
 		
 	case REMOTE_NDIS_RESET_MSG:
-		DEBUG(KERN_INFO "%s: REMOTE_NDIS_RESET_MSG\n", 
+		DEBUG("%s: REMOTE_NDIS_RESET_MSG\n", 
 			__FUNCTION__ );
 		return rndis_reset_response (configNr,
 					     (rndis_reset_msg_type *) buf);
 
 	case REMOTE_NDIS_KEEPALIVE_MSG:
 		/* For USB: host does this every 5 seconds */
-		DEBUG(KERN_INFO "%s: REMOTE_NDIS_KEEPALIVE_MSG\n", 
+#ifdef	VERBOSE
+		DEBUG("%s: REMOTE_NDIS_KEEPALIVE_MSG\n", 
 			__FUNCTION__ );
+#endif
 		return rndis_keepalive_response (configNr,
 						 (rndis_keepalive_msg_type *) 
 						 buf);
 		
 	default: 
-		printk (KERN_ERR "%s: unknown RNDIS Message Type 0x%08X\n", 
-			__FUNCTION__ , MsgType);
+		/* At least Windows XP emits some undefined RNDIS messages.
+		 * In one case those messages seemed to relate to the host
+		 * suspending itself.
+		 */
+		printk (KERN_WARNING
+			"%s: unknown RNDIS message 0x%08X len %d\n", 
+			__FUNCTION__ , MsgType, MsgLength);
+		{
+			unsigned i;
+			for (i = 0; i < MsgLength; i += 16) {
+				DEBUG ("%03d: "
+					" %02x %02x %02x %02x"
+					" %02x %02x %02x %02x"
+					" %02x %02x %02x %02x"
+					" %02x %02x %02x %02x"
+					"\n",
+					i,
+					buf[i], buf [i+1],
+						buf[i+2], buf[i+3],
+					buf[i+4], buf [i+5],
+						buf[i+6], buf[i+7],
+					buf[i+8], buf [i+9],
+						buf[i+10], buf[i+11],
+					buf[i+12], buf [i+13],
+						buf[i+14], buf[i+15]);
+			}
+		}
 		break;
 	}
 	
@@ -1079,13 +1127,12 @@
 int rndis_register (int (* rndis_control_ack) (struct net_device *))
 {
 	u8 i;
-	DEBUG("%s: ", __FUNCTION__ );
 	
 	for (i = 0; i < RNDIS_MAX_CONFIGS; i++) {
 		if (!rndis_per_dev_params [i].used) {
 			rndis_per_dev_params [i].used = 1;
 			rndis_per_dev_params [i].ack = rndis_control_ack;
-			DEBUG("configNr = %d\n", i);
+			DEBUG("%s: configNr = %d\n", __FUNCTION__, i);
 			return i;
 		}
 	}
@@ -1145,10 +1192,10 @@
 	if (!skb) return;
 	skb_push (skb, sizeof (struct rndis_packet_msg_type));
 	memset (skb->data, 0, sizeof (struct rndis_packet_msg_type));
-	*((u32 *) skb->data) = 1;
-	*((u32 *) skb->data + 1) = skb->len;
-	*((u32 *) skb->data + 2) = 36;
-	*((u32 *) skb->data + 3) = skb->len - 44;
+	*((u32 *) skb->data) = __constant_cpu_to_le32 (1);
+	*((u32 *) skb->data + 1) = cpu_to_le32(skb->len);
+	*((u32 *) skb->data + 2) = __constant_cpu_to_le32 (36);
+	*((u32 *) skb->data + 3) = cpu_to_le32(skb->len - 44);
 	
 	return;
 }
@@ -1208,14 +1255,16 @@
 
 int rndis_rm_hdr (u8 *buf, u32 *length)
 {
-	u32 i, messageLen, dataOffset;
+	u32 i, messageLen, dataOffset, *tmp;
 	
+	tmp = (u32 *) buf; 
+
 	if (!buf || !length) return -1;
-	if (*((u32 *) buf) != 1) return -1;
+	if (cpu_to_le32p(tmp++) != 1) return -1;
 	
-	messageLen = *((u32 *) buf + 1);
-	
-	dataOffset = *((u32 *) buf + 2) + 8;
+	messageLen = cpu_to_le32p(tmp++);
+	dataOffset = cpu_to_le32p(tmp++) + 8;
+
 	if (messageLen < dataOffset || messageLen > *length) return -1;
 	
 	for (i = dataOffset; i < messageLen; i++)
--- diff/drivers/usb/gadget/rndis.h	2004-06-11 19:17:31.000000000 +0100
+++ source/drivers/usb/gadget/rndis.h	2004-06-11 19:22:05.000000000 +0100
@@ -59,10 +59,18 @@
 
 #define RNDIS_MEDIUM_802_3		0x00000000U
 
+/* from drivers/net/sk98lin/h/skgepnmi.h */
+#define OID_PNP_CAPABILITIES			0xFD010100
+#define OID_PNP_SET_POWER			0xFD010101
+#define OID_PNP_QUERY_POWER			0xFD010102
+#define OID_PNP_ADD_WAKE_UP_PATTERN		0xFD010103
+#define OID_PNP_REMOVE_WAKE_UP_PATTERN		0xFD010104
+#define OID_PNP_ENABLE_WAKE_UP			0xFD010106
+
+
 /* supported OIDs */
 static const u32 oid_supported_list [] = 
 {
-	/* mandatory general */
 	/* the general stuff */
 	OID_GEN_SUPPORTED_LIST,
 	OID_GEN_HARDWARE_STATUS,
@@ -70,7 +78,6 @@
 	OID_GEN_MEDIA_IN_USE,
 	OID_GEN_MAXIMUM_FRAME_SIZE,
 	OID_GEN_LINK_SPEED,
-	OID_GEN_TRANSMIT_BUFFER_SPACE,
 	OID_GEN_TRANSMIT_BLOCK_SIZE,
 	OID_GEN_RECEIVE_BLOCK_SIZE,
 	OID_GEN_VENDOR_ID,
@@ -78,10 +85,11 @@
 	OID_GEN_VENDOR_DRIVER_VERSION,
 	OID_GEN_CURRENT_PACKET_FILTER,
 	OID_GEN_MAXIMUM_TOTAL_SIZE,
-	OID_GEN_MAC_OPTIONS,
 	OID_GEN_MEDIA_CONNECT_STATUS,
 	OID_GEN_PHYSICAL_MEDIUM,
+#if 0
 	OID_GEN_RNDIS_CONFIG_PARAMETER,
+#endif
 	
 	/* the statistical stuff */
 	OID_GEN_XMIT_OK,
@@ -89,6 +97,7 @@
 	OID_GEN_XMIT_ERROR,
 	OID_GEN_RCV_ERROR,
 	OID_GEN_RCV_NO_BUFFER,
+#ifdef	RNDIS_OPTIONAL_STATS
 	OID_GEN_DIRECTED_BYTES_XMIT,
 	OID_GEN_DIRECTED_FRAMES_XMIT,
 	OID_GEN_MULTICAST_BYTES_XMIT,
@@ -103,6 +112,7 @@
 	OID_GEN_BROADCAST_FRAMES_RCV,
 	OID_GEN_RCV_CRC_ERROR,
 	OID_GEN_TRANSMIT_QUEUE_LENGTH,
+#endif	/* RNDIS_OPTIONAL_STATS */
 
     	/* mandatory 802.3 */
 	/* the general stuff */
@@ -115,7 +125,30 @@
 	/* the statistical stuff */
 	OID_802_3_RCV_ERROR_ALIGNMENT,
 	OID_802_3_XMIT_ONE_COLLISION,
-	OID_802_3_XMIT_MORE_COLLISIONS
+	OID_802_3_XMIT_MORE_COLLISIONS,
+#ifdef	RNDIS_OPTIONAL_STATS
+	OID_802_3_XMIT_DEFERRED,
+	OID_802_3_XMIT_MAX_COLLISIONS,
+	OID_802_3_RCV_OVERRUN,
+	OID_802_3_XMIT_UNDERRUN,
+	OID_802_3_XMIT_HEARTBEAT_FAILURE,
+	OID_802_3_XMIT_TIMES_CRS_LOST,
+	OID_802_3_XMIT_LATE_COLLISIONS,
+#endif	/* RNDIS_OPTIONAL_STATS */
+
+#ifdef	RNDIS_PM
+	/* PM and wakeup are mandatory for USB: */
+
+	/* power management */
+	OID_PNP_CAPABILITIES,
+	OID_PNP_QUERY_POWER,
+	OID_PNP_SET_POWER,
+
+	/* wake up host */
+	OID_PNP_ENABLE_WAKE_UP,
+	OID_PNP_ADD_WAKE_UP_PATTERN,
+	OID_PNP_REMOVE_WAKE_UP_PATTERN,
+#endif
 };
 
 
--- diff/drivers/usb/host/ohci-dbg.c	2004-06-11 19:17:31.000000000 +0100
+++ source/drivers/usb/host/ohci-dbg.c	2004-06-11 19:22:05.000000000 +0100
@@ -134,13 +134,13 @@
 	struct ohci_regs	*regs = controller->regs;
 	u32			temp;
 
-	temp = readl (&regs->revision) & 0xff;
+	temp = ohci_readl (&regs->revision) & 0xff;
 	ohci_dbg_sw (controller, next, size,
 		"OHCI %d.%d, %s legacy support registers\n",
 		0x03 & (temp >> 4), (temp & 0x0f),
 		(temp & 0x10) ? "with" : "NO");
 
-	temp = readl (&regs->control);
+	temp = ohci_readl (&regs->control);
 	ohci_dbg_sw (controller, next, size,
 		"control 0x%03x%s%s%s HCFS=%s%s%s%s%s CBSR=%d\n",
 		temp,
@@ -155,7 +155,7 @@
 		temp & OHCI_CTRL_CBSR
 		);
 
-	temp = readl (&regs->cmdstatus);
+	temp = ohci_readl (&regs->cmdstatus);
 	ohci_dbg_sw (controller, next, size,
 		"cmdstatus 0x%05x SOC=%d%s%s%s%s\n", temp,
 		(temp & OHCI_SOC) >> 16,
@@ -166,26 +166,26 @@
 		);
 
 	ohci_dump_intr_mask (controller, "intrstatus",
-			readl (&regs->intrstatus), next, size);
+			ohci_readl (&regs->intrstatus), next, size);
 	ohci_dump_intr_mask (controller, "intrenable",
-			readl (&regs->intrenable), next, size);
+			ohci_readl (&regs->intrenable), next, size);
 	// intrdisable always same as intrenable
 
 	maybe_print_eds (controller, "ed_periodcurrent",
-			readl (&regs->ed_periodcurrent), next, size);
+			ohci_readl (&regs->ed_periodcurrent), next, size);
 
 	maybe_print_eds (controller, "ed_controlhead",
-			readl (&regs->ed_controlhead), next, size);
+			ohci_readl (&regs->ed_controlhead), next, size);
 	maybe_print_eds (controller, "ed_controlcurrent",
-			readl (&regs->ed_controlcurrent), next, size);
+			ohci_readl (&regs->ed_controlcurrent), next, size);
 
 	maybe_print_eds (controller, "ed_bulkhead",
-			readl (&regs->ed_bulkhead), next, size);
+			ohci_readl (&regs->ed_bulkhead), next, size);
 	maybe_print_eds (controller, "ed_bulkcurrent",
-			readl (&regs->ed_bulkcurrent), next, size);
+			ohci_readl (&regs->ed_bulkcurrent), next, size);
 
 	maybe_print_eds (controller, "donehead",
-			readl (&regs->donehead), next, size);
+			ohci_readl (&regs->donehead), next, size);
 }
 
 #define dbg_port_sw(hc,num,value,next,size) \
@@ -637,7 +637,7 @@
 			"hcca frame 0x%04x\n", OHCI_FRAME_NO(ohci->hcca));
 
 	/* other registers mostly affect frame timings */
-	rdata = readl (&regs->fminterval);
+	rdata = ohci_readl (&regs->fminterval);
 	temp = scnprintf (next, size,
 			"fmintvl 0x%08x %sFSMPS=0x%04x FI=0x%04x\n",
 			rdata, (rdata >> 31) ? " FIT" : "",
@@ -645,20 +645,20 @@
 	size -= temp;
 	next += temp;
 
-	rdata = readl (&regs->fmremaining);
+	rdata = ohci_readl (&regs->fmremaining);
 	temp = scnprintf (next, size, "fmremaining 0x%08x %sFR=0x%04x\n",
 			rdata, (rdata >> 31) ? " FRT" : "",
 			rdata & 0x3fff);
 	size -= temp;
 	next += temp;
 
-	rdata = readl (&regs->periodicstart);
+	rdata = ohci_readl (&regs->periodicstart);
 	temp = scnprintf (next, size, "periodicstart 0x%04x\n",
 			rdata & 0x3fff);
 	size -= temp;
 	next += temp;
 
-	rdata = readl (&regs->lsthresh);
+	rdata = ohci_readl (&regs->lsthresh);
 	temp = scnprintf (next, size, "lsthresh 0x%04x\n",
 			rdata & 0x3fff);
 	size -= temp;
--- diff/drivers/usb/host/ohci-hcd.c	2004-06-11 19:17:31.000000000 +0100
+++ source/drivers/usb/host/ohci-hcd.c	2004-06-11 19:22:05.000000000 +0100
@@ -17,6 +17,7 @@
  *
  * History:
  * 
+ * 2004/03/24 LH7A404 support (Durgesh Pattamatta & Marc Singer)
  * 2004/02/04 use generic dma_* functions instead of pci_* (dsaxena@plexity.net)
  * 2003/02/24 show registers in sysfs (Kevin Brosius)
  *
@@ -393,7 +394,7 @@
 
 	/* boot firmware should have set this up (5.1.1.3.1) */
 	if (!ohci->fminterval) {
-		temp = readl (&ohci->regs->fminterval);
+		temp = ohci_readl (&ohci->regs->fminterval);
 		if (temp & 0x3fff0000)
 			ohci->fminterval = temp;
 		else
@@ -405,7 +406,7 @@
 	 * On PA-RISC, PDC can leave IR set incorrectly; ignore it there.
 	 */
 #ifndef __hppa__
-	if (readl (&ohci->regs->control) & OHCI_CTRL_IR) {
+	if (ohci_readl (&ohci->regs->control) & OHCI_CTRL_IR) {
 		ohci_dbg (ohci, "USB HC TakeOver from BIOS/SMM\n");
 
 		/* this timeout is arbitrary.  we make it long, so systems
@@ -416,7 +417,7 @@
 
 		writel (OHCI_INTR_OC, &ohci->regs->intrenable);
 		writel (OHCI_OCR, &ohci->regs->cmdstatus);
-		while (readl (&ohci->regs->control) & OHCI_CTRL_IR) {
+		while (ohci_readl (&ohci->regs->control) & OHCI_CTRL_IR) {
 			msleep (10);
 			if (--temp == 0) {
 				ohci_err (ohci, "USB HC TakeOver failed!\n");
@@ -430,13 +431,13 @@
 	writel (OHCI_INTR_MIE, &ohci->regs->intrdisable);
 
 	ohci_dbg (ohci, "reset, control = 0x%x\n",
-		readl (&ohci->regs->control));
+		  ohci_readl (&ohci->regs->control));
 
   	/* Reset USB (needed by some controllers); RemoteWakeupConnected
 	 * saved if boot firmware (BIOS/SMM/...) told us it's connected
 	 * (for OHCI integrated on mainboard, it normally is)
 	 */
-	ohci->hc_control = readl (&ohci->regs->control);
+	ohci->hc_control = ohci_readl (&ohci->regs->control);
 	ohci->hc_control &= OHCI_CTRL_RWC;	/* hcfs 0 = RESET */
 	if (ohci->hc_control)
 		ohci->hcd.can_wakeup = 1;
@@ -450,13 +451,13 @@
 				&ohci->regs->roothub.portstatus [temp]);
 	}
 	// flush those pci writes
-	(void) readl (&ohci->regs->control);
+	(void) ohci_readl (&ohci->regs->control);
 	msleep (50);
 
 	/* HC Reset requires max 10 us delay */
 	writel (OHCI_HCR,  &ohci->regs->cmdstatus);
 	temp = 30;	/* ... allow extra time */
-	while ((readl (&ohci->regs->cmdstatus) & OHCI_HCR) != 0) {
+	while ((ohci_readl (&ohci->regs->cmdstatus) & OHCI_HCR) != 0) {
 		if (--temp == 0) {
 			ohci_err (ohci, "USB HC reset timed out!\n");
 			return -1;
@@ -473,7 +474,7 @@
 	 */
 	writel (ohci->hc_control, &ohci->regs->control);
 	// flush those pci writes
-	(void) readl (&ohci->regs->control);
+	(void) ohci_readl (&ohci->regs->control);
 
 	return 0;
 }
@@ -505,8 +506,8 @@
 	/* some OHCI implementations are finicky about how they init.
 	 * bogus values here mean not even enumeration could work.
 	 */
-	if ((readl (&ohci->regs->fminterval) & 0x3fff0000) == 0
-			|| !readl (&ohci->regs->periodicstart)) {
+	if ((ohci_readl (&ohci->regs->fminterval) & 0x3fff0000) == 0
+			|| !ohci_readl (&ohci->regs->periodicstart)) {
 		ohci_err (ohci, "init err\n");
 		return -EOVERFLOW;
 	}
@@ -548,7 +549,7 @@
 	writel (RH_HS_LPSC, &ohci->regs->roothub.status);
 	writel (power_switching ? RH_B_PPCM : 0, &ohci->regs->roothub.b);
 	// flush those pci writes
-	(void) readl (&ohci->regs->control);
+	(void) ohci_readl (&ohci->regs->control);
 
 	// POTPGT delay is bits 24-31, in 2 ms units.
 	mdelay ((roothub_a (ohci) >> 23) & 0x1fe);
@@ -592,19 +593,20 @@
 	struct ohci_regs	*regs = ohci->regs;
  	int			ints; 
 
-	/* we can eliminate a (slow) readl() if _only_ WDH caused this irq */
+	/* we can eliminate a (slow) ohci_readl()
+	   if _only_ WDH caused this irq */
 	if ((ohci->hcca->done_head != 0)
 			&& ! (le32_to_cpup (&ohci->hcca->done_head) & 0x01)) {
 		ints =  OHCI_INTR_WDH;
 
 	/* cardbus/... hardware gone before remove() */
-	} else if ((ints = readl (&regs->intrstatus)) == ~(u32)0) {
+	} else if ((ints = ohci_readl (&regs->intrstatus)) == ~(u32)0) {
 		disable (ohci);
 		ohci_dbg (ohci, "device removed!\n");
 		return IRQ_HANDLED;
 
 	/* interrupt for some other device? */
-	} else if ((ints &= readl (&regs->intrenable)) == 0) {
+	} else if ((ints &= ohci_readl (&regs->intrenable)) == 0) {
 		return IRQ_NONE;
 	} 
 
@@ -650,7 +652,7 @@
 		writel (ints, &regs->intrstatus);
 		writel (OHCI_INTR_MIE, &regs->intrenable);	
 		// flush those pci writes
-		(void) readl (&ohci->regs->control);
+		(void) ohci_readl (&ohci->regs->control);
 	}
 
 	return IRQ_HANDLED;
@@ -798,6 +800,14 @@
 #include "ohci-omap.c"
 #endif
 
-#if !(defined(CONFIG_PCI) || defined(CONFIG_SA1111) || defined(CONFIG_ARCH_OMAP))
+#ifdef CONFIG_ARCH_LH7A404
+#include "ohci-lh7a404.c"
+#endif
+
+#if !(defined(CONFIG_PCI) \
+      || defined(CONFIG_SA1111) \
+      || defined(CONFIG_ARCH_OMAP) \
+      || defined (CONFIG_ARCH_LH7A404) \
+	)
 #error "missing bus glue for ohci-hcd"
 #endif
--- diff/drivers/usb/host/ohci-hub.c	2004-06-11 19:17:31.000000000 +0100
+++ source/drivers/usb/host/ohci-hub.c	2004-06-11 19:22:05.000000000 +0100
@@ -20,20 +20,20 @@
  * till some bits (mostly reserved) are clear; ok for all revs.
  */
 #define read_roothub(hc, register, mask) ({ \
-	u32 temp = readl (&hc->regs->roothub.register); \
+	u32 temp = ohci_readl (&hc->regs->roothub.register); \
 	if (temp == -1) \
 		disable (hc); \
 	else if (hc->flags & OHCI_QUIRK_AMD756) \
 		while (temp & mask) \
-			temp = readl (&hc->regs->roothub.register); \
+			temp = ohci_readl (&hc->regs->roothub.register); \
 	temp; })
 
 static u32 roothub_a (struct ohci_hcd *hc)
 	{ return read_roothub (hc, a, 0xfc0fe000); }
 static inline u32 roothub_b (struct ohci_hcd *hc)
-	{ return readl (&hc->regs->roothub.b); }
+	{ return ohci_readl (&hc->regs->roothub.b); }
 static inline u32 roothub_status (struct ohci_hcd *hc)
-	{ return readl (&hc->regs->roothub.status); }
+	{ return ohci_readl (&hc->regs->roothub.status); }
 static u32 roothub_portstatus (struct ohci_hcd *hc, int i)
 	{ return read_roothub (hc, portstatus [i], 0xffe0fce0); }
 
@@ -83,14 +83,14 @@
 
 	spin_lock_irq (&ohci->lock);
 
-	ohci->hc_control = readl (&ohci->regs->control);
+	ohci->hc_control = ohci_readl (&ohci->regs->control);
 	switch (ohci->hc_control & OHCI_CTRL_HCFS) {
 	case OHCI_USB_RESUME:
 		ohci_dbg (ohci, "resume/suspend?\n");
 		ohci->hc_control &= ~OHCI_CTRL_HCFS;
 		ohci->hc_control |= OHCI_USB_RESET;
 		writel (ohci->hc_control, &ohci->regs->control);
-		(void) readl (&ohci->regs->control);
+		(void) ohci_readl (&ohci->regs->control);
 		/* FALL THROUGH */
 	case OHCI_USB_RESET:
 		status = -EBUSY;
@@ -109,7 +109,7 @@
 
 		ohci->hc_control &= ~OHCI_SCHED_ENABLES;
 		writel (ohci->hc_control, &ohci->regs->control);
-		ohci->hc_control = readl (&ohci->regs->control);
+		ohci->hc_control = ohci_readl (&ohci->regs->control);
 		writel (OHCI_INTR_SF, &ohci->regs->intrstatus);
 
 		/* sched disables take effect on the next frame,
@@ -120,7 +120,7 @@
 		while (limit > 0) {
 			udelay (250);
 			limit =- 250;
-			if (readl (&ohci->regs->intrstatus) & OHCI_INTR_SF)
+			if (ohci_readl (&ohci->regs->intrstatus) & OHCI_INTR_SF)
 				break;
 		}
 		dl_done_list (ohci, 0);
@@ -128,7 +128,7 @@
 	}
 	dl_done_list (ohci, 0);
 	finish_unlinks (ohci, OHCI_FRAME_NO(ohci->hcca), 0);
-	writel (readl (&ohci->regs->intrstatus), &ohci->regs->intrstatus);
+	writel (ohci_readl (&ohci->regs->intrstatus), &ohci->regs->intrstatus);
 
 	/* maybe resume can wake root hub */
 	if (ohci->hcd.remote_wakeup)
@@ -140,7 +140,7 @@
 	ohci->hc_control &= ~OHCI_CTRL_HCFS;
 	ohci->hc_control |= OHCI_USB_SUSPEND;
 	writel (ohci->hc_control, &ohci->regs->control);
-	(void) readl (&ohci->regs->control);
+	(void) ohci_readl (&ohci->regs->control);
 
 	/* no resumes until devices finish suspending */
 	ohci->next_statechange = jiffies + msecs_to_jiffies (5);
@@ -179,13 +179,13 @@
 		return -EAGAIN;
 
 	spin_lock_irq (&ohci->lock);
-	ohci->hc_control = readl (&ohci->regs->control);
+	ohci->hc_control = ohci_readl (&ohci->regs->control);
 	switch (ohci->hc_control & OHCI_CTRL_HCFS) {
 	case OHCI_USB_SUSPEND:
 		ohci->hc_control &= ~(OHCI_CTRL_HCFS|OHCI_SCHED_ENABLES);
 		ohci->hc_control |= OHCI_USB_RESUME;
 		writel (ohci->hc_control, &ohci->regs->control);
-		(void) readl (&ohci->regs->control);
+		(void) ohci_readl (&ohci->regs->control);
 		ohci_dbg (ohci, "resume root hub\n");
 		break;
 	case OHCI_USB_RESUME:
@@ -210,7 +210,7 @@
 	temp = roothub_a (ohci) & RH_A_NDP;
 	enables = 0;
 	while (temp--) {
-		u32 stat = readl (&ohci->regs->roothub.portstatus [temp]);
+		u32 stat = ohci_readl (&ohci->regs->roothub.portstatus [temp]);
 
 		/* force global, not selective, resume */
 		if (!(stat & RH_PS_PSS))
@@ -222,7 +222,7 @@
 	ohci->hcd.state = USB_STATE_RESUMING;
 	mdelay (20 /* usb 11.5.1.10 */ + 15);
 
-	temp = readl (&ohci->regs->control);
+	temp = ohci_readl (&ohci->regs->control);
 	temp &= OHCI_CTRL_HCFS;
 	if (temp != OHCI_USB_RESUME) {
 		ohci_err (ohci, "controller won't resume\n");
@@ -243,11 +243,11 @@
 	writel (OHCI_INTR_INIT, &ohci->regs->intrenable);
 	if (ohci->ed_rm_list)
 		writel (OHCI_INTR_SF, &ohci->regs->intrenable);
-	writel (readl (&ohci->regs->intrstatus), &ohci->regs->intrstatus);
+	writel (ohci_readl (&ohci->regs->intrstatus), &ohci->regs->intrstatus);
 
 	/* Then re-enable operations */
 	writel (OHCI_USB_OPER, &ohci->regs->control);
-	(void) readl (&ohci->regs->control);
+	(void) ohci_readl (&ohci->regs->control);
 	msleep (3);
 
 	temp = OHCI_CONTROL_INIT | OHCI_USB_OPER;
@@ -255,7 +255,7 @@
 		temp |= OHCI_CTRL_RWC;
 	ohci->hc_control = temp;
 	writel (temp, &ohci->regs->control);
-	(void) readl (&ohci->regs->control);
+	(void) ohci_readl (&ohci->regs->control);
 
 	/* TRSMRCY */
 	msleep (10);
@@ -290,7 +290,7 @@
 		writel (ohci->hc_control, &ohci->regs->control);
 		if (temp)
 			writel (status, &ohci->regs->cmdstatus);
-		(void) readl (&ohci->regs->control);
+		(void) ohci_readl (&ohci->regs->control);
 	}
 
 	ohci->hcd.state = USB_STATE_RUNNING;
@@ -332,7 +332,7 @@
 		if (!HCD_IS_RUNNING(ohci->hcd.state))
 			return -ESHUTDOWN;
 		ohci_err (ohci, "bogus NDP=%d, rereads as NDP=%d\n",
-			ports, readl (&ohci->regs->roothub.a) & RH_A_NDP);
+			ports, ohci_readl (&ohci->regs->roothub.a) & RH_A_NDP);
 		/* retry later; "should not happen" */
 		return 0;
 	}
@@ -496,7 +496,7 @@
 			goto error;
 		}
 		writel (temp, &ohci->regs->roothub.portstatus [wIndex]);
-		// readl (&ohci->regs->roothub.portstatus [wIndex]);
+		// ohci_readl (&ohci->regs->roothub.portstatus [wIndex]);
 		break;
 	case GetHubDescriptor:
 		ohci_hub_descriptor (ohci, (struct usb_hub_descriptor *) buf);
@@ -541,7 +541,7 @@
 				&ohci->regs->roothub.portstatus [wIndex]);
 			break;
 		case USB_PORT_FEAT_RESET:
-			temp = readl (&ohci->regs->roothub.portstatus [wIndex]);
+			temp = ohci_readl (&ohci->regs->roothub.portstatus [wIndex]);
 			if (temp & RH_PS_CCS)
 				writel (RH_PS_PRS,
 				    &ohci->regs->roothub.portstatus [wIndex]);
--- diff/drivers/usb/host/ohci-q.c	2004-06-11 19:17:31.000000000 +0100
+++ source/drivers/usb/host/ohci-q.c	2004-06-11 19:22:05.000000000 +0100
@@ -321,7 +321,7 @@
 			if (!ed->hwNextED) {
 				ohci->hc_control &= ~OHCI_CTRL_CLE;
 				writel (ohci->hc_control, &ohci->regs->control);
-				// a readl() later syncs CLE with the HC
+				// a ohci_readl() later syncs CLE with the HC
 			} else
 				writel (le32_to_cpup (&ed->hwNextED),
 					&ohci->regs->ed_controlhead);
@@ -345,7 +345,7 @@
 			if (!ed->hwNextED) {
 				ohci->hc_control &= ~OHCI_CTRL_BLE;
 				writel (ohci->hc_control, &ohci->regs->control);
-				// a readl() later syncs BLE with the HC
+				// a ohci_readl() later syncs BLE with the HC
 			} else
 				writel (le32_to_cpup (&ed->hwNextED),
 					&ohci->regs->ed_bulkhead);
@@ -481,7 +481,7 @@
 	writel (OHCI_INTR_SF, &ohci->regs->intrstatus);
 	writel (OHCI_INTR_SF, &ohci->regs->intrenable);
 	// flush those writes, and get latest HCCA contents
-	(void) readl (&ohci->regs->control);
+	(void) ohci_readl (&ohci->regs->control);
 
 	/* SF interrupt might get delayed; record the frame counter value that
 	 * indicates when the HC isn't looking at it, so concurrent unlinks
--- diff/drivers/usb/host/ohci.h	2004-06-11 19:17:31.000000000 +0100
+++ source/drivers/usb/host/ohci.h	2004-06-11 19:22:05.000000000 +0100
@@ -429,3 +429,22 @@
 #	define ohci_vdbg(ohci, fmt, args...) do { } while (0)
 #endif
 
+#ifdef CONFIG_ARCH_LH7A404
+	/* Marc Singer: at the time this code was written, the LH7A404
+	 * had a problem reading the USB host registers.  This
+	 * implementation of the ohci_readl function performs the read
+	 * twice as a work-around.
+	 */
+static inline unsigned int ohci_readl (void* regs)
+{
+	*(volatile unsigned int*) regs;
+	return *(volatile unsigned int*) regs;
+}
+#else
+	/* Standard version of ohci_readl uses standard, platform
+	 * specific implementation. */
+static inline unsigned int ohci_readl (void* regs)
+{
+	return readl (regs);
+}
+#endif
--- diff/drivers/usb/host/uhci-hcd.c	2004-06-11 19:17:31.000000000 +0100
+++ source/drivers/usb/host/uhci-hcd.c	2004-06-11 19:22:05.000000000 +0100
@@ -103,8 +103,8 @@
 static void hc_state_transitions(struct uhci_hcd *uhci);
 
 /* If a transfer is still active after this much time, turn off FSBR */
-#define IDLE_TIMEOUT	(HZ / 20)	/* 50 ms */
-#define FSBR_DELAY	(HZ / 20)	/* 50 ms */
+#define IDLE_TIMEOUT	msecs_to_jiffies(50)
+#define FSBR_DELAY	msecs_to_jiffies(50)
 
 /* When we timeout an idle transfer for FSBR, we'll switch it over to */
 /* depth first traversal. We'll do it in groups of this number of TD's */
@@ -1611,6 +1611,7 @@
 	struct uhci_hcd *uhci = hcd_to_uhci(hcd);
 	struct list_head list, *tmp, *head;
 	unsigned long flags;
+	int called_uhci_finish_completion = 0;
 
 	INIT_LIST_HEAD(&list);
 
@@ -1619,6 +1620,7 @@
 	    uhci_get_current_frame_number(uhci) != uhci->urb_remove_age) {
 		uhci_remove_pending_urbps(uhci);
 		uhci_finish_completion(hcd, NULL);
+		called_uhci_finish_completion = 1;
 	}
 
 	head = &uhci->urb_list;
@@ -1646,6 +1648,10 @@
 	}
 	spin_unlock_irqrestore(&uhci->schedule_lock, flags);
 
+	/* Wake up anyone waiting for an URB to complete */
+	if (called_uhci_finish_completion)
+		wake_up_all(&uhci->waitqh);
+
 	head = &list;
 	tmp = head->next;
 	while (tmp != head) {
@@ -1676,7 +1682,7 @@
 	init_timer(&uhci->stall_timer);
 	uhci->stall_timer.function = stall_callback;
 	uhci->stall_timer.data = (unsigned long)hcd;
-	uhci->stall_timer.expires = jiffies + (HZ / 10);
+	uhci->stall_timer.expires = jiffies + msecs_to_jiffies(100);
 	add_timer(&uhci->stall_timer);
 
 	return 0;
@@ -1831,16 +1837,20 @@
 {
 	unsigned int io_addr = uhci->io_addr;
 
+	/* Turn off PIRQ, SMI, and all interrupts.  This also turns off
+	 * the BIOS's USB Legacy Support.
+	 */
+	pci_write_config_word(to_pci_dev(uhci_dev(uhci)), USBLEGSUP, 0);
+	outw(0, uhci->io_addr + USBINTR);
+
 	/* Global reset for 50ms */
 	uhci->state = UHCI_RESET;
 	outw(USBCMD_GRESET, io_addr + USBCMD);
-	set_current_state(TASK_UNINTERRUPTIBLE);
-	schedule_timeout((HZ*50+999) / 1000);
+	msleep(50);
 	outw(0, io_addr + USBCMD);
 
 	/* Another 10ms delay */
-	set_current_state(TASK_UNINTERRUPTIBLE);
-	schedule_timeout((HZ*10+999) / 1000);
+	msleep(10);
 	uhci->resume_detect = 0;
 }
 
@@ -1865,7 +1875,7 @@
 			/* Global resume for >= 20ms */
 			outw(USBCMD_FGR | USBCMD_EGSM, io_addr + USBCMD);
 			uhci->state = UHCI_RESUMING_1;
-			uhci->state_end = jiffies + (20*HZ+999) / 1000;
+			uhci->state_end = jiffies + msecs_to_jiffies(20);
 			break;
 
 		case UHCI_RESUMING_1:		/* End global resume */
@@ -1990,7 +2000,9 @@
 		}
 	}
 
-	/* Turn on all interrupts */
+	/* Turn on PIRQ and all interrupts */
+	pci_write_config_word(to_pci_dev(uhci_dev(uhci)), USBLEGSUP,
+			USBLEGSUP_DEFAULT);
 	outw(USBINTR_TIMEOUT | USBINTR_RESUME | USBINTR_IOC | USBINTR_SP,
 		io_addr + USBINTR);
 
@@ -2054,15 +2066,10 @@
 
 	uhci->io_addr = (unsigned long) hcd->regs;
 
-	/* Turn off all interrupts */
-	outw(0, uhci->io_addr + USBINTR);
-
-	/* Maybe kick BIOS off this hardware.  Then reset, so we won't get
+	/* Kick BIOS off this hardware and reset, so we won't get
 	 * interrupts from any previous setup.
 	 */
 	reset_hc(uhci);
-	pci_write_config_word(to_pci_dev(uhci_dev(uhci)), USBLEGSUP,
-			USBLEGSUP_DEFAULT);
 	return 0;
 }
 
@@ -2369,14 +2376,18 @@
 		/*
 		 * Some systems don't maintain the UHCI register values
 		 * during a PM suspend/resume cycle, so reinitialize
-		 * the Frame Number, the Framelist Base Address, and the
-		 * Interrupt Enable registers.
+		 * the Frame Number, Framelist Base Address, Interrupt
+		 * Enable, and Legacy Support registers.
 		 */
+		pci_write_config_word(to_pci_dev(uhci_dev(uhci)), USBLEGSUP,
+				0);
 		outw(uhci->saved_framenumber, uhci->io_addr + USBFRNUM);
 		outl(uhci->fl->dma_handle, uhci->io_addr + USBFLBASEADD);
 		outw(USBINTR_TIMEOUT | USBINTR_RESUME | USBINTR_IOC |
 				USBINTR_SP, uhci->io_addr + USBINTR);
 		uhci->resume_detect = 1;
+		pci_write_config_word(to_pci_dev(uhci_dev(uhci)), USBLEGSUP,
+				USBLEGSUP_DEFAULT);
 	} else {
 		reset_hc(uhci);
 		start_hc(uhci);
--- diff/drivers/usb/input/hiddev.c	2004-06-11 19:17:31.000000000 +0100
+++ source/drivers/usb/input/hiddev.c	2004-06-11 19:22:05.000000000 +0100
@@ -638,16 +638,22 @@
 				goto inval;
 
 			field = report->field[uref->field_index];
-			if (uref->usage_index >= field->maxusage)
-				goto inval;
 
-			if (cmd == HIDIOCGUSAGES || cmd == HIDIOCSUSAGES) {
-				if (uref_multi->num_values >= HID_MAX_USAGES || 
-				    uref->usage_index >= field->maxusage || 
-				   (uref->usage_index + uref_multi->num_values) >= field->maxusage)
+			if (cmd == HIDIOCGCOLLECTIONINDEX) {
+				if (uref->usage_index >= field->maxusage)
 					goto inval;
+			} else if (uref->usage_index >= field->report_count)
+				goto inval;
+
+			else if ((cmd == HIDIOCGUSAGES ||
+				  cmd == HIDIOCSUSAGES) &&
+				 (uref->usage_index + uref_multi->num_values >=
+				  field->report_count ||
+				  uref->usage_index + uref_multi->num_values <
+				  uref->usage_index))
+				goto inval;
+
 			}
-		}
 
 		switch (cmd) {
 			case HIDIOCGUSAGE:
--- diff/drivers/usb/media/Kconfig	2004-05-19 22:12:18.000000000 +0100
+++ source/drivers/usb/media/Kconfig	2004-06-11 19:22:05.000000000 +0100
@@ -108,7 +108,7 @@
 
 config USB_PWC
 	tristate "USB Philips Cameras"
-	depends on USB && VIDEO_DEV && BROKEN
+	depends on USB && VIDEO_DEV
 	---help---
 	  Say Y or M here if you want to use one of these Philips & OEM
           webcams:
--- diff/drivers/usb/media/pwc-if.c	2004-06-11 19:17:31.000000000 +0100
+++ source/drivers/usb/media/pwc-if.c	2004-06-11 19:22:05.000000000 +0100
@@ -129,7 +129,6 @@
 
 static int pwc_video_open(struct inode *inode, struct file *file);
 static int pwc_video_close(struct inode *inode, struct file *file);
-static int pwc_video_release(struct video_device *);			  
 static ssize_t pwc_video_read(struct file *file, char *buf,
 			  size_t count, loff_t *ppos);
 static unsigned int pwc_video_poll(struct file *file, poll_table *wait);
@@ -1121,12 +1120,6 @@
 	return 0;
 }
 
-static int pwc_video_release(struct video_device *vfd)
-{
-	Trace(TRACE_OPEN, "pwc_video_release() called. Now what?\n");
-}
-		
-
 /*
  *	FIXME: what about two parallel reads ????
  *      ANSWER: Not supported. You can't open the device more than once,
@@ -1855,7 +1848,7 @@
 		}
 	}
 
-	pdev->vdev.release = pwc_video_release;
+	pdev->vdev.release = video_device_release;
 	i = video_register_device(&pdev->vdev, VFL_TYPE_GRABBER, video_nr);
 	if (i < 0) {
 		Err("Failed to register as video device (%d).\n", i);
--- diff/drivers/usb/net/pegasus.h	2004-06-11 19:17:31.000000000 +0100
+++ source/drivers/usb/net/pegasus.h	2004-06-11 19:22:05.000000000 +0100
@@ -121,6 +121,7 @@
 #define	VENDOR_ADMTEK		0x07a6
 #define	VENDOR_AEILAB		0x3334
 #define	VENDOR_ALLIEDTEL	0x07c9
+#define	VENDOR_ATEN		0x0557
 #define	VENDOR_BELKIN		0x050d
 #define	VENDOR_BILLIONTON	0x08dd
 #define	VENDOR_COMPAQ		0x049f
@@ -150,6 +151,8 @@
 
 PEGASUS_DEV( "3Com USB Ethernet 3C460B", VENDOR_3COM, 0x4601,
 		DEFAULT_GPIO_RESET | PEGASUS_II )
+PEGASUS_DEV( "ATEN USB Ethernet UC-110T", VENDOR_ATEN, 0x2007,
+		DEFAULT_GPIO_RESET | PEGASUS_II )
 PEGASUS_DEV( "USB HPNA/Ethernet", VENDOR_ABOCOM, 0x110c,
 		DEFAULT_GPIO_RESET | PEGASUS_II | HAS_HOME_PNA )
 PEGASUS_DEV( "USB HPNA/Ethernet", VENDOR_ABOCOM, 0x4104,
--- diff/drivers/usb/serial/bus.c	2004-05-19 22:12:19.000000000 +0100
+++ source/drivers/usb/serial/bus.c	2004-06-11 19:22:05.000000000 +0100
@@ -78,8 +78,8 @@
 	minor = port->number;
 	tty_register_device (usb_serial_tty_driver, minor, dev);
 	dev_info(&port->serial->dev->dev, 
-		 "%s converter now attached to ttyUSB%d (or usb/tts/%d for devfs)\n",
-		 driver->name, minor, minor);
+		 "%s converter now attached to ttyUSB%d\n",
+		 driver->name, minor);
 
 exit:
 	return retval;
--- diff/drivers/usb/serial/cyberjack.c	2004-06-11 19:17:31.000000000 +0100
+++ source/drivers/usb/serial/cyberjack.c	2004-06-11 19:22:05.000000000 +0100
@@ -109,7 +109,7 @@
 	short		rdtodo;		/* Bytes still to read */
 	unsigned char	wrbuf[5*64];	/* Buffer for collecting data to write */
 	short		wrfilled;	/* Overall data size we already got */
-	short		wrsent;		/* Data akready sent */
+	short		wrsent;		/* Data already sent */
 };
 
 /* do some startup allocations not currently performed by usb_serial_probe() */
@@ -159,8 +159,6 @@
 
 	dbg("%s - usb_clear_halt", __FUNCTION__ );
 	usb_clear_halt(port->serial->dev, port->write_urb->pipe);
-	usb_clear_halt(port->serial->dev, port->read_urb->pipe);
-	usb_clear_halt(port->serial->dev, port->interrupt_in_urb->pipe);
 
 	/* force low_latency on so that our tty_push actually forces
 	 * the data through, otherwise it is scheduled, and with high
@@ -212,7 +210,6 @@
 	unsigned long flags;
 	int result;
 	int wrexpected;
-	unsigned char localbuf[CYBERJACK_LOCAL_BUF_SIZE];	/* Buffer for collecting data to write */
 
 	dbg("%s - port %d", __FUNCTION__, port->number);
 	dbg("%s - from_user %d", __FUNCTION__, from_user);
@@ -229,29 +226,23 @@
 
 	spin_lock_irqsave(&priv->lock, flags);
 
-	if( (count+priv->wrfilled)>sizeof(priv->wrbuf) ||
-		(count>sizeof(localbuf)) ) {
-		/* To much data  for buffer. Reset buffer. */
+	if( (count+priv->wrfilled)>sizeof(priv->wrbuf) ) {
+		/* To much data for buffer. Reset buffer. */
 		priv->wrfilled=0;
 		spin_unlock_irqrestore(&priv->lock, flags);
 		return (0);
 	}
 
-	spin_unlock_irqrestore(&priv->lock, flags);
-
 	/* Copy data */
 	if (from_user) {
-		if (copy_from_user(localbuf, buf, count)) {
+		if (copy_from_user(priv->wrbuf+priv->wrfilled, buf, count)) {
+			spin_unlock_irqrestore(&priv->lock, flags);
 			return -EFAULT;
 		}
 	} else {
-		memcpy (localbuf, buf, count);
+		memcpy (priv->wrbuf+priv->wrfilled, buf, count);
 	}  
 
-	spin_lock_irqsave(&priv->lock, flags);
-
-	memcpy (priv->wrbuf+priv->wrfilled, localbuf, count);
-
 	usb_serial_debug_data (__FILE__, __FUNCTION__, count,
 		priv->wrbuf+priv->wrfilled);
 	priv->wrfilled += count;
--- diff/drivers/usb/serial/ftdi_sio.c	2004-06-11 19:17:31.000000000 +0100
+++ source/drivers/usb/serial/ftdi_sio.c	2004-06-11 19:22:05.000000000 +0100
@@ -1504,6 +1504,7 @@
 	if (status) {
 		err("%s - failed submitting write urb, error %d", __FUNCTION__, status);
 		count = status;
+		kfree (buffer);
 	}
 
 	/* we are done with this urb, so let the host driver
--- diff/drivers/usb/serial/visor.c	2004-06-11 19:17:32.000000000 +0100
+++ source/drivers/usb/serial/visor.c	2004-06-11 19:22:05.000000000 +0100
@@ -247,6 +247,8 @@
 		.driver_info = (kernel_ulong_t)&palm_os_4_probe },
 	{ USB_DEVICE(ACEECA_VENDOR_ID, ACEECA_MEZ1000_ID),
 		.driver_info = (kernel_ulong_t)&palm_os_4_probe },
+	{ USB_DEVICE(KYOCERA_VENDOR_ID, KYOCERA_7135_ID),
+		.driver_info = (kernel_ulong_t)&palm_os_4_probe },
 	{ },					/* optional parameter entry */
 	{ }					/* Terminating entry */
 };
@@ -290,6 +292,7 @@
 	{ USB_DEVICE(SAMSUNG_VENDOR_ID, SAMSUNG_SPH_I500_ID) },
 	{ USB_DEVICE(GARMIN_VENDOR_ID, GARMIN_IQUE_3600_ID) },
 	{ USB_DEVICE(ACEECA_VENDOR_ID, ACEECA_MEZ1000_ID) },
+	{ USB_DEVICE(KYOCERA_VENDOR_ID, KYOCERA_7135_ID) },
 	{ },					/* optional parameter entry */
 	{ }					/* Terminating entry */
 };
@@ -515,6 +518,7 @@
 		dev_err(&port->dev, "%s - usb_submit_urb(write bulk) failed with status = %d\n",
 			__FUNCTION__, status);
 		count = status;
+		kfree (buffer);
 	} else {
 		bytes_out += count;
 	}
@@ -795,7 +799,7 @@
 		dev_err(dev, "%s - error %d getting connection info\n",
 			__FUNCTION__, retval);
 	else
-		usb_serial_debug_data (__FILE__, __FUNCTION__, 0x14, transfer_buffer);
+		usb_serial_debug_data (__FILE__, __FUNCTION__, retval, transfer_buffer);
 
 	kfree (transfer_buffer);
 	return 0;
@@ -881,18 +885,19 @@
 
 	/* Only do this endpoint hack for the Handspring devices with
 	 * interrupt in endpoints, which for now are the Treo devices. */
-	if ((serial->dev->descriptor.idVendor != HANDSPRING_VENDOR_ID) ||
+	if (!((serial->dev->descriptor.idVendor == HANDSPRING_VENDOR_ID) ||
+	      (serial->dev->descriptor.idVendor == KYOCERA_VENDOR_ID)) ||
 	    (serial->num_interrupt_in == 0))
 		return 0;
 
 	dbg("%s", __FUNCTION__);
 
 	/*
-	* It appears that Treos want to use the 1st interrupt endpoint to
-	* communicate with the 2nd bulk out endpoint, so let's swap the 1st
-	* and 2nd bulk in and interrupt endpoints.  Note that swapping the
-	* bulk out endpoints would break lots of apps that want to communicate
-	* on the second port.
+	* It appears that Treos and Kyoceras want to use the 
+	* 1st bulk in endpoint to communicate with the 2nd bulk out endpoint, 
+	* so let's swap the 1st and 2nd bulk in and interrupt endpoints.  
+	* Note that swapping the bulk out endpoints would break lots of 
+	* apps that want to communicate on the second port.
 	*/
 #define COPY_PORT(dest, src)						\
 	dest->read_urb = src->read_urb;					\
--- diff/drivers/usb/serial/visor.h	2004-06-11 19:17:32.000000000 +0100
+++ source/drivers/usb/serial/visor.h	2004-06-11 19:22:05.000000000 +0100
@@ -55,6 +55,9 @@
 #define ACEECA_VENDOR_ID		0x4766
 #define ACEECA_MEZ1000_ID		0x0001
 
+#define KYOCERA_VENDOR_ID		0x0C88
+#define KYOCERA_7135_ID			0x0021 
+
 /****************************************************************************
  * Handspring Visor Vendor specific request codes (bRequest values)
  * A big thank you to Handspring for providing the following information.
--- diff/drivers/usb/storage/scsiglue.c	2004-06-11 19:17:32.000000000 +0100
+++ source/drivers/usb/storage/scsiglue.c	2004-06-11 19:22:05.000000000 +0100
@@ -409,6 +409,9 @@
 	/* emulated HBA */
 	.emulated =			TRUE,
 
+	/* we do our own delay after a device or bus reset */
+	.skip_settle_delay =		1,
+
 	/* sysfs device attributes */
 	.sdev_attrs =			sysfs_device_attr_list,
 
--- diff/drivers/usb/storage/transport.c	2004-06-11 19:17:32.000000000 +0100
+++ source/drivers/usb/storage/transport.c	2004-06-11 19:22:05.000000000 +0100
@@ -908,26 +908,29 @@
 				 USB_RECIP_INTERFACE,
 				 0, us->ifnum, us->iobuf, 1, HZ);
 
+	US_DEBUGP("GetMaxLUN command result is %d, data is %d\n", 
+		  result, us->iobuf[0]);
+
+	/* if we have a successful request, return the result */
+	if (result == 1)
+		return us->iobuf[0];
+
 	/* 
 	 * Some devices (i.e. Iomega Zip100) need this -- apparently
 	 * the bulk pipes get STALLed when the GetMaxLUN request is
 	 * processed.   This is, in theory, harmless to all other devices
 	 * (regardless of if they stall or not).
 	 */
-	if (result < 0) {
+	if (result == -EPIPE) {
 		usb_stor_clear_halt(us, us->recv_bulk_pipe);
 		usb_stor_clear_halt(us, us->send_bulk_pipe);
+		/* return the default -- no LUNs */
+		return 0;
 	}
 
-	US_DEBUGP("GetMaxLUN command result is %d, data is %d\n", 
-		  result, us->iobuf[0]);
-
-	/* if we have a successful request, return the result */
-	if (result == 1)
-		return us->iobuf[0];
-
-	/* return the default -- no LUNs */
-	return 0;
+	/* An answer or a STALL are the only valid responses.  If we get
+	 * something else, return an indication of error */
+	return -1;
 }
 
 int usb_stor_Bulk_transport(Scsi_Cmnd *srb, struct us_data *us)
--- diff/drivers/usb/storage/unusual_devs.h	2004-06-11 19:17:32.000000000 +0100
+++ source/drivers/usb/storage/unusual_devs.h	2004-06-11 19:22:05.000000000 +0100
@@ -359,13 +359,19 @@
 UNUSUAL_DEV(  0x0595, 0x4343, 0x0000, 0x2210,
 		"Fujifilm",
 		"Digital Camera EX-20 DSC",
-		US_SC_8070, US_PR_CBI, NULL, 0 ),
+		US_SC_8070, US_PR_DEVICE, NULL, 0 ),
 
 UNUSUAL_DEV(  0x059f, 0xa601, 0x0200, 0x0200, 
 		"LaCie",
 		"USB Hard Disk",
 		US_SC_RBC, US_PR_CB, NULL, 0 ), 
 
+/* Submitted by Jol Bourquard <numlock@freesurf.ch> */
+UNUSUAL_DEV(  0x05ab, 0x0060, 0x1104, 0x1110,
+		"In-System",
+		"PyroGate External CD-ROM Enclosure (FCD-523)",
+		US_SC_SCSI, US_PR_BULK, NULL, 0 ),
+
 #ifdef CONFIG_USB_STORAGE_ISD200
 UNUSUAL_DEV(  0x05ab, 0x0031, 0x0100, 0x0110,
 		"In-System",
@@ -628,20 +634,14 @@
  * - Some cameras with idProduct=0x1001 and bcdDevice=0x1000 have
  *   bInterfaceProtocol=0x00 (US_PR_CBI) while others have 0x01 (US_PR_CB).
  *   So don't remove the US_PR_CB override!
+ * - Cameras with bcdDevice=0x9009 require the US_SC_8070 override.
  */
-UNUSUAL_DEV( 0x07cf, 0x1001, 0x1000, 0x9009,
+UNUSUAL_DEV( 0x07cf, 0x1001, 0x1000, 0x9999,
 		"Casio",
 		"QV DigitalCamera",
-		US_SC_DEVICE, US_PR_CB, NULL,
+		US_SC_8070, US_PR_CB, NULL,
 		US_FL_NEED_OVERRIDE | US_FL_FIX_INQUIRY ),
 
-/* Later Casio cameras apparently tell the truth */
-UNUSUAL_DEV( 0x07cf, 0x1001, 0x9010, 0x9999,
-		"Casio",
-		"QV DigitalCamera",
-		US_SC_DEVICE, US_PR_DEVICE, NULL,
-		US_FL_FIX_INQUIRY ),
-
 /* Submitted by Hartmut Wahl <hwahl@hwahl.de>*/
 UNUSUAL_DEV( 0x0839, 0x000a, 0x0001, 0x0001,
 		"Samsung",
--- diff/drivers/usb/storage/usb.c	2004-06-11 19:17:32.000000000 +0100
+++ source/drivers/usb/storage/usb.c	2004-06-11 19:22:05.000000000 +0100
@@ -754,8 +754,14 @@
 	down(&us->dev_semaphore);
 
 	/* For bulk-only devices, determine the max LUN value */
-	if (us->protocol == US_PR_BULK)
-		us->max_lun = usb_stor_Bulk_max_lun(us);
+	if (us->protocol == US_PR_BULK) {
+		p = usb_stor_Bulk_max_lun(us);
+		if (p < 0) {
+			up(&us->dev_semaphore);
+			return p;
+		}
+		us->max_lun = p;
+	}
 
 	/* Just before we start our control thread, initialize
 	 * the device if it needs initialization */
--- diff/drivers/video/console/fbcon.c	2004-06-11 19:17:32.000000000 +0100
+++ source/drivers/video/console/fbcon.c	2004-06-11 19:22:05.000000000 +0100
@@ -601,8 +601,9 @@
 	int display_fg = (*default_mode)->vc_num;
 	int logo = 1, rows, cols, charcnt = 256;
 	unsigned short *save = NULL, *r, *q;
+	int cap = info->flags;
 
-	if (vc->vc_num != display_fg || (info->flags & FBINFO_FLAG_MODULE) ||
+	if (vc->vc_num != display_fg || (info->flags & FBINFO_MODULE) ||
 	    (info->fix.type == FB_TYPE_TEXT))
 		logo = 0;
 
@@ -635,10 +636,10 @@
 	rows = info->var.yres / vc->vc_font.height;
 	vc_resize(vc->vc_num, cols, rows);
 
-	if (info->var.accel_flags)
-		p->scrollmode = SCROLL_YNOMOVE;
-	else
-		p->scrollmode = SCROLL_YREDRAW;
+	if ((cap & FBINFO_HWACCEL_COPYAREA) && !(cap & FBINFO_HWACCEL_DISABLED))
+		p->scrollmode = SCROLL_ACCEL;
+	else /* default to something safe */
+		p->scrollmode = SCROLL_REDRAW;
 
 	/*
 	 *  ++guenther: console.c:vc_allocate() relies on initializing
@@ -1245,7 +1246,7 @@
 {
 	struct fb_info *info = registered_fb[(int) con2fb_map[vc->vc_num]];
 	struct display *p = &fb_display[vc->vc_num];
-	int scroll_partial = !(p->scrollmode & __SCROLL_YNOPARTIAL);
+	int scroll_partial = info->flags & FBINFO_PARTIAL_PAN_OK;
 
 	if (!info->fbops->fb_blank && console_blanked)
 		return 0;
@@ -1269,15 +1270,15 @@
 			fbcon_softback_note(vc, t, count);
 		if (logo_shown >= 0)
 			goto redraw_up;
-		switch (p->scrollmode & __SCROLL_YMASK) {
-		case __SCROLL_YMOVE:
+		switch (p->scrollmode) {
+		case SCROLL_ACCEL:
 			accel_bmove(vc, info, t + count, 0, t, 0,
 					 b - t - count, vc->vc_cols);
 			accel_clear(vc, info, b - count, 0, count,
 					 vc->vc_cols);
 			break;
 
-		case __SCROLL_YWRAP:
+		case SCROLL_WRAP:
 			if (b - t - count > 3 * vc->vc_rows >> 2) {
 				if (t > 0)
 					fbcon_bmove(vc, 0, 0, count, 0, t,
@@ -1287,15 +1288,15 @@
 					fbcon_bmove(vc, b - count, 0, b, 0,
 						    vc->vc_rows - b,
 						    vc->vc_cols);
-			} else if (p->scrollmode & __SCROLL_YPANREDRAW)
-				goto redraw_up;
-			else
+			} else if (info->flags & FBINFO_READS_FAST)
 				fbcon_bmove(vc, t + count, 0, t, 0,
 					    b - t - count, vc->vc_cols);
+			else
+				goto redraw_up;
 			fbcon_clear(vc, b - count, 0, count, vc->vc_cols);
 			break;
 
-		case __SCROLL_YPAN:
+		case SCROLL_PAN:
 			if ((p->yscroll + count <=
 			     2 * (p->vrows - vc->vc_rows))
 			    && ((!scroll_partial && (b - t == vc->vc_rows))
@@ -1310,15 +1311,15 @@
 					fbcon_bmove(vc, b - count, 0, b, 0,
 						    vc->vc_rows - b,
 						    vc->vc_cols);
-			} else if (p->scrollmode & __SCROLL_YPANREDRAW)
-				goto redraw_up;
-			else
+			} else if (info->flags & FBINFO_READS_FAST)
 				fbcon_bmove(vc, t + count, 0, t, 0,
 					    b - t - count, vc->vc_cols);
+			else
+				goto redraw_up;
 			fbcon_clear(vc, b - count, 0, count, vc->vc_cols);
 			break;
 
-		case __SCROLL_YREDRAW:
+		case SCROLL_REDRAW:
 		      redraw_up:
 			fbcon_redraw(vc, p, t, b - t - count,
 				     count * vc->vc_cols);
@@ -1336,14 +1337,14 @@
 	case SM_DOWN:
 		if (count > vc->vc_rows)	/* Maximum realistic size */
 			count = vc->vc_rows;
-		switch (p->scrollmode & __SCROLL_YMASK) {
-		case __SCROLL_YMOVE:
+		switch (p->scrollmode) {
+		case SCROLL_ACCEL:
 			accel_bmove(vc, info, t, 0, t + count, 0,
 					 b - t - count, vc->vc_cols);
 			accel_clear(vc, info, t, 0, count, vc->vc_cols);
 			break;
 
-		case __SCROLL_YWRAP:
+		case SCROLL_WRAP:
 			if (b - t - count > 3 * vc->vc_rows >> 2) {
 				if (vc->vc_rows - b > 0)
 					fbcon_bmove(vc, b, 0, b - count, 0,
@@ -1353,15 +1354,15 @@
 				if (t > 0)
 					fbcon_bmove(vc, count, 0, 0, 0, t,
 						    vc->vc_cols);
-			} else if (p->scrollmode & __SCROLL_YPANREDRAW)
-				goto redraw_down;
-			else
+			} else if (info->flags & FBINFO_READS_FAST)
 				fbcon_bmove(vc, t, 0, t + count, 0,
 					    b - t - count, vc->vc_cols);
+			else
+				goto redraw_down;
 			fbcon_clear(vc, t, 0, count, vc->vc_cols);
 			break;
 
-		case __SCROLL_YPAN:
+		case SCROLL_PAN:
 			if ((count - p->yscroll <= p->vrows - vc->vc_rows)
 			    && ((!scroll_partial && (b - t == vc->vc_rows))
 				|| (scroll_partial
@@ -1375,15 +1376,15 @@
 				if (t > 0)
 					fbcon_bmove(vc, count, 0, 0, 0, t,
 						    vc->vc_cols);
-			} else if (p->scrollmode & __SCROLL_YPANREDRAW)
-				goto redraw_down;
-			else
+			} else if (info->flags & FBINFO_READS_FAST)
 				fbcon_bmove(vc, t, 0, t + count, 0,
 					    b - t - count, vc->vc_cols);
+			else
+				goto redraw_down;
 			fbcon_clear(vc, t, 0, count, vc->vc_cols);
 			break;
 
-		case __SCROLL_YREDRAW:
+		case SCROLL_REDRAW:
 		      redraw_down:
 			fbcon_redraw(vc, p, b - 1, b - t - count,
 				     -count * vc->vc_cols);
@@ -1467,21 +1468,27 @@
 
 static __inline__ void updatescrollmode(struct display *p, struct fb_info *info, struct vc_data *vc)
 {
-	int m;
-
-	if (p->scrollmode & __SCROLL_YFIXED)
-		return;
-	if (divides(info->fix.ywrapstep, vc->vc_font.height) &&
-	    divides(vc->vc_font.height, info->var.yres_virtual))
-		m = __SCROLL_YWRAP;
-	else if (divides(info->fix.ypanstep, vc->vc_font.height) &&
-		 info->var.yres_virtual >= info->var.yres + vc->vc_font.height)
-		m = __SCROLL_YPAN;
-	else if (p->scrollmode & __SCROLL_YNOMOVE)
-		m = __SCROLL_YREDRAW;
-	else
-		m = __SCROLL_YMOVE;
-	p->scrollmode = (p->scrollmode & ~__SCROLL_YMASK) | m;
+	int cap = info->flags;
+	int good_pan = (cap & FBINFO_HWACCEL_YPAN)
+		 && divides(info->fix.ypanstep, vc->vc_font.height)
+		 && info->var.yres_virtual >= 2*info->var.yres;
+	int good_wrap = (cap & FBINFO_HWACCEL_YWRAP)
+		 && divides(info->fix.ywrapstep, vc->vc_font.height)
+		 && divides(vc->vc_font.height, info->var.yres_virtual);
+	int reading_fast = cap & FBINFO_READS_FAST;
+	int fast_copyarea = (cap & FBINFO_HWACCEL_COPYAREA) && !(cap & FBINFO_HWACCEL_DISABLED);
+
+	if (good_wrap || good_pan) {
+		if (reading_fast || fast_copyarea)
+			p->scrollmode = good_wrap ? SCROLL_WRAP : SCROLL_PAN;
+		else
+			p->scrollmode = SCROLL_REDRAW;
+	} else {
+		if (reading_fast || fast_copyarea)
+			p->scrollmode = SCROLL_ACCEL;
+		else
+			p->scrollmode = SCROLL_REDRAW;
+	}
 }
 
 static int fbcon_resize(struct vc_data *vc, unsigned int width, 
@@ -1555,12 +1562,12 @@
 	}
 	if (info)
 		info->var.yoffset = p->yscroll = 0;
-        fbcon_resize(vc, vc->vc_cols, vc->vc_rows);
-	switch (p->scrollmode & __SCROLL_YMASK) {
-	case __SCROLL_YWRAP:
+ 	fbcon_resize(vc, vc->vc_cols, vc->vc_rows);
+	switch (p->scrollmode) {
+	case SCROLL_WRAP:
 		scrollback_phys_max = p->vrows - vc->vc_rows;
 		break;
-	case __SCROLL_YPAN:
+	case SCROLL_PAN:
 		scrollback_phys_max = p->vrows - 2 * vc->vc_rows;
 		if (scrollback_phys_max < 0)
 			scrollback_phys_max = 0;
@@ -2133,11 +2140,11 @@
 
 	offset = p->yscroll - scrollback_current;
 	limit = p->vrows;
-	switch (p->scrollmode && __SCROLL_YMASK) {
-	case __SCROLL_YWRAP:
+	switch (p->scrollmode) {
+	case SCROLL_WRAP:
 		info->var.vmode |= FB_VMODE_YWRAP;
 		break;
-	case __SCROLL_YPAN:
+	case SCROLL_PAN:
 		limit -= vc->vc_rows;
 		info->var.vmode &= ~FB_VMODE_YWRAP;
 		break;
--- diff/drivers/video/console/fbcon.h	2004-06-11 19:17:32.000000000 +0100
+++ source/drivers/video/console/fbcon.h	2004-06-11 19:22:05.000000000 +0100
@@ -67,40 +67,27 @@
      *  Scroll Method
      */
      
-/* Internal flags */
-#define __SCROLL_YPAN		0x001
-#define __SCROLL_YWRAP		0x002
-#define __SCROLL_YMOVE		0x003
-#define __SCROLL_YREDRAW	0x004
-#define __SCROLL_YMASK		0x00f
-#define __SCROLL_YFIXED		0x010
-#define __SCROLL_YNOMOVE	0x020
-#define __SCROLL_YPANREDRAW	0x040
-#define __SCROLL_YNOPARTIAL	0x080
-
-/* Only these should be used by the drivers */
-/* Which one should you use? If you have a fast card and slow bus,
-   then probably just 0 to indicate fbcon should choose between
-   YWRAP/YPAN+MOVE/YMOVE. On the other side, if you have a fast bus
-   and even better if your card can do fonting (1->8/32bit painting),
-   you should consider either SCROLL_YREDRAW (if your card is
-   able to do neither YPAN/YWRAP), or SCROLL_YNOMOVE.
-   The best is to test it with some real life scrolling (usually, not
-   all lines on the screen are filled completely with non-space characters,
-   and REDRAW performs much better on such lines, so don't cat a file
-   with every line covering all screen columns, it would not be the right
-   benchmark).
+/* There are several methods fbcon can use to move text around the screen:
+ *
+ * + use the hardware engine to move the text
+ *    (hw-accelerated copyarea() and fillrect())
+ * + use hardware-supported panning on a large virtual screen
+ * + amifb can not only pan, but also wrap the display by N lines
+ *    (i.e. visible line i = physical line (i+N) % yres).
+ * + read what's already rendered on the screen and
+ *     write it in a different place (this is cfb_copyarea())
+ * + re-render the text to the screen
+ *
+ * Whether to use wrapping or panning can only be figured out at
+ * runtime (when we know whether our font height is a multiple
+ * of the pan/wrap step)
+ *
  */
-#define SCROLL_YREDRAW		(__SCROLL_YFIXED|__SCROLL_YREDRAW)
-#define SCROLL_YNOMOVE		(__SCROLL_YNOMOVE|__SCROLL_YPANREDRAW)
 
-/* SCROLL_YNOPARTIAL, used in combination with the above, is for video
-   cards which can not handle using panning to scroll a portion of the
-   screen without excessive flicker.  Panning will only be used for
-   whole screens.
- */
-/* Namespace consistency */
-#define SCROLL_YNOPARTIAL	__SCROLL_YNOPARTIAL
+#define SCROLL_ACCEL	0x001
+#define SCROLL_PAN	0x002
+#define SCROLL_WRAP	0x003
+#define SCROLL_REDRAW	0x004
 
 extern int fb_console_init(void);
 
--- diff/drivers/video/console/sticore.c	2004-05-19 22:12:22.000000000 +0100
+++ source/drivers/video/console/sticore.c	2004-06-11 19:22:05.000000000 +0100
@@ -22,7 +22,6 @@
 #include <linux/pci.h>
 #include <linux/font.h>
 
-#include <asm/pgalloc.h>
 #include <asm/hardware.h>
 #include <asm/parisc-device.h>
 #include <asm/cacheflush.h>
--- diff/drivers/video/sis/300vtbl.h	2004-05-19 22:12:23.000000000 +0100
+++ source/drivers/video/sis/300vtbl.h	2004-06-11 19:22:05.000000000 +0100
@@ -1,4 +1,5 @@
 /* $XFree86$ */
+/* $XdotOrg$ */
 /*
  * Register settings for SiS 300 series
  *
@@ -31,13 +32,10 @@
  * * 2) Redistributions in binary form must reproduce the above copyright
  * *    notice, this list of conditions and the following disclaimer in the
  * *    documentation and/or other materials provided with the distribution.
- * * 3) All advertising materials mentioning features or use of this software
- * *    must display the following acknowledgement: "This product includes
- * *    software developed by Thomas Winischhofer, Vienna, Austria."
- * * 4) The name of the author may not be used to endorse or promote products
+ * * 3) The name of the author may not be used to endorse or promote products
  * *    derived from this software without specific prior written permission.
  * *
- * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESSED OR
  * * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
  * * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
  * * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
@@ -52,20 +50,7 @@
  *
  */
 
-typedef struct _SiS300_StStruct
-{
-	UCHAR St_ModeID;
-	USHORT St_ModeFlag;
-	UCHAR St_StTableIndex;
-	UCHAR St_CRT2CRTC;
-	UCHAR St_ResInfo;
-	UCHAR VB_StTVFlickerIndex;
-	UCHAR VB_StTVEdgeIndex;
-	UCHAR VB_StTVYFilterIndex;
-	UCHAR St_PDC;
-} SiS300_StStruct;
-
-static const SiS300_StStruct  SiS300_SModeIDTable[] =
+static const SiS_StStruct  SiS300_SModeIDTable[] =
 {
 	{0x01,0x9208,0x01,0x00,0x00,0x00,0x00,0x00, 0},
 	{0x01,0x1210,0x14,0x01,0x01,0x00,0x00,0x00, 0},
@@ -89,206 +74,168 @@
 	{0xff,     0,   0,   0,   0,   0,   0,   0, 0}
 };
 
-typedef struct _SiS300_ExtStruct
+static const SiS_ExtStruct  SiS300_EModeIDTable[] =
 {
-	UCHAR  Ext_ModeID;
-	USHORT Ext_ModeFlag;
-	UCHAR  Ext_ModeOffset;
-	USHORT Ext_VESAID;
-	UCHAR  Ext_RESINFO;
-	UCHAR  VB_ExtTVFlickerIndex;
-	UCHAR  VB_ExtTVEdgeIndex;
-	UCHAR  VB_ExtTVYFilterIndex;
-	UCHAR  VB_ExtTVYFilterIndexROM661;
-	UCHAR  REFindex;
-} SiS300_ExtStruct;
-
-static const SiS300_ExtStruct  SiS300_EModeIDTable[] =
-{
-	{0x6a,0x2212,0x04,0x0102,SIS_RI_800x600,  0x00,0x00,0x00,0x00,0x00},  /* 800x600x? */
-	{0x2e,0x0a1b,0x03,0x0101,SIS_RI_640x480,  0x00,0x00,0x00,0x00,0x08},
-	{0x2f,0x021b,0x03,0x0100,SIS_RI_640x400,  0x00,0x00,0x00,0x00,0x10},  /* 640x400x8 */
-	{0x30,0x2a1b,0x04,0x0103,SIS_RI_800x600,  0x00,0x00,0x00,0x00,0x00},
-	{0x31,0x0a1b,0x0a,0x0000,SIS_RI_720x480,  0x00,0x00,0x00,0x00,0x11},  /* 720x480x8 */
-	{0x32,0x2a1b,0x0a,0x0000,SIS_RI_720x576,  0x00,0x00,0x00,0x00,0x12},  /* 720x576x8 */
-	{0x33,0x0a1d,0x0a,0x0000,SIS_RI_720x480,  0x00,0x00,0x00,0x00,0x11},  /* 720x480x16 */
-	{0x34,0x2a1d,0x0a,0x0000,SIS_RI_720x576,  0x00,0x00,0x00,0x00,0x12},  /* 720x576x16 */
-	{0x35,0x0a1f,0x0a,0x0000,SIS_RI_720x480,  0x00,0x00,0x00,0x00,0x11},  /* 720x480x32 */
-	{0x36,0x2a1f,0x0a,0x0000,SIS_RI_720x576,  0x00,0x00,0x00,0x00,0x12},  /* 720x576x32 */
-	{0x37,0x0212,0x05,0x0104,SIS_RI_1024x768, 0x00,0x00,0x00,0x00,0x13},  /* 1024x768x? */
-	{0x38,0x0a1b,0x05,0x0105,SIS_RI_1024x768, 0x00,0x00,0x00,0x00,0x13},  /* 1024x768x8 */
-	{0x3a,0x0e3b,0x06,0x0107,SIS_RI_1280x1024,0x00,0x00,0x00,0x00,0x1a},  /* 1280x1024x8 */
-	{0x3c,0x063b,0x07,0x0130,SIS_RI_1600x1200,0x00,0x00,0x00,0x00,0x1e},
-	{0x3d,0x067d,0x07,0x0131,SIS_RI_1600x1200,0x00,0x00,0x00,0x00,0x1e},
-	{0x40,0x921c,0x00,0x010d,SIS_RI_320x200,  0x00,0x00,0x00,0x00,0x23},  /* 320x200x15 */
-	{0x41,0x921d,0x00,0x010e,SIS_RI_320x200,  0x00,0x00,0x00,0x00,0x23},  /* 320x200x16 */
-	{0x43,0x0a1c,0x03,0x0110,SIS_RI_640x480,  0x00,0x00,0x00,0x00,0x08},
-	{0x44,0x0a1d,0x03,0x0111,SIS_RI_640x480,  0x00,0x00,0x00,0x00,0x08},
-	{0x46,0x2a1c,0x04,0x0113,SIS_RI_800x600,  0x00,0x00,0x00,0x00,0x00},  /* 800x600x15 */
-	{0x47,0x2a1d,0x04,0x0114,SIS_RI_800x600,  0x00,0x00,0x00,0x00,0x00},  /* 800x600x16 */
-	{0x49,0x0a3c,0x05,0x0116,SIS_RI_1024x768, 0x00,0x00,0x00,0x00,0x13},
-	{0x4a,0x0a3d,0x05,0x0117,SIS_RI_1024x768, 0x00,0x00,0x00,0x00,0x13},
-	{0x4c,0x0e7c,0x06,0x0119,SIS_RI_1280x1024,0x00,0x00,0x00,0x00,0x1a},
-	{0x4d,0x0e7d,0x06,0x011a,SIS_RI_1280x1024,0x00,0x00,0x00,0x00,0x1a},
-	{0x50,0x921b,0x00,0x0132,SIS_RI_320x240,  0x00,0x00,0x00,0x00,0x24},  /* 320x240x8  */
-	{0x51,0xb21b,0x01,0x0133,SIS_RI_400x300,  0x00,0x00,0x00,0x00,0x25},  /* 400x300x8  */
-	{0x52,0x921b,0x02,0x0134,SIS_RI_512x384,  0x00,0x00,0x00,0x00,0x26},  /* 512x384x8  */
-	{0x56,0x921d,0x00,0x0135,SIS_RI_320x240,  0x00,0x00,0x00,0x00,0x24},  /* 320x240x16 */
-	{0x57,0xb21d,0x01,0x0136,SIS_RI_400x300,  0x00,0x00,0x00,0x00,0x25},  /* 400x300x16 */
-	{0x58,0x921d,0x02,0x0137,SIS_RI_512x384,  0x00,0x00,0x00,0x00,0x26},  /* 512x384x16 */
-	{0x59,0x921b,0x00,0x0138,SIS_RI_320x200,  0x00,0x00,0x00,0x00,0x23},  /* 320x200x8  */
-	{0x5c,0x921f,0x02,0x0000,SIS_RI_512x384,  0x00,0x00,0x00,0x00,0x26},  /* 512x384x32 */
-	{0x5d,0x021d,0x03,0x0139,SIS_RI_640x400,  0x00,0x00,0x00,0x00,0x10},  /* 640x400x16 */
- 	{0x5e,0x021f,0x03,0x0000,SIS_RI_640x400,  0x00,0x00,0x00,0x00,0x10},  /* 640x400x32 */
-	{0x62,0x0a3f,0x03,0x013a,SIS_RI_640x480,  0x00,0x00,0x00,0x00,0x08},
-	{0x63,0x2a3f,0x04,0x013b,SIS_RI_800x600,  0x00,0x00,0x00,0x00,0x00},  /* 800x600x32 */
-	{0x64,0x0a7f,0x05,0x013c,SIS_RI_1024x768, 0x00,0x00,0x00,0x00,0x13},
-	{0x65,0x0eff,0x06,0x013d,SIS_RI_1280x1024,0x00,0x00,0x00,0x00,0x1a},
-	{0x66,0x06ff,0x07,0x013e,SIS_RI_1600x1200,0x00,0x00,0x00,0x00,0x1e},
-	{0x68,0x067b,0x08,0x013f,SIS_RI_1920x1440,0x00,0x00,0x00,0x00,0x27},
-	{0x69,0x06fd,0x08,0x0140,SIS_RI_1920x1440,0x00,0x00,0x00,0x00,0x27},
-	{0x6b,0x07ff,0x08,0x0000,SIS_RI_1920x1440,0x00,0x00,0x00,0x00,0x27},
-	{0x6c,0x067b,0x09,0x0000,SIS_RI_2048x1536,0x00,0x00,0x00,0x00,0x28},  /* 2048x1536x8 - not in BIOS! */
-	{0x6d,0x06fd,0x09,0x0000,SIS_RI_2048x1536,0x00,0x00,0x00,0x00,0x28},  /* 2048x1536x16 - not in BIOS! */
-	{0x70,0x2a1b,0x04,0x0000,SIS_RI_800x480,  0x00,0x00,0x07,0x00,0x2d},  /* 800x480x8 */
-	{0x71,0x0a1b,0x05,0x0000,SIS_RI_1024x576, 0x00,0x00,0x00,0x00,0x30},  /* 1024x576x8 */
-	{0x74,0x0a1d,0x05,0x0000,SIS_RI_1024x576, 0x00,0x00,0x00,0x00,0x30},  /* 1024x576x16 */
-	{0x75,0x0e3d,0x06,0x0000,SIS_RI_1280x720, 0x00,0x00,0x00,0x00,0x33},  /* 1280x720x16 */
-	{0x76,0x2a1f,0x04,0x0000,SIS_RI_800x480,  0x00,0x00,0x07,0x00,0x2d},  /* 800x480x32 */
-	{0x77,0x0a3f,0x05,0x0000,SIS_RI_1024x576, 0x00,0x00,0x00,0x00,0x30},  /* 1024x576x32 */
-	{0x78,0x0eff,0x06,0x0000,SIS_RI_1280x720, 0x00,0x00,0x00,0x00,0x33},  /* 1280x720x32 */
-	{0x79,0x0e3b,0x06,0x0000,SIS_RI_1280x720, 0x00,0x00,0x00,0x00,0x33},  /* 1280x720x8 */
-	{0x7a,0x2a1d,0x04,0x0000,SIS_RI_800x480,  0x00,0x00,0x07,0x00,0x2d},  /* 800x480x16 */
-	{0x7c,0x0a3b,0x06,0x0000,SIS_RI_1280x960, 0x00,0x00,0x00,0x00,0x29},  /* 1280x960x8 */
-	{0x7d,0x0a7d,0x06,0x0000,SIS_RI_1280x960, 0x00,0x00,0x00,0x00,0x29},  /* 1280x960x16 */
-	{0x7e,0x0aff,0x06,0x0000,SIS_RI_1280x960, 0x00,0x00,0x00,0x00,0x29},  /* 1280x960x32 */
-	{0x20,0x0a1b,0x05,0x0000,SIS_RI_1024x600, 0x00,0x00,0x00,0x00,0x2b},  /* 1024x600 */
-	{0x21,0x0a3d,0x05,0x0000,SIS_RI_1024x600, 0x00,0x00,0x00,0x00,0x2b},
-	{0x22,0x0a7f,0x05,0x0000,SIS_RI_1024x600, 0x00,0x00,0x00,0x00,0x2b},
-	{0x23,0x0a1b,0x0c,0x0000,SIS_RI_1152x768, 0x00,0x00,0x00,0x00,0x2c},  /* 1152x768 */
-	{0x24,0x0a3d,0x0c,0x0000,SIS_RI_1152x768, 0x00,0x00,0x00,0x00,0x2c},
-	{0x25,0x0a7f,0x0c,0x0000,SIS_RI_1152x768, 0x00,0x00,0x00,0x00,0x2c},
-	{0x29,0x0e1b,0x0c,0x0000,SIS_RI_1152x864, 0x00,0x00,0x00,0x00,0x36},  /* 1152x864 */
-	{0x2a,0x0e3d,0x0c,0x0000,SIS_RI_1152x864, 0x00,0x00,0x00,0x00,0x36},
-	{0x2b,0x0e7f,0x0c,0x0000,SIS_RI_1152x864, 0x00,0x00,0x00,0x00,0x36},
-	{0x39,0x2a1b,0x0d,0x0000,SIS_RI_848x480,  0x00,0x00,0x00,0x00,0x38},  /* 848x480 */
-	{0x3b,0x2a3d,0x0d,0x0000,SIS_RI_848x480,  0x00,0x00,0x00,0x00,0x38},
-	{0x3e,0x2a7f,0x0d,0x0000,SIS_RI_848x480,  0x00,0x00,0x00,0x00,0x38},
-	{0x3f,0x2a1b,0x0d,0x0000,SIS_RI_856x480,  0x00,0x00,0x00,0x00,0x3a},  /* 856x480 */
-	{0x42,0x2a3d,0x0d,0x0000,SIS_RI_856x480,  0x00,0x00,0x00,0x00,0x3a},
-	{0x45,0x2a7f,0x0d,0x0000,SIS_RI_856x480,  0x00,0x00,0x00,0x00,0x3a},
-	{0x48,0x223b,0x0e,0x0000,SIS_RI_1360x768, 0x00,0x00,0x00,0x00,0x3c},  /* 1360x768 */
-	{0x4b,0x227d,0x0e,0x0000,SIS_RI_1360x768, 0x00,0x00,0x00,0x00,0x3c},
-	{0x4e,0x22ff,0x0e,0x0000,SIS_RI_1360x768, 0x00,0x00,0x00,0x00,0x3c},
-	{0x4f,0x921f,0x00,0x0000,SIS_RI_320x200,  0x00,0x00,0x00,0x00,0x23},  /* 320x200x32 */
-	{0x53,0x921f,0x00,0x0000,SIS_RI_320x240,  0x00,0x00,0x00,0x00,0x24},  /* 320x240x32 */
-	{0x54,0xb21f,0x01,0x0000,SIS_RI_400x300,  0x00,0x00,0x00,0x00,0x25},  /* 400x300x32 */
-	{0x55,0x2e3b,0x06,0x0000,SIS_RI_1280x768, 0x00,0x00,0x00,0x00,0x3d},  /* 1280x768   */
-	{0x5a,0x2e7d,0x06,0x0000,SIS_RI_1280x768, 0x00,0x00,0x00,0x00,0x3d},
-	{0x5b,0x2eff,0x06,0x0000,SIS_RI_1280x768, 0x00,0x00,0x00,0x00,0x3d},
-	{0x5f,0x2a1b,0x0f,0x0000,SIS_RI_768x576,  0x00,0x00,0x00,0x00,0x3e},  /* 768x576x8 */
-	{0x60,0x2a1d,0x0f,0x0000,SIS_RI_768x576,  0x00,0x00,0x00,0x00,0x3e},  /* 768x576x16 */
-	{0x61,0x2a1f,0x0f,0x0000,SIS_RI_768x576,  0x00,0x00,0x00,0x00,0x3e},  /* 768x576x32 */
-	{0x67,0x2e3b,0x0e,0x0000,SIS_RI_1360x1024,0x00,0x00,0x00,0x00,0x3f},  /* 1360x1024x8 (BARCO) */
-	{0x6f,0x2e7d,0x0e,0x0000,SIS_RI_1360x1024,0x00,0x00,0x00,0x00,0x3f},  /* 1360x1024x16 (BARCO) */
-	{0x72,0x2eff,0x0e,0x0000,SIS_RI_1360x1024,0x00,0x00,0x00,0x00,0x3f},  /* 1360x1024x32 (BARCO) */
-	{0xff,0x0000,0x00,0xffff,0,               0x00,0x00,0x00,0x00,0x00}
-};
-
-typedef struct _SiS300_Ext2Struct
-{
-	USHORT Ext_InfoFlag;
-	UCHAR  Ext_CRT1CRTC;  /* Index in SiS300_CRT1Table */
-	UCHAR  Ext_CRTVCLK;   /* Index in VCLK array */
-	UCHAR  Ext_CRT2CRTC;  /* Index in LCD Paneltype arrays (&3f) */
-	UCHAR  ModeID;
-	USHORT XRes;
-	USHORT YRes;
-	UCHAR  Ext_PDC;
-} SiS300_Ext2Struct;
-
-static const SiS300_Ext2Struct  SiS300_RefIndex[] =
-{
-	{0x085f,0x0d,0x03,0x05,0x6a, 800, 600, 0}, /* 00 */
-	{0x0467,0x0e,0x44,0x05,0x6a, 800, 600, 0}, /* 01 */
-	{0x0067,0x0f,0x07,0x48,0x6a, 800, 600, 0}, /* 02 - CRT1CRTC was 0x4f */
-	{0x0067,0x10,0x06,0x8b,0x6a, 800, 600, 0}, /* 03 */
-	{0x0147,0x11,0x08,0x00,0x6a, 800, 600, 0}, /* 04 */
-	{0x0147,0x12,0x0c,0x00,0x6a, 800, 600, 0}, /* 05 */
-	{0x0047,0x11,0x4e,0x00,0x6a, 800, 600, 0}, /* 06 - CRT1CRTC was 0x51 */
-	{0x0047,0x11,0x13,0x00,0x6a, 800, 600, 0}, /* 07 */
-	{0xc85f,0x05,0x00,0x04,0x2e, 640, 480, 0}, /* 08 */
-	{0xc067,0x06,0x02,0x04,0x2e, 640, 480, 0}, /* 09 */
-	{0xc067,0x07,0x02,0x47,0x2e, 640, 480, 0}, /* 0a */
-	{0xc067,0x08,0x03,0x8a,0x2e, 640, 480, 0}, /* 0b */
-	{0xc047,0x09,0x05,0x00,0x2e, 640, 480, 0}, /* 0c */
-	{0xc047,0x0a,0x08,0x00,0x2e, 640, 480, 0}, /* 0d */
-	{0xc047,0x0b,0x0a,0x00,0x2e, 640, 480, 0}, /* 0e */
-	{0xc047,0x0c,0x10,0x00,0x2e, 640, 480, 0}, /* 0f */
-	{0x487f,0x04,0x00,0x00,0x2f, 640, 400, 0}, /* 10 */
-	{0xc04f,0x31,0x01,0x06,0x31, 720, 480, 0}, /* 11 */
-	{0x004f,0x32,0x03,0x06,0x32, 720, 576, 0}, /* 12 */
-	{0x0187,0x15,0x05,0x00,0x37,1024, 768, 0}, /* 13 */
-        {0xc877,0x16,0x09,0x06,0x37,1024, 768, 0}, /* 14 */
-	{0xc067,0x17,0x0b,0x49,0x37,1024, 768, 0}, /* 15 - CRT1CRTC was 0x97 */
-	{0x0267,0x18,0x0d,0x00,0x37,1024, 768, 0}, /* 16 */
-	{0x0047,0x19,0x11,0x8c,0x37,1024, 768, 0}, /* 17 - CRT1CRTC was 0x59 */
-	{0x0047,0x1a,0x52,0x00,0x37,1024, 768, 0}, /* 18 */
-	{0x0007,0x1b,0x16,0x00,0x37,1024, 768, 0}, /* 19 - CRT1CRTC was 0x5b */
-	{0x0387,0x1c,0x4d,0x00,0x3a,1280,1024, 0}, /* 1a - CRT1CRTC was 0x5c */
-	{0x0077,0x1d,0x14,0x07,0x3a,1280,1024, 0}, /* 1b */
-	{0x0047,0x1e,0x17,0x00,0x3a,1280,1024, 0}, /* 1c */
-	{0x0007,0x1f,0x98,0x00,0x3a,1280,1024, 0}, /* 1d */
-	{0x0007,0x20,0x59,0x00,0x3c,1600,1200, 0}, /* 1e - CRT1CRTC was 0x60 */
-	{0x0007,0x21,0x5a,0x00,0x3c,1600,1200, 0}, /* 1f */
-	{0x0007,0x22,0x1b,0x00,0x3c,1600,1200, 0}, /* 20 */
-	{0x0007,0x23,0x1d,0x00,0x3c,1600,1200, 0}, /* 21 - CRT1CRTC was 0x63 */
-	{0x0007,0x24,0x1e,0x00,0x3c,1600,1200, 0}, /* 22 */
-	{0x407f,0x00,0x00,0x00,0x40, 320, 200, 0}, /* 23 */
-	{0xc07f,0x01,0x00,0x04,0x50, 320, 240, 0}, /* 24 */
-	{0x0077,0x02,0x04,0x05,0x51, 400, 300, 0}, /* 25 */
-	{0xc877,0x03,0x09,0x06,0x52, 512, 384, 0}, /* 26 */  /* was c077 */
-	{0x8207,0x25,0x1f,0x00,0x68,1920,1440, 0}, /* 27 */
-	{0x0007,0x26,0x20,0x00,0x6c,2048,1536, 0}, /* 28 */
-	{0x0067,0x27,0x14,0x08,0x6e,1280, 960, 0}, /* 29 - TW: 1280x960-60 */
-	{0x0027,0x45,0x3c,0x08,0x6e,1280, 960, 0}, /* 2a - TW: 1280x960-85 */
-	{0xc077,0x33,0x09,0x06,0x20,1024, 600, 0}, /* 2b */
-	{0xc077,0x34,0x0b,0x06,0x23,1152, 768, 0}, /* 2c */	/* VCLK 0x09 */
-	{0x0057,0x35,0x27,0x08,0x70, 800, 480, 0}, /* 2d */
-	{0x0047,0x36,0x37,0x08,0x70, 800, 480, 0}, /* 2e */
-	{0x0047,0x37,0x08,0x08,0x70, 800, 480, 0}, /* 2f */
-	{0x0057,0x38,0x09,0x09,0x71,1024, 576, 0}, /* 30 */
-	{0x0047,0x39,0x38,0x09,0x71,1024, 576, 0}, /* 31 */
-	{0x0047,0x3a,0x11,0x09,0x71,1024, 576, 0}, /* 32 */
-	{0x0057,0x3b,0x39,0x0a,0x75,1280, 720, 0}, /* 33 */
-	{0x0047,0x3c,0x3a,0x0a,0x75,1280, 720, 0}, /* 34 */
-	{0x0007,0x3d,0x3b,0x0a,0x75,1280, 720, 0}, /* 35 */
-	{0x0047,0x3e,0x34,0x06,0x29,1152, 864, 0}, /* 36 1152x864-75Hz */
-	{0x0047,0x44,0x3a,0x06,0x29,1152, 864, 0}, /* 37 1152x864-85Hz */
-	{0x00c7,0x3f,0x28,0x00,0x39, 848, 480, 0}, /* 38 848x480-38Hzi */
-	{0xc067,0x40,0x3d,0x0b,0x39, 848, 480, 0}, /* 39 848x480-60Hz  */
-	{0x00c7,0x41,0x28,0x00,0x3f, 856, 480, 0}, /* 3a 856x480-38Hzi */
-	{0xc047,0x42,0x28,0x00,0x3f, 856, 480, 0}, /* 3b 856x480-60Hz  */
-	{0x0067,0x43,0x3e,0x0c,0x48,1360, 768, 0}, /* 3c 1360x768-60Hz */
-	{0x0077,0x46,0x3f,0x08,0x55,1280, 768, 0}, /* 3d 1280x768-60Hz */
-	{0x004f,0x47,0x03,0x06,0x5f, 768, 576, 0}, /* 3e 768x576 */
-	{0x0027,0x48,0x13,0x08,0x67,1360,1024, 0}, /* 3f 1360x1024-59Hz (BARCO1366 only) */
-	{0xffff,   0,   0,   0,   0,   0,   0, 0}
-};
-
-typedef struct _SiS_VBModeIDTableStruct
-{
-	UCHAR  ModeID;
-	UCHAR  VB_TVDelayIndex;
-	UCHAR  VB_TVFlickerIndex;
-	UCHAR  VB_TVPhaseIndex;
-	UCHAR  VB_TVYFilterIndex;
-	UCHAR  VB_LCDDelayIndex;
-	UCHAR  _VB_LCDHIndex;
-	UCHAR  _VB_LCDVIndex;
-}SiS_VBModeIDTableStruct;
+	{0x6a,0x2212,0x0102,SIS_RI_800x600,  0x00,0x00,0x00,0x00,0x00,-1},  /* 800x600x? */
+	{0x2e,0x0a1b,0x0101,SIS_RI_640x480,  0x00,0x00,0x00,0x00,0x08,-1},
+	{0x2f,0x021b,0x0100,SIS_RI_640x400,  0x00,0x00,0x00,0x00,0x10,-1},  /* 640x400x8 */
+	{0x30,0x2a1b,0x0103,SIS_RI_800x600,  0x00,0x00,0x00,0x00,0x00,-1},
+	{0x31,0x0a1b,0x0000,SIS_RI_720x480,  0x00,0x00,0x00,0x00,0x11,-1},  /* 720x480x8 */
+	{0x32,0x2a1b,0x0000,SIS_RI_720x576,  0x00,0x00,0x00,0x00,0x12,-1},  /* 720x576x8 */
+	{0x33,0x0a1d,0x0000,SIS_RI_720x480,  0x00,0x00,0x00,0x00,0x11,-1},  /* 720x480x16 */
+	{0x34,0x2a1d,0x0000,SIS_RI_720x576,  0x00,0x00,0x00,0x00,0x12,-1},  /* 720x576x16 */
+	{0x35,0x0a1f,0x0000,SIS_RI_720x480,  0x00,0x00,0x00,0x00,0x11,-1},  /* 720x480x32 */
+	{0x36,0x2a1f,0x0000,SIS_RI_720x576,  0x00,0x00,0x00,0x00,0x12,-1},  /* 720x576x32 */
+	{0x37,0x0212,0x0104,SIS_RI_1024x768, 0x00,0x00,0x00,0x00,0x13,-1},  /* 1024x768x? */
+	{0x38,0x0a1b,0x0105,SIS_RI_1024x768, 0x00,0x00,0x00,0x00,0x13,-1},  /* 1024x768x8 */
+	{0x3a,0x0e3b,0x0107,SIS_RI_1280x1024,0x00,0x00,0x00,0x00,0x1a,-1},  /* 1280x1024x8 */
+	{0x3c,0x063b,0x0130,SIS_RI_1600x1200,0x00,0x00,0x00,0x00,0x1e,-1},
+	{0x3d,0x067d,0x0131,SIS_RI_1600x1200,0x00,0x00,0x00,0x00,0x1e,-1},
+	{0x40,0x921c,0x010d,SIS_RI_320x200,  0x00,0x00,0x00,0x00,0x23,-1},  /* 320x200x15 */
+	{0x41,0x921d,0x010e,SIS_RI_320x200,  0x00,0x00,0x00,0x00,0x23,-1},  /* 320x200x16 */
+	{0x43,0x0a1c,0x0110,SIS_RI_640x480,  0x00,0x00,0x00,0x00,0x08,-1},
+	{0x44,0x0a1d,0x0111,SIS_RI_640x480,  0x00,0x00,0x00,0x00,0x08,-1},
+	{0x46,0x2a1c,0x0113,SIS_RI_800x600,  0x00,0x00,0x00,0x00,0x00,-1},  /* 800x600x15 */
+	{0x47,0x2a1d,0x0114,SIS_RI_800x600,  0x00,0x00,0x00,0x00,0x00,-1},  /* 800x600x16 */
+	{0x49,0x0a3c,0x0116,SIS_RI_1024x768, 0x00,0x00,0x00,0x00,0x13,-1},
+	{0x4a,0x0a3d,0x0117,SIS_RI_1024x768, 0x00,0x00,0x00,0x00,0x13,-1},
+	{0x4c,0x0e7c,0x0119,SIS_RI_1280x1024,0x00,0x00,0x00,0x00,0x1a,-1},
+	{0x4d,0x0e7d,0x011a,SIS_RI_1280x1024,0x00,0x00,0x00,0x00,0x1a,-1},
+	{0x50,0x921b,0x0132,SIS_RI_320x240,  0x00,0x00,0x00,0x00,0x24,-1},  /* 320x240x8  */
+	{0x51,0xb21b,0x0133,SIS_RI_400x300,  0x00,0x00,0x00,0x00,0x25,-1},  /* 400x300x8  */
+	{0x52,0x921b,0x0134,SIS_RI_512x384,  0x00,0x00,0x00,0x00,0x26,-1},  /* 512x384x8  */
+	{0x56,0x921d,0x0135,SIS_RI_320x240,  0x00,0x00,0x00,0x00,0x24,-1},  /* 320x240x16 */
+	{0x57,0xb21d,0x0136,SIS_RI_400x300,  0x00,0x00,0x00,0x00,0x25,-1},  /* 400x300x16 */
+	{0x58,0x921d,0x0137,SIS_RI_512x384,  0x00,0x00,0x00,0x00,0x26,-1},  /* 512x384x16 */
+	{0x59,0x921b,0x0138,SIS_RI_320x200,  0x00,0x00,0x00,0x00,0x23,-1},  /* 320x200x8  */
+	{0x5c,0x921f,0x0000,SIS_RI_512x384,  0x00,0x00,0x00,0x00,0x26,-1},  /* 512x384x32 */
+	{0x5d,0x021d,0x0139,SIS_RI_640x400,  0x00,0x00,0x00,0x00,0x10,-1},  /* 640x400x16 */
+ 	{0x5e,0x021f,0x0000,SIS_RI_640x400,  0x00,0x00,0x00,0x00,0x10,-1},  /* 640x400x32 */
+	{0x62,0x0a3f,0x013a,SIS_RI_640x480,  0x00,0x00,0x00,0x00,0x08,-1},
+	{0x63,0x2a3f,0x013b,SIS_RI_800x600,  0x00,0x00,0x00,0x00,0x00,-1},  /* 800x600x32 */
+	{0x64,0x0a7f,0x013c,SIS_RI_1024x768, 0x00,0x00,0x00,0x00,0x13,-1},
+	{0x65,0x0eff,0x013d,SIS_RI_1280x1024,0x00,0x00,0x00,0x00,0x1a,-1},
+	{0x66,0x06ff,0x013e,SIS_RI_1600x1200,0x00,0x00,0x00,0x00,0x1e,-1},
+	{0x68,0x067b,0x013f,SIS_RI_1920x1440,0x00,0x00,0x00,0x00,0x27,-1},
+	{0x69,0x06fd,0x0140,SIS_RI_1920x1440,0x00,0x00,0x00,0x00,0x27,-1},
+	{0x6b,0x07ff,0x0000,SIS_RI_1920x1440,0x00,0x00,0x00,0x00,0x27,-1},
+	{0x6c,0x067b,0x0000,SIS_RI_2048x1536,0x00,0x00,0x00,0x00,0x28,-1},  /* 2048x1536x8 - not in BIOS! */
+	{0x6d,0x06fd,0x0000,SIS_RI_2048x1536,0x00,0x00,0x00,0x00,0x28,-1},  /* 2048x1536x16 - not in BIOS! */
+	{0x70,0x2a1b,0x0000,SIS_RI_800x480,  0x00,0x00,0x07,0x00,0x2d,-1},  /* 800x480x8 */
+	{0x71,0x0a1b,0x0000,SIS_RI_1024x576, 0x00,0x00,0x00,0x00,0x30,-1},  /* 1024x576x8 */
+	{0x74,0x0a1d,0x0000,SIS_RI_1024x576, 0x00,0x00,0x00,0x00,0x30,-1},  /* 1024x576x16 */
+	{0x75,0x0e3d,0x0000,SIS_RI_1280x720, 0x00,0x00,0x00,0x00,0x33,-1},  /* 1280x720x16 */
+	{0x76,0x2a1f,0x0000,SIS_RI_800x480,  0x00,0x00,0x07,0x00,0x2d,-1},  /* 800x480x32 */
+	{0x77,0x0a3f,0x0000,SIS_RI_1024x576, 0x00,0x00,0x00,0x00,0x30,-1},  /* 1024x576x32 */
+	{0x78,0x0eff,0x0000,SIS_RI_1280x720, 0x00,0x00,0x00,0x00,0x33,-1},  /* 1280x720x32 */
+	{0x79,0x0e3b,0x0000,SIS_RI_1280x720, 0x00,0x00,0x00,0x00,0x33,-1},  /* 1280x720x8 */
+	{0x7a,0x2a1d,0x0000,SIS_RI_800x480,  0x00,0x00,0x07,0x00,0x2d,-1},  /* 800x480x16 */
+	{0x7c,0x0a3b,0x0000,SIS_RI_1280x960, 0x00,0x00,0x00,0x00,0x29,-1},  /* 1280x960x8 */
+	{0x7d,0x0a7d,0x0000,SIS_RI_1280x960, 0x00,0x00,0x00,0x00,0x29,-1},  /* 1280x960x16 */
+	{0x7e,0x0aff,0x0000,SIS_RI_1280x960, 0x00,0x00,0x00,0x00,0x29,-1},  /* 1280x960x32 */
+	{0x20,0x0a1b,0x0000,SIS_RI_1024x600, 0x00,0x00,0x00,0x00,0x2b,-1},  /* 1024x600 */
+	{0x21,0x0a3d,0x0000,SIS_RI_1024x600, 0x00,0x00,0x00,0x00,0x2b,-1},
+	{0x22,0x0a7f,0x0000,SIS_RI_1024x600, 0x00,0x00,0x00,0x00,0x2b,-1},
+	{0x23,0x0a1b,0x0000,SIS_RI_1152x768, 0x00,0x00,0x00,0x00,0x2c,-1},  /* 1152x768 */
+	{0x24,0x0a3d,0x0000,SIS_RI_1152x768, 0x00,0x00,0x00,0x00,0x2c,-1},
+	{0x25,0x0a7f,0x0000,SIS_RI_1152x768, 0x00,0x00,0x00,0x00,0x2c,-1},
+	{0x29,0x0e1b,0x0000,SIS_RI_1152x864, 0x00,0x00,0x00,0x00,0x36,-1},  /* 1152x864 */
+	{0x2a,0x0e3d,0x0000,SIS_RI_1152x864, 0x00,0x00,0x00,0x00,0x36,-1},
+	{0x2b,0x0e7f,0x0000,SIS_RI_1152x864, 0x00,0x00,0x00,0x00,0x36,-1},
+	{0x39,0x2a1b,0x0000,SIS_RI_848x480,  0x00,0x00,0x00,0x00,0x38,-1},  /* 848x480 */
+	{0x3b,0x2a3d,0x0000,SIS_RI_848x480,  0x00,0x00,0x00,0x00,0x38,-1},
+	{0x3e,0x2a7f,0x0000,SIS_RI_848x480,  0x00,0x00,0x00,0x00,0x38,-1},
+	{0x3f,0x2a1b,0x0000,SIS_RI_856x480,  0x00,0x00,0x00,0x00,0x3a,-1},  /* 856x480 */
+	{0x42,0x2a3d,0x0000,SIS_RI_856x480,  0x00,0x00,0x00,0x00,0x3a,-1},
+	{0x45,0x2a7f,0x0000,SIS_RI_856x480,  0x00,0x00,0x00,0x00,0x3a,-1},
+	{0x48,0x223b,0x0000,SIS_RI_1360x768, 0x00,0x00,0x00,0x00,0x3c,-1},  /* 1360x768 */
+	{0x4b,0x227d,0x0000,SIS_RI_1360x768, 0x00,0x00,0x00,0x00,0x3c,-1},
+	{0x4e,0x22ff,0x0000,SIS_RI_1360x768, 0x00,0x00,0x00,0x00,0x3c,-1},
+	{0x4f,0x921f,0x0000,SIS_RI_320x200,  0x00,0x00,0x00,0x00,0x23,-1},  /* 320x200x32 */
+	{0x53,0x921f,0x0000,SIS_RI_320x240,  0x00,0x00,0x00,0x00,0x24,-1},  /* 320x240x32 */
+	{0x54,0xb21f,0x0000,SIS_RI_400x300,  0x00,0x00,0x00,0x00,0x25,-1},  /* 400x300x32 */
+	{0x55,0x2e3b,0x0000,SIS_RI_1280x768, 0x00,0x00,0x00,0x00,0x3d,-1},  /* 1280x768   */
+	{0x5a,0x2e7d,0x0000,SIS_RI_1280x768, 0x00,0x00,0x00,0x00,0x3d,-1},
+	{0x5b,0x2eff,0x0000,SIS_RI_1280x768, 0x00,0x00,0x00,0x00,0x3d,-1},
+	{0x5f,0x2a1b,0x0000,SIS_RI_768x576,  0x00,0x00,0x00,0x00,0x3e,-1},  /* 768x576x8 */
+	{0x60,0x2a1d,0x0000,SIS_RI_768x576,  0x00,0x00,0x00,0x00,0x3e,-1},  /* 768x576x16 */
+	{0x61,0x2a1f,0x0000,SIS_RI_768x576,  0x00,0x00,0x00,0x00,0x3e,-1},  /* 768x576x32 */
+	{0x67,0x2e3b,0x0000,SIS_RI_1360x1024,0x00,0x00,0x00,0x00,0x3f,-1},  /* 1360x1024x8 (BARCO) */
+	{0x6f,0x2e7d,0x0000,SIS_RI_1360x1024,0x00,0x00,0x00,0x00,0x3f,-1},  /* 1360x1024x16 (BARCO) */
+	{0x72,0x2eff,0x0000,SIS_RI_1360x1024,0x00,0x00,0x00,0x00,0x3f,-1},  /* 1360x1024x32 (BARCO) */
+	{0xff,0x0000,0xffff,0,               0x00,0x00,0x00,0x00,0x00}
+};
+
+static const SiS_Ext2Struct  SiS300_RefIndex[] =
+{
+	{0x085f,0x0d,0x03,0x05,0x05,0x6a, 800, 600, 0}, /* 00 */
+	{0x0467,0x0e,0x44,0x05,0x05,0x6a, 800, 600, 0}, /* 01 */
+	{0x0067,0x0f,0x07,0x48,0x00,0x6a, 800, 600, 0}, /* 02 - CRT1CRTC was 0x4f */
+	{0x0067,0x10,0x06,0x8b,0x00,0x6a, 800, 600, 0}, /* 03 */
+	{0x0147,0x11,0x08,0x00,0x00,0x6a, 800, 600, 0}, /* 04 */
+	{0x0147,0x12,0x0c,0x00,0x00,0x6a, 800, 600, 0}, /* 05 */
+	{0x0047,0x11,0x4e,0x00,0x00,0x6a, 800, 600, 0}, /* 06 - CRT1CRTC was 0x51 */
+	{0x0047,0x11,0x13,0x00,0x00,0x6a, 800, 600, 0}, /* 07 */
+	{0xc85f,0x05,0x00,0x04,0x04,0x2e, 640, 480, 0}, /* 08 */
+	{0xc067,0x06,0x02,0x04,0x04,0x2e, 640, 480, 0}, /* 09 */
+	{0xc067,0x07,0x02,0x47,0x04,0x2e, 640, 480, 0}, /* 0a */
+	{0xc067,0x08,0x03,0x8a,0x04,0x2e, 640, 480, 0}, /* 0b */
+	{0xc047,0x09,0x05,0x00,0x00,0x2e, 640, 480, 0}, /* 0c */
+	{0xc047,0x0a,0x08,0x00,0x00,0x2e, 640, 480, 0}, /* 0d */
+	{0xc047,0x0b,0x0a,0x00,0x00,0x2e, 640, 480, 0}, /* 0e */
+	{0xc047,0x0c,0x10,0x00,0x00,0x2e, 640, 480, 0}, /* 0f */
+	{0x487f,0x04,0x00,0x00,0x00,0x2f, 640, 400, 0}, /* 10 */
+	{0xc04f,0x31,0x01,0x06,0x00,0x31, 720, 480, 0}, /* 11 */
+	{0x004f,0x32,0x03,0x06,0x00,0x32, 720, 576, 0}, /* 12 */
+	{0x0187,0x15,0x05,0x00,0x00,0x37,1024, 768, 0}, /* 13 */
+        {0xc877,0x16,0x09,0x06,0x06,0x37,1024, 768, 0}, /* 14 */
+	{0xc067,0x17,0x0b,0x49,0x06,0x37,1024, 768, 0}, /* 15 - CRT1CRTC was 0x97 */
+	{0x0267,0x18,0x0d,0x00,0x06,0x37,1024, 768, 0}, /* 16 */
+	{0x0047,0x19,0x11,0x8c,0x00,0x37,1024, 768, 0}, /* 17 - CRT1CRTC was 0x59 */
+	{0x0047,0x1a,0x52,0x00,0x00,0x37,1024, 768, 0}, /* 18 */
+	{0x0007,0x1b,0x16,0x00,0x00,0x37,1024, 768, 0}, /* 19 - CRT1CRTC was 0x5b */
+	{0x0387,0x1c,0x4d,0x00,0x00,0x3a,1280,1024, 0}, /* 1a - CRT1CRTC was 0x5c */
+	{0x0077,0x1d,0x14,0x07,0x00,0x3a,1280,1024, 0}, /* 1b */
+	{0x0047,0x1e,0x17,0x00,0x00,0x3a,1280,1024, 0}, /* 1c */
+	{0x0007,0x1f,0x98,0x00,0x00,0x3a,1280,1024, 0}, /* 1d */
+	{0x0007,0x20,0x59,0x00,0x00,0x3c,1600,1200, 0}, /* 1e - CRT1CRTC was 0x60 */
+	{0x0007,0x21,0x5a,0x00,0x00,0x3c,1600,1200, 0}, /* 1f */
+	{0x0007,0x22,0x1b,0x00,0x00,0x3c,1600,1200, 0}, /* 20 */
+	{0x0007,0x23,0x1d,0x00,0x00,0x3c,1600,1200, 0}, /* 21 - CRT1CRTC was 0x63 */
+	{0x0007,0x24,0x1e,0x00,0x00,0x3c,1600,1200, 0}, /* 22 */
+	{0x407f,0x00,0x00,0x00,0x00,0x40, 320, 200, 0}, /* 23 */
+	{0xc07f,0x01,0x00,0x04,0x04,0x50, 320, 240, 0}, /* 24 */
+	{0x0077,0x02,0x04,0x05,0x05,0x51, 400, 300, 0}, /* 25 */
+	{0xc877,0x03,0x09,0x06,0x06,0x52, 512, 384, 0}, /* 26 */  /* was c077 */
+	{0x8207,0x25,0x1f,0x00,0x00,0x68,1920,1440, 0}, /* 27 */
+	{0x0007,0x26,0x20,0x00,0x00,0x6c,2048,1536, 0}, /* 28 */
+	{0x0067,0x27,0x14,0x08,0x0a,0x6e,1280, 960, 0}, /* 29 - 1280x960-60 */
+	{0x0027,0x45,0x3c,0x08,0x0a,0x6e,1280, 960, 0}, /* 2a - 1280x960-85 */
+	{0xc077,0x33,0x09,0x06,0x00,0x20,1024, 600, 0}, /* 2b */
+	{0xc077,0x34,0x0b,0x06,0x00,0x23,1152, 768, 0}, /* 2c */	/* VCLK 0x09 */
+	{0x0057,0x35,0x27,0x08,0x00,0x70, 800, 480, 0}, /* 2d */
+	{0x0047,0x36,0x37,0x08,0x00,0x70, 800, 480, 0}, /* 2e */
+	{0x0047,0x37,0x08,0x08,0x00,0x70, 800, 480, 0}, /* 2f */
+	{0x0057,0x38,0x09,0x09,0x00,0x71,1024, 576, 0}, /* 30 */
+	{0x0047,0x39,0x38,0x09,0x00,0x71,1024, 576, 0}, /* 31 */
+	{0x0047,0x3a,0x11,0x09,0x00,0x71,1024, 576, 0}, /* 32 */
+	{0x0057,0x3b,0x39,0x0a,0x00,0x75,1280, 720, 0}, /* 33 */
+	{0x0047,0x3c,0x3a,0x0a,0x00,0x75,1280, 720, 0}, /* 34 */
+	{0x0007,0x3d,0x3b,0x0a,0x00,0x75,1280, 720, 0}, /* 35 */
+	{0x0047,0x3e,0x34,0x06,0x00,0x29,1152, 864, 0}, /* 36 1152x864-75Hz */
+	{0x0047,0x44,0x3a,0x06,0x00,0x29,1152, 864, 0}, /* 37 1152x864-85Hz */
+	{0x00c7,0x3f,0x28,0x00,0x00,0x39, 848, 480, 0}, /* 38 848x480-38Hzi */
+	{0xc067,0x40,0x3d,0x0b,0x0b,0x39, 848, 480, 0}, /* 39 848x480-60Hz  */
+	{0x00c7,0x41,0x28,0x00,0x00,0x3f, 856, 480, 0}, /* 3a 856x480-38Hzi */
+	{0xc047,0x42,0x28,0x00,0x00,0x3f, 856, 480, 0}, /* 3b 856x480-60Hz  */
+	{0x0067,0x43,0x3e,0x0c,0x0b,0x48,1360, 768, 0}, /* 3c 1360x768-60Hz */
+	{0x0077,0x46,0x3f,0x08,0x00,0x55,1280, 768, 0}, /* 3d 1280x768-60Hz */
+	{0x004f,0x47,0x03,0x06,0x00,0x5f, 768, 576, 0}, /* 3e 768x576 */
+	{0x0027,0x48,0x13,0x08,0x08,0x67,1360,1024, 0}, /* 3f 1360x1024-59Hz (BARCO1366 only) */
+	{0xffff,   0,   0,   0,   0,   0,   0,   0, 0}
+};
 
-static const SiS_VBModeIDTableStruct  SiS300_VBModeIDTable[] =
+static const SiS_VBModeStruct SiS300_VBModeIDTable[] =
 {
 	{0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
 	{0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x01},
@@ -355,12 +302,7 @@
 	{0xff,0x00,0x00,0x00,0x00,0x00,0x00,0x00}
 };
 
-typedef struct _SiS300_CRT1TableStruct
-{
-	UCHAR CR[17];
-} SiS300_CRT1TableStruct;
-
-static const SiS300_CRT1TableStruct  SiS300_CRT1Table[] =
+static const SiS_CRT1TableStruct  SiS300_CRT1Table[] =
 {
 #if 1
  {{0x2d,0x27,0x28,0x90,0x2c,0x80,0xbf,0x1f,    /* 0x00 - 320x200 */
@@ -625,13 +567,7 @@
    0x00}}   /* 0x48 */
 };
 
-typedef struct _SiS300_MCLKDataStruct
-{
-	UCHAR SR28,SR29,SR2A;
-	USHORT CLOCK;
-} SiS300_MCLKDataStruct;
-
-static const SiS300_MCLKDataStruct  SiS300_MCLKData_630[] =
+static const SiS_MCLKDataStruct  SiS300_MCLKData_630[] =
 {
 	{ 0x5a,0x64,0x80, 66},
 	{ 0xb3,0x45,0x80, 83},
@@ -643,7 +579,7 @@
 	{ 0x37,0x61,0x80,100}
 };
 
-static const SiS300_MCLKDataStruct  SiS300_MCLKData_300[] =
+static const SiS_MCLKDataStruct  SiS300_MCLKData_300[] =
 {
 	{ 0x68,0x43,0x80,125},
 	{ 0x68,0x43,0x80,125},
@@ -655,13 +591,7 @@
 	{ 0x37,0x61,0x80,100}
 };
 
-typedef struct _SiS300_VCLKDataStruct
-{
-	UCHAR SR2B,SR2C;
-	USHORT CLOCK;
-} SiS300_VCLKDataStruct;
-
-static const SiS300_VCLKDataStruct  SiS300_VCLKData[] =
+static SiS_VCLKDataStruct SiS300_VCLKData[] =
 {
 	{ 0x1b,0xe1, 25}, /* 0x00 */
 	{ 0x4e,0xe4, 28}, /* 0x01 */
@@ -736,14 +666,7 @@
 	{ 0x37,0x61,100}, /* 0x43 */  /* 1280x960 LCD */
 	{ 0xe3,0x9a,106}, /* 0x44 */  /* 1360x1024 - special for Barco iQ R300 */
 	{ 0xe2,0x46,135}, /* 0x45 */  /* 1280x1024-75, better clock for VGA2 */
-	{ 0xff,0x00,  0}
-};
-
-static const UCHAR  SiS300_ScreenOffset[] =
-{
-	0x14,0x19,0x20,0x28,0x32,0x40,0x50,
-        0x64,0x78,0x80,0x2d,0x35,0x48,0x35,
-	0x55,0x30,0xff
+	{    0,   0,  0}  /* 0x46 custom (will be filled out) */
 };
 
 #ifndef LINUX_XF86
@@ -789,12 +712,7 @@
 static UCHAR SiS300_CR49[2];
 #endif
 
-typedef struct _SiS300_PanelDelayTblStruct
-{
-	UCHAR timer[2];
-} SiS300_PanelDelayTblStruct;
-
-static const SiS300_PanelDelayTblStruct  SiS300_PanelDelayTbl[] =
+static const SiS_PanelDelayTblStruct  SiS300_PanelDelayTbl[] =
 {
 	{{0x05,0xaa}},
 	{{0x05,0x14}},
@@ -815,7 +733,7 @@
 };
 
 #if 0
-static const SiS300_PanelDelayTblStruct  SiS300_PanelDelayTblLVDS[] =
+static const SiS_PanelDelayTblStruct  SiS300_PanelDelayTblLVDS[] =
 {
 	{{0x05,0xaa}},
 	{{0x05,0x14}},
@@ -840,28 +758,18 @@
 /* SIS VIDEO BRIDGE ----------------------------------------- */
 /**************************************************************/
 
-typedef struct _SiS300_LCDDataStruct
+static const SiS_LCDDataStruct  SiS300_St2LCD1024x768Data[] =
 {
-	USHORT RVBHCMAX;
-	USHORT RVBHCFACT;
-	USHORT VGAHT;
-	USHORT VGAVT;
-	USHORT LCDHT;
-	USHORT LCDVT;
-} SiS300_LCDDataStruct;
-
-static const SiS300_LCDDataStruct  SiS300_StLCD1024x768Data[] =
-{
-	{   66,  31, 992, 510,1320, 816},
-	{   66,  31, 992, 510,1320, 816},
-	{  176,  75, 900, 510,1320, 816},
-	{  176,  75, 900, 510,1320, 816},
-	{   66,  31, 992, 510,1320, 816},
-	{   27,  16,1024, 650,1350, 832},
+	{   62,  25, 800, 546,1344, 806},
+	{   32,  15, 930, 546,1344, 806},
+	{   32,  15, 930, 546,1344, 806},
+	{  104,  45, 945, 496,1344, 806},
+	{   62,  25, 800, 546,1344, 806},
+	{   31,  18,1008, 624,1344, 806},
 	{    1,   1,1344, 806,1344, 806}
 };
 
-static const SiS300_LCDDataStruct  SiS300_ExtLCD1024x768Data[] =
+static const SiS_LCDDataStruct  SiS300_ExtLCD1024x768Data[] =
 {
 	{   12,   5, 896, 512,1344, 806},
 	{   12,   5, 896, 510,1344, 806},
@@ -878,30 +786,19 @@
 	{    1,   1,1344, 806,1344, 806}
 };
 
-static const SiS300_LCDDataStruct  SiS300_St2LCD1024x768Data[] =
-{
-	{   62,  25, 800, 546,1344, 806},
-	{   32,  15, 930, 546,1344, 806},
-	{   32,  15, 930, 546,1344, 806},
-	{  104,  45, 945, 496,1344, 806},
-	{   62,  25, 800, 546,1344, 806},
-	{   31,  18,1008, 624,1344, 806},
-	{    1,   1,1344, 806,1344, 806}
-};
-
-static const SiS300_LCDDataStruct  SiS300_StLCD1280x1024Data[] =
+static const SiS_LCDDataStruct  SiS300_St2LCD1280x1024Data[] =
 {
-	{    4,   1, 880, 510,1650,1088},
-	{    4,   1, 880, 510,1650,1088},
+	{   22,   5, 800, 510,1650,1088},
+	{   22,   5, 800, 510,1650,1088},
 	{  176,  45, 900, 510,1650,1088},
 	{  176,  45, 900, 510,1650,1088},
-	{    4,   1, 880, 510,1650,1088},
+	{   22,   5, 800, 510,1650,1088},
 	{   13,   5,1024, 675,1560,1152},
 	{   16,   9,1266, 804,1688,1072},
 	{    1,   1,1688,1066,1688,1066}
 };
 
-static const SiS300_LCDDataStruct  SiS300_ExtLCD1280x1024Data[] =
+static const SiS_LCDDataStruct  SiS300_ExtLCD1280x1024Data[] =
 {
 	{  211,  60,1024, 501,1688,1066},
 	{  211,  60,1024, 508,1688,1066},
@@ -913,74 +810,18 @@
 	{    1,   1,1688,1066,1688,1066}
 };
 
-static const SiS300_LCDDataStruct  SiS300_St2LCD1280x1024Data[] =
-{
-	{   22,   5, 800, 510,1650,1088},
-	{   22,   5, 800, 510,1650,1088},
-	{  176,  45, 900, 510,1650,1088},
-	{  176,  45, 900, 510,1650,1088},
-	{   22,   5, 800, 510,1650,1088},
-	{   13,   5,1024, 675,1560,1152},
-	{   16,   9,1266, 804,1688,1072},
-	{    1,   1,1688,1066,1688,1066}
-};
-
-static const SiS300_LCDDataStruct  SiS300_NoScaleData1024x768[] =
-{
-	{    1,   1, 800, 449, 800, 449},
-	{    1,   1, 800, 449, 800, 449},
-	{    1,   1, 900, 449, 900, 449},
-	{    1,   1, 900, 449, 900, 449},
-	{    1,   1, 800, 525, 800, 525},
-	{    1,   1,1056, 628,1056, 628},
-	{    1,   1,1344, 806,1344, 806},
-	{    1,   1,1688,1066,1688,1066}
-};
-
-static const SiS300_LCDDataStruct  SiS300_NoScaleData1280x1024[] =  /* TW: Fake */
-{
-	{    1,   1, 800, 449, 800, 449},
-	{    1,   1, 800, 449, 800, 449},
-	{    1,   1, 900, 449, 900, 449},
-	{    1,   1, 900, 449, 900, 449},
-	{    1,   1, 800, 525, 800, 525},
-	{    1,   1,1056, 628,1056, 628},
-	{    1,   1,1344, 806,1344, 806},
-	{    1,   1,1688,1066,1688,1066}
-};
-
-typedef struct _SiS300_Part2PortTblStruct
-{
- 	UCHAR CR[12];
-} SiS300_Part2PortTblStruct;
-
-static const SiS300_Part2PortTblStruct SiS300_CRT2Part2_1024x768_1[] =
+static const SiS_Part2PortTblStruct SiS300_CRT2Part2_1024x768_1[] =
 { /* VESA Timing */
- {{0x21,0x12,0xbf,0xe4,0xc0,0x21,0x45,0x09,0x00,0xa9,0x09,0x04}},
- {{0x2c,0x12,0x9a,0xae,0x88,0x21,0x45,0x09,0x00,0xa9,0x09,0x04}},
- {{0x21,0x12,0xbf,0xe4,0xc0,0x21,0x45,0x09,0x00,0xa9,0x09,0x04}},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}},
- {{0x22,0x13,0xfe,0x25,0xff,0x21,0x45,0x0a,0x00,0xa9,0x0d,0x04}},
- {{0x22,0x13,0xfe,0x25,0xff,0x21,0x45,0x0a,0x00,0xa9,0x0d,0x04}},
- {{0x22,0x13,0xfe,0x25,0xff,0x21,0x45,0x0a,0x00,0xa9,0x0d,0x04}}
+  {{0x21,0x12,0xbf,0xe4,0xc0,0x21,0x45,0x09,0x00,0xa9,0x09,0x04}},
+  {{0x2c,0x12,0x9a,0xae,0x88,0x21,0x45,0x09,0x00,0xa9,0x09,0x04}},
+  {{0x21,0x12,0xbf,0xe4,0xc0,0x21,0x45,0x09,0x00,0xa9,0x09,0x04}},
+  {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}},
+  {{0x22,0x13,0xfe,0x25,0xff,0x21,0x45,0x0a,0x00,0xa9,0x0d,0x04}},
+  {{0x22,0x13,0xfe,0x25,0xff,0x21,0x45,0x0a,0x00,0xa9,0x0d,0x04}},
+  {{0x22,0x13,0xfe,0x25,0xff,0x21,0x45,0x0a,0x00,0xa9,0x0d,0x04}}
 };
 
-static const SiS300_Part2PortTblStruct SiS300_CRT2Part2_1280x1024_1[] =
-{	/* TW: Temporary data, invalid */
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}}
-};
-
-static const SiS300_Part2PortTblStruct SiS300_CRT2Part2_1400x1050_1[] =
-{	/* TW: Temporary data, invalid */
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}}
-};
-
-static const SiS300_Part2PortTblStruct SiS300_CRT2Part2_1600x1200_1[] =
-{	/* TW: Temporary data, invalid */
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}}
-};
-
-static const SiS300_Part2PortTblStruct SiS300_CRT2Part2_1024x768_2[] =
+static const SiS_Part2PortTblStruct SiS300_CRT2Part2_1024x768_2[] =
 {  /* Non-VESA */
  {{0x28,0x12,0xa3,0xd0,0xaa,0x5a,0x45,0x0a,0x07,0xfa,0x0a,0x24}},
  {{0x2c,0x12,0x9a,0xae,0x88,0x5a,0x45,0x0a,0x07,0xfa,0x0a,0x24}},
@@ -991,38 +832,23 @@
  {{0x36,0x13,0x13,0x25,0xff,0x5a,0x45,0x0a,0x07,0xfa,0x0a,0x24}}
 };
 
-static const SiS300_Part2PortTblStruct SiS300_CRT2Part2_1280x1024_2[] =
+static const SiS_Part2PortTblStruct SiS300_CRT2Part2_1024x768_3[] =
 {
  {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}}
 };
 
-static const SiS300_Part2PortTblStruct SiS300_CRT2Part2_1400x1050_2[] =
+static const SiS_Part2PortTblStruct SiS300_CRT2Part2_1280x1024_1[] =
 {
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}}
-};
-
-static const SiS300_Part2PortTblStruct SiS300_CRT2Part2_1600x1200_2[] =
-{	/* TW: Temporary data, invalid */
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}}
-};
-
-static const SiS300_Part2PortTblStruct SiS300_CRT2Part2_1024x768_3[] =
-{	/* TW: Temporary data, invalid */
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}}
-};
-
-static const SiS300_Part2PortTblStruct SiS300_CRT2Part2_1280x1024_3[] =
-{	/* TW: Temporary data, invalid */
   {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}}
 };
 
-static const SiS300_Part2PortTblStruct SiS300_CRT2Part2_1400x1050_3[] =
-{	/* TW: Temporary data, invalid */
-  {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}}
+static const SiS_Part2PortTblStruct SiS300_CRT2Part2_1280x1024_2[] =
+{
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}}
 };
 
-static const SiS300_Part2PortTblStruct SiS300_CRT2Part2_1600x1200_3[] =
-{	/* TW: Temporary data, invalid */
+static const SiS_Part2PortTblStruct SiS300_CRT2Part2_1280x1024_3[] =
+{
   {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}}
 };
 
@@ -1030,15 +856,7 @@
 /* LVDS/Chrontel -------------------------------------------- */
 /**************************************************************/
 
-typedef struct _SiS300_LVDSDataStruct
-{
-	USHORT VGAHT;
-	USHORT VGAVT;
-	USHORT LCDHT;
-	USHORT LCDVT;
-} SiS300_LVDSDataStruct;
-
-static const SiS300_LVDSDataStruct  SiS300_CHTVUPALData[] =
+static const SiS_LVDSDataStruct  SiS300_CHTVUPALData[] =
 {
 	{1008, 625,1008, 625},
 	{1008, 625,1008, 625},
@@ -1048,7 +866,7 @@
 	{ 936, 836, 936, 836}
 };
 
-static const SiS300_LVDSDataStruct  SiS300_CHTVOPALData[] =
+static const SiS_LVDSDataStruct  SiS300_CHTVOPALData[] =
 {
 	{1008, 625,1008, 625},
 	{1008, 625,1008, 625},
@@ -1058,7 +876,7 @@
 	{ 960, 750, 960, 750}
 };
 
-static const SiS300_LVDSDataStruct  SiS300_CHTVSOPALData[] =
+static const SiS_LVDSDataStruct  SiS300_CHTVSOPALData[] =
 {
 	{1008, 625,1008, 625},
 	{1008, 625,1008, 625},
@@ -1068,13 +886,8 @@
 	{ 944, 625, 944, 625}
 };
 
-typedef struct _SiS300_LVDSDesStruct
-{
-	USHORT LCDHDES;
-	USHORT LCDVDES;
-} SiS300_LVDSDesStruct;
 
-static const SiS300_LVDSDesStruct  SiS300_PanelType00_1[] =
+static const SiS_LVDSDesStruct  SiS300_PanelType00_1[] =
 {
 	{ 1059, 626 },   /* 2.08 */
 	{ 1059, 624 },
@@ -1098,7 +911,7 @@
 #endif
 };
 
-static const SiS300_LVDSDesStruct  SiS300_PanelType01_1[] =
+static const SiS_LVDSDesStruct  SiS300_PanelType01_1[] =
 {
 	{   0,   0 },  /* 2.08 */
 	{   0,   0 },
@@ -1122,7 +935,7 @@
 #endif
 };
 
-static const SiS300_LVDSDesStruct  SiS300_PanelType02_1[] =
+static const SiS_LVDSDesStruct  SiS300_PanelType02_1[] =
 {
 	{ 1059, 626 },  /* 2.08 */
 	{ 1059, 624 },
@@ -1146,7 +959,7 @@
 #endif
 };
 
-static const SiS300_LVDSDesStruct  SiS300_PanelType03_1[] =
+static const SiS_LVDSDesStruct  SiS300_PanelType03_1[] =
 {
 	{   8, 436},
 	{   8, 440},
@@ -1159,7 +972,7 @@
 	{1343, 794}
 };
 
-static const SiS300_LVDSDesStruct  SiS300_PanelType04_1[] =	/* 1280x1024 */
+static const SiS_LVDSDesStruct  SiS300_PanelType04_1[] =	/* 1280x1024 */
 {
 	{1343, 798},
 	{1343, 794},
@@ -1172,7 +985,7 @@
 	{   0,   0}
 };
 
-static const SiS300_LVDSDesStruct  SiS300_PanelType05_1[] =
+static const SiS_LVDSDesStruct  SiS300_PanelType05_1[] =
 {
 	{1343, 798},
 	{1343, 794},
@@ -1185,7 +998,7 @@
 	{   0,   0}
 };
 
-static const SiS300_LVDSDesStruct  SiS300_PanelType06_1[] =
+static const SiS_LVDSDesStruct  SiS300_PanelType06_1[] =	/* Clevo Trumpion 1024x768 */
 {
 	{1343, 798},
 	{1343, 794},
@@ -1198,7 +1011,7 @@
 	{   0,   0}
 };
 
-static const SiS300_LVDSDesStruct  SiS300_PanelType07_1[] =
+static const SiS_LVDSDesStruct  SiS300_PanelType07_1[] =
 {
 	{1343, 798},
 	{1343, 794},
@@ -1211,7 +1024,7 @@
 	{   0,   0}
 };
 
-static const SiS300_LVDSDesStruct  SiS300_PanelType08_1[] =
+static const SiS_LVDSDesStruct  SiS300_PanelType08_1[] =
 {
 	{1059, 626},
 	{1059, 624},
@@ -1224,7 +1037,7 @@
 	{   0,   0}
 };
 
-static const SiS300_LVDSDesStruct  SiS300_PanelType09_1[] =
+static const SiS_LVDSDesStruct  SiS300_PanelType09_1[] =
 {
 	{1343, 798},
 	{1343, 794},
@@ -1237,7 +1050,7 @@
 	{   0,   0}
 };
 
-static const SiS300_LVDSDesStruct  SiS300_PanelType0a_1[] =
+static const SiS_LVDSDesStruct  SiS300_PanelType0a_1[] =
 {
 	{1059, 626},
 	{1059, 624},
@@ -1250,7 +1063,7 @@
 	{   0,   0}
 };
 
-static const SiS300_LVDSDesStruct  SiS300_PanelType0b_1[] =
+static const SiS_LVDSDesStruct  SiS300_PanelType0b_1[] =
 {
 	{1343,   0},
 	{1343,   0},
@@ -1263,7 +1076,7 @@
 	{   0,   0}
 };
 
-static const SiS300_LVDSDesStruct  SiS300_PanelType0c_1[] =
+static const SiS_LVDSDesStruct  SiS300_PanelType0c_1[] =
 {
 	{1343, 798},
 	{1343, 794},
@@ -1276,7 +1089,7 @@
 	{   0,   0}
 };
 
-static const SiS300_LVDSDesStruct  SiS300_PanelType0d_1[] =
+static const SiS_LVDSDesStruct  SiS300_PanelType0d_1[] =
 {
 	{1343, 798},
 	{1343, 794},
@@ -1289,7 +1102,7 @@
 	{   0,   0}
 };
 
-static const SiS300_LVDSDesStruct  SiS300_PanelType0e_1[] =
+static const SiS_LVDSDesStruct  SiS300_PanelType0e_1[] =
 {
 	{1343, 798},
 	{1343, 794},
@@ -1302,7 +1115,7 @@
 	{   0,   0}     /* 1280x960 - not applicable */
 };
 
-static const SiS300_LVDSDesStruct  SiS300_PanelType0f_1[] =
+static const SiS_LVDSDesStruct  SiS300_PanelType0f_1[] =
 {
 	{1343, 798},
 	{1343, 794},
@@ -1315,7 +1128,7 @@
 	{   0,   0}
 };
 
-static const SiS300_LVDSDesStruct  SiS300_PanelType00_2[] =
+static const SiS_LVDSDesStruct  SiS300_PanelType00_2[] =
 {
 	{976, 527},
 	{976, 502},
@@ -1328,7 +1141,7 @@
 	{  0,   0}
 };
 
-static const SiS300_LVDSDesStruct  SiS300_PanelType01_2[] =
+static const SiS_LVDSDesStruct  SiS300_PanelType01_2[] =
 {
 	{1152, 622},
 	{1152, 597},
@@ -1341,7 +1154,7 @@
 	{   0,   0}
 };
 
-static const SiS300_LVDSDesStruct  SiS300_PanelType02_2[] =
+static const SiS_LVDSDesStruct  SiS300_PanelType02_2[] =
 {
 	{976, 527},
 	{976, 502},
@@ -1354,7 +1167,7 @@
 	{  0,   0}
 };
 
-static const SiS300_LVDSDesStruct  SiS300_PanelType03_2[] =
+static const SiS_LVDSDesStruct  SiS300_PanelType03_2[] =
 {
 	{1152, 622},
 	{1152, 597},
@@ -1367,7 +1180,7 @@
 	{1152, 597}
 };
 
-static const SiS300_LVDSDesStruct  SiS300_PanelType04_2[] =
+static const SiS_LVDSDesStruct  SiS300_PanelType04_2[] =
 {
 	{1152, 622},
 	{1152, 597},
@@ -1380,7 +1193,7 @@
 	{   0,   0}
 };
 
-static const SiS300_LVDSDesStruct  SiS300_PanelType05_2[] =
+static const SiS_LVDSDesStruct  SiS300_PanelType05_2[] =
 {
 	{1152, 622},
 	{1152, 597},
@@ -1393,7 +1206,7 @@
 	{   0,   0}
 };
 
-static const SiS300_LVDSDesStruct  SiS300_PanelType06_2[] =
+static const SiS_LVDSDesStruct  SiS300_PanelType06_2[] =
 {
 	{1152, 622},
 	{1152, 597},
@@ -1406,7 +1219,7 @@
 	{   0,   0}
 };
 
-static const SiS300_LVDSDesStruct  SiS300_PanelType07_2[] =
+static const SiS_LVDSDesStruct  SiS300_PanelType07_2[] =
 {
  	{1152, 622},
  	{1152, 597},
@@ -1419,7 +1232,7 @@
 	{   0,   0}
 };
 
-static const SiS300_LVDSDesStruct  SiS300_PanelType08_2[] =
+static const SiS_LVDSDesStruct  SiS300_PanelType08_2[] =
 {
  	{976, 527},
  	{976, 502},
@@ -1432,7 +1245,7 @@
  	{  0,   0}
 };
 
-static const SiS300_LVDSDesStruct  SiS300_PanelType09_2[] =
+static const SiS_LVDSDesStruct  SiS300_PanelType09_2[] =
 {
  	{1152, 622},
  	{1152, 597},
@@ -1445,7 +1258,7 @@
  	{   0,   0}
 };
 
-static const SiS300_LVDSDesStruct  SiS300_PanelType0a_2[] =
+static const SiS_LVDSDesStruct  SiS300_PanelType0a_2[] =
 {
  	{976, 527},
  	{976, 502},
@@ -1458,7 +1271,7 @@
  	{  0,   0}
 };
 
-static const SiS300_LVDSDesStruct  SiS300_PanelType0b_2[] =
+static const SiS_LVDSDesStruct  SiS300_PanelType0b_2[] =
 {
  	{ 1152, 700},
  	{ 1152, 675},
@@ -1471,7 +1284,7 @@
  	{    0,   0}
 };
 
-static const SiS300_LVDSDesStruct  SiS300_PanelType0c_2[] =
+static const SiS_LVDSDesStruct  SiS300_PanelType0c_2[] =
 {
  	{1152, 622},
  	{1152, 597},
@@ -1484,7 +1297,7 @@
  	{   0,   0}
 };
 
-static const SiS300_LVDSDesStruct  SiS300_PanelType0d_2[] =
+static const SiS_LVDSDesStruct  SiS300_PanelType0d_2[] =
 {
  	{1152, 622},
  	{1152, 597},
@@ -1497,7 +1310,7 @@
  	{   0,   0}
 };
 
-static const SiS300_LVDSDesStruct  SiS300_PanelType0e_2[] =
+static const SiS_LVDSDesStruct  SiS300_PanelType0e_2[] =
 {
  	{1152, 622},
  	{1152, 597},
@@ -1510,7 +1323,7 @@
  	{   0,   0}
 };
 
-static const SiS300_LVDSDesStruct  SiS300_PanelType0f_2[] =
+static const SiS_LVDSDesStruct  SiS300_PanelType0f_2[] =
 {
  	{1152, 622},
  	{1152, 597},
@@ -1523,8 +1336,36 @@
  	{   0,   0}
 };
 
+static const SiS_LVDSDesStruct  SiS300_PanelTypeNS_1[]=
+{
+	{ 0,   0},
+	{ 0,   0},
+	{ 0,   0},
+	{ 0,   0},
+	{ 0,   0},
+	{ 0,   0},
+	{ 0, 805},
+	{ 0,   0},
+	{ 0,   0},
+	{ 0,   0}
+};
+
+static const SiS_LVDSDesStruct  SiS300_PanelTypeNS_2[] =
+{
+	{ 0 , 0},
+	{ 0 , 0},
+	{ 0 , 0},
+	{ 0 , 0},
+	{ 0 , 0},
+	{ 0 , 0},
+	{ 0 , 0},
+	{ 0 , 0},
+	{ 0 , 0},
+	{ 0 , 0}
+};
+
 /* Custom data for Barco iQ R200/300/400 (BIOS 2.00.07) */
-static const SiS300_LVDSDesStruct  SiS300_PanelType04_1a[] =	/* 1280x1024 (1366x1024) */
+static const SiS_LVDSDesStruct  SiS300_PanelType04_1a[] =	/* 1280x1024 (1366x1024) */
 {
 	{1330, 798},  /* 320x200 */
 	{1330, 794},
@@ -1537,7 +1378,7 @@
 	{   0,   0}   /* 1360x1024          */
 };
 
-static const SiS300_LVDSDesStruct  SiS300_PanelType04_2a[] =
+static const SiS_LVDSDesStruct  SiS300_PanelType04_2a[] =
 {
 	{1152, 622},
 	{1152, 597},
@@ -1551,7 +1392,7 @@
 };
 
 /* Custom data for Barco iQ G200/300/400 (BIOS 2.00.07) */
-static const SiS300_LVDSDesStruct  SiS300_PanelType04_1b[] =	/* 1024x768 */
+static const SiS_LVDSDesStruct  SiS300_PanelType04_1b[] =	/* 1024x768 */
 {
 	{1330, 798},  /* 320x200 */
 	{1330, 794},
@@ -1562,7 +1403,7 @@
 	{   0, 805}   /* 1024x768 / 512x384 */
 };
 
-static const SiS300_LVDSDesStruct  SiS300_PanelType04_2b[] =
+static const SiS_LVDSDesStruct  SiS300_PanelType04_2b[] =
 {
 	{1152, 622},
 	{1152, 597},
@@ -1575,12 +1416,7 @@
 
 /* CRT1 CRTC for slave modes */
 
-typedef struct _SiS300_LVDSCRT1DataStruct
-{
-UCHAR CR[15];
-} SiS300_LVDSCRT1DataStruct;
-
-static const SiS300_LVDSCRT1DataStruct  SiS300_LVDSCRT1800x600_1[] =
+static const SiS_LVDSCRT1DataStruct  SiS300_LVDSCRT1800x600_1[] =
 {
 	{{0x65,0x4f,0x89,0x56,0x83,0xaf,0x1f,
 	  0x90,0x85,0x8f,0xab,0x30,0x00,0x05,
@@ -1602,7 +1438,7 @@
 	  0x01 }}
 };
 
-static const SiS300_LVDSCRT1DataStruct  SiS300_LVDSCRT1800x600_1_H[] =
+static const SiS_LVDSCRT1DataStruct  SiS300_LVDSCRT1800x600_1_H[] =
 {
 	{{0x30,0x27,0x94,0x2c,0x92,0xaf,0x1f,
 	  0x90,0x85,0x8f,0xab,0x30,0x00,0x04,
@@ -1624,7 +1460,7 @@
 	  0x01 }}
 };
 
-static const SiS300_LVDSCRT1DataStruct  SiS300_LVDSCRT11024x768_1[] =
+static const SiS_LVDSCRT1DataStruct  SiS300_LVDSCRT11024x768_1[] =
 {
 	{{0x64,0x4f,0x88,0x54,0x9f,0xc4,0x1f,
 	  0x92,0x89,0x8f,0xb5,0x30,0x00,0x01,
@@ -1649,7 +1485,7 @@
 	  0x01}}
 };
 
-static const SiS300_LVDSCRT1DataStruct  SiS300_LVDSCRT11024x768_1_H[] =
+static const SiS_LVDSCRT1DataStruct  SiS300_LVDSCRT11024x768_1_H[] =
 {
 	{{0x2f,0x27,0x93,0x2b,0x90,0xc4,0x1f,
 	  0x92,0x89,0x8f,0xb5,0x30,0x00,0x44,
@@ -1698,7 +1534,7 @@
 #endif
 };
 
-static const SiS300_LVDSCRT1DataStruct  SiS300_LVDSCRT11280x1024_1[] =
+static const SiS_LVDSCRT1DataStruct  SiS300_LVDSCRT11280x1024_1[] =
 {
 	{{0x63,0x4f,0x87,0x54,0x9f,0xb4,0x1f,
 	  0x92,0x89,0x8f,0xb5,0x30,0x00,0x01,
@@ -1723,7 +1559,7 @@
 	  0x01 }}
 };
 
-static const SiS300_LVDSCRT1DataStruct  SiS300_LVDSCRT11280x1024_1_H[] =
+static const SiS_LVDSCRT1DataStruct  SiS300_LVDSCRT11280x1024_1_H[] =
 {
 	{{0x2f,0x27,0x93,0x2b,0x90,0xb4,0x1f,
 	  0x92,0x89,0x8f,0xb5,0x30,0x00,0x04,
@@ -1748,7 +1584,7 @@
 	  0x01 }}
 };
 
-static const SiS300_LVDSCRT1DataStruct  SiS300_LVDSCRT1800x600_2[] =
+static const SiS_LVDSCRT1DataStruct  SiS300_LVDSCRT1800x600_2[] =
 {
 	{{0x7f,0x4f,0x83,0x62,0x12,0x72,0x3e,
 	  0xf4,0x88,0x8f,0x73,0x20,0x00,0x06,
@@ -1770,7 +1606,7 @@
 	  0x01 }}
 };
 
-static const SiS300_LVDSCRT1DataStruct  SiS300_LVDSCRT1800x600_2_H[] =
+static const SiS_LVDSCRT1DataStruct  SiS300_LVDSCRT1800x600_2_H[] =
 {
 	{{0x3d,0x27,0x81,0x32,0x1a,0x72,0x3e,
 	  0xf4,0x88,0x8f,0x73,0x20,0x00,0x05,
@@ -1792,7 +1628,7 @@
 	  0x01 }}
 };
 
-static const SiS300_LVDSCRT1DataStruct  SiS300_LVDSCRT11024x768_2[] =
+static const SiS_LVDSCRT1DataStruct  SiS300_LVDSCRT11024x768_2[] =
 {
 	{{0xa3,0x4f,0x87,0x6e,0x9f,0x24,0xbb,
 	  0x4a,0x80,0x8f,0x25,0x30,0x00,0x06,
@@ -1817,7 +1653,7 @@
 	  0x01 }}
 };
 
-static const SiS300_LVDSCRT1DataStruct  SiS300_LVDSCRT11024x768_2_H[] =
+static const SiS_LVDSCRT1DataStruct  SiS300_LVDSCRT11024x768_2_H[] =
 {
 	{{0x4f,0x27,0x93,0x39,0x01,0x24,0xbb,
 	  0x4a,0x80,0x8f,0x25,0x30,0x00,0x01,
@@ -1842,7 +1678,7 @@
 	  0x01 }}
 };
 
-static const SiS300_LVDSCRT1DataStruct  SiS300_LVDSCRT11280x1024_2[] =
+static const SiS_LVDSCRT1DataStruct  SiS300_LVDSCRT11280x1024_2[] =
 {
 	{{0xa3,0x4f,0x87,0x6e,0x9f,0x24,0xbb,
 	  0x4a,0x80,0x8f,0x25,0x30,0x00,0x06,
@@ -1867,7 +1703,7 @@
 	  0x01 }}
 };
 
-static const SiS300_LVDSCRT1DataStruct  SiS300_LVDSCRT11280x1024_2_H[] =
+static const SiS_LVDSCRT1DataStruct  SiS300_LVDSCRT11280x1024_2_H[] =
 {
 	{{0x4f,0x27,0x93,0x39,0x81,0x24,0xbb,
 	  0x4a,0x80,0x8f,0x25,0x30,0x00,0x01,
@@ -1892,7 +1728,64 @@
 	  0x01}}
 };
 
-static const SiS300_LVDSCRT1DataStruct  SiS300_CHTVCRT1UNTSC[] =
+static const SiS_LVDSCRT1DataStruct  SiS300_LVDSCRT1XXXxXXX_1[] =
+{
+ {{0x5f,0x4f,0x82,0x55,0x81,0xbf,0x1f,
+   0x9c,0x8e,0x96,0xb9,0x30,0x00,0x05,
+   0x00}},
+ {{0x5f,0x4f,0x82,0x55,0x81,0xbf,0x1f,
+   0x9c,0x8e,0x96,0xb9,0x30,0x00,0x05,
+   0x00}},
+ {{0x5f,0x4f,0x82,0x55,0x81,0xbf,0x1f,
+   0x9c,0x8e,0x96,0xb9,0x30,0x00,0x05,
+   0x00}},
+ {{0x5f,0x4f,0x82,0x55,0x81,0xbf,0x1f,
+   0x9c,0x8e,0x96,0xb9,0x30,0x00,0x05,
+   0x00}},
+ {{0x5f,0x4f,0x82,0x55,0x81,0x0b,0x3e,
+   0xe9,0x8b,0xe7,0x04,0x00,0x00,0x05,
+   0x00}},
+ {{0x7f,0x63,0x83,0x6c,0x1c,0x72,0xf0,
+   0x58,0x8c,0x57,0x73,0x20,0x00,0x06,
+   0x01}},
+ {{0xa3,0x7f,0x87,0x86,0x97,0x24,0xf5,
+   0x02,0x88,0xff,0x25,0x10,0x00,0x02,
+   0x01}},
+ {{0xce,0x9f,0x92,0xa8,0x14,0x28,0x5a,
+   0x00,0x84,0xff,0x29,0x09,0x00,0x07,
+   0x01}},
+ {{0xce,0x9f,0x92,0xa9,0x17,0x24,0xf5,
+   0x02,0x88,0xff,0x25,0x10,0x00,0x07,
+   0x01}}
+};
+
+static const SiS_LVDSCRT1DataStruct  SiS300_LVDSCRT1XXXxXXX_1_H[] =
+{
+ {{0x38,0x27,0x9c,0x2c,0x80,0xbf,0x1f,
+   0x9c,0x8e,0x96,0xb9,0x30,0x00,0x00,
+   0x00}},
+ {{0x38,0x27,0x9c,0x2c,0x80,0xbf,0x1f,
+   0x9c,0x8e,0x96,0xb9,0x30,0x00,0x00,
+   0x00}},
+ {{0x38,0x27,0x9c,0x2c,0x80,0xbf,0x1f,
+   0x9c,0x8e,0x96,0xb9,0x30,0x00,0x00,
+   0x00}},
+ {{0x38,0x27,0x9c,0x2c,0x80,0xbf,0x1f,
+   0x9c,0x8e,0x96,0xb9,0x30,0x00,0x00,
+   0x00}},
+ {{0x38,0x27,0x9c,0x2c,0x80,0x0b,0x3e,
+   0xe9,0x8b,0xe7,0x04,0x00,0x00,0x00,
+   0x00}},
+ {{0x4d,0x31,0x91,0x3b,0x03,0x72,0xf0,
+   0x58,0x8c,0x57,0x73,0x20,0x00,0x01,
+   0x01}},
+ {{0x63,0x3f,0x87,0x4a,0x92,0x24,0xf5,
+   0x02,0x88,0xff,0x25,0x10,0x00,0x01,
+   0x01}}
+};
+
+
+static const SiS_LVDSCRT1DataStruct  SiS300_CHTVCRT1UNTSC[] =
 {
 	{{0x64,0x4f,0x88,0x56,0x9f,0x56,0x3e,
 	  0xe8,0x84,0x8f,0x57,0x20,0x00,0x01,
@@ -1914,7 +1807,7 @@
 	  0x01 }}
 };
 
-static const SiS300_LVDSCRT1DataStruct  SiS300_CHTVCRT1ONTSC[] =
+static const SiS_LVDSCRT1DataStruct  SiS300_CHTVCRT1ONTSC[] =
 {
 	{{0x64,0x4f,0x88,0x5a,0x9f,0x0b,0x3e,
 	  0xc0,0x84,0x8f,0x0c,0x20,0x00,0x01,
@@ -1936,7 +1829,7 @@
 	  0x01 }}
 };
 
-static const SiS300_LVDSCRT1DataStruct  SiS300_CHTVCRT1UPAL[] =
+static const SiS_LVDSCRT1DataStruct  SiS300_CHTVCRT1UPAL[] =
 {
 	{{0x79,0x4f,0x9d,0x5a,0x90,0x6f,0x3e,
 	  0xf8,0x83,0x8f,0x70,0x20,0x00,0x05,
@@ -1958,7 +1851,7 @@
 	  0x01 }}
 };
 
-static const SiS300_LVDSCRT1DataStruct  SiS300_CHTVCRT1OPAL[] =
+static const SiS_LVDSCRT1DataStruct  SiS300_CHTVCRT1OPAL[] =
 {
 	{{0x79,0x4f,0x9d,0x5a,0x90,0x6f,0x3e,
 	  0xf0,0x83,0x8f,0x70,0x20,0x00,0x05,
@@ -1980,7 +1873,7 @@
 	  0x01 }}
 };
 
-static const SiS300_LVDSCRT1DataStruct  SiS300_CHTVCRT1SOPAL[] =
+static const SiS_LVDSCRT1DataStruct  SiS300_CHTVCRT1SOPAL[] =
 {
 	{{0x79,0x4f,0x9d,0x5a,0x90,0x6f,0x3e,
 	  0xf0,0x83,0x8f,0x70,0x20,0x00,0x05,
@@ -2002,12 +1895,7 @@
 	  0x01 }}
 };
 
-typedef struct _SiS300_CHTVRegDataStruct
-{
-	UCHAR Reg[16];
-} SiS300_CHTVRegDataStruct;
-
-static const SiS300_CHTVRegDataStruct SiS300_CHTVReg_UNTSC[] =
+static const SiS_CHTVRegDataStruct SiS300_CHTVReg_UNTSC[] =
 {
 	{{0x4a,0x94,0x00,0x48,0xfe,0,0,0,0,0,0,0,0,0,0,0}},
 	{{0x4a,0x94,0x00,0x48,0xfe,0,0,0,0,0,0,0,0,0,0,0}},
@@ -2017,7 +1905,7 @@
 	{{0x8d,0xc4,0x00,0x3b,0xfb,0,0,0,0,0,0,0,0,0,0,0}}  /* Mode 24: 800x600 NTSC 7/10 */
 };
 
-static const SiS300_CHTVRegDataStruct SiS300_CHTVReg_ONTSC[] =
+static const SiS_CHTVRegDataStruct SiS300_CHTVReg_ONTSC[] =
 {
 	{{0x49,0x94,0x00,0x34,0xfe,0,0,0,0,0,0,0,0,0,0,0}},
 	{{0x49,0x94,0x00,0x34,0xfe,0,0,0,0,0,0,0,0,0,0,0}},
@@ -2027,7 +1915,7 @@
 	{{0x8c,0xb4,0x00,0x32,0xf9,0,0,0,0,0,0,0,0,0,0,0}}  /* Mode 23: 800x600 NTSC 3/4 */
 };
 
-static const SiS300_CHTVRegDataStruct SiS300_CHTVReg_UPAL[] =
+static const SiS_CHTVRegDataStruct SiS300_CHTVReg_UPAL[] =
 {
 	{{0x41,0x12,0x01,0x50,0x34,0,0,0,0,0,0,0,0,0,0,0}},
 	{{0x41,0x12,0x00,0x50,0x00,0,0,0,0,0,0,0,0,0,0,0}},
@@ -2038,7 +1926,7 @@
 
 };
 
-static const SiS300_CHTVRegDataStruct SiS300_CHTVReg_OPAL[] =
+static const SiS_CHTVRegDataStruct SiS300_CHTVReg_OPAL[] =
 {
 	{{0x41,0x12,0x01,0x50,0x34,0,0,0,0,0,0,0,0,0,0,0}}, /* Mode 9: 640x400 PAL 1/1 */
 	{{0x41,0x12,0x00,0x50,0x00,0,0,0,0,0,0,0,0,0,0,0}},
@@ -2049,7 +1937,7 @@
 
 };
 
-static const SiS300_CHTVRegDataStruct SiS300_CHTVReg_SOPAL[] =
+static const SiS_CHTVRegDataStruct SiS300_CHTVReg_SOPAL[] =
 {
 	{{0x41,0x12,0x01,0x50,0x34,0,0,0,0,0,0,0,0,0,0,0}}, /* Mode 9: 640x400 PAL 1/1 */
 	{{0x41,0x12,0x00,0x50,0x00,0,0,0,0,0,0,0,0,0,0,0}},
--- diff/drivers/video/sis/310vtbl.h	2004-05-19 22:12:23.000000000 +0100
+++ source/drivers/video/sis/310vtbl.h	2004-06-11 19:22:05.000000000 +0100
@@ -1,4 +1,5 @@
 /* $XFree86$ */
+/* $XdotOrg$ */
 /*
  * Register settings for SiS 315/330 series
  *
@@ -31,13 +32,10 @@
  * * 2) Redistributions in binary form must reproduce the above copyright
  * *    notice, this list of conditions and the following disclaimer in the
  * *    documentation and/or other materials provided with the distribution.
- * * 3) All advertising materials mentioning features or use of this software
- * *    must display the following acknowledgement: "This product includes
- * *    software developed by Thomas Winischhofer, Vienna, Austria."
- * * 4) The name of the author may not be used to endorse or promote products
+ * * 3) The name of the author may not be used to endorse or promote products
  * *    derived from this software without specific prior written permission.
  * *
- * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESSED OR
  * * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
  * * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
  * * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
@@ -52,20 +50,7 @@
  *
  */
 
-typedef struct _SiS310_StStruct
-{
-	UCHAR St_ModeID;
-	USHORT St_ModeFlag;
-	UCHAR St_StTableIndex;
-	UCHAR St_CRT2CRTC;
-	UCHAR St_ResInfo;
-	UCHAR VB_StTVFlickerIndex;
-	UCHAR VB_StTVEdgeIndex;
-	UCHAR VB_StTVYFilterIndex;
-	UCHAR St_PDC;
-} SiS310_StStruct;
-
-static const SiS310_StStruct SiS310_SModeIDTable[]=
+static const SiS_StStruct SiS310_SModeIDTable[]=
 {
 	{0x01,0x9208,0x01,0x00,0x00,0x00,0x01,0x00, 0x40},
 	{0x01,0x1210,0x14,0x01,0x01,0x00,0x01,0x00, 0x40},
@@ -89,207 +74,192 @@
 	{0xff,0x0000,0x00,0x00,0x00,0x00,0x00,0x00, 0x40}
 };
 
-typedef struct _SiS310_ExtStruct
+static const SiS_ExtStruct  SiS310_EModeIDTable[]=
 {
-	UCHAR  Ext_ModeID;
-	USHORT Ext_ModeFlag;
-	UCHAR  Ext_ModeOffset;
-	USHORT Ext_VESAID;
-	UCHAR  Ext_RESINFO;
-	UCHAR  VB_ExtTVFlickerIndex;
-	UCHAR  VB_ExtTVEdgeIndex;
-	UCHAR  VB_ExtTVYFilterIndex;
-	UCHAR  VB_ExtTVYFilterIndexROM661;
-	UCHAR  REFindex;
-} SiS310_ExtStruct;
-
-static const SiS310_ExtStruct  SiS310_EModeIDTable[]=
-{
-	{0x6a,0x2212,0x04,0x0102,SIS_RI_800x600,  0x00,0x00,0x07,0x06,0x00}, /* 800x600x? */
-	{0x2e,0x0a1b,0x03,0x0101,SIS_RI_640x480,  0x00,0x00,0x05,0x05,0x08}, /* 640x480x8 */
-        {0x2f,0x0a1b,0x03,0x0100,SIS_RI_640x400,  0x00,0x00,0x05,0x05,0x10}, /* 640x400x8 */
-	{0x30,0x2a1b,0x04,0x0103,SIS_RI_800x600,  0x00,0x00,0x07,0x06,0x00}, /* 800x600x8 */
-        {0x31,0x0a1b,0x0a,0x0000,SIS_RI_720x480,  0x00,0x00,0x06,0x06,0x11}, /* 720x480x8 */
-	{0x32,0x0a1b,0x0a,0x0000,SIS_RI_720x576,  0x00,0x00,0x06,0x06,0x12}, /* 720x576x8 */
-	{0x33,0x0a1d,0x0a,0x0000,SIS_RI_720x480,  0x00,0x00,0x06,0x06,0x11}, /* 720x480x16 */
-	{0x34,0x2a1d,0x0a,0x0000,SIS_RI_720x576,  0x00,0x00,0x06,0x06,0x12}, /* 720x576x16 */
-	{0x35,0x0a1f,0x0a,0x0000,SIS_RI_720x480,  0x00,0x00,0x06,0x06,0x11}, /* 720x480x32 */
-	{0x36,0x2a1f,0x0a,0x0000,SIS_RI_720x576,  0x00,0x00,0x06,0x06,0x12}, /* 720x576x32 */
-	{0x37,0x0212,0x05,0x0104,SIS_RI_1024x768, 0x00,0x00,0x08,0x07,0x13}, /* 1024x768x? */
-	{0x38,0x0a1b,0x05,0x0105,SIS_RI_1024x768, 0x00,0x00,0x08,0x07,0x13}, /* 1024x768x8 */
-	{0x3a,0x0e3b,0x06,0x0107,SIS_RI_1280x1024,0x00,0x00,0x00,0x00,0x1a}, /* 1280x1024x8 */
-	{0x3c,0x0e3b,0x07,0x0130,SIS_RI_1600x1200,0x00,0x00,0x00,0x00,0x1e}, /* 1600x1200x8 */
-	{0x3d,0x0e7d,0x07,0x0131,SIS_RI_1600x1200,0x00,0x00,0x00,0x00,0x1e}, /* 1600x1200x16 */
-	{0x40,0x9a1c,0x00,0x010d,SIS_RI_320x200,  0x00,0x00,0x04,0x04,0x25}, /* 320x200x15 */
-	{0x41,0x9a1d,0x00,0x010e,SIS_RI_320x200,  0x00,0x00,0x04,0x04,0x25}, /* 320x200x16 */
-	{0x43,0x0a1c,0x03,0x0110,SIS_RI_640x480,  0x00,0x00,0x05,0x05,0x08},
-	{0x44,0x0a1d,0x03,0x0111,SIS_RI_640x480,  0x00,0x00,0x05,0x05,0x08}, /* 640x480x16 */
-	{0x46,0x2a1c,0x04,0x0113,SIS_RI_800x600,  0x00,0x00,0x07,0x06,0x00},
-	{0x47,0x2a1d,0x04,0x0114,SIS_RI_800x600,  0x00,0x00,0x07,0x06,0x00}, /* 800x600x16 */
-	{0x49,0x0a3c,0x05,0x0116,SIS_RI_1024x768, 0x00,0x00,0x00,0x07,0x13},
-	{0x4a,0x0a3d,0x05,0x0117,SIS_RI_1024x768, 0x00,0x00,0x08,0x07,0x13}, /* 1024x768x16 */
-	{0x4c,0x0e7c,0x06,0x0119,SIS_RI_1280x1024,0x00,0x00,0x00,0x00,0x1a},
-	{0x4d,0x0e7d,0x06,0x011a,SIS_RI_1280x1024,0x00,0x00,0x00,0x00,0x1a}, /* 1280x1024x16 */
-	{0x50,0x9a1b,0x00,0x0132,SIS_RI_320x240,  0x00,0x00,0x04,0x04,0x26}, /* 320x240x8  */
-	{0x51,0xba1b,0x01,0x0133,SIS_RI_400x300,  0x00,0x00,0x07,0x07,0x27}, /* 400x300x8  */
-  	{0x52,0xba1b,0x02,0x0134,SIS_RI_512x384,  0x00,0x00,0x00,0x00,0x28}, /* 512x384x8  */
-	{0x56,0x9a1d,0x00,0x0135,SIS_RI_320x240,  0x00,0x00,0x04,0x04,0x26}, /* 320x240x16 */
-	{0x57,0xba1d,0x01,0x0136,SIS_RI_400x300,  0x00,0x00,0x07,0x07,0x27}, /* 400x300x16 */
- 	{0x58,0xba1d,0x02,0x0137,SIS_RI_512x384,  0x00,0x00,0x00,0x00,0x28}, /* 512x384x16 */
-	{0x59,0x9a1b,0x00,0x0138,SIS_RI_320x200,  0x00,0x00,0x04,0x04,0x25}, /* 320x200x8  */
-	{0x5a,0x021b,0x00,0x0138,SIS_RI_320x240,  0x00,0x00,0x00,0x00,0x3f}, /* 320x240x8  fstn */
-	{0x5b,0x0a1d,0x00,0x0135,SIS_RI_320x240,  0x00,0x00,0x00,0x00,0x3f}, /* 320x240x16 fstn */
-	{0x5c,0xba1f,0x02,0x0000,SIS_RI_512x384,  0x00,0x00,0x00,0x00,0x28}, /* 512x384x32 */
-	{0x5d,0x0a1d,0x03,0x0139,SIS_RI_640x400,  0x00,0x00,0x05,0x07,0x10},
-	{0x5e,0x0a1f,0x03,0x0000,SIS_RI_640x400,  0x00,0x00,0x05,0x07,0x10}, /* 640x400x32 */
-	{0x62,0x0a3f,0x03,0x013a,SIS_RI_640x480,  0x00,0x00,0x05,0x05,0x08}, /* 640x480x32 */
-	{0x63,0x2a3f,0x04,0x013b,SIS_RI_800x600,  0x00,0x00,0x07,0x06,0x00}, /* 800x600x32 */
-	{0x64,0x0a7f,0x05,0x013c,SIS_RI_1024x768, 0x00,0x00,0x08,0x07,0x13}, /* 1024x768x32 */
-	{0x65,0x0eff,0x06,0x013d,SIS_RI_1280x1024,0x00,0x00,0x00,0x00,0x1a}, /* 1280x1024x32 */
-	{0x66,0x0eff,0x07,0x013e,SIS_RI_1600x1200,0x00,0x00,0x00,0x00,0x1e}, /* 1600x1200x32 */
-	{0x68,0x067b,0x08,0x013f,SIS_RI_1920x1440,0x00,0x00,0x00,0x00,0x29}, /* 1920x1440x8 */
-	{0x69,0x06fd,0x08,0x0140,SIS_RI_1920x1440,0x00,0x00,0x00,0x00,0x29}, /* 1920x1440x16 */
-	{0x6b,0x07ff,0x08,0x0141,SIS_RI_1920x1440,0x00,0x00,0x00,0x00,0x29}, /* 1920x1440x32 */
-	{0x6c,0x067b,0x09,0x0000,SIS_RI_2048x1536,0x00,0x00,0x00,0x00,0x2f}, /* 2048x1536x8 */
-	{0x6d,0x06fd,0x09,0x0000,SIS_RI_2048x1536,0x00,0x00,0x00,0x00,0x2f}, /* 2048x1536x16 */
-	{0x6e,0x07ff,0x09,0x0000,SIS_RI_2048x1536,0x00,0x00,0x00,0x00,0x2f}, /* 2048x1536x32 */
-	{0x70,0x2a1b,0x04,0x0000,SIS_RI_800x480,  0x00,0x00,0x07,0x07,0x34}, /* 800x480x8 */
-	{0x71,0x0a1b,0x05,0x0000,SIS_RI_1024x576, 0x00,0x00,0x00,0x00,0x37}, /* 1024x576x8 */
-	{0x74,0x0a1d,0x05,0x0000,SIS_RI_1024x576, 0x00,0x00,0x00,0x00,0x37}, /* 1024x576x16 */
-	{0x75,0x0a3d,0x06,0x0000,SIS_RI_1280x720, 0x00,0x00,0x00,0x00,0x3a}, /* 1280x720x16 */
-	{0x76,0x2a1f,0x04,0x0000,SIS_RI_800x480,  0x00,0x00,0x07,0x07,0x34}, /* 800x480x32 */
-	{0x77,0x0a1f,0x05,0x0000,SIS_RI_1024x576, 0x00,0x00,0x00,0x00,0x37}, /* 1024x576x32 */
-	{0x78,0x0a3f,0x06,0x0000,SIS_RI_1280x720, 0x00,0x00,0x00,0x00,0x3a}, /* 1280x720x32 */
-	{0x79,0x0a3b,0x06,0x0000,SIS_RI_1280x720, 0x00,0x00,0x00,0x00,0x3a}, /* 1280x720x8 */
-	{0x7a,0x2a1d,0x04,0x0000,SIS_RI_800x480,  0x00,0x00,0x07,0x07,0x34}, /* 800x480x16 */
-	{0x7c,0x0e3b,0x06,0x0000,SIS_RI_1280x960, 0x00,0x00,0x00,0x00,0x3d}, /* 1280x960x8 */
-	{0x7d,0x0e7d,0x06,0x0000,SIS_RI_1280x960, 0x00,0x00,0x00,0x00,0x3d}, /* 1280x960x16 */
-	{0x7e,0x0eff,0x06,0x0000,SIS_RI_1280x960, 0x00,0x00,0x00,0x00,0x3d}, /* 1280x960x32 */
-	{0x23,0x0e3b,0x06,0x0000,SIS_RI_1280x768, 0x00,0x00,0x00,0x00,0x40}, /* 1280x768x8 */
-	{0x24,0x0e7d,0x06,0x0000,SIS_RI_1280x768, 0x00,0x00,0x00,0x00,0x40}, /* 1280x768x16 */
-	{0x25,0x0eff,0x06,0x0000,SIS_RI_1280x768, 0x00,0x00,0x00,0x00,0x40}, /* 1280x768x32 */
-	{0x26,0x0e3b,0x0c,0x0000,SIS_RI_1400x1050,0x00,0x00,0x00,0x00,0x41}, /* 1400x1050x8 */
-	{0x27,0x0e7d,0x0c,0x0000,SIS_RI_1400x1050,0x00,0x00,0x00,0x00,0x41}, /* 1400x1050x16 */
-	{0x28,0x0eff,0x0c,0x0000,SIS_RI_1400x1050,0x00,0x00,0x00,0x00,0x41}, /* 1400x1050x32*/
-	{0x29,0x0e1b,0x0d,0x0000,SIS_RI_1152x864, 0x00,0x00,0x00,0x00,0x43}, /* 1152x864 */
-	{0x2a,0x0e3d,0x0d,0x0000,SIS_RI_1152x864, 0x00,0x00,0x00,0x00,0x43},
-	{0x2b,0x0e7f,0x0d,0x0000,SIS_RI_1152x864, 0x00,0x00,0x00,0x00,0x43},
-	{0x39,0x2a1b,0x0b,0x0000,SIS_RI_848x480,  0x00,0x00,0x00,0x00,0x45}, /* 848x480 */
-	{0x3b,0x2a3d,0x0b,0x0000,SIS_RI_848x480,  0x00,0x00,0x00,0x00,0x45},
-	{0x3e,0x2a7f,0x0b,0x0000,SIS_RI_848x480,  0x00,0x00,0x00,0x00,0x45},
-	{0x3f,0x2a1b,0x0b,0x0000,SIS_RI_856x480,  0x00,0x00,0x00,0x00,0x47}, /* 856x480 */
-	{0x42,0x2a3d,0x0b,0x0000,SIS_RI_856x480,  0x00,0x00,0x00,0x00,0x47},
-	{0x45,0x2a7f,0x0b,0x0000,SIS_RI_856x480,  0x00,0x00,0x00,0x00,0x47},
-	{0x48,0x2a1b,0x0e,0x0000,SIS_RI_1360x768, 0x00,0x00,0x00,0x00,0x49}, /* 1360x768 */
-	{0x4b,0x2a3d,0x0e,0x0000,SIS_RI_1360x768, 0x00,0x00,0x00,0x00,0x49},
-	{0x4e,0x2a7f,0x0e,0x0000,SIS_RI_1360x768, 0x00,0x00,0x00,0x00,0x49},
-	{0x4f,0x9a1f,0x00,0x0000,SIS_RI_320x200,  0x00,0x00,0x04,0x04,0x25}, /* 320x200x32 */
-	{0x53,0x9a1f,0x00,0x0000,SIS_RI_320x240,  0x00,0x00,0x04,0x04,0x26}, /* 320x240x32 */
-	{0x54,0xba1f,0x01,0x0000,SIS_RI_400x300,  0x00,0x00,0x07,0x07,0x27}, /* 400x300x32 */
-	{0x5f,0x2a1b,0x0f,0x0000,SIS_RI_768x576,  0x00,0x00,0x06,0x06,0x4a}, /* 768x576x8 */
-	{0x60,0x2a1d,0x0f,0x0000,SIS_RI_768x576,  0x00,0x00,0x06,0x06,0x4a}, /* 768x576x16 */
-	{0x61,0x2a1f,0x0f,0x0000,SIS_RI_768x576,  0x00,0x00,0x06,0x06,0x4a}, /* 768x576x32 */
-	{0xff,0x0000,0x00,0x0000,0,               0x00,0x00,0x00,0x00,0x00}
-};
-
-typedef struct _SiS310_Ext2Struct
-{
-	USHORT Ext_InfoFlag;
-	UCHAR  Ext_CRT1CRTC;
-	UCHAR  Ext_CRTVCLK;
-	UCHAR  Ext_CRT2CRTC;
-	UCHAR  ModeID;
-	USHORT XRes;
-	USHORT YRes;
-	UCHAR  Ext_PDC;
-} SiS310_Ext2Struct;
-
-static const SiS310_Ext2Struct SiS310_RefIndex[]=
-{
-	{0x085f,0x0d,0x03,0x05,0x6a, 800, 600, 0x40}, /* 0x0 */
-	{0x0067,0x0e,0x04,0x05,0x6a, 800, 600, 0x40}, /* 0x1 */
-	{0x0067,0x0f,0x08,0x48,0x6a, 800, 600, 0x40}, /* 0x2 */
-	{0x0067,0x10,0x07,0x8b,0x6a, 800, 600, 0x40}, /* 0x3 */
-	{0x0047,0x11,0x0a,0x00,0x6a, 800, 600, 0x40}, /* 0x4 */
-	{0x0047,0x12,0x0d,0x00,0x6a, 800, 600, 0x40}, /* 0x5 */
-	{0x0047,0x13,0x13,0x00,0x6a, 800, 600, 0x20}, /* 0x6 */
-	{0x0107,0x14,0x1c,0x00,0x6a, 800, 600, 0x20}, /* 0x7 */
-	{0xc85f,0x05,0x00,0x04,0x2e, 640, 480, 0x40}, /* 0x8 */
-	{0xc067,0x06,0x02,0x04,0x2e, 640, 480, 0x40}, /* 0x9 */
-	{0xc067,0x07,0x02,0x47,0x2e, 640, 480, 0x40}, /* 0xa */
-	{0xc067,0x08,0x03,0x8a,0x2e, 640, 480, 0x40}, /* 0xb */
-	{0xc047,0x09,0x05,0x00,0x2e, 640, 480, 0x40}, /* 0xc */
-	{0xc047,0x0a,0x09,0x00,0x2e, 640, 480, 0x40}, /* 0xd */
-	{0xc047,0x0b,0x0e,0x00,0x2e, 640, 480, 0x40}, /* 0xe */
-	{0xc047,0x0c,0x15,0x00,0x2e, 640, 480, 0x40}, /* 0xf */
-	{0x487f,0x04,0x00,0x00,0x2f, 640, 400, 0x30}, /* 0x10 */
-	{0xc04f,0x3c,0x01,0x06,0x31, 720, 480, 0x30}, /* 0x11 */
-	{0x004f,0x3d,0x03,0x06,0x32, 720, 576, 0x30}, /* 0x12 */
-	{0x0087,0x15,0x06,0x00,0x37,1024, 768, 0x30}, /* 0x13 */
-	{0xc877,0x16,0x0b,0x06,0x37,1024, 768, 0x20}, /* 0x14 */
-	{0xc067,0x17,0x0f,0x49,0x37,1024, 768, 0x20}, /* 0x15 */
-	{0x0067,0x18,0x11,0x00,0x37,1024, 768, 0x20}, /* 0x16 */
-	{0x0047,0x19,0x16,0x8c,0x37,1024, 768, 0x20}, /* 0x17 */
-	{0x0107,0x1a,0x1b,0x00,0x37,1024, 768, 0x10}, /* 0x18 */
-	{0x0107,0x1b,0x1f,0x00,0x37,1024, 768, 0x10}, /* 0x19 */
-	{0x0087,0x1c,0x11,0x00,0x3a,1280,1024, 0x30}, /* 0x1a */
-	{0x0137,0x1d,0x19,0x07,0x3a,1280,1024, 0x00}, /* 0x1b */
-	{0x0107,0x1e,0x1e,0x00,0x3a,1280,1024, 0x00}, /* 0x1c */
-	{0x0207,0x1f,0x20,0x00,0x3a,1280,1024, 0x00}, /* 0x1d */
-	{0x0227,0x20,0x21,0x09,0x3c,1600,1200, 0x00}, /* 0x1e */
-	{0x0407,0x21,0x22,0x00,0x3c,1600,1200, 0x00}, /* 0x1f */
-	{0x0407,0x22,0x23,0x00,0x3c,1600,1200, 0x00}, /* 0x20 */
-	{0x0407,0x23,0x25,0x00,0x3c,1600,1200, 0x00}, /* 0x21 */
-	{0x0007,0x24,0x26,0x00,0x3c,1600,1200, 0x00}, /* 0x22 */
-	{0x0007,0x25,0x2c,0x00,0x3c,1600,1200, 0x00}, /* 0x23 */
-	{0x0007,0x26,0x34,0x00,0x3c,1600,1200, 0x00}, /* 0x24 */
-	{0x407f,0x00,0x00,0x00,0x40, 320, 200, 0x30}, /* 0x25 */
-	{0xc07f,0x01,0x00,0x04,0x50, 320, 240, 0x30}, /* 0x26 */
-	{0x007f,0x02,0x04,0x05,0x51, 400, 300, 0x30}, /* 0x27 */
-	{0xc077,0x03,0x0b,0x06,0x52, 512, 384, 0x30}, /* 0x28 */
-	{0x8007,0x27,0x27,0x00,0x68,1920,1440, 0x00}, /* 0x29 */
-	{0x4007,0x28,0x29,0x00,0x68,1920,1440, 0x00}, /* 0x2a */
-	{0x4007,0x29,0x2e,0x00,0x68,1920,1440, 0x00}, /* 0x2b */
-	{0x4007,0x2a,0x30,0x00,0x68,1920,1440, 0x00}, /* 0x2c */
-	{0x4007,0x2b,0x35,0x00,0x68,1920,1440, 0x00}, /* 0x2d */
-	{0x4005,0x2c,0x39,0x00,0x68,1920,1440, 0x00}, /* 0x2e */
-	{0x4007,0x2d,0x2b,0x00,0x6c,2048,1536, 0x00}, /* 0x2f */
-	{0x4007,0x2e,0x31,0x00,0x6c,2048,1536, 0x00}, /* 0x30 */
-	{0x4007,0x2f,0x33,0x00,0x6c,2048,1536, 0x00}, /* 0x31 */
-	{0x4007,0x30,0x37,0x00,0x6c,2048,1536, 0x00}, /* 0x32 */
-	{0x4005,0x31,0x38,0x00,0x6c,2048,1536, 0x00}, /* 0x33 */
-	{0x0057,0x32,0x40,0x08,0x70, 800, 480, 0x30}, /* 0x34 */
-	{0x0047,0x33,0x07,0x08,0x70, 800, 480, 0x30}, /* 0x35 */
-	{0x0047,0x34,0x0a,0x08,0x70, 800, 480, 0x30}, /* 0x36 */
-	{0x0057,0x35,0x0b,0x09,0x71,1024, 576, 0x30}, /* 0x37 */
-	{0x0047,0x36,0x11,0x09,0x71,1024, 576, 0x30}, /* 0x38 */
-	{0x0047,0x37,0x16,0x09,0x71,1024, 576, 0x30}, /* 0x39 */
-	{0x0117,0x38,0x19,0x0a,0x75,1280, 720, 0x30}, /* 0x3a */
-	{0x0107,0x39,0x1e,0x0a,0x75,1280, 720, 0x30}, /* 0x3b */
-	{0x0207,0x3a,0x20,0x0a,0x75,1280, 720, 0x30}, /* 0x3c */
-	{0x0127,0x3b,0x19,0x08,0x7c,1280, 960, 0x30}, /* 0x3d */
-	{0x0227,0x4c,0x59,0x08,0x7c,1280, 960, 0x20}, /* 0x3e */
-	{0xc07f,0x4e,0x00,0x06,0x5a, 320, 240, 0x30}, /* 0x3f */    /* FSTN 320x240 */
-        {0x0077,0x42,0x5b,0x08,0x23,1280, 768, 0x30}, /* 0x40 */    /* TW: 0x5b was 0x12 */
-	{0x0127,0x43,0x4d,0x08,0x26,1400,1050, 0x30}, /* 0x41 */
-	{0x0207,0x4b,0x5a,0x08,0x26,1400,1050, 0x30}, /* 0x42 Non-BIOS, new */
-	{0x0107,0x44,0x19,0x00,0x29,1152, 864, 0x30}, /* 0x43 Non-BIOS, new */
-	{0x0107,0x4a,0x1e,0x00,0x29,1152, 864, 0x30}, /* 0x44 Non-BIOS, new */
-	{0x0087,0x45,0x57,0x00,0x39, 848, 480, 0x30}, /* 0x45 848x480-38Hzi - Non-BIOS, new */
-	{0xc067,0x46,0x55,0x0b,0x39, 848, 480, 0x30}, /* 0x46 848x480-60Hz  - Non-BIOS, new */
-	{0x0087,0x47,0x57,0x00,0x3f, 856, 480, 0x30}, /* 0x47 856x480-38Hzi - Non-BIOS, new */
-	{0xc047,0x48,0x57,0x00,0x3f, 856, 480, 0x30}, /* 0x48 856x480-60Hz  - Non-BIOS, new */
-	{0x0067,0x49,0x58,0x0c,0x48,1360, 768, 0x30}, /* 0x49 1360x768-60Hz - Non-BIOS, new */
-	{0x004f,0x4d,0x03,0x06,0x5f, 768, 576, 0x30}, /* 0x4a 768x576 */
-	{0xffff,0x00,0x00,0x00,0x00,   0,   0, 0}
+	{0x6a,0x2212,0x0102,SIS_RI_800x600,  0x00,0x00,0x07,0x06,0x00, 3}, /* 800x600x? */
+	{0x2e,0x0a1b,0x0101,SIS_RI_640x480,  0x00,0x00,0x05,0x05,0x08, 2}, /* 640x480x8 */
+        {0x2f,0x0a1b,0x0100,SIS_RI_640x400,  0x00,0x00,0x05,0x05,0x10, 0}, /* 640x400x8 */
+	{0x30,0x2a1b,0x0103,SIS_RI_800x600,  0x00,0x00,0x07,0x06,0x00, 3}, /* 800x600x8 */
+        {0x31,0x4a1b,0x0000,SIS_RI_720x480,  0x00,0x00,0x06,0x06,0x11,-1}, /* 720x480x8 */
+	{0x32,0x4a1b,0x0000,SIS_RI_720x576,  0x00,0x00,0x06,0x06,0x12,-1}, /* 720x576x8 */
+	{0x33,0x4a1d,0x0000,SIS_RI_720x480,  0x00,0x00,0x06,0x06,0x11,-1}, /* 720x480x16 */
+	{0x34,0x6a1d,0x0000,SIS_RI_720x576,  0x00,0x00,0x06,0x06,0x12,-1}, /* 720x576x16 */
+	{0x35,0x4a1f,0x0000,SIS_RI_720x480,  0x00,0x00,0x06,0x06,0x11,-1}, /* 720x480x32 */
+	{0x36,0x6a1f,0x0000,SIS_RI_720x576,  0x00,0x00,0x06,0x06,0x12,-1}, /* 720x576x32 */
+	{0x37,0x0212,0x0104,SIS_RI_1024x768, 0x00,0x00,0x08,0x07,0x13, 4}, /* 1024x768x? */
+	{0x38,0x0a1b,0x0105,SIS_RI_1024x768, 0x00,0x00,0x08,0x07,0x13, 4}, /* 1024x768x8 */
+	{0x3a,0x0e3b,0x0107,SIS_RI_1280x1024,0x00,0x00,0x00,0x00,0x1a, 8}, /* 1280x1024x8 */
+	{0x3c,0x0e3b,0x0130,SIS_RI_1600x1200,0x00,0x00,0x00,0x00,0x1e,10}, /* 1600x1200x8 */
+	{0x3d,0x0e7d,0x0131,SIS_RI_1600x1200,0x00,0x00,0x00,0x00,0x1e,10}, /* 1600x1200x16 */
+	{0x40,0x9a1c,0x010d,SIS_RI_320x200,  0x00,0x00,0x04,0x04,0x25, 0}, /* 320x200x15 */
+	{0x41,0x9a1d,0x010e,SIS_RI_320x200,  0x00,0x00,0x04,0x04,0x25, 0}, /* 320x200x16 */
+	{0x43,0x0a1c,0x0110,SIS_RI_640x480,  0x00,0x00,0x05,0x05,0x08, 2},
+	{0x44,0x0a1d,0x0111,SIS_RI_640x480,  0x00,0x00,0x05,0x05,0x08, 2}, /* 640x480x16 */
+	{0x46,0x2a1c,0x0113,SIS_RI_800x600,  0x00,0x00,0x07,0x06,0x00, 3},
+	{0x47,0x2a1d,0x0114,SIS_RI_800x600,  0x00,0x00,0x07,0x06,0x00, 3}, /* 800x600x16 */
+	{0x49,0x0a3c,0x0116,SIS_RI_1024x768, 0x00,0x00,0x00,0x07,0x13, 4},
+	{0x4a,0x0a3d,0x0117,SIS_RI_1024x768, 0x00,0x00,0x08,0x07,0x13, 4}, /* 1024x768x16 */
+	{0x4c,0x0e7c,0x0119,SIS_RI_1280x1024,0x00,0x00,0x00,0x00,0x1a, 8},
+	{0x4d,0x0e7d,0x011a,SIS_RI_1280x1024,0x00,0x00,0x00,0x00,0x1a, 8}, /* 1280x1024x16 */
+	{0x50,0x9a1b,0x0132,SIS_RI_320x240,  0x00,0x00,0x04,0x04,0x26, 2}, /* 320x240x8  */
+	{0x51,0xba1b,0x0133,SIS_RI_400x300,  0x00,0x00,0x07,0x07,0x27, 3}, /* 400x300x8  */
+  	{0x52,0xba1b,0x0134,SIS_RI_512x384,  0x00,0x00,0x00,0x00,0x28, 4}, /* 512x384x8  */
+	{0x56,0x9a1d,0x0135,SIS_RI_320x240,  0x00,0x00,0x04,0x04,0x26, 2}, /* 320x240x16 */
+	{0x57,0xba1d,0x0136,SIS_RI_400x300,  0x00,0x00,0x07,0x07,0x27, 3}, /* 400x300x16 */
+ 	{0x58,0xba1d,0x0137,SIS_RI_512x384,  0x00,0x00,0x00,0x00,0x28, 4}, /* 512x384x16 */
+	{0x59,0x9a1b,0x0138,SIS_RI_320x200,  0x00,0x00,0x04,0x04,0x25, 0}, /* 320x200x8  */
+	{0x5a,0x021b,0x0138,SIS_RI_320x240,  0x00,0x00,0x00,0x00,0x3f, 2}, /* 320x240x8  fstn */
+	{0x5b,0x0a1d,0x0135,SIS_RI_320x240,  0x00,0x00,0x00,0x00,0x3f, 2}, /* 320x240x16 fstn */
+	{0x5c,0xba1f,0x0000,SIS_RI_512x384,  0x00,0x00,0x00,0x00,0x28, 4}, /* 512x384x32 */
+	{0x5d,0x0a1d,0x0139,SIS_RI_640x400,  0x00,0x00,0x05,0x07,0x10, 0},
+	{0x5e,0x0a1f,0x0000,SIS_RI_640x400,  0x00,0x00,0x05,0x07,0x10, 0}, /* 640x400x32 */
+	{0x62,0x0a3f,0x013a,SIS_RI_640x480,  0x00,0x00,0x05,0x05,0x08, 2}, /* 640x480x32 */
+	{0x63,0x2a3f,0x013b,SIS_RI_800x600,  0x00,0x00,0x07,0x06,0x00, 3}, /* 800x600x32 */
+	{0x64,0x0a7f,0x013c,SIS_RI_1024x768, 0x00,0x00,0x08,0x07,0x13, 4}, /* 1024x768x32 */
+	{0x65,0x0eff,0x013d,SIS_RI_1280x1024,0x00,0x00,0x00,0x00,0x1a, 8}, /* 1280x1024x32 */
+	{0x66,0x0eff,0x013e,SIS_RI_1600x1200,0x00,0x00,0x00,0x00,0x1e,10}, /* 1600x1200x32 */
+	{0x68,0x067b,0x013f,SIS_RI_1920x1440,0x00,0x00,0x00,0x00,0x29,-1}, /* 1920x1440x8 */
+	{0x69,0x06fd,0x0140,SIS_RI_1920x1440,0x00,0x00,0x00,0x00,0x29,-1}, /* 1920x1440x16 */
+	{0x6b,0x07ff,0x0141,SIS_RI_1920x1440,0x00,0x00,0x00,0x00,0x29,-1}, /* 1920x1440x32 */
+	{0x6c,0x067b,0x0000,SIS_RI_2048x1536,0x00,0x00,0x00,0x00,0x2f,-1}, /* 2048x1536x8 */
+	{0x6d,0x06fd,0x0000,SIS_RI_2048x1536,0x00,0x00,0x00,0x00,0x2f,-1}, /* 2048x1536x16 */
+	{0x6e,0x07ff,0x0000,SIS_RI_2048x1536,0x00,0x00,0x00,0x00,0x2f,-1}, /* 2048x1536x32 */
+	{0x70,0x6a1b,0x0000,SIS_RI_800x480,  0x00,0x00,0x07,0x07,0x34,-1}, /* 800x480x8 */
+	{0x71,0x4a1b,0x0000,SIS_RI_1024x576, 0x00,0x00,0x00,0x00,0x37,-1}, /* 1024x576x8 */
+	{0x74,0x4a1d,0x0000,SIS_RI_1024x576, 0x00,0x00,0x00,0x00,0x37,-1}, /* 1024x576x16 */
+	{0x75,0x0a3d,0x0000,SIS_RI_1280x720, 0x00,0x00,0x00,0x00,0x3a, 5}, /* 1280x720x16 */
+	{0x76,0x6a1f,0x0000,SIS_RI_800x480,  0x00,0x00,0x07,0x07,0x34,-1}, /* 800x480x32 */
+	{0x77,0x4a1f,0x0000,SIS_RI_1024x576, 0x00,0x00,0x00,0x00,0x37,-1}, /* 1024x576x32 */
+	{0x78,0x0a3f,0x0000,SIS_RI_1280x720, 0x00,0x00,0x00,0x00,0x3a, 5}, /* 1280x720x32 */
+	{0x79,0x0a3b,0x0000,SIS_RI_1280x720, 0x00,0x00,0x00,0x00,0x3a, 5}, /* 1280x720x8 */
+	{0x7a,0x6a1d,0x0000,SIS_RI_800x480,  0x00,0x00,0x07,0x07,0x34,-1}, /* 800x480x16 */
+	{0x7c,0x0e3b,0x0000,SIS_RI_1280x960, 0x00,0x00,0x00,0x00,0x3d,-1}, /* 1280x960x8 */
+	{0x7d,0x0e7d,0x0000,SIS_RI_1280x960, 0x00,0x00,0x00,0x00,0x3d,-1}, /* 1280x960x16 */
+	{0x7e,0x0eff,0x0000,SIS_RI_1280x960, 0x00,0x00,0x00,0x00,0x3d,-1}, /* 1280x960x32 */
+	{0x23,0x0e3b,0x0000,SIS_RI_1280x768, 0x00,0x00,0x00,0x00,0x40, 6}, /* 1280x768x8 */
+	{0x24,0x0e7d,0x0000,SIS_RI_1280x768, 0x00,0x00,0x00,0x00,0x40, 6}, /* 1280x768x16 */
+	{0x25,0x0eff,0x0000,SIS_RI_1280x768, 0x00,0x00,0x00,0x00,0x40, 6}, /* 1280x768x32 */
+	{0x26,0x0e3b,0x0000,SIS_RI_1400x1050,0x00,0x00,0x00,0x00,0x41, 9}, /* 1400x1050x8 */
+	{0x27,0x0e7d,0x0000,SIS_RI_1400x1050,0x00,0x00,0x00,0x00,0x41, 9}, /* 1400x1050x16 */
+	{0x28,0x0eff,0x0000,SIS_RI_1400x1050,0x00,0x00,0x00,0x00,0x41, 9}, /* 1400x1050x32*/
+	{0x29,0x4e1b,0x0000,SIS_RI_1152x864, 0x00,0x00,0x00,0x00,0x43,-1}, /* 1152x864 */
+	{0x2a,0x4e3d,0x0000,SIS_RI_1152x864, 0x00,0x00,0x00,0x00,0x43,-1},
+	{0x2b,0x4e7f,0x0000,SIS_RI_1152x864, 0x00,0x00,0x00,0x00,0x43,-1},
+	{0x39,0x6a1b,0x0000,SIS_RI_848x480,  0x00,0x00,0x00,0x00,0x45,-1}, /* 848x480 */
+	{0x3b,0x6a3d,0x0000,SIS_RI_848x480,  0x00,0x00,0x00,0x00,0x45,-1},
+	{0x3e,0x6a7f,0x0000,SIS_RI_848x480,  0x00,0x00,0x00,0x00,0x45,-1},
+	{0x3f,0x6a1b,0x0000,SIS_RI_856x480,  0x00,0x00,0x00,0x00,0x47,-1}, /* 856x480 */
+	{0x42,0x6a3d,0x0000,SIS_RI_856x480,  0x00,0x00,0x00,0x00,0x47,-1},
+	{0x45,0x6a7f,0x0000,SIS_RI_856x480,  0x00,0x00,0x00,0x00,0x47,-1},
+	{0x48,0x6a3b,0x0000,SIS_RI_1360x768, 0x00,0x00,0x00,0x00,0x49,-1}, /* 1360x768 */
+	{0x4b,0x6a7d,0x0000,SIS_RI_1360x768, 0x00,0x00,0x00,0x00,0x49,-1},
+	{0x4e,0x6aff,0x0000,SIS_RI_1360x768, 0x00,0x00,0x00,0x00,0x49,-1},
+	{0x4f,0x9a1f,0x0000,SIS_RI_320x200,  0x00,0x00,0x04,0x04,0x25, 0}, /* 320x200x32 */
+	{0x53,0x9a1f,0x0000,SIS_RI_320x240,  0x00,0x00,0x04,0x04,0x26, 2}, /* 320x240x32 */
+	{0x54,0xba1f,0x0000,SIS_RI_400x300,  0x00,0x00,0x07,0x07,0x27, 3}, /* 400x300x32 */
+	{0x5f,0x6a1b,0x0000,SIS_RI_768x576,  0x00,0x00,0x06,0x06,0x4a,-1}, /* 768x576 */
+	{0x60,0x6a1d,0x0000,SIS_RI_768x576,  0x00,0x00,0x06,0x06,0x4a,-1},
+	{0x61,0x6a3f,0x0000,SIS_RI_768x576,  0x00,0x00,0x06,0x06,0x4a,-1},
+	{0x14,0x0e3b,0x0000,SIS_RI_1280x800, 0x00,0x00,0x00,0x00,0x4b, 7}, /* 1280x800 */
+	{0x15,0x0e7d,0x0000,SIS_RI_1280x800, 0x00,0x00,0x00,0x00,0x4b, 7},
+	{0x16,0x0eff,0x0000,SIS_RI_1280x800, 0x00,0x00,0x00,0x00,0x4b, 7},
+	{0x17,0x0e3b,0x0000,SIS_RI_1680x1050,0x00,0x00,0x00,0x00,0x4c, 9}, /* 1680x1050 */
+	{0x18,0x0e7d,0x0000,SIS_RI_1680x1050,0x00,0x00,0x00,0x00,0x4c, 9},
+	{0x19,0x0eff,0x0000,SIS_RI_1680x1050,0x00,0x00,0x00,0x00,0x4c, 9},
+	{0x2c,0x267b,0x0000,SIS_RI_1920x1080,0x00,0x00,0x00,0x00,0x4d,-1}, /* 1920x1080(i) */
+	{0x2d,0x26fd,0x0000,SIS_RI_1920x1080,0x00,0x00,0x00,0x00,0x4d,-1},
+	{0x73,0x27ff,0x0000,SIS_RI_1920x1080,0x00,0x00,0x00,0x00,0x4d,-1},
+	{0x1d,0x6a1b,0x0000,SIS_RI_960x540,  0x00,0x00,0x00,0x00,0x4e,-1}, /* 960x540 */
+	{0x1e,0x6a3d,0x0000,SIS_RI_960x540,  0x00,0x00,0x00,0x00,0x4e,-1},
+	{0x1f,0x6a7f,0x0000,SIS_RI_960x540,  0x00,0x00,0x00,0x00,0x4e,-1},
+	{0xff,0x0000,0x0000,0,               0x00,0x00,0x00,0x00,0x00,-1}
+};
+
+static const SiS_Ext2Struct SiS310_RefIndex[]=
+{
+	{0x085f,0x0d,0x03,0x05,0x05,0x6a, 800, 600, 0x40}, /* 0x0 */
+	{0x0067,0x0e,0x04,0x05,0x05,0x6a, 800, 600, 0x40}, /* 0x1 */
+	{0x0067,0x0f,0x08,0x48,0x05,0x6a, 800, 600, 0x40}, /* 0x2 */
+	{0x0067,0x10,0x07,0x8b,0x05,0x6a, 800, 600, 0x40}, /* 0x3 */
+	{0x0047,0x11,0x0a,0x00,0x05,0x6a, 800, 600, 0x40}, /* 0x4 */
+	{0x0047,0x12,0x0d,0x00,0x05,0x6a, 800, 600, 0x40}, /* 0x5 */
+	{0x0047,0x13,0x13,0x00,0x05,0x6a, 800, 600, 0x20}, /* 0x6 */
+	{0x0107,0x14,0x1c,0x00,0x05,0x6a, 800, 600, 0x20}, /* 0x7 */
+	{0xc85f,0x05,0x00,0x04,0x04,0x2e, 640, 480, 0x40}, /* 0x8 */
+	{0xc067,0x06,0x02,0x04,0x04,0x2e, 640, 480, 0x40}, /* 0x9 */
+	{0xc067,0x07,0x02,0x47,0x04,0x2e, 640, 480, 0x40}, /* 0xa */
+	{0xc067,0x08,0x03,0x8a,0x04,0x2e, 640, 480, 0x40}, /* 0xb */
+	{0xc047,0x09,0x05,0x00,0x04,0x2e, 640, 480, 0x40}, /* 0xc */
+	{0xc047,0x0a,0x09,0x00,0x04,0x2e, 640, 480, 0x40}, /* 0xd */
+	{0xc047,0x0b,0x0e,0x00,0x04,0x2e, 640, 480, 0x40}, /* 0xe */
+	{0xc047,0x0c,0x15,0x00,0x04,0x2e, 640, 480, 0x40}, /* 0xf */
+	{0x487f,0x04,0x00,0x00,0x00,0x2f, 640, 400, 0x30}, /* 0x10 */
+	{0xc06f,0x3c,0x01,0x06,0x13,0x31, 720, 480, 0x30}, /* 0x11 */
+	{0x006f,0x3d,0x03,0x06,0x14,0x32, 720, 576, 0x30}, /* 0x12 */
+	{0x0087,0x15,0x06,0x00,0x06,0x37,1024, 768, 0x30}, /* 0x13 */
+	{0xc877,0x16,0x0b,0x06,0x06,0x37,1024, 768, 0x20}, /* 0x14 */
+	{0xc067,0x17,0x0f,0x49,0x06,0x37,1024, 768, 0x20}, /* 0x15 */
+	{0x0067,0x18,0x11,0x00,0x06,0x37,1024, 768, 0x20}, /* 0x16 */
+	{0x0047,0x19,0x16,0x8c,0x06,0x37,1024, 768, 0x20}, /* 0x17 */
+	{0x0107,0x1a,0x1b,0x00,0x06,0x37,1024, 768, 0x10}, /* 0x18 */
+	{0x0107,0x1b,0x1f,0x00,0x06,0x37,1024, 768, 0x10}, /* 0x19 */
+	{0x0087,0x1c,0x11,0x00,0x07,0x3a,1280,1024, 0x30}, /* 0x1a */
+	{0x0137,0x1d,0x19,0x07,0x07,0x3a,1280,1024, 0x00}, /* 0x1b */
+	{0x0107,0x1e,0x1e,0x00,0x07,0x3a,1280,1024, 0x00}, /* 0x1c */
+	{0x0207,0x1f,0x20,0x00,0x07,0x3a,1280,1024, 0x00}, /* 0x1d */
+	{0x0227,0x20,0x21,0x09,0x09,0x3c,1600,1200, 0x00}, /* 0x1e */
+	{0x0407,0x21,0x22,0x00,0x09,0x3c,1600,1200, 0x00}, /* 0x1f */
+	{0x0407,0x22,0x23,0x00,0x09,0x3c,1600,1200, 0x00}, /* 0x20 */
+	{0x0407,0x23,0x25,0x00,0x09,0x3c,1600,1200, 0x00}, /* 0x21 */
+	{0x0007,0x24,0x26,0x00,0x09,0x3c,1600,1200, 0x00}, /* 0x22 */
+	{0x0007,0x25,0x2c,0x00,0x09,0x3c,1600,1200, 0x00}, /* 0x23 */
+	{0x0007,0x26,0x34,0x00,0x09,0x3c,1600,1200, 0x00}, /* 0x24 */
+	{0x407f,0x00,0x00,0x00,0x00,0x40, 320, 200, 0x30}, /* 0x25 */
+	{0xc07f,0x01,0x00,0x04,0x04,0x50, 320, 240, 0x30}, /* 0x26 */
+	{0x007f,0x02,0x04,0x05,0x05,0x51, 400, 300, 0x30}, /* 0x27 */
+	{0xc077,0x03,0x0b,0x06,0x06,0x52, 512, 384, 0x30}, /* 0x28 */
+	{0x8007,0x27,0x27,0x00,0x00,0x68,1920,1440, 0x00}, /* 0x29 */
+	{0x4007,0x28,0x29,0x00,0x00,0x68,1920,1440, 0x00}, /* 0x2a */
+	{0x4007,0x29,0x2e,0x00,0x00,0x68,1920,1440, 0x00}, /* 0x2b */
+	{0x4007,0x2a,0x30,0x00,0x00,0x68,1920,1440, 0x00}, /* 0x2c */
+	{0x4007,0x2b,0x35,0x00,0x00,0x68,1920,1440, 0x00}, /* 0x2d */
+	{0x4005,0x2c,0x39,0x00,0x00,0x68,1920,1440, 0x00}, /* 0x2e */
+	{0x4007,0x2d,0x2b,0x00,0x00,0x6c,2048,1536, 0x00}, /* 0x2f */
+	{0x4007,0x2e,0x31,0x00,0x00,0x6c,2048,1536, 0x00}, /* 0x30 */
+	{0x4007,0x2f,0x33,0x00,0x00,0x6c,2048,1536, 0x00}, /* 0x31 */
+	{0x4007,0x30,0x37,0x00,0x00,0x6c,2048,1536, 0x00}, /* 0x32 */
+	{0x4005,0x31,0x38,0x00,0x00,0x6c,2048,1536, 0x00}, /* 0x33 */
+	{0x0077,0x32,0x40,0x08,0x18,0x70, 800, 480, 0x30}, /* 0x34 */
+	{0x0047,0x33,0x07,0x08,0x18,0x70, 800, 480, 0x30}, /* 0x35 */
+	{0x0047,0x34,0x0a,0x08,0x18,0x70, 800, 480, 0x30}, /* 0x36 */
+	{0x0077,0x35,0x0b,0x09,0x19,0x71,1024, 576, 0x30}, /* 0x37 */
+	{0x0047,0x36,0x11,0x09,0x19,0x71,1024, 576, 0x30}, /* 0x38 */
+	{0x0047,0x37,0x16,0x09,0x19,0x71,1024, 576, 0x30}, /* 0x39 */
+	{0x1137,0x38,0x19,0x0a,0x0c,0x75,1280, 720, 0x30}, /* 0x3a */
+	{0x1107,0x39,0x1e,0x0a,0x0c,0x75,1280, 720, 0x30}, /* 0x3b */
+	{0x1307,0x3a,0x20,0x0a,0x0c,0x75,1280, 720, 0x30}, /* 0x3c */
+	{0x0127,0x3b,0x19,0x08,0x0a,0x7c,1280, 960, 0x30}, /* 0x3d */
+	{0x0227,0x4c,0x59,0x08,0x0a,0x7c,1280, 960, 0x20}, /* 0x3e */
+	{0xc07f,0x4e,0x00,0x06,0x04,0x5a, 320, 240, 0x30}, /* 0x3f */    /* FSTN 320x240 */
+        {0x0077,0x42,0x5b,0x08,0x11,0x23,1280, 768, 0x30}, /* 0x40 */    /* 0x5b was 0x12 */
+	{0x0127,0x43,0x4d,0x08,0x0b,0x26,1400,1050, 0x30}, /* 0x41 */
+	{0x0207,0x4b,0x5a,0x08,0x0b,0x26,1400,1050, 0x30}, /* 0x42 1400x1050-75Hz */
+	{0x0127,0x44,0x19,0x00,0x1a,0x29,1152, 864, 0x30}, /* 0x43 1152x864-75Hz  */
+	{0x0127,0x4a,0x1e,0x00,0x1a,0x29,1152, 864, 0x30}, /* 0x44 1152x864-85Hz  */
+	{0x0087,0x45,0x57,0x00,0x16,0x39, 848, 480, 0x30}, /* 0x45 848x480-38Hzi  */
+	{0xc067,0x46,0x55,0x0b,0x16,0x39, 848, 480, 0x30}, /* 0x46 848x480-60Hz   */
+	{0x0087,0x47,0x57,0x00,0x17,0x3f, 856, 480, 0x30}, /* 0x47 856x480-38Hzi  */
+	{0xc067,0x48,0x57,0x00,0x17,0x3f, 856, 480, 0x30}, /* 0x48 856x480-60Hz   */
+	{0x0067,0x49,0x58,0x0c,0x1b,0x48,1360, 768, 0x30}, /* 0x49 1360x768-60Hz  */
+	{0x006f,0x4d,0x03,0x06,0x15,0x5f, 768, 576, 0x30}, /* 0x4a 768x576-56Hz   */
+	{0x0067,0x4f,0x5c,0x08,0x0d,0x14,1280, 800, 0x30}, /* 0x4b 1280x800-60Hz  */
+	{0x0067,0x50,0x5d,0x0c,0x0e,0x17,1680,1050, 0x30}, /* 0x4c 1680x1050-60Hz */
+	{0x0087,0x51,0x69,0x00,0x00,0x2c,1920,1080, 0x30}, /* 0x4d 1920x1080 60Hzi */
+	{0x0067,0x52,0x6a,0x00,0x1c,0x1d, 960, 540, 0x30}, /* 0x4e 960x540 60Hz */
+	{0xffff,0x00,0x00,0x00,0x00,0x00,   0,   0,    0}
 };
 
-typedef struct _SiS310_CRT1TableStruct
-{
- 	UCHAR CR[17];
-} SiS310_CRT1TableStruct;
-
-static const SiS310_CRT1TableStruct SiS310_CRT1Table[]=
+static const SiS_CRT1TableStruct SiS310_CRT1Table[]=
 {
  {{0x2d,0x27,0x28,0x90,0x2c,0x80,0xbf,0x1f,
    0x9c,0x8e,0x8f,0x96,0xb9,0x30,0x00,0x00,
@@ -310,7 +280,7 @@
  {{0x5f,0x4f,0x50,0x82,0x55,0x81,0x0b,0x3e,
    0xe9,0x8b,0xdf,0xe7,0x04,0x00,0x00,0x05,
    0x00}}, /* 0x5 */
-#endif   
+#endif
  {{0x5f,0x4f,0x4f,0x83,0x55,0x81,0x0b,0x3e,    /* 0x05 - corrected 640x480-60 */
    0xe9,0x8b,0xdf,0xe8,0x0c,0x00,0x00,0x05,
    0x00}},
@@ -329,16 +299,16 @@
    0xe0,0x83,0xdf,0xdf,0xfc,0x10,0x00,0x05,
    0x00}}, /* 0x8 */
  {{0x65,0x4f,0x4f,0x89,0x58,0x80,0xfb,0x1f,
-   0xe0,0x83,0xdf,0xdf,0xfc,0x10,0x00,0x05,  /* TW: Corrected VBE */
+   0xe0,0x83,0xdf,0xdf,0xfc,0x10,0x00,0x05,  /* Corrected VBE */
    0x61}}, /* 0x9 */
  {{0x65,0x4f,0x4f,0x89,0x58,0x80,0x01,0x3e,
    0xe0,0x83,0xdf,0xdf,0x02,0x00,0x00,0x05,
    0x61}}, /* 0xa */
  {{0x67,0x4f,0x4f,0x8b,0x58,0x81,0x0d,0x3e,
-   0xe0,0x83,0xdf,0xdf,0x0e,0x00,0x00,0x05,  /* TW: Corrected VBE */
+   0xe0,0x83,0xdf,0xdf,0x0e,0x00,0x00,0x05,  /* Corrected VBE */
    0x61}}, /* 0xb */
  {{0x65,0x4f,0x4f,0x89,0x57,0x9f,0xfb,0x1f,
-   0xe6,0x8a,0xdf,0xdf,0xfc,0x10,0x00,0x01,  /* TW: Corrected VDE, VBE */
+   0xe6,0x8a,0xdf,0xdf,0xfc,0x10,0x00,0x01,  /* Corrected VDE, VBE */
    0x00}}, /* 0xc */
  {{0x7b,0x63,0x63,0x9f,0x6a,0x93,0x6f,0xf0,
    0x58,0x8a,0x57,0x57,0x70,0x20,0x00,0x05,
@@ -466,7 +436,7 @@
  {{0x9f,0x7f,0x7f,0x83,0x85,0x91,0x1e,0xf1,
    0xad,0x81,0x3f,0x3f,0x1f,0x30,0x00,0x02,
    0x01}}, /* 0x36 */
- {{0xa7,0x7f,0x7f,0x88,0x89,0x95,0x26,0xf1,   /* TW: 95 was 15 - illegal HBE! */
+ {{0xa7,0x7f,0x7f,0x88,0x89,0x95,0x26,0xf1,   /* 95 was 15 - illegal HBE! */
    0xb1,0x85,0x3f,0x3f,0x27,0x30,0x00,0x02,
    0x01}}, /* 0x37 */
  {{0xce,0x9f,0x9f,0x92,0xa9,0x17,0x28,0xc4,
@@ -498,7 +468,7 @@
  {{0x81,0x6a,0x6a,0x85,0x70,0x00,0x0f,0x3e,
    0xeb,0x8e,0xdf,0xdf,0x10,0x00,0x00,0x02,
    0x00}}, /* 0x3f */
- {{0xa3,0x7f,0x7f,0x87,0x86,0x97,0x1e,0xf1,   /* TW: The following from 650/LVDS BIOS */
+ {{0xa3,0x7f,0x7f,0x87,0x86,0x97,0x1e,0xf1,
    0xae,0x85,0x57,0x57,0x1f,0x30,0x00,0x02,
    0x01}},  /* 0x40 */
  {{0xa3,0x7f,0x7f,0x87,0x86,0x97,0x24,0xf5,
@@ -510,31 +480,31 @@
  {{0xe6,0xae,0xae,0x8a,0xbd,0x90,0x3d,0x10,
    0x1a,0x8d,0x19,0x19,0x3e,0x2f,0x00,0x03,
    0x00}},  /* 0x43 */
- {{0xc3,0x8f,0x8f,0x87,0x9b,0x0b,0x82,0xef, /* New, 1152x864-75, not in BIOS */
+ {{0xc3,0x8f,0x8f,0x87,0x9b,0x0b,0x82,0xef, /* 1152x864-75 */
    0x60,0x83,0x5f,0x5f,0x83,0x10,0x00,0x07,
    0x01}},  /* 0x44 */
- {{0x86,0x69,0x69,0x8A,0x74,0x06,0x8C,0x15, /* New, 848x480-38i, not in BIOS */
+ {{0x86,0x69,0x69,0x8A,0x74,0x06,0x8C,0x15, /* 848x480-38i */
    0x4F,0x83,0xEF,0xEF,0x8D,0x30,0x00,0x02,
    0x00}},  /* 0x45 */
- {{0x83,0x69,0x69,0x87,0x6f,0x1d,0x03,0x3E, /* New, 848x480-60, not in BIOS */
+ {{0x83,0x69,0x69,0x87,0x6f,0x1d,0x03,0x3E, /* 848x480-60 */
    0xE5,0x8d,0xDF,0xe4,0x04,0x00,0x00,0x06,
    0x00}},  /* 0x46 */
- {{0x86,0x6A,0x6A,0x8A,0x74,0x06,0x8C,0x15, /* New, 856x480-38i, not in BIOS */
+ {{0x86,0x6A,0x6A,0x8A,0x74,0x06,0x8C,0x15, /* 856x480-38i */
    0x4F,0x83,0xEF,0xEF,0x8D,0x30,0x00,0x02,
    0x00}},  /* 0x47 */
- {{0x81,0x6A,0x6A,0x85,0x70,0x00,0x0F,0x3E, /* New, 856x480-60, not in BIOS */
+ {{0x81,0x6A,0x6A,0x85,0x70,0x00,0x0F,0x3E, /* 856x480-60 */
    0xEB,0x8E,0xDF,0xDF,0x10,0x00,0x00,0x02,
    0x00}},  /* 0x48 */
- {{0xdd,0xa9,0xa9,0x81,0xb4,0x97,0x26,0xfd, /* New, 1360x768-60, not in BIOS */
+ {{0xdd,0xa9,0xa9,0x81,0xb4,0x97,0x26,0xfd, /* 1360x768-60 */
    0x01,0x8d,0xff,0x00,0x27,0x10,0x00,0x03,
    0x01}},  /* 0x49 */
- {{0xd9,0x8f,0x8f,0x9d,0xba,0x0a,0x8a,0xff, /* New, 1152x864-84, not in any BIOS   */
+ {{0xd9,0x8f,0x8f,0x9d,0xba,0x0a,0x8a,0xff, /* 1152x864-84  */
    0x60,0x8b,0x5f,0x5f,0x8b,0x10,0x00,0x03,
    0x01}},  /* 0x4a */
- {{0xea,0xae,0xae,0x8e,0xba,0x82,0x40,0x10, /* New, 1400x1050-75, not in any BIOS  */
+ {{0xea,0xae,0xae,0x8e,0xba,0x82,0x40,0x10, /* 1400x1050-75  */
    0x1b,0x87,0x19,0x1a,0x41,0x0f,0x00,0x03,
    0x00}},  /* 0x4b */
- {{0xd3,0x9f,0x9f,0x97,0xab,0x1f,0xf1,0xff, /* New, 1280x960-85, not in any BIOS */
+ {{0xd3,0x9f,0x9f,0x97,0xab,0x1f,0xf1,0xff, /* 1280x960-85 */
    0xc0,0x83,0xbf,0xbf,0xf2,0x10,0x00,0x07,
    0x01}},  /* 0x4c */
  {{0x7b,0x5f,0x63,0x9f,0x6a,0x93,0x6f,0xf0, /* 768x576 */
@@ -542,16 +512,22 @@
    0x01}},  /* 0x4d */
  {{0x2d,0x27,0x28,0x90,0x2c,0x80,0x0b,0x3e, /* FSTN 320x480, TEMP - possibly invalid */
    0xe9,0x8b,0xdf,0xe7,0x04,0x00,0x00,0x00,
-   0x00}}   /* 0x4e */
+   0x00}},  /* 0x4e */
+ {{0xcd,0x9f,0x9f,0x91,0xab,0x1c,0x3a,0xff, /* 1280x800-60 */
+   0x20,0x83,0x1f,0x1f,0x3b,0x10,0x00,0x07,
+   0x21}},  /* 0x4f */
+ {{0x15,0xd1,0xd1,0x99,0xe2,0x19,0x3d,0x10, /* 1680x1050-60 */
+   0x1a,0x8d,0x19,0x19,0x3e,0x2f,0x01,0x0c,
+   0x20}},  /* 0x50 */
+ {{0x0e,0xef,0xef,0x92,0xfe,0x03,0x30,0xf0, /* 1920x1080-60i */
+   0x1e,0x83,0x1b,0x1c,0x31,0x00,0x01,0x00,
+   0x61}},  /* 0x51 */
+ {{0x85,0x77,0x77,0x89,0x7d,0x01,0x31,0xf0, /* 960x540-60 */
+   0x1e,0x84,0x1b,0x1c,0x32,0x00,0x00,0x02,
+   0x41}}   /* 0x52 */
 };
 
-typedef struct _SiS310_MCLKDataStruct
-{
-	UCHAR SR28,SR29,SR2A;
-	USHORT CLOCK;
-} SiS310_MCLKDataStruct;
-
-static const SiS310_MCLKDataStruct SiS310_MCLKData_0_315[] =
+static const SiS_MCLKDataStruct SiS310_MCLKData_0_315[] =
 {
 	{ 0x3b,0x22,0x01,143},
 	{ 0x5c,0x23,0x01,166},
@@ -563,7 +539,7 @@
 	{ 0x5c,0x23,0x01,166}
 };
 
-static const SiS310_MCLKDataStruct SiS310_MCLKData_0_650[] =
+static const SiS_MCLKDataStruct SiS310_MCLKData_0_650[] =
 {
 	{ 0x5a,0x64,0x82, 66},
 	{ 0xb3,0x45,0x82, 83},
@@ -575,7 +551,7 @@
 	{ 0x37,0x22,0x82,133}
 };
 
-static const SiS310_MCLKDataStruct SiS310_MCLKData_0_330[] =
+static const SiS_MCLKDataStruct SiS310_MCLKData_0_330[] =
 {
 	{ 0x5c,0x23,0x01,166},
 	{ 0x5c,0x23,0x01,166},
@@ -587,7 +563,7 @@
 	{ 0x79,0x06,0x01,250}
 };
 
-static const SiS310_MCLKDataStruct SiS310_MCLKData_0_660[] =  /* TODO */
+static const SiS_MCLKDataStruct SiS310_MCLKData_0_660[] =
 {
 	{ 0x5c,0x23,0x82,166},
 	{ 0x5c,0x23,0x82,166},
@@ -599,7 +575,19 @@
 	{ 0x37,0x21,0x82,200}
 };
 
-static const SiS310_MCLKDataStruct SiS310_MCLKData_1[] =
+static const SiS_MCLKDataStruct SiS310_MCLKData_0_760[] =
+{
+	{ 0x37,0x22,0x82,133},
+	{ 0x5c,0x23,0x82,166},
+	{ 0x65,0x23,0x82,183},
+	{ 0x7c,0x08,0x82,200},
+	{ 0x29,0x21,0x82,150},
+	{ 0x5c,0x23,0x82,166},
+	{ 0x65,0x23,0x82,183},
+	{ 0x37,0x21,0x82,200}
+};
+
+static const SiS_MCLKDataStruct SiS310_MCLKData_1[] = /* ECLK */
 {
         { 0x29,0x21,0x82,150},
 	{ 0x5c,0x23,0x82,166},
@@ -611,13 +599,7 @@
 	{ 0x37,0x22,0x82,133}
 };
 
-typedef struct _SiS310_VCLKDataStruct
-{
-	UCHAR SR2B,SR2C;
-	USHORT CLOCK;
-} SiS310_VCLKDataStruct;
-
-static const SiS310_VCLKDataStruct SiS310_VCLKData[]=
+static SiS_VCLKDataStruct SiS310_VCLKData[]=
 {
 	{ 0x1b,0xe1, 25}, /* 0x00 */
 	{ 0x4e,0xe4, 28}, /* 0x01 */
@@ -630,7 +612,7 @@
 	{ 0x53,0xe2, 50}, /* 0x08 */
 	{ 0x74,0x67, 52}, /* 0x09 */
 	{ 0x6d,0x66, 56}, /* 0x0a */
-	{ 0x5a,0x64, 65}, /* 0x0b */  /* TW: was 6c c3 - WRONG */
+	{ 0x5a,0x64, 65}, /* 0x0b */  /* was 6c c3 - WRONG */
 	{ 0x46,0x44, 67}, /* 0x0c */
 	{ 0xb1,0x46, 68}, /* 0x0d */
 	{ 0xd3,0x4a, 72}, /* 0x0e */
@@ -677,49 +659,58 @@
 	{ 0xea,0x08,340}, /* 0x37 */
 	{ 0xe8,0x07,376}, /* 0x38 */
 	{ 0xde,0x06,389}, /* 0x39 */
-	{ 0x52,0x2a, 54}, /* 0x3a */  /* 301 TV */
-	{ 0x52,0x6a, 27}, /* 0x3b */  /* 301 TV */
-	{ 0x62,0x24, 70}, /* 0x3c */  /* 301 TV */
-	{ 0x62,0x64, 70}, /* 0x3d */  /* 301 TV */
-	{ 0xa8,0x4c, 30}, /* 0x3e */  /* 301 TV */
-	{ 0x20,0x26, 33}, /* 0x3f */  /* 301 TV */
+	{ 0x52,0x2a, 54}, /* 0x3a 301 TV */
+	{ 0x52,0x6a, 27}, /* 0x3b 301 TV */
+	{ 0x62,0x24, 70}, /* 0x3c 301 TV */
+	{ 0x62,0x64, 70}, /* 0x3d 301 TV */
+	{ 0xa8,0x4c, 30}, /* 0x3e 301 TV */
+	{ 0x20,0x26, 33}, /* 0x3f 301 TV */
 	{ 0x31,0xc2, 39}, /* 0x40 */
-	{ 0x60,0x36, 30}, /* 0x41 */  /* Chrontel */
-	{ 0x40,0x4a, 28}, /* 0x42 */  /* Chrontel */
-	{ 0x9f,0x46, 44}, /* 0x43 */  /* Chrontel */
+	{ 0x60,0x36, 30}, /* 0x41 Chrontel */
+	{ 0x40,0x4a, 28}, /* 0x42 Chrontel */
+	{ 0x9f,0x46, 44}, /* 0x43 Chrontel */
 	{ 0x97,0x2c, 26}, /* 0x44 */
-	{ 0x44,0xe4, 25}, /* 0x45 */  /* Chrontel */
-	{ 0x7e,0x32, 47}, /* 0x46 */  /* Chrontel */
-	{ 0x8a,0x24, 31}, /* 0x47 */  /* Chrontel */
-	{ 0x97,0x2c, 26}, /* 0x48 */  /* Chrontel */
+	{ 0x44,0xe4, 25}, /* 0x45 Chrontel */
+	{ 0x7e,0x32, 47}, /* 0x46 Chrontel */
+	{ 0x8a,0x24, 31}, /* 0x47 Chrontel */
+	{ 0x97,0x2c, 26}, /* 0x48 Chrontel */
 	{ 0xce,0x3c, 39}, /* 0x49 */
-	{ 0x52,0x4a, 36}, /* 0x4a */  /* Chrontel */
+	{ 0x52,0x4a, 36}, /* 0x4a Chrontel */
 	{ 0x34,0x61, 95}, /* 0x4b */
 	{ 0x78,0x27,108}, /* 0x4c - was 102 */
-	{ 0x66,0x43,123}, /* 0x4d */  /* Modes 0x26-0x28 (1400x1050) */
+	{ 0x66,0x43,123}, /* 0x4d Modes 0x26-0x28 (1400x1050) */
 	{ 0x41,0x4e, 21}, /* 0x4e */
-	{ 0xa1,0x4a, 29}, /* 0x4f */  /* Chrontel */
+	{ 0xa1,0x4a, 29}, /* 0x4f Chrontel */
 	{ 0x19,0x42, 42}, /* 0x50 */
-	{ 0x54,0x46, 58}, /* 0x51 */  /* Chrontel */
+	{ 0x54,0x46, 58}, /* 0x51 Chrontel */
 	{ 0x25,0x42, 61}, /* 0x52 */
-	{ 0x44,0x44, 66}, /* 0x53 */  /* Chrontel */
-	{ 0x3a,0x62, 70}, /* 0x54 */  /* Chrontel */
-	{ 0x62,0xc6, 34}, /* 0x55 - added for 848x480-60 (not in any BIOS) */
-	{ 0x6a,0xc6, 37}, /* 0x56 - added for 848x480-75 (not in any BIOS)    - TEMP */
-	{ 0xbf,0xc8, 35}, /* 0x57 - added for 856x480-38i,60 (not in any BIOS) */
-	{ 0x30,0x23, 88}, /* 0x58 - added for 1360x768-62 (is 60Hz!) (not in any BIOS) */
-	{ 0x52,0x07,149}, /* 0x59 - added for 1280x960-85 (Not in any BIOS) */
-	{ 0x56,0x07,156}, /* 0x5a - added for 1400x1050-75 */
-   	{ 0x70,0x29, 81}  /* 0x5b - added for 1280x768 LCD */
-};
-
-typedef struct _SiS310_VBVCLKDataStruct
-{
-	UCHAR Part4_A,Part4_B;
-	USHORT CLOCK;
-} SiS310_VBVCLKDataStruct;
+	{ 0x44,0x44, 66}, /* 0x53 Chrontel */
+	{ 0x3a,0x62, 70}, /* 0x54 Chrontel */
+	{ 0x62,0xc6, 34}, /* 0x55 848x480-60 */
+	{ 0x6a,0xc6, 37}, /* 0x56 848x480-75 - TEMP */
+	{ 0xbf,0xc8, 35}, /* 0x57 856x480-38i,60 */
+	{ 0x30,0x23, 88}, /* 0x58 1360x768-62 (is 60Hz!) */
+	{ 0x52,0x07,149}, /* 0x59 1280x960-85 */
+	{ 0x56,0x07,156}, /* 0x5a 1400x1050-75 */
+   	{ 0x70,0x29, 81}, /* 0x5b 1280x768 LCD */
+	{ 0x45,0x25, 83}, /* 0x5c 1280x800  */
+	{ 0x70,0x0a,147}, /* 0x5d 1680x1050 */
+	{ 0x70,0x24,162}, /* 0x5e 1600x1200 */
+	{ 0x5a,0x64, 65}, /* 0x5f 1280x720 - temp */
+	{ 0x63,0x46, 68}, /* 0x60 1280x768_2 */
+	{ 0x31,0x42, 79}, /* 0x61 1280x768_3 - temp */
+	{    0,   0,  0}, /* 0x62 - custom (will be filled out at run-time) */
+	{ 0x5a,0x64, 65}, /* 0x63 1280x720 (LCD LVDS) */
+	{ 0x70,0x28, 90}, /* 0x64 1152x864@60 */
+	{ 0x41,0xc4, 32}, /* 0x65 848x480@60 */
+	{ 0x5c,0xc6, 32}, /* 0x66 856x480@60 */
+	{ 0x76,0xe7, 27}, /* 0x67 720x480@60 */
+	{ 0x5f,0xc6, 33}, /* 0x68 720/768x576@60 */
+	{ 0x52,0x27, 75}, /* 0x69 1920x1080i 60Hz interlaced */
+	{ 0x7c,0x6b, 38}  /* 0x6a 960x540@60 */
+};
 
-static const SiS310_VBVCLKDataStruct SiS310_VBVCLKData[]=
+static SiS_VBVCLKDataStruct SiS310_VBVCLKData[]=
 {
 	{ 0x1b,0xe1, 25}, /* 0x00 */
 	{ 0x4e,0xe4, 28}, /* 0x01 */
@@ -732,7 +723,7 @@
 	{ 0x53,0x47, 50}, /* 0x08 */
 	{ 0x74,0x67, 52}, /* 0x09 */
 	{ 0x6d,0x66, 56}, /* 0x0a */
-	{ 0x35,0x62, 65}, /* 0x0b */  /* Was 0x5a,0x64 - 650/LVDS+301 bios: 35,62  */
+	{ 0x35,0x62, 65}, /* 0x0b */  /* Was 0x5a,0x64 - 650/LVDS+301: 35,62  */
 	{ 0x46,0x44, 67}, /* 0x0c */
 	{ 0xb1,0x46, 68}, /* 0x0d */
 	{ 0xd3,0x4a, 72}, /* 0x0e */
@@ -785,47 +776,55 @@
 	{ 0xea,0x08,340}, /* 0x37 */
 	{ 0xe8,0x07,376}, /* 0x38 */
 	{ 0xde,0x06,389}, /* 0x39 */
-	{ 0x52,0x2a, 54}, /* 0x3a */  /* 301 TV */
-	{ 0x52,0x6a, 27}, /* 0x3b */  /* 301 TV */
-	{ 0x62,0x24, 70}, /* 0x3c */  /* 301 TV */
-	{ 0x62,0x64, 70}, /* 0x3d */  /* 301 TV */
-	{ 0xa8,0x4c, 30}, /* 0x3e */  /* 301 TV */
-	{ 0x20,0x26, 33}, /* 0x3f */  /* 301 TV */
+	{ 0x52,0x2a, 54}, /* 0x3a 301 TV - start */
+	{ 0x52,0x6a, 27}, /* 0x3b 301 TV */
+	{ 0x62,0x24, 70}, /* 0x3c 301 TV */
+	{ 0x62,0x64, 70}, /* 0x3d 301 TV */
+	{ 0xa8,0x4c, 30}, /* 0x3e 301 TV */
+	{ 0x20,0x26, 33}, /* 0x3f 301 TV */
 	{ 0x31,0xc2, 39}, /* 0x40 */
-	{ 0x2e,0x48, 25}, /* 0x41 */  /* Replacement for LCD on 315 for index 0 */
-	{ 0x24,0x46, 25}, /* 0x42 */  /* Replacement for LCD on 315 for modes 0x01, 0x03, 0x0f, 0x10, 0x12 */
-	{ 0x26,0x64, 28}, /* 0x43 */  /* Replacement for LCD on 315 for index 1 */
-	{ 0x37,0x64, 40}, /* 0x44 */  /* Replacement for LCD on 315 for index 4 */
-	{ 0xa1,0x42,108}, /* 0x45 */  /* 1280x960 LCD */
-	{ 0x37,0x61,100}, /* 0x46 */  /* 1280x960 LCD */
+	{ 0x2e,0x48, 25}, /* 0x41 Replacement for LCD on 315 for index 0 */
+	{ 0x24,0x46, 25}, /* 0x42 Replacement for LCD on 315 for modes 0x01, 0x03, 0x0f, 0x10, 0x12 */
+	{ 0x26,0x64, 28}, /* 0x43 Replacement for LCD on 315 for index 1 */
+	{ 0x37,0x64, 40}, /* 0x44 Replacement for LCD on 315 for index 4 */
+	{ 0xa1,0x42,108}, /* 0x45 1280x960 LCD */
+	{ 0x37,0x61,100}, /* 0x46 1280x960 LCD */
 	{ 0x78,0x27,108}, /* 0x47 */
-	{ 0x97,0x2c, 26}, /* 0x48 */  /* UNUSED - Entries from here new, not in any BIOS */
-	{ 0xce,0x3c, 39}, /* 0x49 */  /* UNUSED */
-	{ 0x52,0x4a, 36}, /* 0x4a */  /* UNUSED */
-	{ 0x34,0x61, 95}, /* 0x4b */  /* UNUSED */
-	{ 0x78,0x27,108}, /* 0x4c */  /* UNUSED */
-	{ 0x66,0x43,123}, /* 0x4d */  /* 1400x1050-60 */
-	{ 0x41,0x4e, 21}, /* 0x4e */  /* UNUSED */
-	{ 0xa1,0x4a, 29}, /* 0x4f */  /* UNUSED */
-	{ 0x19,0x42, 42}, /* 0x50 */  /* UNUSED */
-	{ 0x54,0x46, 58}, /* 0x51 */  /* UNUSED */
-	{ 0x25,0x42, 61}, /* 0x52 */  /* UNUSED */
-	{ 0x44,0x44, 66}, /* 0x53 */  /* UNUSED */
-	{ 0x3a,0x62, 70}, /* 0x54 */  /* UNUSED */
-	{ 0x62,0xc6, 34}, /* 0x55 */  /* 848x480-60 */
-	{ 0x6a,0xc6, 37}, /* 0x56 */  /* 848x480-75 - TEMP, UNUSED */
-	{ 0xbf,0xc8, 35}, /* 0x57 */  /* 856x480-38i,60  */
-	{ 0x30,0x23, 88}, /* 0x58 */  /* 1360x768-62 (is 60Hz!) TEMP, UNUSED */
-	{ 0x52,0x07,149}, /* 0x59 */  /* 1280x960-85  */
-	{ 0x56,0x07,156}, /* 0x5a */  /* 1400x1050-75 */
-   	{ 0x70,0x29, 81}  /* 0x5b */  /* 1280x768 LCD */
-};
-
-static const UCHAR SiS310_ScreenOffset[] =
-{
-        0x14,0x19,0x20,0x28,0x32,0x40,0x50,0x64,
-	0x78,0x80,0x2d,0x35,0x57,0x48,0x55,0x30,
-	0xff
+	{ 0x97,0x2c, 26}, /* 0x48 UNUSED */
+	{ 0xce,0x3c, 39}, /* 0x49 UNUSED */
+	{ 0x52,0x4a, 36}, /* 0x4a UNUSED */
+	{ 0x34,0x61, 95}, /* 0x4b UNUSED */
+	{ 0x78,0x27,108}, /* 0x4c UNUSED */
+	{ 0x66,0x43,123}, /* 0x4d 1400x1050-60 */
+	{ 0x41,0x4e, 21}, /* 0x4e UNUSED */
+	{ 0xa1,0x4a, 29}, /* 0x4f UNUSED */
+	{ 0x19,0x42, 42}, /* 0x50 UNUSED */
+	{ 0x54,0x46, 58}, /* 0x51 UNUSED */
+	{ 0x25,0x42, 61}, /* 0x52 UNUSED */
+	{ 0x44,0x44, 66}, /* 0x53 UNUSED */
+	{ 0x3a,0x62, 70}, /* 0x54 UNUSED */
+	{ 0x62,0xc6, 34}, /* 0x55 848x480-60 */
+	{ 0x6a,0xc6, 37}, /* 0x56 848x480-75 - TEMP, UNUSED */
+	{ 0xbf,0xc8, 35}, /* 0x57 856x480-38i,60  */
+	{ 0x30,0x23, 88}, /* 0x58 1360x768-62 (is 60Hz!) TEMP, UNUSED */
+	{ 0x52,0x07,149}, /* 0x59 1280x960-85  */
+	{ 0x56,0x07,156}, /* 0x5a 1400x1050-75 */
+   	{ 0x70,0x29, 81}, /* 0x5b 1280x768 LCD */
+	{ 0x45,0x25, 83}, /* 0x5c 1280x800 LCD - (was 0x9c,0x62, 69 - wrong?) */
+	{ 0xbe,0x44,121}, /* 0x5d 1680x1050 LCD */
+	{ 0x70,0x24,162}, /* 0x5e 1600x1200 LCD */
+	{ 0x52,0x27, 75}, /* 0x5f 1280x720 LCD TMDS + HDTV (correct) */
+	{ 0x63,0x46, 68}, /* 0x60 1280x768_2 */
+	{ 0x31,0x42, 79}, /* 0x61 1280x768_3 - temp */
+	{    0,   0,  0}, /* 0x62 - custom (will be filled out at run-time) */
+	{ 0x5a,0x64, 65}, /* 0x63 1280x720 (LCD LVDS) */
+	{ 0x70,0x28, 90}, /* 0x64 1152x864@60 */
+	{ 0x41,0xc4, 32}, /* 0x65 848x480@60 */
+	{ 0x5c,0xc6, 32}, /* 0x66 856x480@60 */
+	{ 0x76,0xe7, 27}, /* 0x67 720x480@60 */
+	{ 0x5f,0xc6, 33}, /* 0x68 720/768x576@60 */
+	{ 0x52,0x27, 75}, /* 0x69 1920x1080i 60Hz interlaced (UNUSED) */
+	{ 0x7c,0x6b, 38}  /* 0x6a 960x540@60 */
 };
 
 static const DRAM4Type SiS310_SR15[8] = {
@@ -873,12 +872,7 @@
 static const USHORT SiS310_YCSenseData2    = 0x016b;
 #endif
 
-typedef struct _SiS310_PanelDelayTblStruct
-{
- 	UCHAR timer[2];
-} SiS310_PanelDelayTblStruct;
-
-static const SiS310_PanelDelayTblStruct SiS310_PanelDelayTbl[]=
+static const SiS_PanelDelayTblStruct SiS310_PanelDelayTbl[]=
 {
         {{0x10,0x40}},
 	{{0x10,0x40}},
@@ -898,7 +892,7 @@
 	{{0x10,0x40}}
 };
 
-static const SiS310_PanelDelayTblStruct SiS310_PanelDelayTblLVDS[]=
+static const SiS_PanelDelayTblStruct SiS310_PanelDelayTblLVDS[]=
 {
 	{{0x28,0xc8}},
 	{{0x28,0xc8}},
@@ -922,28 +916,18 @@
 /* SIS VIDEO BRIDGE ----------------------------------------- */
 /**************************************************************/
 
-typedef struct _SiS310_LCDDataStruct
-{
-	USHORT RVBHCMAX;
-	USHORT RVBHCFACT;
-	USHORT VGAHT;
-	USHORT VGAVT;
-	USHORT LCDHT;
-	USHORT LCDVT;
-} SiS310_LCDDataStruct;
-
-static const SiS310_LCDDataStruct  SiS310_StLCD1024x768Data[]=
+static const SiS_LCDDataStruct  SiS310_St2LCD1024x768Data[] =
 {
 	{   62,  25, 800, 546,1344, 806},
 	{   32,  15, 930, 546,1344, 806},
-	{   32,  15, 930, 546,1344, 806},
+        {   62,  25, 800, 546,1344, 806},
 	{  104,  45, 945, 496,1344, 806},
 	{   62,  25, 800, 546,1344, 806},
 	{   31,  18,1008, 624,1344, 806},
 	{    1,   1,1344, 806,1344, 806}
 };
 
-static const SiS310_LCDDataStruct  SiS310_ExtLCD1024x768Data[] =   
+static const SiS_LCDDataStruct  SiS310_ExtLCD1024x768Data[] =
 {
 	{   42,  25,1536, 419,1344, 806},
 	{   48,  25,1536, 369,1344, 806},
@@ -951,28 +935,10 @@
 	{   48,  25,1536, 369,1344, 806},
 	{   12,   5, 896, 500,1344, 806},
 	{   42,  25,1024, 625,1344, 806},
-	{    1,   1,1344, 806,1344, 806},
-	{   12,   5, 896, 500,1344, 806},
-	{   42,  25,1024, 625,1344, 806},
-	{    1,   1,1344, 806,1344, 806},
-	{   12,   5, 896, 500,1344, 806},
-	{   42,  25,1024, 625,1344, 806},
-	{    1,   1,1344, 806,1344, 806}
-	 
-};
-
-static const SiS310_LCDDataStruct  SiS310_St2LCD1024x768Data[] =  
-{
-	{   62,  25, 800, 546,1344, 806},
-	{   32,  15, 930, 546,1344, 806},
-        {   62,  25, 800, 546,1344, 806},    
-	{  104,  45, 945, 496,1344, 806},
-	{   62,  25, 800, 546,1344, 806},
-	{   31,  18,1008, 624,1344, 806},
 	{    1,   1,1344, 806,1344, 806}
 };
 
-static const SiS310_LCDDataStruct  SiS310_StLCD1280x1024Data[] =
+static const SiS_LCDDataStruct  SiS310_St2LCD1280x1024Data[] =
 {
 	{   22,   5, 800, 510,1650,1088},
 	{   22,   5, 800, 510,1650,1088},
@@ -984,7 +950,7 @@
 	{    1,   1,1688,1066,1688,1066}
 };
 
-static const SiS310_LCDDataStruct  SiS310_ExtLCD1280x1024Data[] =
+static const SiS_LCDDataStruct  SiS310_ExtLCD1280x1024Data[] =
 {
 	{  211,  60,1024, 501,1688,1066},
 	{  211,  60,1024, 508,1688,1066},
@@ -993,53 +959,10 @@
 	{  211,  60,1024, 500,1688,1066},
 	{  211,  75,1024, 625,1688,1066},
 	{  211, 120,1280, 798,1688,1066},
-	{    1,   1,1688,1066,1688,1066},
-	{    1,   1,1800,1000,1688,1066}  /* 1280x960 - does not work, use panel scaler instead */
-};
-
-static const SiS310_LCDDataStruct  SiS310_St2LCD1280x1024Data[] =
-{
-	{   22,   5, 800, 510,1650,1088},
-	{   22,   5, 800, 510,1650,1088},
-	{  176,  45, 900, 510,1650,1088},
-	{  176,  45, 900, 510,1650,1088},
-	{   22,   5, 800, 510,1650,1088},
-	{   13,   5,1024, 675,1560,1152},
-	{   16,   9,1266, 804,1688,1072},
 	{    1,   1,1688,1066,1688,1066}
 };
 
-static const SiS310_LCDDataStruct  SiS310_NoScaleData1024x768[] =  
-{
-        {    1,   1,1344, 806,1344, 806},
-	{    1,   1,1344, 806,1344, 806},
-	{    1,   1,1344, 806,1344, 806},
-	{    1,   1,1344, 806,1344, 806},  /* 640x400 - does not work */
-	{    1,   1,1344, 806,1344, 806},  /* 640x480 - does not work */
-	{    1,   1,1344, 806,1344, 806},
-	{    1,   1,1344, 806,1344, 806},
-	{    1,   1,1344, 806,1344, 806}
-};
-
-static const SiS310_LCDDataStruct  SiS310_NoScaleData1280x1024[] =
-{
-        {    1,   1,1688,1066,1688,1066},
-	{    1,   1,1688,1066,1688,1066},
-	{    1,   1,1688,1066,1688,1066},
-	{    1,   1,1688,1066,1688,1066},
-	{    1,   1,1688,1066,1688,1066},
-	{    1,   1,1688,1066,1688,1066},
-	{    1,   1,1688,1066,1688,1066},
-	{    1,   1,1688,1066,1688,1066},
-	{    1,   1,1688,1066,1688,1066}
-};
-
-typedef struct _SiS310_Part2PortTblStruct
-{
- 	UCHAR CR[12];
-} SiS310_Part2PortTblStruct;
-
-static const SiS310_Part2PortTblStruct SiS310_CRT2Part2_1024x768_1[] =
+static const SiS_Part2PortTblStruct SiS310_CRT2Part2_1024x768_1[] =
 {
  {{0x25,0x12,0xc9,0xdc,0xb6,0x59,0x45,0x09,0x07,0xf9,0x09,0x24}},
  {{0x2c,0x12,0x9a,0xae,0x88,0x59,0x45,0x09,0x07,0xf9,0x09,0x24}},
@@ -1047,646 +970,37 @@
  {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}},
  {{0x38,0x13,0x16,0x0c,0xe6,0x59,0x45,0x09,0x07,0xf9,0x09,0x24}},
  {{0x38,0x18,0x16,0x00,0x00,0x59,0x45,0x09,0x07,0xf9,0x09,0x24}},
- {{0x36,0x13,0x13,0x25,0xff,0x59,0x45,0x09,0x07,0xf9,0x09,0x24}},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}},
- {{0x25,0x12,0xc9,0xdc,0xb6,0x59,0x45,0x09,0x07,0xf9,0x09,0x24}}
+ {{0x36,0x13,0x13,0x25,0xff,0x59,0x45,0x09,0x07,0xf9,0x09,0x24}}
 };
 
-static const SiS310_Part2PortTblStruct SiS310_CRT2Part2_1024x768_2[] =
-{
- {{0x25,0x12,0x51,0x6e,0x48,0x99,0x35,0x89,0x47,0xc1,0x49,0x33}},
- {{0x2c,0x12,0x38,0x55,0x2f,0x99,0x35,0x89,0x47,0xc1,0x49,0x33}},
- {{0x25,0x12,0x51,0x6e,0x48,0x99,0x35,0x89,0x47,0xc1,0x49,0x33}},
- {{0x2c,0x12,0x38,0x55,0x2f,0xc1,0x35,0xb1,0x47,0xe9,0x71,0x33}},
- {{0x2d,0x12,0x79,0x96,0x70,0x99,0x35,0x89,0x47,0xc1,0x49,0x33}},
- {{0x29,0x12,0xb5,0xd2,0xac,0xe9,0x35,0xd9,0x47,0x11,0x99,0x33}},
- {{0x36,0x13,0x13,0x25,0xff,0x59,0x45,0x09,0x07,0xf9,0x09,0x24}},  /* others  */
-/* 0x36,0x13,0x02,0x25,0xff,0x03,0x45,0x09,0x07,0xf9,0x00,0x24        my      */
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}}
-};
+/* *** LCDA *** */
 
-static const SiS310_Part2PortTblStruct SiS310_CRT2Part2_1024x768_3[] =
-{
-#if 1   /* Data from 650/301LVx 1.10.6s and others */
- {{0x25,0x13,0xc9,0x25,0xff,0x59,0x45,0x09,0x07,0xf9,0x09,0x24}},
- {{0x2c,0x13,0x9a,0x25,0xff,0x59,0x45,0x09,0x07,0xf9,0x09,0x24}},
- {{0x25,0x13,0xc9,0x24,0xff,0x59,0x45,0x09,0x07,0xf9,0x09,0x24}},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}},
- {{0x38,0x13,0x13,0x25,0xff,0x59,0x45,0x09,0x07,0xf9,0x09,0x24}},
- {{0x38,0x18,0x16,0x00,0x00,0x59,0x45,0x09,0x07,0xf9,0x09,0x24}},
- {{0x36,0x13,0x13,0x25,0xff,0x59,0x45,0x09,0x07,0xf9,0x09,0x24}},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}},
- {{0x25,0x13,0xc9,0x25,0xff,0xf9,0x45,0x09,0x07,0xf9,0x09,0x24}}
+#if 0
+static const SiS_LVDSDataStruct  SiS_LCDA1600x1200Data_1[]=
+{ /* Clevo, 651+301C */
+	{1200, 450, 2048,1250},
+	{1200, 400, 2048,1250},
+	{1280, 450, 2048,1250},
+	{1280, 400, 2048,1250},
+	{1200, 530, 2048,1250},
+	{1360, 650, 2048,1250},
+	{1584, 818, 2048,1250},
+	{1688,1066, 2048,1250},
+	{1688,1066, 2048,1250},
+#if 0
+	{2048,1250, 2048,1250}   /* this should be correct */
 #endif
-#if 0    /* Data from my 301LV */
- {{0x36,0x13,0x02,0x25,0xff,0x21,0x45,0x09,0x07,0x88,0x09,0x24}},   /* TEST */
- {{0x36,0x13,0x02,0x25,0xff,0x21,0x45,0x09,0x07,0x88,0x09,0x24}},
- {{0x36,0x13,0x02,0x25,0xff,0x21,0x45,0x09,0x07,0x88,0x09,0x24}},
- {{0x36,0x13,0x02,0x25,0xff,0x21,0x45,0x09,0x07,0x88,0x09,0x24}},
- {{0x36,0x13,0x02,0x25,0xff,0x21,0x45,0x09,0x07,0x88,0x09,0x24}},
- {{0x36,0x13,0x02,0x25,0xff,0x21,0x45,0x09,0x07,0x88,0x09,0x24}},
- {{0x36,0x13,0x02,0x25,0xff,0x21,0x45,0x09,0x07,0x88,0x09,0x24}},
- {{0x36,0x13,0x02,0x25,0xff,0x21,0x45,0x09,0x07,0x88,0x09,0x24}},
- {{0x36,0x13,0x02,0x25,0xff,0x21,0x45,0x09,0x07,0x88,0x09,0x24}}
+#if 1
+	{2160,1250, 2048,1250}   /* ? */
 #endif
 };
-
-static const SiS310_Part2PortTblStruct SiS310_CRT2Part2_1280x1024_1[] =
-{ /* Acer; BIOS data invalid, last row taken from _3 */
- {{0x25,0x12,0x51,0x6E,0x48,0x99,0x35,0x89,0x47,0xC1,0x49,0x33}},
- {{0x2C,0x12,0x38,0x55,0x2F,0x99,0x35,0x89,0x47,0xC1,0x49,0x33}},
- {{0x25,0x12,0x51,0x6E,0x48,0x99,0x35,0x89,0x47,0xC1,0x49,0x33}},
- {{0x2C,0x12,0x38,0x55,0x2F,0xC1,0x35,0xB1,0x47,0xE9,0x71,0x33}},
- {{0x2D,0x12,0x79,0x96,0x70,0x99,0x35,0x89,0x47,0xC1,0x49,0x33}},
- {{0x29,0x12,0xB5,0xD2,0xAC,0xE9,0x35,0xD9,0x47,0x11,0x99,0x33}},
- {{0x36,0x13,0x02,0x25,0xFF,0x03,0x45,0x09,0x07,0xF9,0x00,0x24}},
- {{0x47,0x1C,0x14,0x29,0xFF,0xBD,0x23,0x0A,0x07,0x23,0x8A,0x12}}
-};
-
-static const SiS310_Part2PortTblStruct SiS310_CRT2Part2_1280x1024_2[] =
-{ /* Acer */
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}}
-};
-
-/*   1     2    4    5    6   1c   1d   1f   20   21   23   25   */
-static const SiS310_Part2PortTblStruct SiS310_CRT2Part2_1280x1024_3[] =
-{ /* Acer */
- {{0x31,0x1B,0xC4,0xDA,0xB0,0xBD,0x23,0x0A,0x07,0x23,0x8A,0x12}},
- {{0x34,0x1B,0x9F,0xC0,0x80,0xB8,0x23,0x0A,0x07,0x14,0x8A,0x12}},
- {{0x3E,0x1B,0xCF,0xF0,0xB0,0xB8,0x23,0x0A,0x07,0x14,0x8A,0x12}},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}},
- {{0x48,0x1C,0x15,0x29,0xFF,0xBD,0x23,0x0A,0x07,0x23,0x8A,0x12}},
- {{0x48,0x1C,0x15,0x29,0xFF,0xBD,0x23,0x0A,0x07,0x23,0x8A,0x12}},
- {{0x48,0x1C,0x15,0x29,0xFF,0xBD,0x23,0x0A,0x07,0x23,0x8A,0x12}},
- {{0x47,0x1C,0x14,0x29,0xFF,0xBD,0x23,0x0A,0x07,0x23,0x8A,0x12}}
-};
-
-static const SiS310_Part2PortTblStruct SiS310_CRT2Part2_1400x1050_1[] =
-{
- {{0x43,0x24,0x21,0x29,0x19,0xea,0x23,0x0a,0x07,0x32,0xc6,0x42}},
- {{0x43,0x24,0x21,0x29,0x19,0xea,0x23,0x0a,0x07,0x32,0xc6,0x42}},
- {{0x43,0x24,0x21,0x29,0x19,0xea,0x23,0x0a,0x07,0x32,0xc6,0x42}},
- {{0x43,0x24,0x21,0x29,0x19,0xea,0x23,0x0a,0x07,0x32,0xc6,0x42}},
- {{0x43,0x24,0x21,0x29,0x19,0xea,0x23,0x0a,0x07,0x32,0xc6,0x32}},
- {{0x43,0x24,0x21,0x29,0x19,0xea,0x23,0x0a,0x07,0x32,0xc6,0x32}},
- {{0x43,0x24,0x21,0x29,0x19,0xea,0x23,0x0a,0x07,0x32,0xc6,0x32}},
- {{0x43,0x24,0x21,0x29,0x19,0xea,0x23,0x0a,0x07,0x32,0xc6,0x32}},
- {{0x43,0x24,0x21,0x29,0x19,0xea,0x23,0x0a,0x07,0x32,0xc6,0x42}}
-};
-
-static const SiS310_Part2PortTblStruct SiS310_CRT2Part2_1400x1050_2[] =
-{
- {{0x2b,0x12,0xd9,0xe5,0xd5,0x2c,0x23,0x98,0x27,0x3e,0x08,0x42}},
- {{0x22,0x12,0xc0,0xcc,0xbc,0x2c,0x23,0x98,0x27,0x3e,0x08,0x42}},
- {{0x2b,0x12,0xd9,0xe5,0xd5,0x2c,0x23,0x98,0x27,0x3e,0x08,0x42}},
- {{0x22,0x12,0xc0,0xcc,0xbc,0x2c,0x23,0x98,0x27,0x3e,0x08,0x42}},
- {{0x33,0x13,0x01,0x0d,0xfd,0x2c,0x23,0x98,0x27,0x3e,0x08,0x42}},
- {{0x3f,0x1b,0x3d,0x49,0x39,0x54,0x23,0xc0,0x27,0x66,0x30,0x42}},
- {{0x33,0x1b,0x91,0x9d,0x8d,0x8c,0x23,0xf8,0x27,0x9e,0x68,0x42}},
- {{0x43,0x24,0x11,0x1d,0x0d,0xcc,0x23,0x38,0x37,0xde,0xa8,0x42}},
- {{0x43,0x24,0x21,0x29,0x19,0xea,0x23,0x0a,0x07,0x32,0xc6,0x42}}
-};
-
-static const SiS310_Part2PortTblStruct SiS310_CRT2Part2_1400x1050_3[] =
-{
- {{0x43,0x24,0x21,0x29,0x19,0xea,0x23,0x0a,0x07,0x32,0xc6,0x42}},
- {{0x43,0x24,0x21,0x29,0x19,0xea,0x23,0x0a,0x07,0x32,0xc6,0x42}},
- {{0x43,0x24,0x21,0x29,0x19,0xea,0x23,0x0a,0x07,0x32,0xc6,0x42}},
- {{0x43,0x24,0x21,0x29,0x19,0xea,0x23,0x0a,0x07,0x32,0xc6,0x42}},
- {{0x43,0x24,0x21,0x29,0x19,0xea,0x23,0x0a,0x07,0x32,0xc6,0x32}},
- {{0x43,0x24,0x21,0x29,0x19,0xea,0x23,0x0a,0x07,0x32,0xc6,0x32}},
- {{0x43,0x24,0x21,0x29,0x19,0xea,0x23,0x0a,0x07,0x32,0xc6,0x32}},
- {{0x43,0x24,0x21,0x29,0x19,0xea,0x23,0x0a,0x07,0x32,0xc6,0x32}},
- {{0x43,0x24,0x21,0x29,0x19,0xea,0x23,0x0a,0x07,0x32,0xc6,0x32}}
-};
-
-static const SiS310_Part2PortTblStruct SiS310_CRT2Part2_1600x1200_1[] =
-{
- {{0x4C,0x24,0xC8,0xE1,0xAF,0x70,0x34,0x0A,0x07,0xFC,0x2A,0x53}},
- {{0x4C,0x24,0xC8,0xE1,0xAF,0x70,0x34,0x0A,0x07,0xFC,0x2A,0x53}},
- {{0x4C,0x24,0xC8,0xE1,0xAF,0x70,0x34,0x0A,0x07,0xFC,0x2A,0x53}},
- {{0x4C,0x24,0xC8,0xE1,0xAF,0x70,0x34,0x0A,0x07,0xFC,0x2A,0x53}},
- {{0x4C,0x24,0xC8,0xE1,0xAF,0x70,0x34,0x0A,0x07,0xFC,0x2A,0x53}},
- {{0x4C,0x24,0xC8,0xE1,0xAF,0x70,0x34,0x0A,0x07,0xFC,0x2A,0x53}},
- {{0x4C,0x24,0xC8,0xE1,0xAF,0x70,0x34,0x0A,0x07,0xFC,0x2A,0x53}},
- {{0x4C,0x24,0xC8,0xE1,0xAF,0x70,0x34,0x0A,0x07,0xFC,0x2A,0x53}},
- {{0x4C,0x24,0xC8,0xE1,0xAF,0x70,0x34,0x0A,0x07,0xFC,0x2A,0x53}},
- {{0x4C,0x24,0xC8,0xE1,0xAF,0x70,0x34,0x0A,0x07,0xFC,0x2A,0x53}}
-};
-
-static const SiS310_Part2PortTblStruct SiS310_CRT2Part2_1600x1200_2[] =
-{
- {{0x32,0x1B,0x2C,0x52,0x20,0x80,0x20,0x52,0x30,0xA3,0x3A,0x02}},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}},
- {{0x32,0x1B,0x2C,0x52,0x20,0x80,0x20,0x52,0x30,0xA3,0x3A,0x02}},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}},
- {{0x3A,0x1B,0x54,0x7A,0x48,0x80,0x24,0x52,0x30,0xA3,0x3A,0x02}},
- {{0x36,0x1B,0x90,0xB6,0x84,0xA8,0x24,0x7A,0x30,0xCB,0x62,0x02}},
- {{0x3A,0x1C,0xE4,0x0A,0xD8,0xE0,0x24,0xB2,0x30,0x03,0x9A,0x02}},
- {{0x4A,0x24,0x64,0x8A,0x58,0x20,0x34,0xF2,0x30,0x43,0xDA,0x52}},
- {{0x47,0x24,0x71,0x97,0x65,0x3E,0x34,0x10,0x40,0x61,0xF8,0x02}},
- {{0x4C,0x24,0xC8,0xE1,0xAF,0x70,0x34,0x0A,0x07,0xFC,0x2A,0x53}}
-};
-
-static const SiS310_Part2PortTblStruct SiS310_CRT2Part2_1600x1200_3[] =
-{
- {{0x4C,0x24,0xC8,0xE1,0xAF,0x70,0x34,0x0A,0x07,0xFC,0x2A,0x53}},
- {{0x4C,0x24,0xC8,0xE1,0xAF,0x70,0x34,0x0A,0x07,0xFC,0x2A,0x53}},
- {{0x4C,0x24,0xC8,0xE1,0xAF,0x70,0x34,0x0A,0x07,0xFC,0x2A,0x53}},
- {{0x4C,0x24,0xC8,0xE1,0xAF,0x70,0x34,0x0A,0x07,0xFC,0x2A,0x53}},
- {{0x4C,0x24,0xC8,0xE1,0xAF,0x70,0x34,0x0A,0x07,0xFC,0x2A,0x53}},
- {{0x4C,0x24,0xC8,0xE1,0xAF,0x70,0x34,0x0A,0x07,0xFC,0x2A,0x53}},
- {{0x4C,0x24,0xC8,0xE1,0xAF,0x70,0x34,0x0A,0x07,0xFC,0x2A,0x53}},
- {{0x4C,0x24,0xC8,0xE1,0xAF,0x70,0x34,0x0A,0x07,0xFC,0x2A,0x53}},
- {{0x4C,0x24,0xC8,0xE1,0xAF,0x70,0x34,0x0A,0x07,0xFC,0x2A,0x53}},
- {{0x4C,0x24,0xC8,0xE1,0xAF,0x70,0x34,0x0A,0x07,0xFC,0x2A,0x53}}
-};
-
-/* CRT1 CRTC for LCDA */
-
-typedef struct _SiS310_LCDACRT1DataStruct
-{
- 	UCHAR CR[17];
-}SiS310_LCDACRT1DataStruct;
-
-static const SiS310_LCDACRT1DataStruct  SiS310_LCDACRT11024x768_1[]=
-{
- {{0x73,0x4f,0x4f,0x97,0x59,0x84,0xb4,0x1f,
-   0x92,0x89,0x8f,0x8f,0xb5,0x30,0x00,0x05,
-   0x00}},
- {{0x73,0x4f,0x4f,0x97,0x59,0x84,0x82,0x1f,
-   0x60,0x87,0x5d,0x5d,0x83,0x10,0x00,0x05,
-   0x00}},
- {{0x73,0x4f,0x4f,0x97,0x59,0x84,0xb4,0x1f,
-   0x92,0x89,0x8f,0x8f,0xb5,0x30,0x00,0x05,
-   0x00}},
- {{0x73,0x4f,0x4f,0x97,0x59,0x84,0x82,0x1f,
-   0x60,0x87,0x5d,0x5d,0x83,0x10,0x00,0x05,
-   0x00}},
- {{0x73,0x4f,0x4f,0x97,0x59,0x84,0x04,0x3e,
-   0xE2,0x89,0xdf,0xdf,0x05,0x00,0x00,0x05,
-   0x00}},
- {{0x87,0x63,0x63,0x8B,0x6D,0x18,0x7c,0xf0,
-   0x5A,0x81,0x57,0x57,0x7D,0x00,0x00,0x06,
-   0x01}},
- {{0xA3,0x7f,0x7f,0x87,0x89,0x94,0x24,0xf5,
-   0x02,0x89,0xff,0xff,0x25,0x10,0x00,0x02,
-   0x01}}
-};
-
-static const SiS310_LCDACRT1DataStruct  SiS310_LCDACRT11024x768_1_H[]=
-{
- {{0x4b,0x27,0x27,0x8f,0x31,0x1c,0xb4,0x1f,
-   0x92,0x89,0x8f,0x8f,0xb5,0x30,0x00,0x05,
-   0x00}},
- {{0x4b,0x27,0x27,0x8f,0x31,0x1c,0x82,0x1f,
-   0x60,0x87,0x5D,0x5D,0x83,0x10,0x00,0x05,
-   0x00}},
- {{0x4b,0x27,0x27,0x8f,0x31,0x1c,0xb4,0x1f,
-   0x92,0x89,0x8f,0x8f,0xb5,0x30,0x00,0x05,
-   0x00}},
- {{0x4b,0x27,0x27,0x8f,0x31,0x1c,0x82,0x1f,
-   0x60,0x87,0x5D,0x5D,0x83,0x10,0x00,0x05,
-   0x00}},
- {{0x4b,0x27,0x27,0x8f,0x31,0x1c,0x04,0x3e,
-   0xE2,0x89,0xDf,0xDf,0x05,0x00,0x00,0x05,
-   0x00}},
- {{0x55,0x31,0x31,0x99,0x3b,0x06,0x7c,0xf0,
-   0x5A,0x81,0x57,0x57,0x7D,0x00,0x00,0x01,
-   0x01}},
- {{0x63,0x3F,0x3F,0x87,0x49,0x94,0x24,0xF5,
-   0x02,0x89,0xFF,0xFF,0x25,0x10,0x00,0x01,
-   0x01}}
-};
-
-static const SiS310_LCDACRT1DataStruct  SiS310_LCDACRT11024x768_2[]=
-{
- {{0xa3,0x4f,0x4f,0x0f,0x6e,0x1f,0x24,0xbb,
-   0x4a,0x81,0x8f,0xdb,0xda,0x20,0x00,0x06,
-   0x00}},
- {{0xa3,0x4f,0x4f,0x0f,0x6e,0x1f,0x24,0xbb,
-   0x31,0x88,0x5d,0xc2,0xc1,0x20,0x00,0x06,
-   0x00}},
- {{0xa3,0x4f,0x4f,0x0f,0x6e,0x1f,0x24,0xbb,
-   0x4a,0x81,0x8f,0xdb,0xda,0x20,0x00,0x06,
-   0x00}},
- {{0xa3,0x4f,0x4f,0x0f,0x6e,0x1f,0x24,0xbb,
-   0x31,0x88,0x5d,0xc2,0xc1,0x20,0x00,0x06,
-   0x01}},
- {{0xa3,0x4f,0x4f,0x0f,0x6e,0x1f,0x24,0xb3,
-   0x72,0x89,0xdf,0x03,0x02,0x30,0x00,0x06,
-   0x01}},
- {{0xa3,0x63,0x63,0x98,0x78,0x19,0x24,0xf1,
-   0xbb,0x82,0x57,0x57,0x25,0x10,0x00,0x02,
-   0x01}},
- {{0xa3,0x7f,0x7f,0x87,0x89,0x94,0x24,0xf5,
-   0x02,0x89,0xff,0xff,0x25,0x10,0x00,0x02,
-   0x01}}
-};
-
-static const SiS310_LCDACRT1DataStruct  SiS310_LCDACRT11024x768_2_H[]=
-{
- {{0x7b,0x27,0x27,0x0f,0x46,0x97,0x24,0xbb,
-   0x4a,0x81,0x8f,0xdb,0xda,0x20,0x00,0x01,
-   0x00 }},
- {{0x7b,0x27,0x27,0x0f,0x46,0x97,0x24,0xbb,
-   0x31,0x88,0x5d,0xc2,0xc1,0x20,0x00,0x01,
-   0x00 }},
- {{0x7b,0x27,0x27,0x0f,0x46,0x97,0x24,0xbb,
-   0x4a,0x81,0x8f,0xdb,0xda,0x20,0x00,0x01,
-   0x00 }},
- {{0x7b,0x27,0x27,0x0f,0x46,0x97,0x24,0xbb,
-   0x31,0x88,0x5d,0xc2,0xc1,0x20,0x00,0x01,
-   0x00 }},
- {{0x7b,0x27,0x27,0x0f,0x46,0x97,0x24,0xb3,
-   0x72,0x89,0xdf,0x03,0x02,0x30,0x00,0x01,
-   0x01 }},
- {{0x71,0x31,0x31,0x98,0x46,0x17,0x24,0xf1,
-   0xbb,0x82,0x57,0x57,0x25,0x10,0x00,0x02,
-   0x01 }},
- {{0x63,0x3f,0x3f,0x87,0x4c,0x97,0x24,0xf5,
-   0x0f,0x86,0xff,0xff,0x25,0x30,0x00,0x01,
-   0x01 }}
-};
-
-static const SiS310_LCDACRT1DataStruct  SiS310_LCDACRT11280x1024_1[]=
-{ /* Acer */
- {{0x7e,0x4f,0x4f,0x82,0x58,0x04,0xb8,0x1f,
-   0x90,0x84,0x8f,0x8f,0xb9,0x30,0x00,0x06,
-   0x00}},
- {{0x7e,0x4f,0x4f,0x82,0x58,0x04,0x86,0x1f,
-   0x5e,0x82,0x5d,0x5d,0x87,0x10,0x00,0x06,
-   0x00}},
- {{0x7e,0x4f,0x4f,0x82,0x58,0x04,0xb8,0x1f,
-   0x90,0x84,0x8f,0x8f,0xb9,0x30,0x00,0x06,
-   0x00}},
- {{0x7e,0x4f,0x4f,0x82,0x58,0x04,0x86,0x1f,
-   0x5e,0x82,0x5d,0x5d,0x87,0x10,0x00,0x06,
-   0x00}},
- {{0x7e,0x4f,0x4f,0x82,0x58,0x04,0x08,0x3e,
-   0xe0,0x84,0xdf,0xdf,0x09,0x00,0x00,0x06,
-   0x00}},
- {{0x92,0x63,0x63,0x96,0x6c,0x18,0x80,0xf0,
-   0x58,0x8c,0x57,0x57,0x81,0x20,0x00,0x06,
-   0x01}},
- {{0xae,0x7f,0x7f,0x92,0x88,0x94,0x28,0xf5,
-   0x00,0x84,0xff,0xff,0x29,0x10,0x00,0x02,
-   0x01}},
- {{0xce,0x9f,0x9f,0x92,0xa8,0x14,0x28,0x5a,
-   0x00,0x84,0xff,0xff,0x29,0x01,0x00,0x07,
-   0x01}}
-};
-
-static const SiS310_LCDACRT1DataStruct  SiS310_LCDACRT11280x1024_1_H[]=
-{  /* Acer */
- {{0x56,0x27,0x27,0x9a,0x31,0x1c,0xb8,0x1f,
-   0x90,0x84,0x8f,0x8f,0xb9,0x30,0x00,0x05,
-   0x00}},
- {{0x56,0x27,0x27,0x9a,0x31,0x1c,0x86,0x1f,
-   0x5e,0x82,0x5d,0x5d,0x87,0x10,0x00,0x05,
-   0x00}},
- {{0x56,0x27,0x27,0x9a,0x31,0x1c,0xb8,0x1f,
-   0x90,0x84,0x8f,0x8f,0xb9,0x30,0x00,0x05,
-   0x00}},
- {{0x56,0x27,0x27,0x9a,0x31,0x1c,0x86,0x1f,
-   0x5e,0x82,0x5d,0x5d,0x87,0x10,0x00,0x05,
-   0x01}},
- {{0x56,0x27,0x27,0x9a,0x31,0x1c,0x08,0x3e,
-   0xe0,0x84,0xdf,0xdf,0x09,0x00,0x00,0x05,
-   0x00}},
- {{0x60,0x31,0x31,0x84,0x3a,0x86,0x80,0xf0,
-   0x58,0x8c,0x57,0x57,0x81,0x20,0x00,0x01,
-   0x01}},
- {{0x6e,0x3f,0x3f,0x92,0x48,0x94,0x28,0xf5,
-   0x00,0x84,0xff,0xff,0x29,0x10,0x00,0x01,
-   0x01}}
-};
-
-static const SiS310_LCDACRT1DataStruct  SiS310_LCDACRT11280x1024_2[]=
-{  /* Illegal data in BIOS (Acer, Compaq) */
- {{0xa3,0x4f,0x4f,0x87,0x6e,0x9f,0x24,0xbb,
-   0x4a,0x80,0x8f,0x8f,0x25,0x30,0x00,0x06,
-   0x00}},
- {{0xa3,0x4f,0x4f,0x87,0x6e,0x9f,0x24,0xbb,
-   0x31,0x87,0x5d,0x5d,0x25,0x30,0x00,0x06,
-   0x00}},
- {{0xa3,0x4f,0x4f,0x87,0x6e,0x9f,0x24,0xbb,
-   0x4a,0x80,0x8f,0x8f,0x25,0x30,0x00,0x06,
-   0x00}},
- {{0xa3,0x4f,0x4f,0x87,0x6e,0x9f,0x24,0xbb,
-   0x31,0x87,0x5d,0x5d,0x25,0x30,0x00,0x06,
-   0x00}},
- {{0xa3,0x4f,0x4f,0x87,0x6e,0x9f,0x24,0xbb,
-   0x72,0x88,0xdf,0xdf,0x25,0x30,0x00,0x06,
-   0x00}},
- {{0xa3,0x63,0x63,0x87,0x78,0x89,0x24,0xf1,
-   0xae,0x84,0x57,0x57,0x25,0x30,0x00,0x02,
-   0x01}},
- {{0xa3,0x7f,0x7f,0x87,0x86,0x97,0x24,0xf5,
-   0x02,0x88,0xff,0xff,0x25,0x10,0x00,0x02,
-   0x01}}
-};
-
-static const SiS310_LCDACRT1DataStruct  SiS310_LCDACRT11280x1024_2_H[]=
-{  /* Illegal data in BIOS (Acer, Compaq) */
- {{0x4f,0x27,0x27,0x93,0x39,0x81,0x24,0xbb,
-   0x4a,0x80,0x8f,0x8f,0x25,0x30,0x00,0x01,
-   0x00 }},
- {{0x4f,0x27,0x27,0x93,0x39,0x81,0x24,0xbb,
-   0x31,0x87,0x5d,0x5d,0x25,0x30,0x00,0x01,
-   0x00 }},
- {{0x4f,0x27,0x27,0x93,0x39,0x81,0x24,0xbb,
-   0x4a,0x80,0x8f,0x8f,0x25,0x30,0x00,0x01,
-   0x00 }},
- {{0x4f,0x27,0x27,0x93,0x39,0x81,0x24,0xbb,
-   0x31,0x87,0x5d,0x5d,0x25,0x30,0x00,0x01,
-   0x00 }},
- {{0x4f,0x27,0x27,0x93,0x39,0x81,0x24,0xbb,
-   0x72,0x88,0xdf,0xdf,0x25,0x30,0x00,0x01,
-   0x00 }},
- {{0x4f,0x31,0x31,0x93,0x3e,0x86,0x24,0xf1,
-   0xae,0x84,0x57,0x57,0x25,0x30,0x00,0x01,
-   0x01 }},
- {{0x4f,0x3f,0x3f,0x93,0x45,0x0d,0x24,0xf5,
-   0x02,0x88,0xff,0xff,0x25,0x10,0x00,0x01,
-   0x01 }}
-};
-
-static const SiS310_LCDACRT1DataStruct  SiS310_LCDACRT11400x1050_1[]=
-{
- {{0x6f,0x4f,0x4f,0x93,0x54,0x82,0x9e,0x1f,
-   0x93,0x86,0x8f,0x8f,0x9f,0x30,0x00,0x05,
-   0x00}},
- {{0x6f,0x4f,0x4f,0x93,0x54,0x82,0x6c,0x1f,
-   0x60,0x84,0x5d,0x5d,0x6d,0x10,0x00,0x05,
-   0x00}},
- {{0x6f,0x4f,0x4f,0x93,0x54,0x82,0x9e,0x1f,
-   0x93,0x86,0x8f,0x8f,0x9f,0x30,0x00,0x05,
-   0x00}},
- {{0x6f,0x4f,0x4f,0x93,0x54,0x82,0x6c,0x1f,
-   0x60,0x84,0x5d,0x5d,0x6d,0x10,0x00,0x05,
-   0x00}},
- {{0x6f,0x4f,0x4f,0x93,0x54,0x82,0xee,0x1f,
-   0xe2,0x86,0xdf,0xdf,0xef,0x10,0x00,0x05,
-   0x00}},
- {{0x83,0x63,0x63,0x87,0x68,0x16,0x66,0xf0,
-   0x5a,0x8e,0x57,0x57,0x67,0x20,0x00,0x06,
-   0x01}},
- {{0x9f,0x7f,0x7f,0x83,0x84,0x92,0x0e,0xf5,
-   0x02,0x86,0xff,0xff,0x0f,0x10,0x00,0x02,
-   0x01}},
- {{0xbf,0x9f,0x9f,0x83,0xa4,0x12,0x0e,0x5a,
-   0x02,0x86,0xff,0xff,0x0f,0x09,0x00,0x07,
-   0x01}},
- {{0xce,0xae,0xae,0x92,0xb3,0x01,0x28,0x10,
-   0x1a,0x80,0x19,0x19,0x29,0x0f,0x00,0x03,
-   0x00}}
-};
-
-static const SiS310_LCDACRT1DataStruct  SiS310_LCDACRT11400x1050_1_H[]=
-{
-  {{0x47,0x27,0x27,0x8b,0x2c,0x1a,0x9e,0x1f,
-    0x93,0x86,0x8f,0x8f,0x9f,0x30,0x00,0x05,
-    0x00}},
-  {{0x47,0x27,0x27,0x8b,0x2c,0x1a,0x6c,0x1f,
-    0x60,0x84,0x5d,0x5d,0x6d,0x10,0x00,0x05,
-    0x00}},
-  {{0x47,0x27,0x27,0x8b,0x30,0x1e,0x9e,0x1f,
-    0x92,0x86,0x8f,0x8f,0x9f,0x30,0x00,0x05,
-    0x00}},
-  {{0x47,0x27,0x27,0x8b,0x2c,0x1a,0x6c,0x1f,
-    0x60,0x84,0x5d,0x5d,0x6d,0x10,0x00,0x05,
-    0x00}},
-  {{0x47,0x27,0x27,0x8b,0x2c,0x1a,0xee,0x1f,
-    0xe2,0x86,0xdf,0xdf,0xef,0x10,0x00,0x05,
-    0x00}},
-  {{0x51,0x31,0x31,0x95,0x36,0x04,0x66,0xf0,
-    0x5a,0x8e,0x57,0x57,0x67,0x20,0x00,0x01,
-    0x01}},
-  {{0x5f,0x3f,0x3f,0x83,0x44,0x92,0x0e,0xf5,
-    0x02,0x86,0xff,0xff,0x0f,0x10,0x00,0x01,
-    0x01}},
-  {{0x6f,0x4f,0x4f,0x93,0x54,0x82,0x0e,0x5a,
-    0x02,0x86,0xff,0xff,0x0f,0x09,0x00,0x05,
-    0x01}},
-  {{0x76,0x56,0x56,0x9a,0x5b,0x89,0x28,0x10,
-    0x1c,0x80,0x19,0x19,0x29,0x0b,0x00,0x05,
-    0x00}}
-};
-
-static const SiS310_LCDACRT1DataStruct  SiS310_LCDACRT11400x1050_2[]=
-{
- {{0xce,0x4f,0x4f,0x92,0x8c,0x1a,0x28,0x9a,
-   0xdb,0x8f,0x8f,0x8f,0x29,0x21,0x00,0x03,
-   0x00}},
- {{0xce,0x4f,0x4f,0x92,0x8c,0x1a,0x28,0x9a,
-   0xc2,0x86,0x5d,0x5d,0x29,0x01,0x00,0x03,
-   0x01}},
- {{0xce,0x4f,0x4f,0x92,0x8c,0x1a,0x28,0x9a,
-   0xdb,0x8f,0x8f,0x8f,0x29,0x21,0x00,0x03,
-   0x00}},
- {{0xce,0x4f,0x4f,0x92,0x8c,0x1a,0x28,0x9a,
-   0xc2,0x86,0x5d,0x5d,0x29,0x01,0x00,0x03,
-   0x00}},
- {{0xce,0x4f,0x4f,0x92,0x8c,0x1a,0x28,0x9e,
-   0x03,0x87,0xdf,0xdf,0x29,0x01,0x00,0x03,
-   0x00}},
- {{0xce,0x63,0x63,0x92,0x96,0x04,0x28,0xd4,
-   0x3f,0x83,0x57,0x57,0x29,0x01,0x00,0x07,
-   0x01}},
- {{0xce,0x7f,0x7f,0x92,0xa4,0x12,0x28,0xd4,
-   0x93,0x87,0xff,0xff,0x29,0x21,0x00,0x07,
-   0x01}},
- {{0xce,0x9f,0x9f,0x92,0xb4,0x02,0x28,0x5a,
-   0x13,0x87,0xff,0xff,0x29,0x29,0x00,0x03,
-   0x01}},
- {{0xce,0xae,0xae,0x92,0xbc,0x0a,0x28,0x10,
-   0x20,0x84,0x19,0x19,0x29,0x0f,0x00,0x03,
-   0x00}}
-};
-
-static const SiS310_LCDACRT1DataStruct  SiS310_LCDACRT11400x1050_2_H[]=
-{
- {{0xa6,0x27,0x27,0x8a,0x64,0x92,0x28,0x9a,
-   0xdb,0x8f,0x8f,0x8f,0x29,0x21,0x00,0x06,
-   0x00}},
- {{0xa6,0x27,0x27,0x8a,0x64,0x92,0x28,0x9a,
-   0xc2,0x86,0x5d,0x5d,0x29,0x01,0x00,0x06,
-   0x00}},
- {{0xa6,0x27,0x27,0x8a,0x64,0x92,0x28,0x9a,
-   0xdb,0x8f,0x8f,0x8f,0x29,0x21,0x00,0x06,
-   0x00}},
- {{0xa6,0x27,0x27,0x8a,0x64,0x92,0x28,0x9a,
-   0xc2,0x86,0x5d,0x5d,0x29,0x01,0x00,0x06,
-   0x00}},
- {{0xa6,0x27,0x27,0x8a,0x64,0x92,0x28,0x9e,
-   0x03,0x87,0xdf,0xdf,0x29,0x01,0x00,0x06,
-   0x00}},
- {{0x9c,0x31,0x31,0x80,0x64,0x92,0x28,0xd4,
-   0x3f,0x83,0x57,0x57,0x29,0x01,0x00,0x06,
-   0x01}},
- {{0x8e,0x3f,0x3f,0x92,0x64,0x12,0x28,0xd4,
-   0x93,0x87,0xff,0xff,0x29,0x21,0x00,0x06,
-   0x01}},
- {{0x7e,0x4f,0x4f,0x82,0x64,0x12,0x28,0x5a,
-   0x13,0x87,0xff,0xff,0x29,0x29,0x00,0x06,
-   0x01}},
- {{0x76,0x56,0x56,0x9a,0x64,0x92,0x28,0x10,
-   0x20,0x84,0x19,0x19,0x29,0x0f,0x00,0x05,
-   0x00}}
-};
-
-static const SiS310_LCDACRT1DataStruct  SiS310_LCDACRT11600x1200_1[]=
-{
- {{0x83,0x4F,0x4F,0x87,0x51,0x09,0xC0,0x1F,
-   0x90,0x84,0x8F,0x8F,0xC1,0x30,0x00,0x06,
-   0x00}},
- {{0x83,0x4F,0x4F,0x87,0x51,0x09,0x8E,0x1F,
-   0x5E,0x82,0x5D,0x5D,0x8F,0x10,0x00,0x06,
-   0x00}},
- {{0x83,0x4F,0x4F,0x87,0x51,0x09,0xC0,0x1F,
-   0x90,0x84,0x8F,0x8F,0xC1,0x30,0x00,0x06,
-   0x00}},
- {{0x83,0x4F,0x4F,0x87,0x51,0x09,0x8E,0x1F,
-   0x5E,0x82,0x5D,0x5D,0x8F,0x10,0x00,0x06,
-   0x00}},
- {{0x83,0x4F,0x4F,0x87,0x51,0x09,0x10,0x3E,
-   0xE0,0x84,0xDF,0xDF,0x11,0x00,0x00,0x06,
-   0x00}},
- {{0x97,0x63,0x63,0x9B,0x65,0x1D,0x88,0xF0,
-   0x58,0x8C,0x57,0x57,0x89,0x20,0x00,0x06,
-   0x01}},
- {{0xB3,0x7F,0x7F,0x97,0x81,0x99,0x30,0xF5,
-   0x00,0x84,0xFF,0xFF,0x31,0x10,0x00,0x02,
-   0x01}},
- {{0xD3,0x9F,0x9F,0x97,0xA1,0x19,0x30,0x5A,
-   0x00,0x84,0xFF,0xFF,0x31,0x09,0x00,0x07,
-   0x01}},
- {{0xE2,0xAE,0xAE,0x86,0xB0,0x88,0x4A,0x10,
-   0x1A,0x8E,0x19,0x19,0x4B,0x2F,0x00,0x03,
-   0x00}},
- {{0xFB,0xC7,0xC7,0x9F,0xC9,0x81,0xE0,0x10,
-   0xB0,0x84,0xAF,0xAF,0xE1,0x2F,0x00,0x07,
-   0x00}}
-};
-
-static const SiS310_LCDACRT1DataStruct  SiS310_LCDACRT11600x1200_1_H[]=
-{
- {{0x69,0x27,0x27,0x8D,0x30,0x88,0xC0,0x1F,
-   0x90,0x84,0x8F,0x8F,0xC1,0x30,0x00,0x01,
-   0x00}},
- {{0x69,0x27,0x27,0x8D,0x30,0x88,0x8E,0x1F,
-   0x5E,0x82,0x5D,0x5D,0x87,0x10,0x00,0x01,
-   0x00}},
- {{0x69,0x27,0x27,0x8D,0x30,0x88,0xC0,0x1F,
-   0x90,0x84,0x8F,0x8F,0xC1,0x30,0x00,0x01,
-   0x00}},
- {{0x69,0x27,0x27,0x8D,0x30,0x88,0x8E,0x1F,
-   0x5E,0x82,0x5D,0x5D,0x87,0x10,0x00,0x01,
-   0x00}},
- {{0x69,0x27,0x27,0x8D,0x30,0x88,0x10,0x3E,
-   0xE0,0x84,0xDF,0xDF,0x11,0x00,0x00,0x01,
-   0x00}},
- {{0x73,0x31,0x31,0x97,0x3A,0x92,0x88,0xF0,
-   0x58,0x8C,0x57,0x57,0x89,0x20,0x00,0x01,
-   0x01}},
- {{0x81,0x3F,0x3F,0x85,0x48,0x00,0x30,0xF5,
-   0x00,0x84,0xFF,0xFF,0x31,0x10,0x00,0x06,
-   0x01}},
- {{0x91,0x4F,0x4F,0x95,0x58,0x10,0x30,0x5A,
-   0x00,0x84,0xFF,0xFF,0x31,0x09,0x00,0x06,
-   0x01}},
- {{0xD4,0x9F,0x9F,0x98,0xA8,0x00,0x30,0x5A,
-   0x00,0x84,0xFF,0xFF,0x31,0x09,0x00,0x03,
-   0x01}},
- {{0xA5,0x63,0x63,0x89,0x6C,0x84,0xE0,0x10,
-   0xB0,0x84,0xAF,0xAF,0xE1,0x2F,0x00,0x02,
-   0x00}}
-};
-
-static const SiS310_LCDACRT1DataStruct  SiS310_LCDACRT11600x1200_2[]=
-{
- {{0x09,0x4F,0x4F,0x8D,0xA3,0x1B,0xE0,0x9E,
-   0x37,0x8B,0x8F,0x8F,0xE1,0x21,0x01,0x04,
-   0x00}},
- {{0x09,0x4F,0x4F,0x8D,0xA3,0x1B,0xE0,0x9E,
-   0x1E,0x82,0x5D,0x5D,0xE1,0x01,0x01,0x04,
-   0x00}},
- {{0x09,0x4F,0x4F,0x8D,0xA3,0x1B,0xE0,0x9E,
-   0x37,0x8B,0x8F,0x8F,0xE1,0x21,0x01,0x04,
-   0x00}},
- {{0x09,0x4F,0x4F,0x8D,0xA3,0x1B,0xE0,0x9E,
-   0x1E,0x82,0x5D,0x5D,0xE1,0x01,0x01,0x04,
-   0x00}},
- {{0x09,0x4F,0x4F,0x8D,0xA3,0x1B,0xE0,0x9E,
-   0x5F,0x83,0xDF,0xDF,0xE1,0x01,0x01,0x04,
-   0x00}},
- {{0x09,0x63,0x63,0x8D,0xAD,0x05,0xE0,0xD4,
-   0x9B,0x8F,0x57,0x57,0xE1,0x21,0x01,0x00,
-   0x01}},
- {{0x09,0x7F,0x7F,0x8D,0xBB,0x13,0xE0,0xD4,
-   0xEF,0x83,0xFF,0xFF,0xE1,0x21,0x01,0x00,
-   0x01}},
- {{0x09,0x9F,0x9F,0x8D,0xCB,0x03,0xE0,0x5A,
-   0x6F,0x83,0xFF,0xFF,0xE1,0x29,0x01,0x04,
-   0x01}},
- {{0xD4,0x9F,0x9F,0x98,0xA8,0x00,0x30,0x5A,
-   0x00,0x84,0xFF,0xFF,0x31,0x09,0x00,0x03,
-   0x01}},
- {{0x09,0xC7,0xC7,0x8D,0xDF,0x17,0xE0,0x10,
-   0xC7,0x8B,0xAF,0xAF,0xE1,0x0F,0x01,0x04,
-   0x00}}
-};
-
-static const SiS310_LCDACRT1DataStruct  SiS310_LCDACRT11600x1200_2_H[]=
-{
- {{0xE1,0x27,0x27,0x85,0x7B,0x93,0xE0,0x9E,
-   0x37,0x8B,0x8F,0x8F,0xE1,0x21,0x00,0x03,
-   0x00}},
- {{0xE1,0x27,0x27,0x85,0x7B,0x93,0xE0,0x9E,
-   0x1E,0x82,0x5D,0x5D,0xE1,0x01,0x00,0x03,
-   0x00}},
- {{0xE1,0x27,0x27,0x85,0x7B,0x93,0xE0,0x9E,
-   0x37,0x8B,0x8F,0x8F,0xE1,0x21,0x00,0x03,
-   0x00}},
- {{0xE1,0x27,0x27,0x85,0x7B,0x93,0xE0,0x9E,
-   0x1E,0x82,0x5D,0x5D,0xE1,0x01,0x00,0x03,
-   0x00}},
- {{0xE1,0x27,0x27,0x85,0x7B,0x93,0xE0,0x9E,
-   0x5F,0x83,0xDF,0xDF,0xE1,0x01,0x00,0x03,
-   0x00}},
- {{0xD7,0x31,0x31,0x9B,0x7B,0x13,0xE0,0xD4,
-   0x9B,0x8F,0x57,0x57,0xE1,0x21,0x00,0x03,
-   0x01}},
- {{0xC9,0x3F,0x3F,0x8D,0x7B,0x13,0xE0,0xD4,
-   0xEF,0x83,0xFF,0xFF,0xE1,0x21,0x00,0x03,
-   0x01}},
- {{0xB9,0x4F,0x4F,0x9D,0x7B,0x93,0xE0,0x5A,
-   0x6F,0x83,0xFF,0xFF,0xE1,0x29,0x00,0x02,
-   0x01}},
- {{0xD4,0x9F,0x9F,0x98,0xA8,0x00,0x30,0x5A,
-   0x00,0x84,0xFF,0xFF,0x31,0x09,0x00,0x03,
-   0x01}},
- {{0xA5,0x63,0x63,0x89,0x7B,0x93,0xE0,0x10,
-   0xC7,0x8B,0xAF,0xAF,0xE1,0x0F,0x00,0x02,
-   0x00}}
-};
-
+#endif
 
 /**************************************************************/
 /* LVDS, CHRONTEL ------------------------------------------- */
 /**************************************************************/
 
-typedef struct _SiS310_LVDSDataStruct
-{
-	USHORT VGAHT;
-	USHORT VGAVT;
-	USHORT LCDHT;
-	USHORT LCDVT;
-} SiS310_LVDSDataStruct;
-
-static const SiS310_LVDSDataStruct  SiS310_CHTVUPALData[]=
+static const SiS_LVDSDataStruct  SiS310_CHTVUPALData[]=
 {
 	{1008, 625,1008, 625},
 	{1008, 625,1008, 625},
@@ -1697,7 +1011,7 @@
 	{1400,1000,1400,1000}
 };
 
-static const SiS310_LVDSDataStruct  SiS310_CHTVOPALData[]=
+static const SiS_LVDSDataStruct  SiS310_CHTVOPALData[]=
 {
 	{1008, 625,1008, 625},
 	{1008, 625,1008, 625},
@@ -1708,7 +1022,7 @@
         {1400, 875,1400, 875}
 };
 
-static const SiS310_LVDSDataStruct  SiS310_CHTVUPALMData[]=
+static const SiS_LVDSDataStruct  SiS310_CHTVUPALMData[]=
 {
 	{ 840, 600, 840, 600},
 	{ 840, 600, 840, 600},
@@ -1719,7 +1033,7 @@
         {1160, 945,1160, 945}
 };
 
-static const SiS310_LVDSDataStruct  SiS310_CHTVOPALMData[]=
+static const SiS_LVDSDataStruct  SiS310_CHTVOPALMData[]=
 {
 	{ 840, 525, 840, 525},
 	{ 840, 525, 840, 525},
@@ -1730,7 +1044,7 @@
         {1160, 840,1160, 840}
 };
 
-static const SiS310_LVDSDataStruct  SiS310_CHTVUPALNData[]=
+static const SiS_LVDSDataStruct  SiS310_CHTVUPALNData[]=
 {
 	{1008, 625,1008, 625},
 	{1008, 625,1008, 625},
@@ -1741,7 +1055,7 @@
 	{1400,1000,1400,1000}
 };
 
-static const SiS310_LVDSDataStruct  SiS310_CHTVOPALNData[]=
+static const SiS_LVDSDataStruct  SiS310_CHTVOPALNData[]=
 {
 	{1008, 625,1008, 625},
 	{1008, 625,1008, 625},
@@ -1752,7 +1066,7 @@
         {1400, 875,1400, 875}
 };
 
-static const SiS310_LVDSDataStruct  SiS310_CHTVSOPALData[]=   /* TW: (super overscan - no effect on 7019) */
+static const SiS_LVDSDataStruct  SiS310_CHTVSOPALData[]=   /* (super overscan - no effect on 7019) */
 {
 	{1008, 625,1008, 625},
 	{1008, 625,1008, 625},
@@ -1763,13 +1077,8 @@
         {1400, 875,1400, 875}
 };
 
-typedef struct _SiS310_LVDSDesStruct
-{
-	USHORT LCDHDES;
-	USHORT LCDVDES;
-} SiS310_LVDSDesStruct;
 
-static const SiS310_LVDSDesStruct  SiS310_PanelType00_1[]=  /* 800x600 */
+static const SiS_LVDSDesStruct  SiS310_PanelType00_1[]=  /* 800x600 */
 {
 	{ 0, 0},
 	{ 0, 0},
@@ -1782,7 +1091,7 @@
 	{ 0, 0}
 };
 
-static const SiS310_LVDSDesStruct  SiS310_PanelType01_1[]=  /* 1024x768 */
+static const SiS_LVDSDesStruct  SiS310_PanelType01_1[]=  /* 1024x768 */
 {
 	{ 0, 0},
 	{ 0, 0},
@@ -1795,7 +1104,7 @@
 	{ 0, 0}
 };
 
-static const SiS310_LVDSDesStruct  SiS310_PanelType02_1[]=  /* 1280x1024 */
+static const SiS_LVDSDesStruct  SiS310_PanelType02_1[]=  /* 1280x1024 */
 {
 	{ 0, 0},
 	{ 0, 0},
@@ -1810,7 +1119,7 @@
 };
 
 
-static const SiS310_LVDSDesStruct  SiS310_PanelType03_1[]=
+static const SiS_LVDSDesStruct  SiS310_PanelType03_1[]=
 {
 	{ 0, 0},
 	{ 0, 0},
@@ -1823,7 +1132,7 @@
 	{ 0, 0}
 };
 
-static const SiS310_LVDSDesStruct  SiS310_PanelType04_1[]=
+static const SiS_LVDSDesStruct  SiS310_PanelType04_1[]=
 {
 	{1343, 798},
 	{1343, 794},
@@ -1836,7 +1145,7 @@
 	{ 0,   0}
 };
 
-static const SiS310_LVDSDesStruct  SiS310_PanelType05_1[]=
+static const SiS_LVDSDesStruct  SiS310_PanelType05_1[]=
 {
 	{1343, 798},
 	{1343, 794},
@@ -1849,7 +1158,7 @@
 	{ 0,   0}
 };
 
-static const SiS310_LVDSDesStruct  SiS310_PanelType06_1[]=
+static const SiS_LVDSDesStruct  SiS310_PanelType06_1[]=
 {
 	{1343, 798},
 	{1343, 794},
@@ -1862,7 +1171,7 @@
 	{ 0,   0}
 };
 
-static const SiS310_LVDSDesStruct  SiS310_PanelType07_1[]=
+static const SiS_LVDSDesStruct  SiS310_PanelType07_1[]=
 {
 	{1343, 798},
 	{1343, 794},
@@ -1875,7 +1184,7 @@
 	{ 0,   0}
 };
 
-static const SiS310_LVDSDesStruct  SiS310_PanelType08_1[]=   /* 1400x1050 */
+static const SiS_LVDSDesStruct  SiS310_PanelType08_1[]=   /* 1400x1050 */
 {
 	{ 0, 0},
 	{ 0, 0},
@@ -1890,7 +1199,7 @@
 	{ 0, 0}
 };
 
-static const SiS310_LVDSDesStruct  SiS310_PanelType09_1[]=   /* 1280x768 */
+static const SiS_LVDSDesStruct  SiS310_PanelType09_1[]=   /* 1280x768 */
 {
 	{ 0, 0},
 	{ 0, 0},
@@ -1905,7 +1214,7 @@
 	{ 0, 0}
 };
 
-static const SiS310_LVDSDesStruct  SiS310_PanelType0a_1[]=  /* 1600x1200 */
+static const SiS_LVDSDesStruct  SiS310_PanelType0a_1[]=  /* 1600x1200 */
 {
 	{ 0, 0},
 	{ 0, 0},
@@ -1920,7 +1229,7 @@
 	{ 0, 0}
 };
 
-static const SiS310_LVDSDesStruct  SiS310_PanelType0b_1[]=  /* 640x480_2 */
+static const SiS_LVDSDesStruct  SiS310_PanelType0b_1[]=  /* 640x480_2 */
 {
 	{ 0, 524},
 	{ 0, 524},
@@ -1932,7 +1241,7 @@
 	{ 0, 524}
 };
 
-static const SiS310_LVDSDesStruct  SiS310_PanelType0c_1[]=  /* 640x480_3 */
+static const SiS_LVDSDesStruct  SiS310_PanelType0c_1[]=  /* 640x480_3 */
 {
 	{ 0, 524},
 	{ 0, 524},
@@ -1944,7 +1253,7 @@
 	{ 0, 524}
 };
 
-static const SiS310_LVDSDesStruct  SiS310_PanelType0d_1[]=
+static const SiS_LVDSDesStruct  SiS310_PanelType0d_1[]=
 {
 	{1343, 798},
 	{1343, 794},
@@ -1957,7 +1266,7 @@
 	{ 0,   0}
 };
 
-static const SiS310_LVDSDesStruct  SiS310_PanelType0e_1[]=
+static const SiS_LVDSDesStruct  SiS310_PanelType0e_1[]=
 {
 	{1343, 798},
 	{1343, 794},
@@ -1970,7 +1279,7 @@
 	{ 0,   0}
 };
 
-static const SiS310_LVDSDesStruct  SiS310_PanelType0f_1[]=
+static const SiS_LVDSDesStruct  SiS310_PanelType0f_1[]=
 {
 	{1343, 798},
 	{1343, 794},
@@ -1983,7 +1292,7 @@
 	{ 0,   0}
 };
 
-static const SiS310_LVDSDesStruct  SiS310_PanelType00_2[]=
+static const SiS_LVDSDesStruct  SiS310_PanelType00_2[]=
 {
 	{980, 528},
 	{980, 503},
@@ -1996,7 +1305,7 @@
 	{ 0,   0}
 };
 
-static const SiS310_LVDSDesStruct  SiS310_PanelType01_2[]= 
+static const SiS_LVDSDesStruct  SiS310_PanelType01_2[]=
 {
 	{1152, 622},
 	{1152, 597},
@@ -2009,7 +1318,7 @@
 	{ 0,   0}
 };
 
-static const SiS310_LVDSDesStruct  SiS310_PanelType02_2[]= 
+static const SiS_LVDSDesStruct  SiS310_PanelType02_2[]=
 {
 	{1368, 754},
 	{1368, 729},
@@ -2024,7 +1333,7 @@
 	{ 0,   0}
 };
 
-static const SiS310_LVDSDesStruct  SiS310_PanelType03_2[]=  
+static const SiS_LVDSDesStruct  SiS310_PanelType03_2[]=
 {
 	{ 0,   0},
 	{ 0,   0},
@@ -2035,7 +1344,7 @@
 	{ 0,   0}
 };
 
-static const SiS310_LVDSDesStruct  SiS310_PanelType04_2[]=  
+static const SiS_LVDSDesStruct  SiS310_PanelType04_2[]=
 {
 	{ 0,   0},
 	{ 0,   0},
@@ -2048,7 +1357,7 @@
 	{ 0,   0}
 };
 
-static const SiS310_LVDSDesStruct  SiS310_PanelType05_2[]=  
+static const SiS_LVDSDesStruct  SiS310_PanelType05_2[]=
 {
 	{1152, 622},
 	{1152, 597},
@@ -2061,7 +1370,7 @@
 	{ 0,   0}
 };
 
-static const SiS310_LVDSDesStruct  SiS310_PanelType06_2[]=  
+static const SiS_LVDSDesStruct  SiS310_PanelType06_2[]=
 {
 	{1152, 622},
 	{1152, 597},
@@ -2074,7 +1383,7 @@
 	{ 0,   0}
 };
 
-static const SiS310_LVDSDesStruct  SiS310_PanelType07_2[]=  
+static const SiS_LVDSDesStruct  SiS310_PanelType07_2[]=
 {
 	{1152, 622},
 	{1152, 597},
@@ -2087,7 +1396,7 @@
 	{ 0,   0}
 };
 
-static const SiS310_LVDSDesStruct  SiS310_PanelType08_2[]=  /* 1400x1050 */
+static const SiS_LVDSDesStruct  SiS310_PanelType08_2[]=  /* 1400x1050 */
 {
 	{1308, 741},
 	{1308, 716},
@@ -2102,7 +1411,7 @@
 	{   0,   0}
 };
 
-static const SiS310_LVDSDesStruct  SiS310_PanelType09_2[]= /* 1280x768 */
+static const SiS_LVDSDesStruct  SiS310_PanelType09_2[]= /* 1280x768 */
 {
 	{1083, 622},
 	{1083, 597},
@@ -2115,7 +1424,7 @@
 	{   0,   0}
 };
 
-static const SiS310_LVDSDesStruct  SiS310_PanelType0a_2[]=  /* 1600x1200 */
+static const SiS_LVDSDesStruct  SiS310_PanelType0a_2[]=  /* 1600x1200 */
 {
 	{1568, 920},
 	{1568, 895},
@@ -2141,7 +1450,7 @@
 #endif
 };
 
-static const SiS310_LVDSDesStruct  SiS310_PanelType0b_2[]=  /* 640x480_2 */
+static const SiS_LVDSDesStruct  SiS310_PanelType0b_2[]=  /* 640x480_2 */
 {
 	{1152, 622},
 	{1152, 597},
@@ -2154,7 +1463,7 @@
 	{ 0,   0}
 };
 
-static const SiS310_LVDSDesStruct  SiS310_PanelType0c_2[]=  /* 640x480_3 */
+static const SiS_LVDSDesStruct  SiS310_PanelType0c_2[]=  /* 640x480_3 */
 {
 	{1152, 622},
 	{1152, 597},
@@ -2167,7 +1476,7 @@
 	{ 0,   0}
 };
 
-static const SiS310_LVDSDesStruct  SiS310_PanelType0d_2[]=  
+static const SiS_LVDSDesStruct  SiS310_PanelType0d_2[]=
 {
 	{1152, 622},
 	{1152, 597},
@@ -2180,7 +1489,7 @@
 	{ 0,   0}
 };
 
-static const SiS310_LVDSDesStruct  SiS310_PanelType0e_2[]=
+static const SiS_LVDSDesStruct  SiS310_PanelType0e_2[]=
 {
 	{1152, 622},
 	{1152, 597},
@@ -2193,7 +1502,7 @@
 	{ 0,   0}
 };
 
-static const SiS310_LVDSDesStruct  SiS310_PanelType0f_2[] =
+static const SiS_LVDSDesStruct  SiS310_PanelType0f_2[] =
 {
 	{1152, 622},
 	{1152, 597},
@@ -2206,14 +1515,37 @@
 	{ 0,   0}
 };
 
-/* CRT1 CRTC for SlaveModes and LCDA */
+static const SiS_LVDSDesStruct  SiS310_PanelTypeNS_1[]=
+{
+	{ 8,   0},
+	{ 8,   0},
+	{ 8,   0},
+	{ 8,   0},
+	{ 8,   0},
+	{ 0,   0},
+	{ 0,   0},
+	{ 0,   0},
+	{ 0, 806},
+	{ 0,   0}
+};
 
-typedef struct _SiS310_LVDSCRT1DataStruct
+static const SiS_LVDSDesStruct  SiS310_PanelTypeNS_2[] =
 {
- 	UCHAR CR[15];
-} SiS310_LVDSCRT1DataStruct;
+	{ 0 , 0},
+	{ 0 , 0},
+	{ 0 , 0},
+	{ 0 , 0},
+	{ 0 , 0},
+	{ 0 , 0},
+	{ 0 , 0},
+	{ 0 , 0},
+	{ 0 , 0},
+	{ 0 , 0}
+};
 
-static const SiS310_LVDSCRT1DataStruct  SiS310_LVDSCRT1800x600_1[] =
+/* CRT1 CRTC for SlaveModes and LCDA */
+
+static const SiS_LVDSCRT1DataStruct  SiS310_LVDSCRT1800x600_1[] =
 {
  {{0x6b,0x4f,0x8f,0x55,0x85,0xaa,0x1f,
    0x90,0x85,0x8f,0xab,0x30,0x00,0x05,
@@ -2235,7 +1567,7 @@
    0x01 }}
 };
 
-static const SiS310_LVDSCRT1DataStruct  SiS310_LVDSCRT1800x600_1_H[] =
+static const SiS_LVDSCRT1DataStruct  SiS310_LVDSCRT1800x600_1_H[] =
 {
  {{0x43,0x27,0x87,0x2d,0x1d,0xaa,0x1f,
    0x90,0x85,0x8f,0xab,0x30,0x00,0x05,
@@ -2257,7 +1589,7 @@
    0x01 }}
 };
 
-static const SiS310_LVDSCRT1DataStruct  SiS310_LVDSCRT1800x600_2[]=
+static const SiS_LVDSCRT1DataStruct  SiS310_LVDSCRT1800x600_2[]=
 {
  {{0x7f,0x4f,0x83,0x62,0x12,0x72,0x3e,
    0xff,0x84,0x8f,0x73,0x00,0x00,0x06,
@@ -2279,7 +1611,7 @@
    0x01 }}
 };
 
-static const SiS310_LVDSCRT1DataStruct  SiS310_LVDSCRT1800x600_2_H[] =
+static const SiS_LVDSCRT1DataStruct  SiS310_LVDSCRT1800x600_2_H[] =
 {
  {{0x57,0x27,0x9b,0x3a,0x0a,0x72,0x3e,
    0xff,0x84,0x8f,0x73,0x00,0x00,0x01,
@@ -2301,7 +1633,7 @@
    0x01 }}
 };
 
-static const SiS310_LVDSCRT1DataStruct  SiS310_LVDSCRT11024x768_1[] =
+static const SiS_LVDSCRT1DataStruct  SiS310_LVDSCRT11024x768_1[] =
 {
  {{0x73,0x4f,0x97,0x53,0x84,0xb4,0x1f,
    0x92,0x89,0x8f,0xb5,0x30,0x00,0x05,
@@ -2326,7 +1658,7 @@
    0x01}}
 };
 
-static const SiS310_LVDSCRT1DataStruct  SiS310_LVDSCRT11024x768_1_H[] =
+static const SiS_LVDSCRT1DataStruct  SiS310_LVDSCRT11024x768_1_H[] =
 {
  {{0x4b,0x27,0x8f,0x2b,0x1c,0xb4,0x1f,
    0x92,0x89,0x8f,0xb5,0x30,0x00,0x05,
@@ -2351,7 +1683,7 @@
    0x01 }}
 };
 
-static const SiS310_LVDSCRT1DataStruct  SiS310_LVDSCRT11024x768_2[] =
+static const SiS_LVDSCRT1DataStruct  SiS310_LVDSCRT11024x768_2[] =
 {
  {{0xa3,0x4f,0x87,0x6e,0x9f,0x24,0xbb,
    0x57,0x8e,0x8f,0x25,0x30,0x00,0x06,
@@ -2376,7 +1708,7 @@
    0x01 }}
 };
 
-static const SiS310_LVDSCRT1DataStruct  SiS310_LVDSCRT11024x768_2_H[] =
+static const SiS_LVDSCRT1DataStruct  SiS310_LVDSCRT11024x768_2_H[] =
 {
  {{0x7b,0x27,0x9f,0x46,0x97,0x24,0xbb,
    0x57,0x8e,0x8f,0x25,0x30,0x00,0x01,
@@ -2401,7 +1733,7 @@
    0x01 }}
 };
 
-static const SiS310_LVDSCRT1DataStruct  SiS310_LVDSCRT11280x1024_1[] =
+static const SiS_LVDSCRT1DataStruct  SiS310_LVDSCRT11280x1024_1[] =
 {
  {{0x7e,0x4f,0x82,0x58,0x04,0xb8,0x1f,
    0x90,0x84,0x8f,0xb9,0x30,0x00,0x06,
@@ -2429,7 +1761,7 @@
    0x01}}
 };
 
-static const SiS310_LVDSCRT1DataStruct  SiS310_LVDSCRT11280x1024_1_H[] =
+static const SiS_LVDSCRT1DataStruct  SiS310_LVDSCRT11280x1024_1_H[] =
 {
  {{0x56,0x27,0x9a,0x31,0x1c,0xb8,0x1f,
    0x90,0x84,0x8f,0xb9,0x30,0x00,0x05,
@@ -2454,7 +1786,7 @@
    0x01}}
 };
 
-static const SiS310_LVDSCRT1DataStruct  SiS310_LVDSCRT11280x1024_2[] =  
+static const SiS_LVDSCRT1DataStruct  SiS310_LVDSCRT11280x1024_2[] =
 {
  {{0xce,0x72,0x91,0x81,0x8f,0x28,0x92,
    0xc8,0x8c,0x5d,0x5c,0x01,0x00,0x02,
@@ -2482,7 +1814,7 @@
    0x01}}
 };
 
-static const SiS310_LVDSCRT1DataStruct  SiS310_LVDSCRT11280x1024_2_H[] = 
+static const SiS_LVDSCRT1DataStruct  SiS310_LVDSCRT11280x1024_2_H[] =
 {
  {{0xa6,0x4a,0x89,0x59,0x07,0x28,0x92,
    0xc8,0x8c,0x5d,0x5c,0x01,0x00,0x06,
@@ -2507,7 +1839,7 @@
    0x01}}
 };
 
-static const SiS310_LVDSCRT1DataStruct  SiS310_LVDSCRT11400x1050_1[] =
+static const SiS_LVDSCRT1DataStruct  SiS310_LVDSCRT11400x1050_1[] =
 {
   {{0x6f,0x4f,0x93,0x54,0x82,0x9e,0x1f,
     0x8f,0x81,0x8f,0x9f,0x30,0x00,0x05,
@@ -2567,7 +1899,7 @@
 #endif   
 };
 
-static const SiS310_LVDSCRT1DataStruct  SiS310_LVDSCRT11400x1050_1_H[] = 
+static const SiS_LVDSCRT1DataStruct  SiS310_LVDSCRT11400x1050_1_H[] =
 {
  {{0x47,0x27,0x8b,0x2c,0x1a,0x9e,0x1f,
    0x8f,0x81,0x8f,0x9f,0x30,0x00,0x05,
@@ -2627,7 +1959,7 @@
 #endif   
 };
 
-static const SiS310_LVDSCRT1DataStruct  SiS310_LVDSCRT11400x1050_2[] =  
+static const SiS_LVDSCRT1DataStruct  SiS310_LVDSCRT11400x1050_2[] =
 {
  {{0xce,0x72,0x91,0x84,0x92,0x28,0x92,
    0xd7,0x8b,0x5d,0x5c,0x21,0x00,0x02,
@@ -2687,7 +2019,7 @@
 #endif   
 };
 
-static const SiS310_LVDSCRT1DataStruct  SiS310_LVDSCRT11400x1050_2_H[] =  
+static const SiS_LVDSCRT1DataStruct  SiS310_LVDSCRT11400x1050_2_H[] =
 {
  {{0xa6,0x4a,0x89,0x5c,0x0a,0x28,0x92,
    0xd7,0x8b,0x5d,0x5c,0x21,0x00,0x06,
@@ -2747,7 +2079,7 @@
 #endif   
 };
 
-static const SiS310_LVDSCRT1DataStruct  SiS310_LVDSCRT11600x1200_1[] =
+static const SiS_LVDSCRT1DataStruct  SiS310_LVDSCRT11600x1200_1[] =
 {
  {{0x83,0x4F,0x87,0x5B,0x13,0x06,0x3E,
    0xB3,0x86,0x8F,0x07,0x20,0x00,0x06,
@@ -2813,7 +2145,7 @@
 #endif
 };
 
-static const SiS310_LVDSCRT1DataStruct  SiS310_LVDSCRT11600x1200_1_H[] =
+static const SiS_LVDSCRT1DataStruct  SiS310_LVDSCRT11600x1200_1_H[] =
 {
  {{0x5B,0x27,0x9F,0x33,0x0B,0x06,0x2E,
    0xB3,0x86,0x8F,0x07,0x20,0x00,0x01,
@@ -2879,7 +2211,7 @@
 #endif
 };
 
-static const SiS310_LVDSCRT1DataStruct  SiS310_LVDSCRT11600x1200_2[] =
+static const SiS_LVDSCRT1DataStruct  SiS310_LVDSCRT11600x1200_2[] =
 {
  {{0xFB,0x87,0x86,0x97,0x0F,0x26,0x97,
    0x43,0x86,0xDB,0xDA,0x11,0x00,0x07,
@@ -2945,7 +2277,7 @@
 #endif
 };
 
-static const SiS310_LVDSCRT1DataStruct  SiS310_LVDSCRT11600x1200_2_H[] = 
+static const SiS_LVDSCRT1DataStruct  SiS310_LVDSCRT11600x1200_2_H[] =
 {
  {{0xD3,0x5F,0x9E,0x6F,0x07,0x26,0x97,
    0x43,0x86,0xDB,0xDA,0x11,0x00,0x02,
@@ -3011,9 +2343,66 @@
 #endif
 };
 
+static const SiS_LVDSCRT1DataStruct  SiS310_LVDSCRT1XXXxXXX_1[] =
+{
+ {{0x5f,0x4f,0x82,0x55,0x81,0xbf,0x1f,
+   0x9c,0x8e,0x96,0xb9,0x30,0x00,0x05,
+   0x00}},
+ {{0x5f,0x4f,0x82,0x55,0x81,0xbf,0x1f,
+   0x9c,0x8e,0x96,0xb9,0x30,0x00,0x05,
+   0x00}},
+ {{0x5f,0x4f,0x82,0x55,0x81,0xbf,0x1f,
+   0x9c,0x8e,0x96,0xb9,0x30,0x00,0x05,
+   0x00}},
+ {{0x5f,0x4f,0x82,0x55,0x81,0xbf,0x1f,
+   0x9c,0x8e,0x96,0xb9,0x30,0x00,0x05,
+   0x00}},
+ {{0x5f,0x4f,0x82,0x55,0x81,0x0b,0x3e,
+   0xe9,0x8b,0xe7,0x04,0x00,0x00,0x05,
+   0x00}},
+ {{0x7f,0x63,0x83,0x6c,0x1c,0x72,0xf0,
+   0x58,0x8c,0x57,0x73,0x20,0x00,0x06,
+   0x01}},
+ {{0xa3,0x7f,0x87,0x86,0x97,0x24,0xf5,
+   0x02,0x88,0xff,0x25,0x10,0x00,0x02,
+   0x01}},
+ {{0xce,0x9f,0x92,0xa8,0x14,0x28,0x5a,
+   0x00,0x84,0xff,0x29,0x09,0x00,0x07,
+   0x01}},
+ {{0xce,0x9f,0x92,0xa9,0x17,0x24,0xf5,
+   0x02,0x88,0xff,0x25,0x10,0x00,0x07,
+   0x01}}
+};
+
+static const SiS_LVDSCRT1DataStruct  SiS310_LVDSCRT1XXXxXXX_1_H[] =
+{
+ {{0x38,0x27,0x9c,0x2c,0x80,0xbf,0x1f,
+   0x9c,0x8e,0x96,0xb9,0x30,0x00,0x00,
+   0x00}},
+ {{0x38,0x27,0x9c,0x2c,0x80,0xbf,0x1f,
+   0x9c,0x8e,0x96,0xb9,0x30,0x00,0x00,
+   0x00}},
+ {{0x38,0x27,0x9c,0x2c,0x80,0xbf,0x1f,
+   0x9c,0x8e,0x96,0xb9,0x30,0x00,0x00,
+   0x00}},
+ {{0x38,0x27,0x9c,0x2c,0x80,0xbf,0x1f,
+   0x9c,0x8e,0x96,0xb9,0x30,0x00,0x00,
+   0x00}},
+ {{0x38,0x27,0x9c,0x2c,0x80,0x0b,0x3e,
+   0xe9,0x8b,0xe7,0x04,0x00,0x00,0x00,
+   0x00}},
+ {{0x4d,0x31,0x91,0x3b,0x03,0x72,0xf0,
+   0x58,0x8c,0x57,0x73,0x20,0x00,0x01,
+   0x01}},
+ {{0x63,0x3f,0x87,0x4a,0x92,0x24,0xf5,
+   0x02,0x88,0xff,0x25,0x10,0x00,0x01,
+   0x01}}
+};
+
+
 /* CRT1 CRTC for Chrontel TV slave modes */
 
-static const SiS310_LVDSCRT1DataStruct  SiS310_CHTVCRT1UNTSC[] =  
+static const SiS_LVDSCRT1DataStruct  SiS310_CHTVCRT1UNTSC[] =
 { 
  {{0x64,0x4f,0x88,0x56,0x9f,0x56,0x3e,
    0xe8,0x84,0x8f,0x57,0x20,0x00,0x01,
@@ -3038,7 +2427,7 @@
    0x01}}
 };
 
-static const SiS310_LVDSCRT1DataStruct  SiS310_CHTVCRT1ONTSC[] =
+static const SiS_LVDSCRT1DataStruct  SiS310_CHTVCRT1ONTSC[] =
 {
  {{0x63,0x4f,0x87,0x5a,0x9f,0x0b,0x3e,
    0xc0,0x84,0x8f,0x0c,0x20,0x00,0x01,
@@ -3063,7 +2452,7 @@
    0x01 }}
 };
 
-static const SiS310_LVDSCRT1DataStruct  SiS310_CHTVCRT1UPAL[] =    
+static const SiS_LVDSCRT1DataStruct  SiS310_CHTVCRT1UPAL[] =
 { 
  {{0x79,0x4f,0x9d,0x5a,0x90,0x6f,0x3e,
    0xf8,0x83,0x8f,0x70,0x20,0x00,0x05,
@@ -3088,7 +2477,7 @@
    0x01}}
 };
 
-static const SiS310_LVDSCRT1DataStruct  SiS310_CHTVCRT1OPAL[] =
+static const SiS_LVDSCRT1DataStruct  SiS310_CHTVCRT1OPAL[] =
 {
  {{0x79,0x4f,0x9d,0x5a,0x90,0x6f,0x3e,
    0xf0,0x83,0x8f,0x70,0x20,0x00,0x05,
@@ -3113,12 +2502,8 @@
    0x01 }}
 };
 
-typedef struct _SiS310_CHTVRegDataStruct
-{
- 	UCHAR Reg[16];
-} SiS310_CHTVRegDataStruct;
 
-static const SiS310_CHTVRegDataStruct SiS310_CHTVReg_UNTSC[] =
+static const SiS_CHTVRegDataStruct SiS310_CHTVReg_UNTSC[] =
 {
  {{0x4a,0x77,0xbb,0x94,0x84,0x48,0xfe,0x50,0x04,0x00,0x80,0x00,0x00,0x00,0x00,0x01}},
  {{0x4a,0x77,0xbb,0x94,0x84,0x48,0xfe,0x50,0x04,0x00,0x80,0x00,0x00,0x00,0x00,0x01}},
@@ -3138,7 +2523,7 @@
       for PAL-M and PAL-N all above is corrected.
     */
 
-static const SiS310_CHTVRegDataStruct SiS310_CHTVReg_ONTSC[] =
+static const SiS_CHTVRegDataStruct SiS310_CHTVReg_ONTSC[] =
 {
  {{0x49,0x77,0xbb,0x7b,0x84,0x34,0x00,0x50,0x04,0x00,0x80,0x00,0x00,0x00,0x00,0x01}},
  {{0x49,0x77,0xbb,0x7b,0x84,0x34,0x00,0x50,0x04,0x00,0x80,0x00,0x00,0x00,0x00,0x01}},
@@ -3149,7 +2534,7 @@
  {{0xed,0x77,0xbb,0x66,0x8c,0x21,0x02,0x5a,0x04,0x00,0x80,0x1f,0x9f,0xc1,0x0c,0x00}}
 };
 
-static const SiS310_CHTVRegDataStruct SiS310_CHTVReg_UPAL[] =
+static const SiS_CHTVRegDataStruct SiS310_CHTVReg_UPAL[] =
 {
  {{0x41,0x7f,0xb7,0x34,0xad,0x50,0x34,0x83,0x05,0x00,0x80,0x00,0x00,0x00,0x00,0x01}},
  {{0x41,0x7f,0xb7,0x80,0x85,0x50,0x00,0x83,0x05,0x00,0x80,0x00,0x00,0x00,0x00,0x01}},
@@ -3160,7 +2545,7 @@
  {{0xe5,0x7f,0xb7,0x1d,0xa7,0x3e,0x04,0x5a,0x05,0x00,0x80,0x20,0x3e,0xe4,0x22,0x00}}
 };
 
-static const SiS310_CHTVRegDataStruct SiS310_CHTVReg_OPAL[] =
+static const SiS_CHTVRegDataStruct SiS310_CHTVReg_OPAL[] =
 {
  {{0x41,0x7f,0xb7,0x36,0xad,0x50,0x34,0x83,0x05,0x00,0x80,0x00,0x00,0x00,0x00,0x01}},
  {{0x41,0x7f,0xb7,0x86,0x85,0x50,0x00,0x83,0x05,0x00,0x80,0x00,0x00,0x00,0x00,0x01}},
@@ -3171,7 +2556,7 @@
  {{0xe4,0x7f,0xb7,0x1e,0xaf,0x29,0x37,0x5a,0x05,0x00,0x80,0x25,0x8c,0xb2,0x2a,0x00}}
 };
 
-static const SiS310_CHTVRegDataStruct SiS310_CHTVReg_UPALM[] =
+static const SiS_CHTVRegDataStruct SiS310_CHTVReg_UPALM[] =
 {
  {{0x52,0x77,0xbb,0x94,0x84,0x48,0xfe,0x83,0x04,0x00,0x80,0x00,0x00,0x00,0x00,0x01}},
  {{0x52,0x77,0xbb,0x94,0x84,0x48,0xfe,0x83,0x04,0x00,0x80,0x00,0x00,0x00,0x00,0x01}},
@@ -3187,7 +2572,7 @@
 #endif
 };
 
-static const SiS310_CHTVRegDataStruct SiS310_CHTVReg_OPALM[] =
+static const SiS_CHTVRegDataStruct SiS310_CHTVReg_OPALM[] =
 {
  {{0x51,0x77,0xbb,0x7b,0x84,0x34,0x00,0x83,0x04,0x00,0x80,0x00,0x00,0x00,0x00,0x01}},
  {{0x51,0x77,0xbb,0x7b,0x84,0x34,0x00,0x83,0x04,0x00,0x80,0x00,0x00,0x00,0x00,0x01}},
@@ -3203,7 +2588,7 @@
 #endif
 };
 
-static const SiS310_CHTVRegDataStruct SiS310_CHTVReg_UPALN[] =
+static const SiS_CHTVRegDataStruct SiS310_CHTVReg_UPALN[] =
 {
  {{0x41,0x7f,0xb7,0x34,0xad,0x50,0x34,0x6e,0x05,0x00,0x80,0x00,0x00,0x00,0x00,0x03}},
  {{0x41,0x7f,0xb7,0x80,0x85,0x50,0x00,0x6e,0x05,0x00,0x80,0x00,0x00,0x00,0x00,0x03}},
@@ -3219,7 +2604,7 @@
 #endif
 };
 
-static const SiS310_CHTVRegDataStruct SiS310_CHTVReg_OPALN[] =
+static const SiS_CHTVRegDataStruct SiS310_CHTVReg_OPALN[] =
 {
  {{0x41,0x7f,0xb7,0x36,0xad,0x50,0x34,0x6e,0x05,0x00,0x80,0x00,0x00,0x00,0x00,0x03}},
  {{0x41,0x7f,0xb7,0x86,0x85,0x50,0x00,0x6e,0x05,0x00,0x80,0x00,0x00,0x00,0x00,0x03}},
--- diff/drivers/video/sis/init.c	2004-05-19 22:12:23.000000000 +0100
+++ source/drivers/video/sis/init.c	2004-06-11 19:22:05.000000000 +0100
@@ -1,8 +1,9 @@
 /* $XFree86$ */
+/* $XdotOrg$ */
 /*
  * Mode initializing code (CRT1 section) for
  * for SiS 300/305/540/630/730 and
- *     SiS 315/550/650/M650/651/661FX/M661FX/740/741/M741/330/660/M660/760/M760
+ *     SiS 315/550/650/M650/651/661FX/M661FX/740/741(GX)/M741/330/660/M660/760/M760
  * (Universal module for Linux kernel framebuffer and XFree86 4.x)
  *
  * Copyright (C) 2001-2004 by Thomas Winischhofer, Vienna, Austria
@@ -34,13 +35,10 @@
  * * 2) Redistributions in binary form must reproduce the above copyright
  * *    notice, this list of conditions and the following disclaimer in the
  * *    documentation and/or other materials provided with the distribution.
- * * 3) All advertising materials mentioning features or use of this software
- * *    must display the following acknowledgement: "This product includes
- * *    software developed by Thomas Winischhofer, Vienna, Austria."
- * * 4) The name of the author may not be used to endorse or promote products
+ * * 3) The name of the author may not be used to endorse or promote products
  * *    derived from this software without specific prior written permission.
  * *
- * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESSED OR
  * * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
  * * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
  * * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
@@ -78,13 +76,13 @@
 
 #if defined(ALLOC_PRAGMA)
 #pragma alloc_text(PAGE,SiSSetMode)
-#pragma alloc_text(PAGE,SiSInit)
 #endif
 
 /*********************************************/
 /*         POINTER INITIALIZATION            */
 /*********************************************/
 
+#if defined(SIS300) || defined(SIS315H)
 static void
 InitCommonPointer(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo)
 {
@@ -134,16 +132,17 @@
    SiS_Pr->pSiS_OutputSelect = &SiS_OutputSelect;
    SiS_Pr->pSiS_SoftSetting  = &SiS_SoftSetting;
 
+   SiS_Pr->SiS_LCD1280x720Data      = SiS_LCD1280x720Data;
+   SiS_Pr->SiS_StLCD1280x768_2Data  = SiS_StLCD1280x768_2Data;
+   SiS_Pr->SiS_ExtLCD1280x768_2Data = SiS_ExtLCD1280x768_2Data;
+   SiS_Pr->SiS_LCD1280x768_3Data    = SiS_LCD1280x768_3Data;
+   SiS_Pr->SiS_LCD1280x800Data      = SiS_LCD1280x800Data;
    SiS_Pr->SiS_LCD1280x960Data      = SiS_LCD1280x960Data;
-   SiS_Pr->SiS_ExtLCD1400x1050Data  = SiS_ExtLCD1400x1050Data;
-   SiS_Pr->SiS_ExtLCD1600x1200Data  = SiS_ExtLCD1600x1200Data;
    SiS_Pr->SiS_StLCD1400x1050Data   = SiS_StLCD1400x1050Data;
+   SiS_Pr->SiS_ExtLCD1400x1050Data  = SiS_ExtLCD1400x1050Data;
+   SiS_Pr->SiS_LCD1680x1050Data     = SiS_LCD1680x1050Data;
    SiS_Pr->SiS_StLCD1600x1200Data   = SiS_StLCD1600x1200Data;
-   SiS_Pr->SiS_NoScaleData1400x1050 = SiS_NoScaleData1400x1050;
-   SiS_Pr->SiS_NoScaleData1600x1200 = SiS_NoScaleData1600x1200;
-   SiS_Pr->SiS_ExtLCD1280x768Data   = SiS_ExtLCD1280x768Data;
-   SiS_Pr->SiS_StLCD1280x768Data    = SiS_StLCD1280x768Data;
-   SiS_Pr->SiS_NoScaleData1280x768  = SiS_NoScaleData1280x768;
+   SiS_Pr->SiS_ExtLCD1600x1200Data  = SiS_ExtLCD1600x1200Data;
    SiS_Pr->SiS_NoScaleData          = SiS_NoScaleData;
 
    SiS_Pr->SiS_LVDS320x480Data_1   = SiS_LVDS320x480Data_1;
@@ -172,41 +171,12 @@
    SiS_Pr->SiS_LVDS640x480Data_1   = SiS_LVDS640x480Data_1;
    SiS_Pr->SiS_LVDS640x480Data_2   = SiS_LVDS640x480Data_2;
 
-   SiS_Pr->SiS_LVDSBARCO1366Data_1 = SiS_LVDSBARCO1366Data_1;
-   SiS_Pr->SiS_LVDSBARCO1366Data_2 = SiS_LVDSBARCO1366Data_2;
-   SiS_Pr->SiS_LVDSBARCO1024Data_1 = SiS_LVDSBARCO1024Data_1;
-   SiS_Pr->SiS_LVDSBARCO1024Data_2 = SiS_LVDSBARCO1024Data_2;
    SiS_Pr->SiS_LVDS848x480Data_1   = SiS_LVDS848x480Data_1;
    SiS_Pr->SiS_LVDS848x480Data_2   = SiS_LVDS848x480Data_2;
-
-   SiS_Pr->SiS_CHTVUNTSCData = SiS_CHTVUNTSCData;
-   SiS_Pr->SiS_CHTVONTSCData = SiS_CHTVONTSCData;
-
-   SiS_Pr->SiS_LCDA1024x768Data_1  = SiS_LCDA1024x768Data_1;
-   SiS_Pr->SiS_LCDA1024x768Data_2  = SiS_LCDA1024x768Data_2;
-   SiS_Pr->SiS_LCDA1280x1024Data_1 = SiS_LCDA1280x1024Data_1;
-   SiS_Pr->SiS_LCDA1280x1024Data_2 = SiS_LCDA1280x1024Data_2;
-   SiS_Pr->SiS_LCDA1400x1050Data_1 = SiS_LCDA1400x1050Data_1;
-   SiS_Pr->SiS_LCDA1400x1050Data_2 = SiS_LCDA1400x1050Data_2;
-   SiS_Pr->SiS_LCDA1600x1200Data_1 = SiS_LCDA1600x1200Data_1;
-   SiS_Pr->SiS_LCDA1600x1200Data_2 = SiS_LCDA1600x1200Data_2;
-
-   SiS_Pr->LVDS1024x768Des_1  = SiS_PanelType1076_1;
-   SiS_Pr->LVDS1280x1024Des_1 = SiS_PanelType1210_1;
-   SiS_Pr->LVDS1400x1050Des_1 = SiS_PanelType1296_1;
-   SiS_Pr->LVDS1600x1200Des_1 = SiS_PanelType1600_1;
-   SiS_Pr->LVDS1024x768Des_2  = SiS_PanelType1076_2;
-   SiS_Pr->LVDS1280x1024Des_2 = SiS_PanelType1210_2;
-   SiS_Pr->LVDS1400x1050Des_2 = SiS_PanelType1296_2;
-   SiS_Pr->LVDS1600x1200Des_2 = SiS_PanelType1600_2;
-
-   SiS_Pr->SiS_PanelTypeNS_1 = SiS_PanelTypeNS_1;
-   SiS_Pr->SiS_PanelTypeNS_2 = SiS_PanelTypeNS_2;
-
-   SiS_Pr->SiS_CHTVUNTSCDesData = SiS_CHTVUNTSCDesData;
-   SiS_Pr->SiS_CHTVONTSCDesData = SiS_CHTVONTSCDesData;
-   SiS_Pr->SiS_CHTVUPALDesData  = SiS_CHTVUPALDesData;
-   SiS_Pr->SiS_CHTVOPALDesData  = SiS_CHTVOPALDesData;
+   SiS_Pr->SiS_LVDSBARCO1024Data_1 = SiS_LVDSBARCO1024Data_1;
+   SiS_Pr->SiS_LVDSBARCO1024Data_2 = SiS_LVDSBARCO1024Data_2;
+   SiS_Pr->SiS_LVDSBARCO1366Data_1 = SiS_LVDSBARCO1366Data_1;
+   SiS_Pr->SiS_LVDSBARCO1366Data_2 = SiS_LVDSBARCO1366Data_2;
 
    SiS_Pr->SiS_LVDSCRT11280x768_1    = SiS_LVDSCRT11280x768_1;
    SiS_Pr->SiS_LVDSCRT11024x600_1    = SiS_LVDSCRT11024x600_1;
@@ -221,15 +191,25 @@
    SiS_Pr->SiS_LVDSCRT11024x600_2_H  = SiS_LVDSCRT11024x600_2_H;
    SiS_Pr->SiS_LVDSCRT11152x768_2_H  = SiS_LVDSCRT11152x768_2_H;
    SiS_Pr->SiS_LVDSCRT1320x480_1     = SiS_LVDSCRT1320x480_1;
-   SiS_Pr->SiS_LVDSCRT1XXXxXXX_1     = SiS_LVDSCRT1XXXxXXX_1;
-   SiS_Pr->SiS_LVDSCRT1XXXxXXX_1_H   = SiS_LVDSCRT1XXXxXXX_1_H;
    SiS_Pr->SiS_LVDSCRT1640x480_1     = SiS_LVDSCRT1640x480_1;
    SiS_Pr->SiS_LVDSCRT1640x480_1_H   = SiS_LVDSCRT1640x480_1_H;
    SiS_Pr->SiS_LVDSCRT1640x480_2     = SiS_LVDSCRT1640x480_2;
    SiS_Pr->SiS_LVDSCRT1640x480_2_H   = SiS_LVDSCRT1640x480_2_H;
    SiS_Pr->SiS_LVDSCRT1640x480_3     = SiS_LVDSCRT1640x480_3;
    SiS_Pr->SiS_LVDSCRT1640x480_3_H   = SiS_LVDSCRT1640x480_3_H;
+
+   SiS_Pr->SiS_CHTVUNTSCData = SiS_CHTVUNTSCData;
+   SiS_Pr->SiS_CHTVONTSCData = SiS_CHTVONTSCData;
+
+   SiS_Pr->SiS_CHTVUNTSCDesData = SiS_CHTVUNTSCDesData;
+   SiS_Pr->SiS_CHTVONTSCDesData = SiS_CHTVONTSCDesData;
+   SiS_Pr->SiS_CHTVUPALDesData  = SiS_CHTVUPALDesData;
+   SiS_Pr->SiS_CHTVOPALDesData  = SiS_CHTVOPALDesData;
+
+   SiS_Pr->SiS_PanelMinLVDS   = Panel_800x600;    /* lowest value LVDS/LCDA */
+   SiS_Pr->SiS_PanelMin301    = Panel_1024x768;   /* lowest value 301 */
 }
+#endif
 
 #ifdef SIS300
 static void
@@ -265,19 +245,18 @@
    SiS_StandTable[0x1c].CRTC[4] = 0x54;
    SiS_StandTable[0x1c].CRTC[5] = 0x80;
 
-   SiS_Pr->SiS_SModeIDTable  = (SiS_StStruct *)SiS300_SModeIDTable;
-   SiS_Pr->SiS_VBModeIDTable = (SiS_VBModeStruct *)SiS300_VBModeIDTable;
-   SiS_Pr->SiS_EModeIDTable  = (SiS_ExtStruct *)SiS300_EModeIDTable;
-   SiS_Pr->SiS_RefIndex      = (SiS_Ext2Struct *)SiS300_RefIndex;
-   SiS_Pr->SiS_CRT1Table     = (SiS_CRT1TableStruct *)SiS300_CRT1Table;
+   SiS_Pr->SiS_SModeIDTable  = SiS300_SModeIDTable;
+   SiS_Pr->SiS_VBModeIDTable = SiS300_VBModeIDTable;
+   SiS_Pr->SiS_EModeIDTable  = SiS300_EModeIDTable;
+   SiS_Pr->SiS_RefIndex      = SiS300_RefIndex;
+   SiS_Pr->SiS_CRT1Table     = SiS300_CRT1Table;
    if(HwInfo->jChipType == SIS_300) {
-      SiS_Pr->SiS_MCLKData_0    = (SiS_MCLKDataStruct *)SiS300_MCLKData_300; /* 300 */
+      SiS_Pr->SiS_MCLKData_0    = SiS300_MCLKData_300; /* 300 */
    } else {
-      SiS_Pr->SiS_MCLKData_0    = (SiS_MCLKDataStruct *)SiS300_MCLKData_630; /* 630, 730 */
+      SiS_Pr->SiS_MCLKData_0    = SiS300_MCLKData_630; /* 630, 730 */
    }
-   SiS_Pr->SiS_VCLKData      = (SiS_VCLKDataStruct *)SiS300_VCLKData;
+   SiS_Pr->SiS_VCLKData      = SiS300_VCLKData;
    SiS_Pr->SiS_VBVCLKData    = (SiS_VBVCLKDataStruct *)SiS300_VCLKData;
-   SiS_Pr->SiS_ScreenOffset  = SiS300_ScreenOffset;
 
    SiS_Pr->SiS_SR15  = SiS300_SR15;
 
@@ -306,97 +285,102 @@
    SiS_Pr->pSiS_YCSenseData2    = &SiS300_YCSenseData2;
 #endif
 
-   SiS_Pr->SiS_StLCD1024x768Data    = (SiS_LCDDataStruct *)SiS300_StLCD1024x768Data;
-   SiS_Pr->SiS_ExtLCD1024x768Data   = (SiS_LCDDataStruct *)SiS300_ExtLCD1024x768Data;
-   SiS_Pr->SiS_St2LCD1024x768Data   = (SiS_LCDDataStruct *)SiS300_St2LCD1024x768Data;
-   SiS_Pr->SiS_StLCD1280x1024Data   = (SiS_LCDDataStruct *)SiS300_StLCD1280x1024Data;
-   SiS_Pr->SiS_ExtLCD1280x1024Data  = (SiS_LCDDataStruct *)SiS300_ExtLCD1280x1024Data;
-   SiS_Pr->SiS_St2LCD1280x1024Data  = (SiS_LCDDataStruct *)SiS300_St2LCD1280x1024Data;
-   SiS_Pr->SiS_NoScaleData1024x768  = (SiS_LCDDataStruct *)SiS300_NoScaleData1024x768;
-   SiS_Pr->SiS_NoScaleData1280x1024 = (SiS_LCDDataStruct *)SiS300_NoScaleData1280x1024;
-
-   SiS_Pr->SiS_PanelDelayTbl     = (SiS_PanelDelayTblStruct *)SiS300_PanelDelayTbl;
-   SiS_Pr->SiS_PanelDelayTblLVDS = (SiS_PanelDelayTblStruct *)SiS300_PanelDelayTbl;
-#if 0
-   SiS_Pr->SiS_PanelDelayTblLVDS = (SiS_PanelDelayTblStruct *)SiS300_PanelDelayTblLVDS;
-#endif
+   SiS_Pr->SiS_PanelDelayTbl     = SiS300_PanelDelayTbl;
+   SiS_Pr->SiS_PanelDelayTblLVDS = SiS300_PanelDelayTbl;
 
-   SiS_Pr->SiS_CHTVUPALData  = (SiS_LVDSDataStruct *)SiS300_CHTVUPALData;
-   SiS_Pr->SiS_CHTVOPALData  = (SiS_LVDSDataStruct *)SiS300_CHTVOPALData;
-   SiS_Pr->SiS_CHTVUPALMData = SiS_CHTVUNTSCData; 			   /* not supported on 300 series */
-   SiS_Pr->SiS_CHTVOPALMData = SiS_CHTVONTSCData; 			   /* not supported on 300 series */
-   SiS_Pr->SiS_CHTVUPALNData = (SiS_LVDSDataStruct *)SiS300_CHTVUPALData;  /* not supported on 300 series */
-   SiS_Pr->SiS_CHTVOPALNData = (SiS_LVDSDataStruct *)SiS300_CHTVOPALData;  /* not supported on 300 series */
-   SiS_Pr->SiS_CHTVSOPALData = (SiS_LVDSDataStruct *)SiS300_CHTVSOPALData;
-
-   SiS_Pr->SiS_PanelType00_1 = (SiS_LVDSDesStruct *)SiS300_PanelType00_1;
-   SiS_Pr->SiS_PanelType01_1 = (SiS_LVDSDesStruct *)SiS300_PanelType01_1;
-   SiS_Pr->SiS_PanelType02_1 = (SiS_LVDSDesStruct *)SiS300_PanelType02_1;
-   SiS_Pr->SiS_PanelType03_1 = (SiS_LVDSDesStruct *)SiS300_PanelType03_1;
-   SiS_Pr->SiS_PanelType04_1 = (SiS_LVDSDesStruct *)SiS300_PanelType04_1;
-   SiS_Pr->SiS_PanelType05_1 = (SiS_LVDSDesStruct *)SiS300_PanelType05_1;
-   SiS_Pr->SiS_PanelType06_1 = (SiS_LVDSDesStruct *)SiS300_PanelType06_1;
-   SiS_Pr->SiS_PanelType07_1 = (SiS_LVDSDesStruct *)SiS300_PanelType07_1;
-   SiS_Pr->SiS_PanelType08_1 = (SiS_LVDSDesStruct *)SiS300_PanelType08_1;
-   SiS_Pr->SiS_PanelType09_1 = (SiS_LVDSDesStruct *)SiS300_PanelType09_1;
-   SiS_Pr->SiS_PanelType0a_1 = (SiS_LVDSDesStruct *)SiS300_PanelType0a_1;
-   SiS_Pr->SiS_PanelType0b_1 = (SiS_LVDSDesStruct *)SiS300_PanelType0b_1;
-   SiS_Pr->SiS_PanelType0c_1 = (SiS_LVDSDesStruct *)SiS300_PanelType0c_1;
-   SiS_Pr->SiS_PanelType0d_1 = (SiS_LVDSDesStruct *)SiS300_PanelType0d_1;
-   SiS_Pr->SiS_PanelType0e_1 = (SiS_LVDSDesStruct *)SiS300_PanelType0e_1;
-   SiS_Pr->SiS_PanelType0f_1 = (SiS_LVDSDesStruct *)SiS300_PanelType0f_1;
-   SiS_Pr->SiS_PanelType00_2 = (SiS_LVDSDesStruct *)SiS300_PanelType00_2;
-   SiS_Pr->SiS_PanelType01_2 = (SiS_LVDSDesStruct *)SiS300_PanelType01_2;
-   SiS_Pr->SiS_PanelType02_2 = (SiS_LVDSDesStruct *)SiS300_PanelType02_2;
-   SiS_Pr->SiS_PanelType03_2 = (SiS_LVDSDesStruct *)SiS300_PanelType03_2;
-   SiS_Pr->SiS_PanelType04_2 = (SiS_LVDSDesStruct *)SiS300_PanelType04_2;
-   SiS_Pr->SiS_PanelType05_2 = (SiS_LVDSDesStruct *)SiS300_PanelType05_2;
-   SiS_Pr->SiS_PanelType06_2 = (SiS_LVDSDesStruct *)SiS300_PanelType06_2;
-   SiS_Pr->SiS_PanelType07_2 = (SiS_LVDSDesStruct *)SiS300_PanelType07_2;
-   SiS_Pr->SiS_PanelType08_2 = (SiS_LVDSDesStruct *)SiS300_PanelType08_2;
-   SiS_Pr->SiS_PanelType09_2 = (SiS_LVDSDesStruct *)SiS300_PanelType09_2;
-   SiS_Pr->SiS_PanelType0a_2 = (SiS_LVDSDesStruct *)SiS300_PanelType0a_2;
-   SiS_Pr->SiS_PanelType0b_2 = (SiS_LVDSDesStruct *)SiS300_PanelType0b_2;
-   SiS_Pr->SiS_PanelType0c_2 = (SiS_LVDSDesStruct *)SiS300_PanelType0c_2;
-   SiS_Pr->SiS_PanelType0d_2 = (SiS_LVDSDesStruct *)SiS300_PanelType0d_2;
-   SiS_Pr->SiS_PanelType0e_2 = (SiS_LVDSDesStruct *)SiS300_PanelType0e_2;
-   SiS_Pr->SiS_PanelType0f_2 = (SiS_LVDSDesStruct *)SiS300_PanelType0f_2;
+   SiS_Pr->SiS_ExtLCD1024x768Data   = SiS300_ExtLCD1024x768Data;
+   SiS_Pr->SiS_St2LCD1024x768Data   = SiS300_St2LCD1024x768Data;
+   SiS_Pr->SiS_ExtLCD1280x1024Data  = SiS300_ExtLCD1280x1024Data;
+   SiS_Pr->SiS_St2LCD1280x1024Data  = SiS300_St2LCD1280x1024Data;
+
+   SiS_Pr->SiS_CRT2Part2_1024x768_1  = SiS300_CRT2Part2_1024x768_1;
+   SiS_Pr->SiS_CRT2Part2_1280x1024_1 = SiS300_CRT2Part2_1280x1024_1;
+   SiS_Pr->SiS_CRT2Part2_1024x768_2  = SiS300_CRT2Part2_1024x768_2;
+   SiS_Pr->SiS_CRT2Part2_1280x1024_2 = SiS300_CRT2Part2_1280x1024_2;
+   SiS_Pr->SiS_CRT2Part2_1024x768_3  = SiS300_CRT2Part2_1024x768_3;
+   SiS_Pr->SiS_CRT2Part2_1280x1024_3 = SiS300_CRT2Part2_1280x1024_3;
+
+   SiS_Pr->SiS_CHTVUPALData  = SiS300_CHTVUPALData;
+   SiS_Pr->SiS_CHTVOPALData  = SiS300_CHTVOPALData;
+   SiS_Pr->SiS_CHTVUPALMData = SiS_CHTVUNTSCData;    /* not supported on 300 series */
+   SiS_Pr->SiS_CHTVOPALMData = SiS_CHTVONTSCData;    /* not supported on 300 series */
+   SiS_Pr->SiS_CHTVUPALNData = SiS300_CHTVUPALData;  /* not supported on 300 series */
+   SiS_Pr->SiS_CHTVOPALNData = SiS300_CHTVOPALData;  /* not supported on 300 series */
+   SiS_Pr->SiS_CHTVSOPALData = SiS300_CHTVSOPALData;
+
+   SiS_Pr->SiS_PanelType00_1 = SiS300_PanelType00_1;
+   SiS_Pr->SiS_PanelType01_1 = SiS300_PanelType01_1;
+   SiS_Pr->SiS_PanelType02_1 = SiS300_PanelType02_1;
+   SiS_Pr->SiS_PanelType03_1 = SiS300_PanelType03_1;
+   SiS_Pr->SiS_PanelType04_1 = SiS300_PanelType04_1;
+   SiS_Pr->SiS_PanelType05_1 = SiS300_PanelType05_1;
+   SiS_Pr->SiS_PanelType06_1 = SiS300_PanelType06_1;
+   SiS_Pr->SiS_PanelType07_1 = SiS300_PanelType07_1;
+   SiS_Pr->SiS_PanelType08_1 = SiS300_PanelType08_1;
+   SiS_Pr->SiS_PanelType09_1 = SiS300_PanelType09_1;
+   SiS_Pr->SiS_PanelType0a_1 = SiS300_PanelType0a_1;
+   SiS_Pr->SiS_PanelType0b_1 = SiS300_PanelType0b_1;
+   SiS_Pr->SiS_PanelType0c_1 = SiS300_PanelType0c_1;
+   SiS_Pr->SiS_PanelType0d_1 = SiS300_PanelType0d_1;
+   SiS_Pr->SiS_PanelType0e_1 = SiS300_PanelType0e_1;
+   SiS_Pr->SiS_PanelType0f_1 = SiS300_PanelType0f_1;
+   SiS_Pr->SiS_PanelType00_2 = SiS300_PanelType00_2;
+   SiS_Pr->SiS_PanelType01_2 = SiS300_PanelType01_2;
+   SiS_Pr->SiS_PanelType02_2 = SiS300_PanelType02_2;
+   SiS_Pr->SiS_PanelType03_2 = SiS300_PanelType03_2;
+   SiS_Pr->SiS_PanelType04_2 = SiS300_PanelType04_2;
+   SiS_Pr->SiS_PanelType05_2 = SiS300_PanelType05_2;
+   SiS_Pr->SiS_PanelType06_2 = SiS300_PanelType06_2;
+   SiS_Pr->SiS_PanelType07_2 = SiS300_PanelType07_2;
+   SiS_Pr->SiS_PanelType08_2 = SiS300_PanelType08_2;
+   SiS_Pr->SiS_PanelType09_2 = SiS300_PanelType09_2;
+   SiS_Pr->SiS_PanelType0a_2 = SiS300_PanelType0a_2;
+   SiS_Pr->SiS_PanelType0b_2 = SiS300_PanelType0b_2;
+   SiS_Pr->SiS_PanelType0c_2 = SiS300_PanelType0c_2;
+   SiS_Pr->SiS_PanelType0d_2 = SiS300_PanelType0d_2;
+   SiS_Pr->SiS_PanelType0e_2 = SiS300_PanelType0e_2;
+   SiS_Pr->SiS_PanelType0f_2 = SiS300_PanelType0f_2;
+   SiS_Pr->SiS_PanelTypeNS_1 = SiS300_PanelTypeNS_1;
+   SiS_Pr->SiS_PanelTypeNS_2 = SiS300_PanelTypeNS_2;
 
    if(SiS_Pr->SiS_CustomT == CUT_BARCO1366) {
-      SiS_Pr->SiS_PanelType04_1 = (SiS_LVDSDesStruct *)SiS300_PanelType04_1a;
-      SiS_Pr->SiS_PanelType04_2 = (SiS_LVDSDesStruct *)SiS300_PanelType04_2a;
+      SiS_Pr->SiS_PanelType04_1 = SiS300_PanelType04_1a;
+      SiS_Pr->SiS_PanelType04_2 = SiS300_PanelType04_2a;
    }
    if(SiS_Pr->SiS_CustomT == CUT_BARCO1024) {
-      SiS_Pr->SiS_PanelType04_1 = (SiS_LVDSDesStruct *)SiS300_PanelType04_1b;
-      SiS_Pr->SiS_PanelType04_2 = (SiS_LVDSDesStruct *)SiS300_PanelType04_2b;
+      SiS_Pr->SiS_PanelType04_1 = SiS300_PanelType04_1b;
+      SiS_Pr->SiS_PanelType04_2 = SiS300_PanelType04_2b;
    }
 
-   SiS_Pr->SiS_LVDSCRT1800x600_1     = (SiS_LVDSCRT1DataStruct *)SiS300_LVDSCRT1800x600_1;
-   SiS_Pr->SiS_LVDSCRT11024x768_1    = (SiS_LVDSCRT1DataStruct *)SiS300_LVDSCRT11024x768_1;
-   SiS_Pr->SiS_LVDSCRT11280x1024_1   = (SiS_LVDSCRT1DataStruct *)SiS300_LVDSCRT11280x1024_1;
-   SiS_Pr->SiS_LVDSCRT1800x600_1_H   = (SiS_LVDSCRT1DataStruct *)SiS300_LVDSCRT1800x600_1_H;
-   SiS_Pr->SiS_LVDSCRT11024x768_1_H  = (SiS_LVDSCRT1DataStruct *)SiS300_LVDSCRT11024x768_1_H;
-   SiS_Pr->SiS_LVDSCRT11280x1024_1_H = (SiS_LVDSCRT1DataStruct *)SiS300_LVDSCRT11280x1024_1_H;
-   SiS_Pr->SiS_LVDSCRT1800x600_2     = (SiS_LVDSCRT1DataStruct *)SiS300_LVDSCRT1800x600_2;
-   SiS_Pr->SiS_LVDSCRT11024x768_2    = (SiS_LVDSCRT1DataStruct *)SiS300_LVDSCRT11024x768_2;
-   SiS_Pr->SiS_LVDSCRT11280x1024_2   = (SiS_LVDSCRT1DataStruct *)SiS300_LVDSCRT11280x1024_2;
-   SiS_Pr->SiS_LVDSCRT1800x600_2_H   = (SiS_LVDSCRT1DataStruct *)SiS300_LVDSCRT1800x600_2_H;
-   SiS_Pr->SiS_LVDSCRT11024x768_2_H  = (SiS_LVDSCRT1DataStruct *)SiS300_LVDSCRT11024x768_2_H;
-   SiS_Pr->SiS_LVDSCRT11280x1024_2_H = (SiS_LVDSCRT1DataStruct *)SiS300_LVDSCRT11280x1024_2_H;
-   SiS_Pr->SiS_CHTVCRT1UNTSC = (SiS_LVDSCRT1DataStruct *)SiS300_CHTVCRT1UNTSC;
-   SiS_Pr->SiS_CHTVCRT1ONTSC = (SiS_LVDSCRT1DataStruct *)SiS300_CHTVCRT1ONTSC;
-   SiS_Pr->SiS_CHTVCRT1UPAL  = (SiS_LVDSCRT1DataStruct *)SiS300_CHTVCRT1UPAL;
-   SiS_Pr->SiS_CHTVCRT1OPAL  = (SiS_LVDSCRT1DataStruct *)SiS300_CHTVCRT1OPAL;
-   SiS_Pr->SiS_CHTVCRT1SOPAL = (SiS_LVDSCRT1DataStruct *)SiS300_CHTVCRT1SOPAL;
-   SiS_Pr->SiS_CHTVReg_UNTSC = (SiS_CHTVRegDataStruct *)SiS300_CHTVReg_UNTSC;
-   SiS_Pr->SiS_CHTVReg_ONTSC = (SiS_CHTVRegDataStruct *)SiS300_CHTVReg_ONTSC;
-   SiS_Pr->SiS_CHTVReg_UPAL  = (SiS_CHTVRegDataStruct *)SiS300_CHTVReg_UPAL;
-   SiS_Pr->SiS_CHTVReg_OPAL  = (SiS_CHTVRegDataStruct *)SiS300_CHTVReg_OPAL;
-   SiS_Pr->SiS_CHTVReg_UPALM = (SiS_CHTVRegDataStruct *)SiS300_CHTVReg_UNTSC;  /* not supported on 300 series */
-   SiS_Pr->SiS_CHTVReg_OPALM = (SiS_CHTVRegDataStruct *)SiS300_CHTVReg_ONTSC;  /* not supported on 300 series */
-   SiS_Pr->SiS_CHTVReg_UPALN = (SiS_CHTVRegDataStruct *)SiS300_CHTVReg_UPAL;   /* not supported on 300 series */
-   SiS_Pr->SiS_CHTVReg_OPALN = (SiS_CHTVRegDataStruct *)SiS300_CHTVReg_OPAL;   /* not supported on 300 series */
-   SiS_Pr->SiS_CHTVReg_SOPAL = (SiS_CHTVRegDataStruct *)SiS300_CHTVReg_SOPAL;
+   SiS_Pr->SiS_LVDSCRT1800x600_1     = SiS300_LVDSCRT1800x600_1;
+   SiS_Pr->SiS_LVDSCRT1800x600_1_H   = SiS300_LVDSCRT1800x600_1_H;
+   SiS_Pr->SiS_LVDSCRT1800x600_2     = SiS300_LVDSCRT1800x600_2;
+   SiS_Pr->SiS_LVDSCRT1800x600_2_H   = SiS300_LVDSCRT1800x600_2_H;
+   SiS_Pr->SiS_LVDSCRT11024x768_1    = SiS300_LVDSCRT11024x768_1;
+   SiS_Pr->SiS_LVDSCRT11024x768_1_H  = SiS300_LVDSCRT11024x768_1_H;
+   SiS_Pr->SiS_LVDSCRT11024x768_2    = SiS300_LVDSCRT11024x768_2;
+   SiS_Pr->SiS_LVDSCRT11024x768_2_H  = SiS300_LVDSCRT11024x768_2_H;
+   SiS_Pr->SiS_LVDSCRT11280x1024_1   = SiS300_LVDSCRT11280x1024_1;
+   SiS_Pr->SiS_LVDSCRT11280x1024_1_H = SiS300_LVDSCRT11280x1024_1_H;
+   SiS_Pr->SiS_LVDSCRT11280x1024_2   = SiS300_LVDSCRT11280x1024_2;
+   SiS_Pr->SiS_LVDSCRT11280x1024_2_H = SiS300_LVDSCRT11280x1024_2_H;
+   SiS_Pr->SiS_LVDSCRT1XXXxXXX_1     = SiS300_LVDSCRT1XXXxXXX_1;
+   SiS_Pr->SiS_LVDSCRT1XXXxXXX_1_H   = SiS300_LVDSCRT1XXXxXXX_1_H;
+
+   SiS_Pr->SiS_CHTVCRT1UNTSC = SiS300_CHTVCRT1UNTSC;
+   SiS_Pr->SiS_CHTVCRT1ONTSC = SiS300_CHTVCRT1ONTSC;
+   SiS_Pr->SiS_CHTVCRT1UPAL  = SiS300_CHTVCRT1UPAL;
+   SiS_Pr->SiS_CHTVCRT1OPAL  = SiS300_CHTVCRT1OPAL;
+   SiS_Pr->SiS_CHTVCRT1SOPAL = SiS300_CHTVCRT1SOPAL;
+   SiS_Pr->SiS_CHTVReg_UNTSC = SiS300_CHTVReg_UNTSC;
+   SiS_Pr->SiS_CHTVReg_ONTSC = SiS300_CHTVReg_ONTSC;
+   SiS_Pr->SiS_CHTVReg_UPAL  = SiS300_CHTVReg_UPAL;
+   SiS_Pr->SiS_CHTVReg_OPAL  = SiS300_CHTVReg_OPAL;
+   SiS_Pr->SiS_CHTVReg_UPALM = SiS300_CHTVReg_UNTSC;  /* not supported on 300 series */
+   SiS_Pr->SiS_CHTVReg_OPALM = SiS300_CHTVReg_ONTSC;  /* not supported on 300 series */
+   SiS_Pr->SiS_CHTVReg_UPALN = SiS300_CHTVReg_UPAL;   /* not supported on 300 series */
+   SiS_Pr->SiS_CHTVReg_OPALN = SiS300_CHTVReg_OPAL;   /* not supported on 300 series */
+   SiS_Pr->SiS_CHTVReg_SOPAL = SiS300_CHTVReg_SOPAL;
    SiS_Pr->SiS_CHTVVCLKUNTSC = SiS300_CHTVVCLKUNTSC;
    SiS_Pr->SiS_CHTVVCLKONTSC = SiS300_CHTVVCLKONTSC;
    SiS_Pr->SiS_CHTVVCLKUPAL  = SiS300_CHTVVCLKUPAL;
@@ -406,40 +390,6 @@
    SiS_Pr->SiS_CHTVVCLKUPALN = SiS300_CHTVVCLKUPAL;   /* not supported on 300 series */
    SiS_Pr->SiS_CHTVVCLKOPALN = SiS300_CHTVVCLKOPAL;   /* not supported on 300 series */
    SiS_Pr->SiS_CHTVVCLKSOPAL = SiS300_CHTVVCLKSOPAL;
-
-   SiS_Pr->SiS_CRT2Part2_1024x768_1  = (SiS_Part2PortTblStruct *)SiS300_CRT2Part2_1024x768_1;
-   SiS_Pr->SiS_CRT2Part2_1280x1024_1 = (SiS_Part2PortTblStruct *)SiS300_CRT2Part2_1280x1024_1;
-   SiS_Pr->SiS_CRT2Part2_1400x1050_1 = (SiS_Part2PortTblStruct *)SiS300_CRT2Part2_1400x1050_1;
-   SiS_Pr->SiS_CRT2Part2_1600x1200_1 = (SiS_Part2PortTblStruct *)SiS300_CRT2Part2_1600x1200_1;
-   SiS_Pr->SiS_CRT2Part2_1024x768_2  = (SiS_Part2PortTblStruct *)SiS300_CRT2Part2_1024x768_2;
-   SiS_Pr->SiS_CRT2Part2_1280x1024_2 = (SiS_Part2PortTblStruct *)SiS300_CRT2Part2_1280x1024_2;
-   SiS_Pr->SiS_CRT2Part2_1400x1050_2 = (SiS_Part2PortTblStruct *)SiS300_CRT2Part2_1400x1050_2;
-   SiS_Pr->SiS_CRT2Part2_1600x1200_2 = (SiS_Part2PortTblStruct *)SiS300_CRT2Part2_1600x1200_2;
-   SiS_Pr->SiS_CRT2Part2_1024x768_3  = (SiS_Part2PortTblStruct *)SiS300_CRT2Part2_1024x768_3;
-   SiS_Pr->SiS_CRT2Part2_1280x1024_3 = (SiS_Part2PortTblStruct *)SiS300_CRT2Part2_1280x1024_3;
-   SiS_Pr->SiS_CRT2Part2_1400x1050_3 = (SiS_Part2PortTblStruct *)SiS300_CRT2Part2_1400x1050_3;
-   SiS_Pr->SiS_CRT2Part2_1600x1200_3 = (SiS_Part2PortTblStruct *)SiS300_CRT2Part2_1600x1200_3;
-
-   /* LCDResInfo will on 300 series be translated to 315 series definitions */
-   SiS_Pr->SiS_Panel320x480   = Panel_320x480;
-   SiS_Pr->SiS_Panel640x480   = Panel_640x480;
-   SiS_Pr->SiS_Panel800x600   = Panel_800x600;
-   SiS_Pr->SiS_Panel1024x768  = Panel_1024x768;
-   SiS_Pr->SiS_Panel1280x1024 = Panel_1280x1024;
-   SiS_Pr->SiS_Panel1280x960  = Panel_1280x960;
-   SiS_Pr->SiS_Panel1024x600  = Panel_1024x600;
-   SiS_Pr->SiS_Panel1152x768  = Panel_1152x768;
-   SiS_Pr->SiS_Panel1280x768  = Panel_1280x768;
-   SiS_Pr->SiS_Panel1600x1200 = 255;  		   /* Something illegal */
-   SiS_Pr->SiS_Panel1400x1050 = 255;
-   SiS_Pr->SiS_Panel640x480_2 = 255;
-   SiS_Pr->SiS_Panel640x480_3 = 255;
-   SiS_Pr->SiS_Panel1152x864  = 255;
-   SiS_Pr->SiS_PanelMax       = Panel_320x480;     /* highest value */
-   SiS_Pr->SiS_PanelMinLVDS   = Panel_800x600;     /* Lowest value LVDS */
-   SiS_Pr->SiS_PanelMin301    = Panel_1024x768;    /* lowest value 301 */
-   SiS_Pr->SiS_PanelCustom    = Panel_Custom;
-   SiS_Pr->SiS_PanelBarco1366 = Panel_Barco1366;
 }
 #endif
 
@@ -477,23 +427,24 @@
    SiS_StandTable[0x1c].CRTC[4] = 0x55;
    SiS_StandTable[0x1c].CRTC[5] = 0x81;
 
-   SiS_Pr->SiS_SModeIDTable  = (SiS_StStruct *)SiS310_SModeIDTable;
-   SiS_Pr->SiS_EModeIDTable  = (SiS_ExtStruct *)SiS310_EModeIDTable;
+   SiS_Pr->SiS_SModeIDTable  = SiS310_SModeIDTable;
+   SiS_Pr->SiS_EModeIDTable  = SiS310_EModeIDTable;
    SiS_Pr->SiS_RefIndex      = (SiS_Ext2Struct *)SiS310_RefIndex;
-   SiS_Pr->SiS_CRT1Table     = (SiS_CRT1TableStruct *)SiS310_CRT1Table;
-   if(HwInfo->jChipType >= SIS_661) {
-      SiS_Pr->SiS_MCLKData_0 = (SiS_MCLKDataStruct *)SiS310_MCLKData_0_660;  /* 661/741/760 */
+   SiS_Pr->SiS_CRT1Table     = SiS310_CRT1Table;
+   if(HwInfo->jChipType >= SIS_760) {
+      SiS_Pr->SiS_MCLKData_0 = SiS310_MCLKData_0_760;  /* 760 */
+   } else if(HwInfo->jChipType >= SIS_661) {
+      SiS_Pr->SiS_MCLKData_0 = SiS310_MCLKData_0_660;  /* 661/741 */
    } else if(HwInfo->jChipType == SIS_330) {
-      SiS_Pr->SiS_MCLKData_0 = (SiS_MCLKDataStruct *)SiS310_MCLKData_0_330;  /* 330 */
+      SiS_Pr->SiS_MCLKData_0 = SiS310_MCLKData_0_330;  /* 330 */
    } else if(HwInfo->jChipType > SIS_315PRO) {
-      SiS_Pr->SiS_MCLKData_0 = (SiS_MCLKDataStruct *)SiS310_MCLKData_0_650;  /* 550, 650, 740 */
+      SiS_Pr->SiS_MCLKData_0 = SiS310_MCLKData_0_650;  /* 550, 650, 740 */
    } else {
-      SiS_Pr->SiS_MCLKData_0 = (SiS_MCLKDataStruct *)SiS310_MCLKData_0_315;  /* 315 */
+      SiS_Pr->SiS_MCLKData_0 = SiS310_MCLKData_0_315;  /* 315 */
    }
-   SiS_Pr->SiS_MCLKData_1    = (SiS_MCLKDataStruct *)SiS310_MCLKData_1;
-   SiS_Pr->SiS_VCLKData      = (SiS_VCLKDataStruct *)SiS310_VCLKData;
-   SiS_Pr->SiS_VBVCLKData    = (SiS_VBVCLKDataStruct *)SiS310_VBVCLKData;
-   SiS_Pr->SiS_ScreenOffset  = SiS310_ScreenOffset;
+   SiS_Pr->SiS_MCLKData_1    = SiS310_MCLKData_1;
+   SiS_Pr->SiS_VCLKData      = SiS310_VCLKData;
+   SiS_Pr->SiS_VBVCLKData    = SiS310_VBVCLKData;
 
    SiS_Pr->SiS_SR15  = SiS310_SR15;
 
@@ -522,124 +473,96 @@
    SiS_Pr->pSiS_YCSenseData2    = &SiS310_YCSenseData2;
 #endif
 
-   SiS_Pr->SiS_StLCD1024x768Data    = (SiS_LCDDataStruct *)SiS310_StLCD1024x768Data;
-   SiS_Pr->SiS_ExtLCD1024x768Data   = (SiS_LCDDataStruct *)SiS310_ExtLCD1024x768Data;
-   SiS_Pr->SiS_St2LCD1024x768Data   = (SiS_LCDDataStruct *)SiS310_St2LCD1024x768Data;
-   SiS_Pr->SiS_StLCD1280x1024Data   = (SiS_LCDDataStruct *)SiS310_StLCD1280x1024Data;
-   SiS_Pr->SiS_ExtLCD1280x1024Data  = (SiS_LCDDataStruct *)SiS310_ExtLCD1280x1024Data;
-   SiS_Pr->SiS_St2LCD1280x1024Data  = (SiS_LCDDataStruct *)SiS310_St2LCD1280x1024Data;
-   SiS_Pr->SiS_NoScaleData1024x768  = (SiS_LCDDataStruct *)SiS310_NoScaleData1024x768;
-   SiS_Pr->SiS_NoScaleData1280x1024 = (SiS_LCDDataStruct *)SiS310_NoScaleData1280x1024;
-
-   SiS_Pr->SiS_PanelDelayTbl     = (SiS_PanelDelayTblStruct *)SiS310_PanelDelayTbl;
-   SiS_Pr->SiS_PanelDelayTblLVDS = (SiS_PanelDelayTblStruct *)SiS310_PanelDelayTblLVDS;
-
-   SiS_Pr->SiS_CHTVUPALData  = (SiS_LVDSDataStruct *)SiS310_CHTVUPALData;
-   SiS_Pr->SiS_CHTVOPALData  = (SiS_LVDSDataStruct *)SiS310_CHTVOPALData;
-   SiS_Pr->SiS_CHTVUPALMData = (SiS_LVDSDataStruct *)SiS310_CHTVUPALMData;
-   SiS_Pr->SiS_CHTVOPALMData = (SiS_LVDSDataStruct *)SiS310_CHTVOPALMData;
-   SiS_Pr->SiS_CHTVUPALNData = (SiS_LVDSDataStruct *)SiS310_CHTVUPALNData;
-   SiS_Pr->SiS_CHTVOPALNData = (SiS_LVDSDataStruct *)SiS310_CHTVOPALNData;
-   SiS_Pr->SiS_CHTVSOPALData = (SiS_LVDSDataStruct *)SiS310_CHTVSOPALData;
-
-   SiS_Pr->SiS_PanelType00_1 = (SiS_LVDSDesStruct *)SiS310_PanelType00_1;
-   SiS_Pr->SiS_PanelType01_1 = (SiS_LVDSDesStruct *)SiS310_PanelType01_1;
-   SiS_Pr->SiS_PanelType02_1 = (SiS_LVDSDesStruct *)SiS310_PanelType02_1;
-   SiS_Pr->SiS_PanelType03_1 = (SiS_LVDSDesStruct *)SiS310_PanelType03_1;
-   SiS_Pr->SiS_PanelType04_1 = (SiS_LVDSDesStruct *)SiS310_PanelType04_1;
-   SiS_Pr->SiS_PanelType05_1 = (SiS_LVDSDesStruct *)SiS310_PanelType05_1;
-   SiS_Pr->SiS_PanelType06_1 = (SiS_LVDSDesStruct *)SiS310_PanelType06_1;
-   SiS_Pr->SiS_PanelType07_1 = (SiS_LVDSDesStruct *)SiS310_PanelType07_1;
-   SiS_Pr->SiS_PanelType08_1 = (SiS_LVDSDesStruct *)SiS310_PanelType08_1;
-   SiS_Pr->SiS_PanelType09_1 = (SiS_LVDSDesStruct *)SiS310_PanelType09_1;
-   SiS_Pr->SiS_PanelType0a_1 = (SiS_LVDSDesStruct *)SiS310_PanelType0a_1;
-   SiS_Pr->SiS_PanelType0b_1 = (SiS_LVDSDesStruct *)SiS310_PanelType0b_1;
-   SiS_Pr->SiS_PanelType0c_1 = (SiS_LVDSDesStruct *)SiS310_PanelType0c_1;
-   SiS_Pr->SiS_PanelType0d_1 = (SiS_LVDSDesStruct *)SiS310_PanelType0d_1;
-   SiS_Pr->SiS_PanelType0e_1 = (SiS_LVDSDesStruct *)SiS310_PanelType0e_1;
-   SiS_Pr->SiS_PanelType0f_1 = (SiS_LVDSDesStruct *)SiS310_PanelType0f_1;
-   SiS_Pr->SiS_PanelType00_2 = (SiS_LVDSDesStruct *)SiS310_PanelType00_2;
-   SiS_Pr->SiS_PanelType01_2 = (SiS_LVDSDesStruct *)SiS310_PanelType01_2;
-   SiS_Pr->SiS_PanelType02_2 = (SiS_LVDSDesStruct *)SiS310_PanelType02_2;
-   SiS_Pr->SiS_PanelType03_2 = (SiS_LVDSDesStruct *)SiS310_PanelType03_2;
-   SiS_Pr->SiS_PanelType04_2 = (SiS_LVDSDesStruct *)SiS310_PanelType04_2;
-   SiS_Pr->SiS_PanelType05_2 = (SiS_LVDSDesStruct *)SiS310_PanelType05_2;
-   SiS_Pr->SiS_PanelType06_2 = (SiS_LVDSDesStruct *)SiS310_PanelType06_2;
-   SiS_Pr->SiS_PanelType07_2 = (SiS_LVDSDesStruct *)SiS310_PanelType07_2;
-   SiS_Pr->SiS_PanelType08_2 = (SiS_LVDSDesStruct *)SiS310_PanelType08_2;
-   SiS_Pr->SiS_PanelType09_2 = (SiS_LVDSDesStruct *)SiS310_PanelType09_2;
-   SiS_Pr->SiS_PanelType0a_2 = (SiS_LVDSDesStruct *)SiS310_PanelType0a_2;
-   SiS_Pr->SiS_PanelType0b_2 = (SiS_LVDSDesStruct *)SiS310_PanelType0b_2;
-   SiS_Pr->SiS_PanelType0c_2 = (SiS_LVDSDesStruct *)SiS310_PanelType0c_2;
-   SiS_Pr->SiS_PanelType0d_2 = (SiS_LVDSDesStruct *)SiS310_PanelType0d_2;
-   SiS_Pr->SiS_PanelType0e_2 = (SiS_LVDSDesStruct *)SiS310_PanelType0e_2;
-   SiS_Pr->SiS_PanelType0f_2 = (SiS_LVDSDesStruct *)SiS310_PanelType0f_2;
-
-   SiS_Pr->SiS_CRT2Part2_1024x768_1  = (SiS_Part2PortTblStruct *)SiS310_CRT2Part2_1024x768_1;
-   SiS_Pr->SiS_CRT2Part2_1280x1024_1 = (SiS_Part2PortTblStruct *)SiS310_CRT2Part2_1280x1024_1;
-   SiS_Pr->SiS_CRT2Part2_1400x1050_1 = (SiS_Part2PortTblStruct *)SiS310_CRT2Part2_1400x1050_1;
-   SiS_Pr->SiS_CRT2Part2_1600x1200_1 = (SiS_Part2PortTblStruct *)SiS310_CRT2Part2_1600x1200_1;
-   SiS_Pr->SiS_CRT2Part2_1024x768_2  = (SiS_Part2PortTblStruct *)SiS310_CRT2Part2_1024x768_2;
-   SiS_Pr->SiS_CRT2Part2_1280x1024_2 = (SiS_Part2PortTblStruct *)SiS310_CRT2Part2_1280x1024_2;
-   SiS_Pr->SiS_CRT2Part2_1400x1050_2 = (SiS_Part2PortTblStruct *)SiS310_CRT2Part2_1400x1050_2;
-   SiS_Pr->SiS_CRT2Part2_1600x1200_2 = (SiS_Part2PortTblStruct *)SiS310_CRT2Part2_1600x1200_2;
-   SiS_Pr->SiS_CRT2Part2_1024x768_3  = (SiS_Part2PortTblStruct *)SiS310_CRT2Part2_1024x768_3;
-   SiS_Pr->SiS_CRT2Part2_1280x1024_3 = (SiS_Part2PortTblStruct *)SiS310_CRT2Part2_1280x1024_3;
-   SiS_Pr->SiS_CRT2Part2_1400x1050_3 = (SiS_Part2PortTblStruct *)SiS310_CRT2Part2_1400x1050_3;
-   SiS_Pr->SiS_CRT2Part2_1600x1200_3 = (SiS_Part2PortTblStruct *)SiS310_CRT2Part2_1600x1200_3;
-
-   SiS_Pr->SiS_LVDSCRT1800x600_1     = (SiS_LVDSCRT1DataStruct *)SiS310_LVDSCRT1800x600_1;
-   SiS_Pr->SiS_LVDSCRT11024x768_1    = (SiS_LVDSCRT1DataStruct *)SiS310_LVDSCRT11024x768_1;
-   SiS_Pr->SiS_LVDSCRT11280x1024_1   = (SiS_LVDSCRT1DataStruct *)SiS310_LVDSCRT11280x1024_1;
-   SiS_Pr->SiS_LVDSCRT11400x1050_1   = (SiS_LVDSCRT1DataStruct *)SiS310_LVDSCRT11400x1050_1;
-   SiS_Pr->SiS_LVDSCRT11600x1200_1   = (SiS_LVDSCRT1DataStruct *)SiS310_LVDSCRT11600x1200_1;
-   SiS_Pr->SiS_LVDSCRT1800x600_1_H   = (SiS_LVDSCRT1DataStruct *)SiS310_LVDSCRT1800x600_1_H;
-   SiS_Pr->SiS_LVDSCRT11024x768_1_H  = (SiS_LVDSCRT1DataStruct *)SiS310_LVDSCRT11024x768_1_H;
-   SiS_Pr->SiS_LVDSCRT11280x1024_1_H = (SiS_LVDSCRT1DataStruct *)SiS310_LVDSCRT11280x1024_1_H;
-   SiS_Pr->SiS_LVDSCRT11400x1050_1_H = (SiS_LVDSCRT1DataStruct *)SiS310_LVDSCRT11400x1050_1_H;
-   SiS_Pr->SiS_LVDSCRT11600x1200_1_H = (SiS_LVDSCRT1DataStruct *)SiS310_LVDSCRT11600x1200_1_H;
-   SiS_Pr->SiS_LVDSCRT1800x600_2     = (SiS_LVDSCRT1DataStruct *)SiS310_LVDSCRT1800x600_2;
-   SiS_Pr->SiS_LVDSCRT11024x768_2    = (SiS_LVDSCRT1DataStruct *)SiS310_LVDSCRT11024x768_2;
-   SiS_Pr->SiS_LVDSCRT11280x1024_2   = (SiS_LVDSCRT1DataStruct *)SiS310_LVDSCRT11280x1024_2;
-   SiS_Pr->SiS_LVDSCRT11400x1050_2   = (SiS_LVDSCRT1DataStruct *)SiS310_LVDSCRT11400x1050_2;
-   SiS_Pr->SiS_LVDSCRT11600x1200_2   = (SiS_LVDSCRT1DataStruct *)SiS310_LVDSCRT11600x1200_2;
-   SiS_Pr->SiS_LVDSCRT1800x600_2_H   = (SiS_LVDSCRT1DataStruct *)SiS310_LVDSCRT1800x600_2_H;
-   SiS_Pr->SiS_LVDSCRT11024x768_2_H  = (SiS_LVDSCRT1DataStruct *)SiS310_LVDSCRT11024x768_2_H;
-   SiS_Pr->SiS_LVDSCRT11280x1024_2_H = (SiS_LVDSCRT1DataStruct *)SiS310_LVDSCRT11280x1024_2_H;
-   SiS_Pr->SiS_LVDSCRT11400x1050_2_H = (SiS_LVDSCRT1DataStruct *)SiS310_LVDSCRT11400x1050_2_H;
-   SiS_Pr->SiS_LVDSCRT11600x1200_2_H = (SiS_LVDSCRT1DataStruct *)SiS310_LVDSCRT11600x1200_2_H;
-   SiS_Pr->SiS_CHTVCRT1UNTSC         = (SiS_LVDSCRT1DataStruct *)SiS310_CHTVCRT1UNTSC;
-   SiS_Pr->SiS_CHTVCRT1ONTSC         = (SiS_LVDSCRT1DataStruct *)SiS310_CHTVCRT1ONTSC;
-   SiS_Pr->SiS_CHTVCRT1UPAL          = (SiS_LVDSCRT1DataStruct *)SiS310_CHTVCRT1UPAL;
-   SiS_Pr->SiS_CHTVCRT1OPAL          = (SiS_LVDSCRT1DataStruct *)SiS310_CHTVCRT1OPAL;
-   SiS_Pr->SiS_CHTVCRT1SOPAL         = (SiS_LVDSCRT1DataStruct *)SiS310_CHTVCRT1OPAL;
-
-   SiS_Pr->SiS_CHTVReg_UNTSC = (SiS_CHTVRegDataStruct *)SiS310_CHTVReg_UNTSC;
-   SiS_Pr->SiS_CHTVReg_ONTSC = (SiS_CHTVRegDataStruct *)SiS310_CHTVReg_ONTSC;
-   SiS_Pr->SiS_CHTVReg_UPAL  = (SiS_CHTVRegDataStruct *)SiS310_CHTVReg_UPAL;
-   SiS_Pr->SiS_CHTVReg_OPAL  = (SiS_CHTVRegDataStruct *)SiS310_CHTVReg_OPAL;
-   SiS_Pr->SiS_CHTVReg_UPALM = (SiS_CHTVRegDataStruct *)SiS310_CHTVReg_UPALM;
-   SiS_Pr->SiS_CHTVReg_OPALM = (SiS_CHTVRegDataStruct *)SiS310_CHTVReg_OPALM;
-   SiS_Pr->SiS_CHTVReg_UPALN = (SiS_CHTVRegDataStruct *)SiS310_CHTVReg_UPALN;
-   SiS_Pr->SiS_CHTVReg_OPALN = (SiS_CHTVRegDataStruct *)SiS310_CHTVReg_OPALN;
-   SiS_Pr->SiS_CHTVReg_SOPAL = (SiS_CHTVRegDataStruct *)SiS310_CHTVReg_OPAL;
-
-   SiS_Pr->SiS_LCDACRT11024x768_1    = (SiS_LCDACRT1DataStruct *)SiS310_LCDACRT11024x768_1;
-   SiS_Pr->SiS_LCDACRT11280x1024_1   = (SiS_LCDACRT1DataStruct *)SiS310_LCDACRT11280x1024_1;
-   SiS_Pr->SiS_LCDACRT11400x1050_1   = (SiS_LCDACRT1DataStruct *)SiS310_LCDACRT11400x1050_1;
-   SiS_Pr->SiS_LCDACRT11600x1200_1   = (SiS_LCDACRT1DataStruct *)SiS310_LCDACRT11600x1200_1;
-   SiS_Pr->SiS_LCDACRT11024x768_1_H  = (SiS_LCDACRT1DataStruct *)SiS310_LCDACRT11024x768_1_H;
-   SiS_Pr->SiS_LCDACRT11280x1024_1_H = (SiS_LCDACRT1DataStruct *)SiS310_LCDACRT11280x1024_1_H;
-   SiS_Pr->SiS_LCDACRT11400x1050_1_H = (SiS_LCDACRT1DataStruct *)SiS310_LCDACRT11400x1050_1_H;
-   SiS_Pr->SiS_LCDACRT11600x1200_1_H = (SiS_LCDACRT1DataStruct *)SiS310_LCDACRT11600x1200_1_H;
-   SiS_Pr->SiS_LCDACRT11024x768_2    = (SiS_LCDACRT1DataStruct *)SiS310_LCDACRT11024x768_2;
-   SiS_Pr->SiS_LCDACRT11280x1024_2   = (SiS_LCDACRT1DataStruct *)SiS310_LCDACRT11280x1024_2;
-   SiS_Pr->SiS_LCDACRT11400x1050_2   = (SiS_LCDACRT1DataStruct *)SiS310_LCDACRT11400x1050_2;
-   SiS_Pr->SiS_LCDACRT11600x1200_2   = (SiS_LCDACRT1DataStruct *)SiS310_LCDACRT11600x1200_2;
-   SiS_Pr->SiS_LCDACRT11024x768_2_H  = (SiS_LCDACRT1DataStruct *)SiS310_LCDACRT11024x768_2_H;
-   SiS_Pr->SiS_LCDACRT11280x1024_2_H = (SiS_LCDACRT1DataStruct *)SiS310_LCDACRT11280x1024_2_H;
-   SiS_Pr->SiS_LCDACRT11400x1050_2_H = (SiS_LCDACRT1DataStruct *)SiS310_LCDACRT11400x1050_2_H;
-   SiS_Pr->SiS_LCDACRT11600x1200_2_H = (SiS_LCDACRT1DataStruct *)SiS310_LCDACRT11600x1200_2_H;
+   SiS_Pr->SiS_PanelDelayTbl     = SiS310_PanelDelayTbl;
+   SiS_Pr->SiS_PanelDelayTblLVDS = SiS310_PanelDelayTblLVDS;
+
+   SiS_Pr->SiS_St2LCD1024x768Data   = SiS310_St2LCD1024x768Data;
+   SiS_Pr->SiS_ExtLCD1024x768Data   = SiS310_ExtLCD1024x768Data;
+   SiS_Pr->SiS_St2LCD1280x1024Data  = SiS310_St2LCD1280x1024Data;
+   SiS_Pr->SiS_ExtLCD1280x1024Data  = SiS310_ExtLCD1280x1024Data;
+
+   SiS_Pr->SiS_CRT2Part2_1024x768_1  = SiS310_CRT2Part2_1024x768_1;
+
+   SiS_Pr->SiS_PanelType00_1 = SiS310_PanelType00_1;
+   SiS_Pr->SiS_PanelType01_1 = SiS310_PanelType01_1;
+   SiS_Pr->SiS_PanelType02_1 = SiS310_PanelType02_1;
+   SiS_Pr->SiS_PanelType03_1 = SiS310_PanelType03_1;
+   SiS_Pr->SiS_PanelType04_1 = SiS310_PanelType04_1;
+   SiS_Pr->SiS_PanelType05_1 = SiS310_PanelType05_1;
+   SiS_Pr->SiS_PanelType06_1 = SiS310_PanelType06_1;
+   SiS_Pr->SiS_PanelType07_1 = SiS310_PanelType07_1;
+   SiS_Pr->SiS_PanelType08_1 = SiS310_PanelType08_1;
+   SiS_Pr->SiS_PanelType09_1 = SiS310_PanelType09_1;
+   SiS_Pr->SiS_PanelType0a_1 = SiS310_PanelType0a_1;
+   SiS_Pr->SiS_PanelType0b_1 = SiS310_PanelType0b_1;
+   SiS_Pr->SiS_PanelType0c_1 = SiS310_PanelType0c_1;
+   SiS_Pr->SiS_PanelType0d_1 = SiS310_PanelType0d_1;
+   SiS_Pr->SiS_PanelType0e_1 = SiS310_PanelType0e_1;
+   SiS_Pr->SiS_PanelType0f_1 = SiS310_PanelType0f_1;
+   SiS_Pr->SiS_PanelType00_2 = SiS310_PanelType00_2;
+   SiS_Pr->SiS_PanelType01_2 = SiS310_PanelType01_2;
+   SiS_Pr->SiS_PanelType02_2 = SiS310_PanelType02_2;
+   SiS_Pr->SiS_PanelType03_2 = SiS310_PanelType03_2;
+   SiS_Pr->SiS_PanelType04_2 = SiS310_PanelType04_2;
+   SiS_Pr->SiS_PanelType05_2 = SiS310_PanelType05_2;
+   SiS_Pr->SiS_PanelType06_2 = SiS310_PanelType06_2;
+   SiS_Pr->SiS_PanelType07_2 = SiS310_PanelType07_2;
+   SiS_Pr->SiS_PanelType08_2 = SiS310_PanelType08_2;
+   SiS_Pr->SiS_PanelType09_2 = SiS310_PanelType09_2;
+   SiS_Pr->SiS_PanelType0a_2 = SiS310_PanelType0a_2;
+   SiS_Pr->SiS_PanelType0b_2 = SiS310_PanelType0b_2;
+   SiS_Pr->SiS_PanelType0c_2 = SiS310_PanelType0c_2;
+   SiS_Pr->SiS_PanelType0d_2 = SiS310_PanelType0d_2;
+   SiS_Pr->SiS_PanelType0e_2 = SiS310_PanelType0e_2;
+   SiS_Pr->SiS_PanelType0f_2 = SiS310_PanelType0f_2;
+   SiS_Pr->SiS_PanelTypeNS_1 = SiS310_PanelTypeNS_1;
+   SiS_Pr->SiS_PanelTypeNS_2 = SiS310_PanelTypeNS_2;
+
+   SiS_Pr->SiS_CHTVUPALData  = SiS310_CHTVUPALData;
+   SiS_Pr->SiS_CHTVOPALData  = SiS310_CHTVOPALData;
+   SiS_Pr->SiS_CHTVUPALMData = SiS310_CHTVUPALMData;
+   SiS_Pr->SiS_CHTVOPALMData = SiS310_CHTVOPALMData;
+   SiS_Pr->SiS_CHTVUPALNData = SiS310_CHTVUPALNData;
+   SiS_Pr->SiS_CHTVOPALNData = SiS310_CHTVOPALNData;
+   SiS_Pr->SiS_CHTVSOPALData = SiS310_CHTVSOPALData;
+
+   SiS_Pr->SiS_LVDSCRT1800x600_1     = SiS310_LVDSCRT1800x600_1;
+   SiS_Pr->SiS_LVDSCRT11024x768_1    = SiS310_LVDSCRT11024x768_1;
+   SiS_Pr->SiS_LVDSCRT11280x1024_1   = SiS310_LVDSCRT11280x1024_1;
+   SiS_Pr->SiS_LVDSCRT11400x1050_1   = SiS310_LVDSCRT11400x1050_1;
+   SiS_Pr->SiS_LVDSCRT11600x1200_1   = SiS310_LVDSCRT11600x1200_1;
+   SiS_Pr->SiS_LVDSCRT1800x600_1_H   = SiS310_LVDSCRT1800x600_1_H;
+   SiS_Pr->SiS_LVDSCRT11024x768_1_H  = SiS310_LVDSCRT11024x768_1_H;
+   SiS_Pr->SiS_LVDSCRT11280x1024_1_H = SiS310_LVDSCRT11280x1024_1_H;
+   SiS_Pr->SiS_LVDSCRT11400x1050_1_H = SiS310_LVDSCRT11400x1050_1_H;
+   SiS_Pr->SiS_LVDSCRT11600x1200_1_H = SiS310_LVDSCRT11600x1200_1_H;
+   SiS_Pr->SiS_LVDSCRT1800x600_2     = SiS310_LVDSCRT1800x600_2;
+   SiS_Pr->SiS_LVDSCRT11024x768_2    = SiS310_LVDSCRT11024x768_2;
+   SiS_Pr->SiS_LVDSCRT11280x1024_2   = SiS310_LVDSCRT11280x1024_2;
+   SiS_Pr->SiS_LVDSCRT11400x1050_2   = SiS310_LVDSCRT11400x1050_2;
+   SiS_Pr->SiS_LVDSCRT11600x1200_2   = SiS310_LVDSCRT11600x1200_2;
+   SiS_Pr->SiS_LVDSCRT1800x600_2_H   = SiS310_LVDSCRT1800x600_2_H;
+   SiS_Pr->SiS_LVDSCRT11024x768_2_H  = SiS310_LVDSCRT11024x768_2_H;
+   SiS_Pr->SiS_LVDSCRT11280x1024_2_H = SiS310_LVDSCRT11280x1024_2_H;
+   SiS_Pr->SiS_LVDSCRT11400x1050_2_H = SiS310_LVDSCRT11400x1050_2_H;
+   SiS_Pr->SiS_LVDSCRT11600x1200_2_H = SiS310_LVDSCRT11600x1200_2_H;
+   SiS_Pr->SiS_LVDSCRT1XXXxXXX_1     = SiS310_LVDSCRT1XXXxXXX_1;
+   SiS_Pr->SiS_LVDSCRT1XXXxXXX_1_H   = SiS310_LVDSCRT1XXXxXXX_1_H;
+   SiS_Pr->SiS_CHTVCRT1UNTSC         = SiS310_CHTVCRT1UNTSC;
+   SiS_Pr->SiS_CHTVCRT1ONTSC         = SiS310_CHTVCRT1ONTSC;
+   SiS_Pr->SiS_CHTVCRT1UPAL          = SiS310_CHTVCRT1UPAL;
+   SiS_Pr->SiS_CHTVCRT1OPAL          = SiS310_CHTVCRT1OPAL;
+   SiS_Pr->SiS_CHTVCRT1SOPAL         = SiS310_CHTVCRT1OPAL;
+
+   SiS_Pr->SiS_CHTVReg_UNTSC = SiS310_CHTVReg_UNTSC;
+   SiS_Pr->SiS_CHTVReg_ONTSC = SiS310_CHTVReg_ONTSC;
+   SiS_Pr->SiS_CHTVReg_UPAL  = SiS310_CHTVReg_UPAL;
+   SiS_Pr->SiS_CHTVReg_OPAL  = SiS310_CHTVReg_OPAL;
+   SiS_Pr->SiS_CHTVReg_UPALM = SiS310_CHTVReg_UPALM;
+   SiS_Pr->SiS_CHTVReg_OPALM = SiS310_CHTVReg_OPALM;
+   SiS_Pr->SiS_CHTVReg_UPALN = SiS310_CHTVReg_UPALN;
+   SiS_Pr->SiS_CHTVReg_OPALN = SiS310_CHTVReg_OPALN;
+   SiS_Pr->SiS_CHTVReg_SOPAL = SiS310_CHTVReg_OPAL;
 
    SiS_Pr->SiS_CHTVVCLKUNTSC = SiS310_CHTVVCLKUNTSC;
    SiS_Pr->SiS_CHTVVCLKONTSC = SiS310_CHTVVCLKONTSC;
@@ -648,28 +571,8 @@
    SiS_Pr->SiS_CHTVVCLKUPALM = SiS310_CHTVVCLKUPALM;
    SiS_Pr->SiS_CHTVVCLKOPALM = SiS310_CHTVVCLKOPALM;
    SiS_Pr->SiS_CHTVVCLKUPALN = SiS310_CHTVVCLKUPALN;
-   SiS_Pr->SiS_CHTVVCLKOPALN = SiS310_CHTVVCLKOPALN;   
+   SiS_Pr->SiS_CHTVVCLKOPALN = SiS310_CHTVVCLKOPALN;
    SiS_Pr->SiS_CHTVVCLKSOPAL = SiS310_CHTVVCLKOPAL;
-
-   SiS_Pr->SiS_Panel320x480   = Panel_320x480;
-   SiS_Pr->SiS_Panel640x480   = Panel_640x480;
-   SiS_Pr->SiS_Panel800x600   = Panel_800x600;
-   SiS_Pr->SiS_Panel1024x768  = Panel_1024x768;
-   SiS_Pr->SiS_Panel1280x1024 = Panel_1280x1024;
-   SiS_Pr->SiS_Panel1280x960  = Panel_1280x960;
-   SiS_Pr->SiS_Panel1600x1200 = Panel_1600x1200;
-   SiS_Pr->SiS_Panel1400x1050 = Panel_1400x1050;
-   SiS_Pr->SiS_Panel1152x768  = Panel_1152x768;
-   SiS_Pr->SiS_Panel1152x864  = Panel_1152x864;
-   SiS_Pr->SiS_Panel1280x768  = Panel_1280x768;
-   SiS_Pr->SiS_Panel1024x600  = Panel_1024x600;
-   SiS_Pr->SiS_Panel640x480_2 = Panel_640x480_2;
-   SiS_Pr->SiS_Panel640x480_3 = Panel_640x480_3;
-   SiS_Pr->SiS_PanelMax       = Panel_320x480;    /* highest value */
-   SiS_Pr->SiS_PanelMinLVDS   = Panel_800x600;    /* lowest value LVDS/LCDA */
-   SiS_Pr->SiS_PanelMin301    = Panel_1024x768;   /* lowest value 301 */
-   SiS_Pr->SiS_PanelCustom    = Panel_Custom;
-   SiS_Pr->SiS_PanelBarco1366 = 255;
 }
 #endif
 
@@ -710,7 +613,8 @@
 /*********************************************/
 
 USHORT
-SiS_GetModeID(int VGAEngine, ULONG VBFlags, int HDisplay, int VDisplay, int Depth, BOOLEAN FSTN)
+SiS_GetModeID(int VGAEngine, ULONG VBFlags, int HDisplay, int VDisplay,
+              int Depth, BOOLEAN FSTN, int LCDwidth, int LCDheight)
 {
    USHORT ModeIndex = 0;
 
@@ -734,54 +638,58 @@
 	  else if(VDisplay == 400) ModeIndex = ModeIndex_640x400[Depth];
           break;
      case 720:
-          if(!(VBFlags & CRT1_LCDA)) {
-             if(VDisplay == 480)      ModeIndex = ModeIndex_720x480[Depth];
-             else if(VDisplay == 576) ModeIndex = ModeIndex_720x576[Depth];
-          }
+          if(VDisplay == 480)      ModeIndex = ModeIndex_720x480[Depth];
+          else if(VDisplay == 576) ModeIndex = ModeIndex_720x576[Depth];
           break;
      case 768:
-          if(!(VBFlags & CRT1_LCDA)) {
-             if(VDisplay == 576) ModeIndex = ModeIndex_768x576[Depth];
-          }
+          if(VDisplay == 576) ModeIndex = ModeIndex_768x576[Depth];
 	  break;
      case 800:
-	  if(VDisplay == 600)    ModeIndex = ModeIndex_800x600[Depth];
-	  else if(!(VBFlags & CRT1_LCDA)) {
-	     if(VDisplay == 480) ModeIndex = ModeIndex_800x480[Depth];
-	  }
+	  if(VDisplay == 600)      ModeIndex = ModeIndex_800x600[Depth];
+	  else if(VDisplay == 480) ModeIndex = ModeIndex_800x480[Depth];
           break;
      case 848:
-          if(!(VBFlags & CRT1_LCDA)) {
-	     if(VDisplay == 480) ModeIndex = ModeIndex_848x480[Depth];
-	  }
+	  if(VDisplay == 480) ModeIndex = ModeIndex_848x480[Depth];
 	  break;
      case 856:
-          if(!(VBFlags & CRT1_LCDA)) {
-	     if(VDisplay == 480) ModeIndex = ModeIndex_856x480[Depth];
+	  if(VDisplay == 480) ModeIndex = ModeIndex_856x480[Depth];
+	  break;
+     case 960:
+	  if(VGAEngine == SIS_315_VGA) {
+	     if(VDisplay == 540) ModeIndex = ModeIndex_960x540[Depth];
 	  }
 	  break;
      case 1024:
-          if(VDisplay == 768) ModeIndex = ModeIndex_1024x768[Depth];
-	  else if(!(VBFlags & CRT1_LCDA)) {
-	     if(VDisplay == 576)    ModeIndex = ModeIndex_1024x576[Depth];
-	     else if(VGAEngine == SIS_300_VGA) {
-	        if(VDisplay == 600) ModeIndex = ModeIndex_1024x600[Depth];
-             }
+          if(VDisplay == 768)      ModeIndex = ModeIndex_1024x768[Depth];
+	  else if(VDisplay == 576) ModeIndex = ModeIndex_1024x576[Depth];
+	  else if((!(VBFlags & CRT1_LCDA)) && (VGAEngine == SIS_300_VGA)) {
+	     if(VDisplay == 600) ModeIndex = ModeIndex_1024x600[Depth];
 	  }
           break;
      case 1152:
-          if(!(VBFlags & CRT1_LCDA)) {
-             if(VDisplay == 864)    ModeIndex = ModeIndex_1152x864[Depth];
-             else if(VGAEngine == SIS_300_VGA) {
-	        if(VDisplay == 768) ModeIndex = ModeIndex_1152x768[Depth];
-             }
+          if(VDisplay == 864) ModeIndex = ModeIndex_1152x864[Depth];
+          if((!(VBFlags & CRT1_LCDA)) && (VGAEngine == SIS_300_VGA)) {
+	     if(VDisplay == 768) ModeIndex = ModeIndex_1152x768[Depth];
 	  }
 	  break;
      case 1280:
-          if(VDisplay == 1024)        ModeIndex = ModeIndex_1280x1024[Depth];
-	  else if(!(VBFlags & CRT1_LCDA)) {
-             if(VDisplay == 960)      ModeIndex = ModeIndex_1280x960[Depth];
-	     else if(VDisplay == 720) ModeIndex = ModeIndex_1280x720[Depth];
+          if(VDisplay == 1024) ModeIndex = ModeIndex_1280x1024[Depth];
+	  else if(VDisplay == 800) {
+	     if(VGAEngine == SIS_315_VGA) {
+	        if((VBFlags & CRT1_LCDA) && (LCDwidth == 1280) && (LCDheight == 800)) {
+	           ModeIndex = ModeIndex_1280x800[Depth];
+	        } else if(!(VBFlags & CRT1_LCDA)) {
+	           ModeIndex = ModeIndex_1280x800[Depth];
+	        }
+	     }
+	  } else if(VDisplay == 720) {
+	     if((VBFlags & CRT1_LCDA) && (LCDwidth == 1280) && (LCDheight == 720)) {
+	        ModeIndex = ModeIndex_1280x720[Depth];
+	     } else if(!(VBFlags & CRT1_LCDA)) {
+	        ModeIndex = ModeIndex_1280x720[Depth];
+	     }
+	  } else if(!(VBFlags & CRT1_LCDA)) {
+             if(VDisplay == 960) ModeIndex = ModeIndex_1280x960[Depth];
 	     else if(VDisplay == 768) {
 	        if(VGAEngine == SIS_300_VGA) {
 	           ModeIndex = ModeIndex_300_1280x768[Depth];
@@ -792,23 +700,39 @@
 	  }
           break;
      case 1360:
+          if(VDisplay == 768) ModeIndex = ModeIndex_1360x768[Depth];
           if(!(VBFlags & CRT1_LCDA)) {
-	     if(VDisplay == 768)     ModeIndex = ModeIndex_1360x768[Depth];
-	     else if(VGAEngine == SIS_300_VGA) {
+	     if(VGAEngine == SIS_300_VGA) {
 	        if(VDisplay == 1024) ModeIndex = ModeIndex_300_1360x1024[Depth];
              }
 	  }
           break;
      case 1400:
           if(VGAEngine == SIS_315_VGA) {
-	     if(VDisplay == 1050) ModeIndex = ModeIndex_1400x1050[Depth];
+	     if(VDisplay == 1050) {
+	        if((VBFlags & CRT1_LCDA) &&
+	           (((LCDwidth == 1400) && (LCDheight == 1050)) ||
+		    ((LCDwidth == 1600) && (LCDheight == 1200)))) {
+	           ModeIndex = ModeIndex_1400x1050[Depth];
+	        } else if(!(VBFlags & CRT1_LCDA)) {
+	           ModeIndex = ModeIndex_1400x1050[Depth];
+	        }
+	     }
 	  }
           break;
      case 1600:
           if(VDisplay == 1200) ModeIndex = ModeIndex_1600x1200[Depth];
           break;
+     case 1680:
+          if(VGAEngine == SIS_315_VGA) {
+             if(VDisplay == 1050) ModeIndex = ModeIndex_1680x1050[Depth];
+	  }
+          break;
      case 1920:
           if(!(VBFlags & CRT1_LCDA)) {
+	     if(VGAEngine == SIS_315_VGA) {
+	        if(VDisplay == 1080) ModeIndex = ModeIndex_1920x1080[Depth];
+	     }
              if(VDisplay == 1440) ModeIndex = ModeIndex_1920x1440[Depth];
 	  }
           break;
@@ -851,14 +775,18 @@
              break;
      	case 400:
 	     if(CustomT != CUT_PANEL848) {
-          	if(VDisplay == 300) ModeIndex = ModeIndex_400x300[Depth];
+	        if(!((VGAEngine == SIS_300_VGA) && (VBFlags & VB_TRUMPION))) {
+          	   if(VDisplay == 300) ModeIndex = ModeIndex_400x300[Depth];
+		}
 	     }
              break;
 	case 512:
 	     if(CustomT != CUT_PANEL848) {
-		if(VDisplay == 384) {
+	        if(!((VGAEngine == SIS_300_VGA) && (VBFlags & VB_TRUMPION))) {
 		   if(LCDwidth != 1024 || LCDheight != 600) {
-		      ModeIndex = ModeIndex_512x384[Depth];
+		      if(VDisplay == 384) {
+		         ModeIndex = ModeIndex_512x384[Depth];
+		      }
 		   }
 		}
 	     }
@@ -898,6 +826,9 @@
 	        if((VDisplay == 768) && (LCDheight == 768)) {
 		   ModeIndex = ModeIndex_310_1280x768[Depth];
 		}
+		if((VDisplay == 800) && (LCDheight == 800)) {
+		   ModeIndex = ModeIndex_310_1280x768[Depth];
+		}
 	     }
 	     break;
 	case 1360:
@@ -940,17 +871,54 @@
 	     if(VDisplay == 480)      ModeIndex = ModeIndex_640x480[Depth];
 	     else if(VDisplay == 400) ModeIndex = ModeIndex_640x400[Depth];
 	     break;
+	case 720:
+	     if(VGAEngine == SIS_315_VGA) {
+	        if(VDisplay == 480)      ModeIndex = ModeIndex_720x480[Depth];
+		else if(VDisplay == 576) ModeIndex = ModeIndex_720x576[Depth];
+	     }
+	     break;
+	case 768:
+	     if(VGAEngine == SIS_315_VGA) {
+	        if(VDisplay == 576) ModeIndex = ModeIndex_768x576[Depth];
+	     }
+	     break;
 	case 800:
 	     if(VDisplay == 600) ModeIndex = ModeIndex_800x600[Depth];
+	     if(VGAEngine == SIS_315_VGA) {
+	        if(VDisplay == 480) ModeIndex = ModeIndex_800x480[Depth];
+	     }
+	     break;
+	case 848:
+	     if(VGAEngine == SIS_315_VGA) {
+	        if(VDisplay == 480) ModeIndex = ModeIndex_848x480[Depth];
+	     }
+	     break;
+	case 856:
+	     if(VGAEngine == SIS_315_VGA) {
+	        if(VDisplay == 480) ModeIndex = ModeIndex_856x480[Depth];
+	     }
+	     break;
+	case 960:
+	     if(VGAEngine == SIS_315_VGA) {
+	        if(VDisplay == 540) ModeIndex = ModeIndex_960x540[Depth];
+	     }
 	     break;
 	case 1024:
 	     if(VDisplay == 768) ModeIndex = ModeIndex_1024x768[Depth];
+	     if(VGAEngine == SIS_315_VGA) {
+	        if(VDisplay == 576) ModeIndex = ModeIndex_1024x576[Depth];
+	     }
+	     break;
+	case 1152:
+	     if(VGAEngine == SIS_315_VGA) {
+	        if(VDisplay == 864) ModeIndex = ModeIndex_1152x864[Depth];
+	     }
 	     break;
 	case 1280:
 	     if(VDisplay == 1024) ModeIndex = ModeIndex_1280x1024[Depth];
 	     else if(VDisplay == 768) {
-		if((LCDheight == 768) ||
-		   ((LCDheight == 1024) && (VBFlags & (VB_301|VB_301B|VB_301C|VB_302B)))) {
+		if((LCDheight == 768) ||  (LCDwidth == 1680) ||
+		   (VBFlags & VB_SISTMDS)) {
 		   if(VGAEngine == SIS_300_VGA) {
 		      ModeIndex = ModeIndex_300_1280x768[Depth];
 		   } else {
@@ -958,24 +926,49 @@
 		   }
 		}
 	     } else if(VDisplay == 960) {
-	        if((LCDheight == 960) ||
-		   ((LCDheight == 1024) && (VBFlags & (VB_301|VB_301B|VB_301C|VB_302B)))) {
+	        if((LCDheight == 960) || (VBFlags & VB_SISTMDS)) {
 		   ModeIndex = ModeIndex_1280x960[Depth];
 		}
+	     } else if(VGAEngine == SIS_315_VGA) {
+	        if(VDisplay == 800) {
+		   if((LCDheight == 800) || (LCDwidth == 1680) ||
+		      (VBFlags & VB_SISTMDS)) {
+		      ModeIndex = ModeIndex_1280x800[Depth];
+		   }
+		} else if(VDisplay == 720) {
+		   if((LCDheight == 720) || (LCDwidth == 1680) || (LCDwidth == 1400) ||
+		      (VBFlags & VB_SISTMDS)) {
+		      ModeIndex = ModeIndex_1280x720[Depth];
+		   }
+		}
+	     }
+	     break;
+	case 1360:
+	     if(VGAEngine == SIS_315_VGA) {
+	        if(VDisplay == 768) ModeIndex = ModeIndex_1360x768[Depth];
 	     }
 	     break;
 	case 1400:
 	     if(VGAEngine == SIS_315_VGA) {
 	        if(VBFlags & (VB_301B | VB_301C | VB_302B | VB_302LV | VB_302ELV)) {
-		   if(LCDheight != 1200) {
-	              if(VDisplay == 1050) ModeIndex = ModeIndex_1400x1050[Depth];
+		   if((LCDwidth == 1400) || (LCDwidth == 1600) || (LCDwidth == 1680)) {
+		      ModeIndex = ModeIndex_1400x1050[Depth];
 		   }
 		}
 	     }
 	     break;
 	case 1600:
-	     if(VBFlags & (VB_301C | VB_302B | VB_302LV | VB_302ELV)) {
-	        if(VDisplay == 1200) ModeIndex = ModeIndex_1600x1200[Depth];
+	     if(VGAEngine == SIS_315_VGA) {
+	        if(VBFlags & (VB_301C | VB_302B | VB_302LV | VB_302ELV)) {
+	           if(VDisplay == 1200) ModeIndex = ModeIndex_1600x1200[Depth];
+		}
+	     }
+	     break;
+	case 1680:
+	     if(VGAEngine == SIS_315_VGA) {
+	        if(VBFlags & (VB_301C | VB_302B | VB_302LV | VB_302ELV)) {
+	           if(VDisplay == 1050) ModeIndex = ModeIndex_1680x1050[Depth];
+		}
 	     }
 	     break;
       }
@@ -1024,8 +1017,8 @@
              if(VDisplay == 300) ModeIndex = ModeIndex_400x300[Depth];
              break;
       	case 512:
-	     if( ((VBFlags & TV_YPBPR) && (VBFlags & (TV_YPBPR525P | TV_YPBPR750P | TV_YPBPR1080I))) ||
-	         (VBFlags & TV_HIVISION) 					    		     ||
+	     if( ((VBFlags & TV_YPBPR) && (VBFlags & (TV_YPBPR750P | TV_YPBPR1080I))) ||
+	         (VBFlags & TV_HIVISION) 					      ||
 	         ((!(VBFlags & (TV_YPBPR | TV_PALM))) && (VBFlags & TV_PAL)) ) {
 	        if(VDisplay == 384) ModeIndex = ModeIndex_512x384[Depth];
 	     }
@@ -1037,17 +1030,19 @@
 	case 720:
 	     if((!(VBFlags & TV_HIVISION)) && (!((VBFlags & TV_YPBPR) && (VBFlags & TV_YPBPR1080I)))) {
                 if(VDisplay == 480) {
-		   if((VBFlags & TV_YPBPR) || (VBFlags & (TV_NTSC | TV_PALM)))
+		   /* if((VBFlags & TV_YPBPR) || (VBFlags & (TV_NTSC | TV_PALM))) */
                       ModeIndex = ModeIndex_720x480[Depth];
                 } else if(VDisplay == 576) {
-		   if((!(VBFlags & (TV_YPBPR | TV_PALM))) && (VBFlags & TV_PAL))
+		   if( ((VBFlags & TV_YPBPR) && (VBFlags & TV_YPBPR750P)) ||
+		       ((!(VBFlags & (TV_YPBPR | TV_PALM))) && (VBFlags & TV_PAL)) )
                       ModeIndex = ModeIndex_720x576[Depth];
                 }
 	     }
              break;
 	case 768:
 	     if((!(VBFlags & TV_HIVISION)) && (!((VBFlags & TV_YPBPR) && (VBFlags & TV_YPBPR1080I)))) {
-	        if((!(VBFlags & (TV_YPBPR | TV_PALM))) && (VBFlags & TV_PAL)) {
+	        if( ((VBFlags & TV_YPBPR) && (VBFlags & TV_YPBPR750P)) ||
+		    ((!(VBFlags & (TV_YPBPR | TV_PALM))) && (VBFlags & TV_PAL)) ) {
           	   if(VDisplay == 576) ModeIndex = ModeIndex_768x576[Depth];
 		}
              }
@@ -1072,9 +1067,16 @@
 	     }
 	     break;
 	case 1280:
-	     if((VBFlags & TV_HIVISION) || ((VBFlags & TV_YPBPR) && (VBFlags & TV_YPBPR1080I))) {
-	        if(VDisplay == 720)       ModeIndex = ModeIndex_1280x720[Depth];
-		else if(VDisplay == 1024) ModeIndex = ModeIndex_1280x1024[Depth];
+	     if(VDisplay == 720) {
+	        if((VBFlags & TV_HIVISION) ||
+		   ((VBFlags & TV_YPBPR) && (VBFlags & (TV_YPBPR1080I | TV_YPBPR750P)))) {
+	           ModeIndex = ModeIndex_1280x720[Depth];
+		}
+	     } else if(VDisplay == 1024) {
+	        if((VBFlags & TV_HIVISION) ||
+		   ((VBFlags & TV_YPBPR) && (VBFlags & TV_YPBPR1080I))) {
+	           ModeIndex = ModeIndex_1280x1024[Depth];
+		}
 	     }
 	     break;
       }
@@ -1122,6 +1124,11 @@
 	case 856:
 		if(VDisplay == 480) ModeIndex = ModeIndex_856x480[Depth];
 		break;
+	case 960:
+		if(VGAEngine == SIS_315_VGA) {
+		   if(VDisplay == 540) ModeIndex = ModeIndex_960x540[Depth];
+		}
+		break;
 	case 1024:
 		if(VDisplay == 768)      ModeIndex = ModeIndex_1024x768[Depth];
 		else if(VDisplay == 576) ModeIndex = ModeIndex_1024x576[Depth];
@@ -1141,6 +1148,7 @@
 		   }
 		} else if(VDisplay == 1024) ModeIndex = ModeIndex_1280x1024[Depth];
 		else if(VDisplay == 720)    ModeIndex = ModeIndex_1280x720[Depth];
+		else if(VDisplay == 800)    ModeIndex = ModeIndex_1280x800[Depth];
 		else if(VDisplay == 960)    ModeIndex = ModeIndex_1280x960[Depth];
 		break;
         case 1360:
@@ -1158,6 +1166,13 @@
 		   }
 		}
 		break;
+	case 1680:
+		if(VGAEngine == SIS_315_VGA) {
+		   if(VBFlags & (VB_301B|VB_301C|VB_302B)) {
+	              if(VDisplay == 1050) ModeIndex = ModeIndex_1680x1050[Depth];
+		   }
+		}
+		break;
    }
 
    return ModeIndex;
@@ -1255,13 +1270,13 @@
 void
 SiS_DisplayOn(SiS_Private *SiS_Pr)
 {
-   SiS_SetRegANDOR(SiS_Pr->SiS_P3c4,0x01,0xDF,0x00);
+   SiS_SetRegAND(SiS_Pr->SiS_P3c4,0x01,0xDF);
 }
 
 void
 SiS_DisplayOff(SiS_Private *SiS_Pr)
 {
-   SiS_SetRegANDOR(SiS_Pr->SiS_P3c4,0x01,0xDF,0x20);
+   SiS_SetRegOR(SiS_Pr->SiS_P3c4,0x01,0x20);
 }
 
 
@@ -1308,9 +1323,11 @@
    /* (SR11 is used for DDC and in enable/disablebridge) */
    SiS_Pr->SiS_SensibleSR11 = FALSE;
    SiS_Pr->SiS_MyCR63 = 0x63;
-   if(HwInfo->jChipType >= SIS_661) {
-      SiS_Pr->SiS_SensibleSR11 = TRUE;
+   if(HwInfo->jChipType >= SIS_330) {
       SiS_Pr->SiS_MyCR63 = 0x53;
+      if(HwInfo->jChipType >= SIS_661) {
+         SiS_Pr->SiS_SensibleSR11 = TRUE;
+      }
    }
 
    /* You should use the macros, not these flags directly */
@@ -1350,6 +1367,10 @@
 	 }
       }
    }
+   if(HwInfo->jChipType == SIS_760) {
+      temp1 = SiS_GetReg(SiS_Pr->SiS_P3d4,0x78);
+      if(temp1 & 0x30) SiS_Pr->SiS_SysFlags |= SF_760LFB;
+   }
 }
 
 /*********************************************/
@@ -1411,7 +1432,7 @@
 void
 SiSSetLVDSetc(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo)
 {
-   ULONG   temp;
+   USHORT temp;
 
    SiS_Pr->SiS_IF_DEF_LVDS = 0;
    SiS_Pr->SiS_IF_DEF_TRUMPION = 0;
@@ -1422,18 +1443,19 @@
 
    SiS_Pr->SiS_ChrontelInit = 0;
 
+   /* Check for SiS30x first */
+   temp = SiS_GetReg(SiS_Pr->SiS_Part4Port,0x00);
+   if((temp == 1) || (temp == 2)) return;
+
    switch(HwInfo->jChipType) {
 #ifdef SIS300
    case SIS_540:
    case SIS_630:
    case SIS_730:
-        /* Check for SiS30x first */
-        temp = SiS_GetReg(SiS_Pr->SiS_Part4Port,0x00);
-	if((temp == 1) || (temp == 2)) return;
       	temp = SiS_GetReg(SiS_Pr->SiS_P3d4,0x37);
       	temp = (temp & 0x0E) >> 1;
-      	if((temp >= 2) && (temp <= 5)) SiS_Pr->SiS_IF_DEF_LVDS = 1;
-      	if(temp == 3)   SiS_Pr->SiS_IF_DEF_TRUMPION = 1;
+      	if((temp >= 2) && (temp <= 5)) 	SiS_Pr->SiS_IF_DEF_LVDS = 1;
+      	if(temp == 3)   		SiS_Pr->SiS_IF_DEF_TRUMPION = 1;
       	if((temp == 4) || (temp == 5)) {
 		/* Save power status (and error check) - UNUSED */
 		SiS_Pr->SiS_Backup70xx = SiS_GetCH700x(SiS_Pr, 0x0e);
@@ -1448,8 +1470,8 @@
    case SIS_330:
         temp = SiS_GetReg(SiS_Pr->SiS_P3d4,0x37);
       	temp = (temp & 0x0E) >> 1;
-      	if((temp >= 2) && (temp <= 3)) SiS_Pr->SiS_IF_DEF_LVDS = 1;
-      	if(temp == 3)  SiS_Pr->SiS_IF_DEF_CH70xx = 2;
+      	if((temp >= 2) && (temp <= 3)) 	SiS_Pr->SiS_IF_DEF_LVDS = 1;
+      	if(temp == 3)  			SiS_Pr->SiS_IF_DEF_CH70xx = 2;
         break;
    case SIS_661:
    case SIS_741:
@@ -1457,9 +1479,9 @@
    case SIS_760:
         temp = SiS_GetReg(SiS_Pr->SiS_P3d4,0x38);
       	temp = (temp & 0xe0) >> 5;
-      	if((temp >= 2) && (temp <= 3)) SiS_Pr->SiS_IF_DEF_LVDS = 1;
-      	if(temp == 3)  SiS_Pr->SiS_IF_DEF_CH70xx = 2;
-	if(temp == 4)  SiS_Pr->SiS_IF_DEF_CONEX = 1;  /* Not yet supported */
+      	if((temp >= 2) && (temp <= 3)) 	SiS_Pr->SiS_IF_DEF_LVDS = 1;
+      	if(temp == 3)  			SiS_Pr->SiS_IF_DEF_CH70xx = 2;
+	if(temp == 4)  			SiS_Pr->SiS_IF_DEF_CONEX = 1;  /* Not yet supported */
         break;
 #endif
    default:
@@ -1487,44 +1509,78 @@
 /*        HELPER: Determine ROM usage        */
 /*********************************************/
 
+BOOLEAN
+SiSDetermineROMLayout661(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo)
+{
+   UCHAR  *ROMAddr  = HwInfo->pjVirtualRomBase;
+   USHORT romversoffs, romvmaj = 1, romvmin = 0;
+
+   if(HwInfo->jChipType >= SIS_661) {
+      if((ROMAddr[0x1a] == 'N') &&
+         (ROMAddr[0x1b] == 'e') &&
+         (ROMAddr[0x1c] == 'w') &&
+         (ROMAddr[0x1d] == 'V')) {
+	 return TRUE;
+      }
+      romversoffs = ROMAddr[0x16] | (ROMAddr[0x17] << 8);
+      if(romversoffs) {
+	 if((ROMAddr[romversoffs+1] == '.') || (ROMAddr[romversoffs+4] == '.')) {
+	    romvmaj = ROMAddr[romversoffs] - '0';
+	    romvmin = ((ROMAddr[romversoffs+2] -'0') * 10) + (ROMAddr[romversoffs+3] - '0');
+	 }
+      }
+      if((romvmaj != 0) || (romvmin >= 92)) {
+	 return TRUE;
+      }
+   } else if(IS_SIS650740) {
+      if((ROMAddr[0x1a] == 'N') &&
+         (ROMAddr[0x1b] == 'e') &&
+         (ROMAddr[0x1c] == 'w') &&
+         (ROMAddr[0x1d] == 'V')) {
+	 return TRUE;
+      }
+   }
+   return FALSE;
+}
+
 static void
 SiSDetermineROMUsage(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo)
 {
    UCHAR  *ROMAddr  = HwInfo->pjVirtualRomBase;
+   USHORT romptr = 0;
+
+   SiS_Pr->SiS_UseROM = FALSE;
+   SiS_Pr->SiS_ROMNew = FALSE;
 
    if((ROMAddr) && (HwInfo->UseROM)) {
-      if((ROMAddr[0x00] != 0x55) || (ROMAddr[0x01] != 0xAA)) {
-         SiS_Pr->SiS_UseROM = FALSE;
-      } else if(HwInfo->jChipType == SIS_300) {
-        /* 300: We check if the code starts below 0x220 by
-	 * checking the jmp instruction at the beginning
-	 * of the BIOS image.
-	 */
-	 if((ROMAddr[3] == 0xe9) &&
-	    ((ROMAddr[5] << 8) | ROMAddr[4]) > 0x21a)
+      if(HwInfo->jChipType == SIS_300) {
+         /* 300: We check if the code starts below 0x220 by
+	  * checking the jmp instruction at the beginning
+	  * of the BIOS image.
+	  */
+	 if((ROMAddr[3] == 0xe9) && ((ROMAddr[5] << 8) | ROMAddr[4]) > 0x21a)
 	    SiS_Pr->SiS_UseROM = TRUE;
-	 else
-	    SiS_Pr->SiS_UseROM = FALSE;
       } else if(HwInfo->jChipType < SIS_315H) {
-#if 0
-        /* Rest of 300 series: We don't use the ROM image if
-	 * the BIOS version < 2.0.0 as such old BIOSes don't
-	 * have the needed data at the expected locations.
-	 */
-         if(ROMAddr[0x06] < '2')  SiS_Pr->SiS_UseROM = FALSE;
-	 else                     SiS_Pr->SiS_UseROM = TRUE;
-#else
-	/* Sony's VAIO BIOS 1.09 follows the standard, so perhaps
-	 * the others do as well
-	 */
+	 /* Sony's VAIO BIOS 1.09 follows the standard, so perhaps
+	  * the others do as well
+	  */
 	 SiS_Pr->SiS_UseROM = TRUE;
-#endif
       } else {
-         /* 315/330 series stick to the standard */
+         /* 315/330 series stick to the standard(s) */
 	 SiS_Pr->SiS_UseROM = TRUE;
+	 if((SiS_Pr->SiS_ROMNew = SiSDetermineROMLayout661(SiS_Pr, HwInfo))) {
+	    /* Find out about LCD data table entry size */
+	    if((romptr = SISGETROMW(0x0102))) {
+	       if(ROMAddr[romptr + (32 * 16)] == 0xff)
+	          SiS_Pr->SiS661LCD2TableSize = 32;
+	       else if(ROMAddr[romptr + (34 * 16)] == 0xff)
+	          SiS_Pr->SiS661LCD2TableSize = 34;
+	       else if(ROMAddr[romptr + (36 * 16)] == 0xff)
+	          SiS_Pr->SiS661LCD2TableSize = 36;  /* 0.94 final */
+	    }
+	 }
       }
-   } else SiS_Pr->SiS_UseROM = FALSE;
-
+   }
 }
 
 /*********************************************/
@@ -1609,7 +1665,8 @@
 
   SiS_Pr->SiS_VBType = 0;
 
-  if(SiS_Pr->SiS_IF_DEF_LVDS == 1) return;
+  if((SiS_Pr->SiS_IF_DEF_LVDS) || (SiS_Pr->SiS_IF_DEF_CONEX))
+     return;
 
   flag = SiS_GetReg(SiS_Pr->SiS_Part4Port,0x00);
 
@@ -1620,7 +1677,6 @@
   if(flag >= 2) {
      SiS_Pr->SiS_VBType = VB_SIS302B;
   } else if(flag == 1) {
-     SiS_Pr->SiS_VBType = VB_SIS301;
      if(rev >= 0xC0) {
        	SiS_Pr->SiS_VBType = VB_SIS301C;
      } else if(rev >= 0xB0) {
@@ -1628,102 +1684,22 @@
 	/* Check if 30xB DH version (no LCD support, use Panel Link instead) */
     	nolcd = SiS_GetReg(SiS_Pr->SiS_Part4Port,0x23);
         if(!(nolcd & 0x02)) SiS_Pr->SiS_VBType |= VB_NoLCD;
+     } else {
+        SiS_Pr->SiS_VBType = VB_SIS301;
      }
   }
   if(SiS_Pr->SiS_VBType & (VB_SIS301B | VB_SIS301C | VB_SIS302B)) {
-     if(rev >= 0xD0) {
-	SiS_Pr->SiS_VBType &= ~(VB_SIS301B | VB_SIS301C | VB_SIS302B | VB_NoLCD);
-	if(rev >= 0xE0) {
-	   flag = SiS_GetReg(SiS_Pr->SiS_Part4Port,0x39);
-	   if(flag == 0xff)
-	      SiS_Pr->SiS_VBType |= VB_SIS302LV;
-	   else
-	      SiS_Pr->SiS_VBType |= VB_SIS302ELV;
-	} else {
-	   SiS_Pr->SiS_VBType |= VB_SIS301LV;
-	}
+     if(rev >= 0xE0) {
+	flag = SiS_GetReg(SiS_Pr->SiS_Part4Port,0x39);
+	if(flag == 0xff) SiS_Pr->SiS_VBType = VB_SIS302LV;
+	else 	 	 SiS_Pr->SiS_VBType = VB_SIS301C;  /* VB_SIS302ELV; */
+     } else if(rev >= 0xD0) {
+	SiS_Pr->SiS_VBType = VB_SIS301LV;
      }
   }
 }
 
 /*********************************************/
-/*            HELPER: GetDRAMSize            */
-/*********************************************/
-
-#ifndef LINUX_XF86
-static ULONG
-GetDRAMSize(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo)
-{
-  ULONG   AdapterMemorySize = 0;
-#ifdef SIS315H
-  USHORT  counter;
-#endif
-
-  switch(HwInfo->jChipType) {
-#ifdef SIS315H
-  case SIS_315H:
-  case SIS_315:
-  case SIS_315PRO:
-    	counter = SiS_GetReg(SiS_Pr->SiS_P3c4,0x14);
-	AdapterMemorySize = 1 << ((counter & 0xF0) >> 4);
-	counter >>= 2;
-	counter &= 0x03;
-	if(counter == 0x02) {
-		AdapterMemorySize += (AdapterMemorySize / 2);      /* DDR asymetric */
-	} else if(counter != 0) {
-		AdapterMemorySize <<= 1;                           /* SINGLE_CHANNEL_2_RANK or DUAL_CHANNEL_1_RANK */
-	}
-	AdapterMemorySize *= (1024*1024);
-        break;
-
-  case SIS_330:
-    	counter = SiS_GetReg(SiS_Pr->SiS_P3c4,0x14);
-	AdapterMemorySize = 1 << ((counter & 0xF0) >> 4);
-	counter &= 0x0c;
-	if(counter != 0) {
-		AdapterMemorySize <<= 1;
-	}
-	AdapterMemorySize *= (1024*1024);
-	break;
-
-  case SIS_550:
-  case SIS_650:
-  case SIS_740:
-  	counter = SiS_GetReg(SiS_Pr->SiS_P3c4,0x14) & 0x3F;
-      	counter++;
-      	AdapterMemorySize = counter * 4;
-      	AdapterMemorySize *= (1024*1024);
-	break;
-
-  case SIS_661:
-  case SIS_741:
-  case SIS_660:
-  case SIS_760:
-        counter = (SiS_GetReg(SiS_Pr->SiS_P3c4,0x79) & 0xf0) >> 4;
-	AdapterMemorySize = 1 << counter;
-      	AdapterMemorySize *= (1024*1024);
-        break;
-#endif
-
-#ifdef SIS300
-  case SIS_300:
-  case SIS_540:
-  case SIS_630:
-  case SIS_730:
-      	AdapterMemorySize = SiS_GetReg(SiS_Pr->SiS_P3c4,0x14) & 0x3F;
-      	AdapterMemorySize++;
-      	AdapterMemorySize *= (1024*1024);
-	break;
-#endif
-  default:
-        break;
-  }
-
-  return AdapterMemorySize;
-}
-#endif
-
-/*********************************************/
 /*           HELPER: Check RAM size          */
 /*********************************************/
 
@@ -1732,8 +1708,8 @@
 SiS_CheckMemorySize(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo,
                     USHORT ModeNo, USHORT ModeIdIndex)
 {
+  USHORT AdapterMemSize = HwInfo->ulVideoMemorySize / (1024*1024);
   USHORT memorysize,modeflag;
-  ULONG  temp;
 
   if(SiS_Pr->UseCustomMode) {
      modeflag = SiS_Pr->CModeFlag;
@@ -1749,11 +1725,8 @@
   memorysize >>= MemorySizeShift;		/* Get required memory size */
   memorysize++;
 
-  temp = GetDRAMSize(SiS_Pr, HwInfo);       	/* Get adapter memory size (in MB) */
-  temp /= (1024*1024);
-
-  if(temp < memorysize) return(FALSE);
-  else return(TRUE);
+  if(AdapterMemSize < memorysize) return FALSE;
+  return TRUE;
 }
 #endif
 
@@ -1767,11 +1740,14 @@
 {
    UCHAR data, temp;
 
-   if(*SiS_Pr->pSiS_SoftSetting & SoftDRAMType) {
-     data = *SiS_Pr->pSiS_SoftSetting & 0x03;
+   if((*SiS_Pr->pSiS_SoftSetting) & SoftDRAMType) {
+     data = (*SiS_Pr->pSiS_SoftSetting) & 0x03;
    } else {
      if(HwInfo->jChipType >= SIS_661) {
         data = SiS_GetReg(SiS_Pr->SiS_P3d4,0x78) & 0x07;
+	if(SiS_Pr->SiS_ROMNew) {
+	   data = ((SiS_GetReg(SiS_Pr->SiS_P3d4,0x78) & 0xc0) >> 6);
+	}
      } else if(IS_SIS550650740) {
         data = SiS_GetReg(SiS_Pr->SiS_P3c4,0x13) & 0x07;
      } else {	/* 315, 330 */
@@ -1798,10 +1774,14 @@
 USHORT
 SiS_GetMCLK(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo)
 {
+  UCHAR  *ROMAddr  = HwInfo->pjVirtualRomBase;
   USHORT index;
 
   index = SiS_Get310DRAMType(SiS_Pr, HwInfo);
   if(HwInfo->jChipType >= SIS_661) {
+     if(SiS_Pr->SiS_ROMNew) {
+        return((USHORT)(SISGETROMW((0x90 + (index * 5) + 3))));
+     }
      return(SiS_Pr->SiS_MCLKData_0[index].CLOCK);
   } else if(index >= 4) {
      index -= 4;
@@ -1827,20 +1807,17 @@
 
   if(SiS_Pr->SiS_ModeType >= ModeEGA) {
      if(ModeNo > 0x13) {
-        AdapterMemorySize = GetDRAMSize(SiS_Pr, HwInfo);
-        SiS_SetMemory(VideoMemoryAddress,AdapterMemorySize,0);
+        SiS_SetMemory(VideoMemoryAddress, AdapterMemorySize, 0);
      } else {
         pBuffer = (USHORT *)VideoMemoryAddress;
-        for(i=0; i<0x4000; i++)
-           pBuffer[i] = 0x0000;
+        for(i=0; i<0x4000; i++) pBuffer[i] = 0x0000;
      }
   } else {
-     pBuffer = (USHORT *)VideoMemoryAddress;
      if(SiS_Pr->SiS_ModeType < ModeCGA) {
-        for(i=0; i<0x4000; i++)
-           pBuffer[i] = 0x0720;
+        pBuffer = (USHORT *)VideoMemoryAddress;
+        for(i=0; i<0x4000; i++) pBuffer[i] = 0x0720;
      } else {
-        SiS_SetMemory(VideoMemoryAddress,0x8000,0);
+        SiS_SetMemory(VideoMemoryAddress, 0x8000, 0);
      }
   }
 }
@@ -1896,10 +1873,10 @@
    UCHAR index;
 
    if(ModeNo <= 0x13) {
-     	index = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_StTableIndex;
+      index = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_StTableIndex;
    } else {
-     	if(SiS_Pr->SiS_ModeType <= 0x02) index = 0x1B;    /* 02 -> ModeEGA  */
-     	else index = 0x0F;
+      if(SiS_Pr->SiS_ModeType <= ModeEGA) index = 0x1B;
+      else index = 0x0F;
    }
    return index;
 }
@@ -1914,7 +1891,7 @@
     USHORT temp,temp1,temp2;
 
     if((ModeNo != 0x03) && (ModeNo != 0x10) && (ModeNo != 0x12))
-       return(1);
+       return(TRUE);
     temp = SiS_GetReg(SiS_Pr->SiS_P3d4,0x11);
     SiS_SetRegOR(SiS_Pr->SiS_P3d4,0x11,0x80);
     temp1 = SiS_GetReg(SiS_Pr->SiS_P3d4,0x00);
@@ -1924,13 +1901,13 @@
     SiS_SetReg(SiS_Pr->SiS_P3d4,0x11,temp);
     if((HwInfo->jChipType >= SIS_315H) ||
        (HwInfo->jChipType == SIS_300)) {
-       if(temp2 == 0x55) return(0);
-       else return(1);
+       if(temp2 == 0x55) return(FALSE);
+       else return(TRUE);
     } else {
-       if(temp2 != 0x55) return(1);
+       if(temp2 != 0x55) return(TRUE);
        else {
           SiS_SetRegOR(SiS_Pr->SiS_P3d4,0x35,0x01);
-          return(0);
+          return(FALSE);
        }
     }
 }
@@ -1944,6 +1921,43 @@
 }
 
 /*********************************************/
+/*            HELPER: ENABLE CRT1            */
+/*********************************************/
+
+static void
+SiS_SetupCR5x(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo)
+{
+   if(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) {
+      if(IS_SIS650) {
+	 SiS_SetRegAND(SiS_Pr->SiS_P3d4,0x51,0x1f);
+	 if(IS_SIS651) SiS_SetRegOR(SiS_Pr->SiS_P3d4,0x51,0x20);
+	 SiS_SetRegAND(SiS_Pr->SiS_P3d4,0x56,0xe7);
+      } else if(IS_SIS661741660760) {
+         SiS_SetRegAND(SiS_Pr->SiS_P3d4,0x61,0xf7);
+	 SiS_SetRegAND(SiS_Pr->SiS_P3d4,0x51,0x1f);
+	 SiS_SetRegAND(SiS_Pr->SiS_P3d4,0x56,0xe7);
+	 if(!SiS_Pr->SiS_ROMNew) {
+	    SiS_SetRegAND(SiS_Pr->SiS_P3d4,0x3a,0xef);
+	 }
+      }
+   }
+}
+
+static void
+SiS_HandleCRT1(SiS_Private *SiS_Pr)
+{
+  SiS_SetRegAND(SiS_Pr->SiS_P3d4,SiS_Pr->SiS_MyCR63,0xbf);
+#if 0
+  if(!(SiS_GetReg(SiS_Pr->SiS_P3c4,0x15) & 0x01)) {
+     if((SiS_GetReg(SiS_Pr->SiS_P3c4,0x15) & 0x0a) ||
+        (SiS_GetReg(SiS_Pr->SiS_P3c4,0x16) & 0x01)) {
+        SiS_SetRegOR(SiS_Pr->SiS_P3d4,SiS_Pr->SiS_MyCR63,0x40);
+     }
+  }
+#endif
+}
+
+/*********************************************/
 /*           HELPER: GetColorDepth           */
 /*********************************************/
 
@@ -1977,28 +1991,22 @@
 SiS_GetOffset(SiS_Private *SiS_Pr,USHORT ModeNo,USHORT ModeIdIndex,
               USHORT RefreshRateTableIndex,PSIS_HW_INFO HwInfo)
 {
-  USHORT temp,colordepth,infoflag;
+  USHORT xres, temp, colordepth, infoflag;
 
   if(SiS_Pr->UseCustomMode) {
      infoflag = SiS_Pr->CInfoFlag;
-     temp = SiS_Pr->CHDisplay / 16;
+     xres = SiS_Pr->CHDisplay;
   } else {
      infoflag = SiS_Pr->SiS_RefIndex[RefreshRateTableIndex].Ext_InfoFlag;
-     temp = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_ModeOffset;
-     temp = SiS_Pr->SiS_ScreenOffset[temp];
+     xres = SiS_Pr->SiS_RefIndex[RefreshRateTableIndex].XRes;
   }
 
   colordepth = SiS_GetColorDepth(SiS_Pr,ModeNo,ModeIdIndex);
 
+  temp = xres / 16;
   if(infoflag & InterlaceMode) temp <<= 1;
-
   temp *= colordepth;
-
-  if( ( ((ModeNo >= 0x26) && (ModeNo <= 0x28)) ||
-        ModeNo == 0x3f ||
-	ModeNo == 0x42 ||
-	ModeNo == 0x45 ) ||
-      (SiS_Pr->UseCustomMode && (SiS_Pr->CHDisplay % 16)) ) {
+  if(xres % 16) {
      colordepth >>= 1;
      temp += colordepth;
   }
@@ -2103,9 +2111,15 @@
      CRTCdata = SiS_Pr->SiS_StandTable[StandTableIndex].CRTC[i];
      SiS_SetReg(SiS_Pr->SiS_P3d4,i,CRTCdata);                     /* Set CRTC(3d4) */
   }
-  if( ( (HwInfo->jChipType == SIS_630) ||
-        (HwInfo->jChipType == SIS_730) )  &&
-      (HwInfo->jChipRevision >= 0x30) ) {       	   /* for 630S0 */
+  if(HwInfo->jChipType >= SIS_661) {
+     SiS_SetupCR5x(SiS_Pr, HwInfo);
+     for(i = 0x13; i <= 0x14; i++) {
+        CRTCdata = SiS_Pr->SiS_StandTable[StandTableIndex].CRTC[i];
+        SiS_SetReg(SiS_Pr->SiS_P3d4,i,CRTCdata);
+     }
+  } else if( ( (HwInfo->jChipType == SIS_630) ||
+               (HwInfo->jChipType == SIS_730) )  &&
+             (HwInfo->jChipRevision >= 0x30) ) {       	   /* for 630S0 */
      if(SiS_Pr->SiS_VBInfo & SetInSlaveMode) {
         if(SiS_Pr->SiS_VBInfo & (SetCRT2ToLCD | SetCRT2ToTV)) {
            SiS_SetReg(SiS_Pr->SiS_P3d4,0x18,0xFE);
@@ -2206,7 +2220,7 @@
 /*********************************************/
 
 static void
-SiS_ClearExt1Regs(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo)
+SiS_ClearExt1Regs(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo, USHORT ModeNo)
 {
   USHORT i;
 
@@ -2216,6 +2230,11 @@
 
   if(HwInfo->jChipType >= SIS_315H) {
      SiS_SetRegAND(SiS_Pr->SiS_P3c4,0x37,0xFE);
+     if(ModeNo <= 0x13) {
+        if(ModeNo == 0x06 || ModeNo >= 0x0e) {
+	   SiS_SetReg(SiS_Pr->SiS_P3c4,0x0e,0x20);
+	}
+     }
   }
 }
 
@@ -2279,45 +2298,6 @@
 /*                  CRTC/2                   */
 /*********************************************/
 
-#ifdef SIS315H
-static void
-SiS_GetLCDACRT1Ptr(SiS_Private *SiS_Pr, USHORT ModeNo, USHORT ModeIdIndex,
-		   USHORT RefreshRateTableIndex, USHORT *ResIndex,
-		   USHORT *DisplayType)
- {
-  USHORT modeflag = 0;
-
-  if(ModeNo <= 0x13) {
-     modeflag = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_ModeFlag;
-     *ResIndex = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_CRT2CRTC;
-  } else {
-     modeflag = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag;
-     *ResIndex = SiS_Pr->SiS_RefIndex[RefreshRateTableIndex].Ext_CRT2CRTC;
-  }
-
-  *ResIndex &= 0x3F;
-
-  *DisplayType = SiS_Pr->SiS_LCDResInfo;
-  if(SiS_Pr->SiS_LCDInfo & DontExpandLCD) *DisplayType += 32;
-  if(modeflag & HalfDCLK)                 *DisplayType += 16;
-
-  if(SiS_Pr->SiS_CustomT == CUT_COMPAQ1280) {
-     if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1280x1024) {
-        *DisplayType = 100;
-	if(SiS_Pr->SiS_LCDInfo & DontExpandLCD) *DisplayType += 2;
-        if(modeflag & HalfDCLK)                 *DisplayType += 1;
-     }
-  } else if(SiS_Pr->SiS_CustomT == CUT_CLEVO1024) {
-     if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1024x768) {
-        *DisplayType = 104;
-	if(SiS_Pr->SiS_LCDInfo & DontExpandLCD) *DisplayType += 2;
-        if(modeflag & HalfDCLK)                 *DisplayType += 1;
-     }
-  }
-
-}
-#endif
-
 static void
 SiS_SetCRT1CRTC(SiS_Private *SiS_Pr, USHORT ModeNo, USHORT ModeIdIndex,
                 USHORT RefreshRateTableIndex,
@@ -2325,10 +2305,6 @@
 {
   UCHAR  index;
   USHORT temp,i,j,modeflag;
-#ifdef SIS315H
-  USHORT ResIndex,DisplayType;
-  const SiS_LCDACRT1DataStruct *LCDACRT1Ptr = NULL;
-#endif
 
   SiS_SetRegAND(SiS_Pr->SiS_P3d4,0x11,0x7f);		/* unlock cr0-7 */
 
@@ -2336,7 +2312,7 @@
 
      modeflag = SiS_Pr->CModeFlag;
 
-     for(i=0,j=0;i<=07;i++,j++) {
+     for(i=0,j=0;i<=7;i++,j++) {
         SiS_SetReg(SiS_Pr->SiS_P3d4,j,SiS_Pr->CCRT1CRTC[i]);
      }
      for(j=0x10;i<=10;i++,j++) {
@@ -2354,7 +2330,7 @@
 
      temp = (SiS_Pr->CCRT1CRTC[16] & 0x01) << 5;
      if(modeflag & DoubleScanMode) temp |= 0x80;
-     SiS_SetRegANDOR(SiS_Pr->SiS_P3d4,0x09,0xDF,temp);
+     SiS_SetRegANDOR(SiS_Pr->SiS_P3d4,0x09,0x5F,temp);
 
   } else {
 
@@ -2364,87 +2340,28 @@
         modeflag = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag;
      }
 
-     if((SiS_Pr->SiS_VBType & VB_SISVB) && (SiS_Pr->SiS_VBInfo & SetCRT2ToLCDA)) {
+     index = SiS_Pr->SiS_RefIndex[RefreshRateTableIndex].Ext_CRT1CRTC;
 
-#ifdef SIS315H
-
-        SiS_GetLCDACRT1Ptr(SiS_Pr, ModeNo, ModeIdIndex, RefreshRateTableIndex, &ResIndex, &DisplayType);
-
-        switch(DisplayType) {
-        case Panel_1024x768      : LCDACRT1Ptr = SiS_Pr->SiS_LCDACRT11024x768_1;     break;
-        case Panel_1280x1024     : LCDACRT1Ptr = SiS_Pr->SiS_LCDACRT11280x1024_1;    break;
-        case Panel_1400x1050     : LCDACRT1Ptr = SiS_Pr->SiS_LCDACRT11400x1050_1;    break;
-        case Panel_1600x1200     : LCDACRT1Ptr = SiS_Pr->SiS_LCDACRT11600x1200_1;    break;
-        case Panel_1024x768  + 16: LCDACRT1Ptr = SiS_Pr->SiS_LCDACRT11024x768_1_H;   break;
-        case Panel_1280x1024 + 16: LCDACRT1Ptr = SiS_Pr->SiS_LCDACRT11280x1024_1_H;  break;
-        case Panel_1400x1050 + 16: LCDACRT1Ptr = SiS_Pr->SiS_LCDACRT11400x1050_1_H;  break;
-        case Panel_1600x1200 + 16: LCDACRT1Ptr = SiS_Pr->SiS_LCDACRT11600x1200_1_H;  break;
-        case Panel_1024x768  + 32: LCDACRT1Ptr = SiS_Pr->SiS_LCDACRT11024x768_2;     break;
-        case Panel_1280x1024 + 32: LCDACRT1Ptr = SiS_Pr->SiS_LCDACRT11280x1024_2;    break;
-        case Panel_1400x1050 + 32: LCDACRT1Ptr = SiS_Pr->SiS_LCDACRT11400x1050_2;    break;
-        case Panel_1600x1200 + 32: LCDACRT1Ptr = SiS_Pr->SiS_LCDACRT11600x1200_2;    break;
-        case Panel_1024x768  + 48: LCDACRT1Ptr = SiS_Pr->SiS_LCDACRT11024x768_2_H;   break;
-        case Panel_1280x1024 + 48: LCDACRT1Ptr = SiS_Pr->SiS_LCDACRT11280x1024_2_H;  break;
-        case Panel_1400x1050 + 48: LCDACRT1Ptr = SiS_Pr->SiS_LCDACRT11400x1050_2_H;  break;
-        case Panel_1600x1200 + 48: LCDACRT1Ptr = SiS_Pr->SiS_LCDACRT11600x1200_2_H;  break;
-        case 100:	  	   LCDACRT1Ptr = Compaq1280x1024_LCDACRT1_1;         break;
-        case 101:		   LCDACRT1Ptr = Compaq1280x1024_LCDACRT1_1_H;       break;
-        case 102:		   LCDACRT1Ptr = SiS_Pr->SiS_LCDACRT11280x1024_2;    break;
-        case 103:		   LCDACRT1Ptr = SiS_Pr->SiS_LCDACRT11280x1024_2_H;  break;
-        case 104:		   LCDACRT1Ptr = Clevo1024x768_LCDACRT1_1;           break;
-        case 105:		   LCDACRT1Ptr = Clevo1024x768_LCDACRT1_1_H;         break;
-        case 106:		   LCDACRT1Ptr = Clevo1024x768_LCDACRT1_2;           break;
-        case 107:		   LCDACRT1Ptr = Clevo1024x768_LCDACRT1_2_H;         break;
-        default:                   LCDACRT1Ptr = SiS_Pr->SiS_LCDACRT11024x768_1;     break;
-        }
-
-        for(i=0, j=0; i<=0x07; i++, j++) {
-           SiS_SetReg(SiS_Pr->SiS_P3d4,i,(LCDACRT1Ptr+ResIndex)->CR[j]);
-        }
-        for(i=0x10, j=8; i<=0x12; i++, j++) {
-           SiS_SetReg(SiS_Pr->SiS_P3d4,i,(LCDACRT1Ptr+ResIndex)->CR[j]);
-        }
-        for(i=0x15, j=11; i<=0x16; i++, j++) {
-           SiS_SetReg(SiS_Pr->SiS_P3d4,i,(LCDACRT1Ptr+ResIndex)->CR[j]);
-        }
-        for(i=0x0A, j=13; i<=0x0C; i++, j++) {
-           SiS_SetReg(SiS_Pr->SiS_P3c4,i,(LCDACRT1Ptr+ResIndex)->CR[j]);
-        }
-
-        temp = (LCDACRT1Ptr+ResIndex)->CR[16] & 0xE0;
-        SiS_SetReg(SiS_Pr->SiS_P3c4,0x0E,temp);
-
-        temp = ((LCDACRT1Ptr+ResIndex)->CR[16] & 0x01) << 5;
-        if(modeflag & DoubleScanMode) temp |= 0x80;
-        SiS_SetRegANDOR(SiS_Pr->SiS_P3d4,0x09,0xDF,temp);
-
-#endif
-
-     } else {
-
-        index = SiS_Pr->SiS_RefIndex[RefreshRateTableIndex].Ext_CRT1CRTC;
-
-        for(i=0,j=0;i<=07;i++,j++) {
-          SiS_SetReg(SiS_Pr->SiS_P3d4,j,SiS_Pr->SiS_CRT1Table[index].CR[i]);
-        }
-        for(j=0x10;i<=10;i++,j++) {
-          SiS_SetReg(SiS_Pr->SiS_P3d4,j,SiS_Pr->SiS_CRT1Table[index].CR[i]);
-        }
-        for(j=0x15;i<=12;i++,j++) {
-          SiS_SetReg(SiS_Pr->SiS_P3d4,j,SiS_Pr->SiS_CRT1Table[index].CR[i]);
-        }
-        for(j=0x0A;i<=15;i++,j++) {
-          SiS_SetReg(SiS_Pr->SiS_P3c4,j,SiS_Pr->SiS_CRT1Table[index].CR[i]);
-        }
+     for(i=0,j=0;i<=7;i++,j++) {
+        SiS_SetReg(SiS_Pr->SiS_P3d4,j,SiS_Pr->SiS_CRT1Table[index].CR[i]);
+     }
+     for(j=0x10;i<=10;i++,j++) {
+        SiS_SetReg(SiS_Pr->SiS_P3d4,j,SiS_Pr->SiS_CRT1Table[index].CR[i]);
+     }
+     for(j=0x15;i<=12;i++,j++) {
+        SiS_SetReg(SiS_Pr->SiS_P3d4,j,SiS_Pr->SiS_CRT1Table[index].CR[i]);
+     }
+     for(j=0x0A;i<=15;i++,j++) {
+        SiS_SetReg(SiS_Pr->SiS_P3c4,j,SiS_Pr->SiS_CRT1Table[index].CR[i]);
+     }
 
-        temp = SiS_Pr->SiS_CRT1Table[index].CR[16] & 0xE0;
-        SiS_SetReg(SiS_Pr->SiS_P3c4,0x0E,temp);
+     temp = SiS_Pr->SiS_CRT1Table[index].CR[16] & 0xE0;
+     SiS_SetReg(SiS_Pr->SiS_P3c4,0x0E,temp);
 
-        temp = ((SiS_Pr->SiS_CRT1Table[index].CR[16]) & 0x01) << 5;
-        if(modeflag & DoubleScanMode)  temp |= 0x80;
-        SiS_SetRegANDOR(SiS_Pr->SiS_P3d4,0x09,0xDF,temp);
+     temp = ((SiS_Pr->SiS_CRT1Table[index].CR[16]) & 0x01) << 5;
+     if(modeflag & DoubleScanMode)  temp |= 0x80;
+     SiS_SetRegANDOR(SiS_Pr->SiS_P3d4,0x09,0x5F,temp);
 
-     }
   }
 
   if(SiS_Pr->SiS_ModeType > ModeVGA) SiS_SetReg(SiS_Pr->SiS_P3d4,0x14,0x4F);
@@ -2482,7 +2399,7 @@
 
    DisplayUnit <<= 5;
    temp = (DisplayUnit & 0xff00) >> 8;
-   if (DisplayUnit & 0xff) temp++;
+   if(DisplayUnit & 0xff) temp++;
    temp++;
    SiS_SetReg(SiS_Pr->SiS_P3c4,0x10,temp);
 }
@@ -2917,7 +2834,8 @@
 {
   USHORT modeflag;
 
-  SiS_SetRegAND(SiS_Pr->SiS_P3c4,0x3D,0xFE);  /* disable auto-threshold */
+  /* disable auto-threshold */
+  SiS_SetRegAND(SiS_Pr->SiS_P3c4,0x3D,0xFE);
 
   if(SiS_Pr->UseCustomMode) {
      modeflag = SiS_Pr->CModeFlag;
@@ -2925,30 +2843,19 @@
      modeflag = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag;
   }
 
-  if(HwInfo->jChipType >= SIS_661) {
-     SiS_SetReg(SiS_Pr->SiS_P3c4,0x08,0xAE);
-     SiS_SetRegAND(SiS_Pr->SiS_P3c4,0x09,0xF0);
-     if(ModeNo > 0x13) {
+  SiS_SetReg(SiS_Pr->SiS_P3c4,0x08,0xAE);
+  SiS_SetRegAND(SiS_Pr->SiS_P3c4,0x09,0xF0);
+  if(ModeNo > 0x13) {
+     if(HwInfo->jChipType >= SIS_661) {
         if(!(modeflag & HalfDCLK)) {
 	   SiS_SetReg(SiS_Pr->SiS_P3c4,0x08,0x34);
-	   if(ModeNo != 0x38) {
-	      SiS_SetRegOR(SiS_Pr->SiS_P3c4,0x3D,0x01);
-	   }
+	   SiS_SetRegOR(SiS_Pr->SiS_P3c4,0x3D,0x01);
 	}
-     }
-  } else {
-     if(ModeNo > 0x13) {
-        if( (!(modeflag & DoubleScanMode)) || (!(modeflag & HalfDCLK))) {
+     } else {
+        if((!(modeflag & DoubleScanMode)) || (!(modeflag & HalfDCLK))) {
            SiS_SetReg(SiS_Pr->SiS_P3c4,0x08,0x34);
-           SiS_SetRegAND(SiS_Pr->SiS_P3c4,0x09,0xF0);
            SiS_SetRegOR(SiS_Pr->SiS_P3c4,0x3D,0x01);
-        } else {
-           SiS_SetReg(SiS_Pr->SiS_P3c4,0x08,0xAE);
-           SiS_SetRegAND(SiS_Pr->SiS_P3c4,0x09,0xF0);
-        }
-     } else {
-        SiS_SetReg(SiS_Pr->SiS_P3c4,0x08,0xAE);
-        SiS_SetRegAND(SiS_Pr->SiS_P3c4,0x09,0xF0);
+	}
      }
   }
 }
@@ -2963,33 +2870,29 @@
                  USHORT ModeNo, USHORT RefreshRateTableIndex,
                  USHORT ModeIdIndex)
 {
-  USHORT data, data2=0;
-  USHORT VCLK, index=0;
+  USHORT data=0, VCLK=0, index=0;
 
-  if(ModeNo <= 0x13) VCLK = 0;
-  else {
+  if(ModeNo > 0x13) {
      if(SiS_Pr->UseCustomMode) {
         VCLK = SiS_Pr->CSRClock;
      } else {
         index = SiS_GetVCLK2Ptr(SiS_Pr,ModeNo,ModeIdIndex,
-	               RefreshRateTableIndex,HwInfo);
+	                      RefreshRateTableIndex,HwInfo);
         VCLK = SiS_Pr->SiS_VCLKData[index].CLOCK;
      }
   }
 
-  if(HwInfo->jChipType < SIS_315H) {		/* 300 series */
+  if(HwInfo->jChipType < SIS_315H) {
 
-     data2 = 0x00;
-     if(VCLK > 150) data2 |= 0x80;
-     SiS_SetRegANDOR(SiS_Pr->SiS_P3c4,0x07,0x7B,data2);
+     if(VCLK > 150) data |= 0x80;
+     SiS_SetRegANDOR(SiS_Pr->SiS_P3c4,0x07,0x7B,data);
 
-     data2 = 0x00;
-     if(VCLK >= 150) data2 |= 0x08;
-     SiS_SetRegANDOR(SiS_Pr->SiS_P3c4,0x32,0xF7,data2);
+     data = 0x00;
+     if(VCLK >= 150) data |= 0x08;
+     SiS_SetRegANDOR(SiS_Pr->SiS_P3c4,0x32,0xF7,data);
 
-  } else { 					/* 315 series */
+  } else {
 
-     data = 0;
      if(VCLK >= 166) data |= 0x0c;
      SiS_SetRegANDOR(SiS_Pr->SiS_P3c4,0x32,0xf3,data);
 
@@ -2998,23 +2901,31 @@
      }
   }
 
-  data2 = 0x03;
-  if((VCLK >= 135) && (VCLK < 160))      data2 = 0x02;
-  else if((VCLK >= 160) && (VCLK < 260)) data2 = 0x01;
-  else if(VCLK >= 260)                   data2 = 0x00;
+  /* DAC speed */
+  if(HwInfo->jChipType >= SIS_661) {
 
-  if(HwInfo->jChipType == SIS_540) {
-     if((VCLK == 203) || (VCLK < 234)) data2 = 0x02;
-  }
+     SiS_SetRegANDOR(SiS_Pr->SiS_P3c4,0x07,0xE8,0x10);
 
-  if(HwInfo->jChipType < SIS_315H) {
-     SiS_SetRegANDOR(SiS_Pr->SiS_P3c4,0x07,0xFC,data2);  	/* DAC speed */
   } else {
-     if(HwInfo->jChipType > SIS_315PRO) {
-        /* This "if" is done in 330 and 650/LVDS/301LV BIOSes; Not in 315 BIOS */
-        if(ModeNo > 0x13) data2 &= 0xfc;
+
+     data = 0x03;
+     if((VCLK >= 135) && (VCLK < 160))      data = 0x02;
+     else if((VCLK >= 160) && (VCLK < 260)) data = 0x01;
+     else if(VCLK >= 260)                   data = 0x00;
+
+     if(HwInfo->jChipType == SIS_540) {
+        if((VCLK == 203) || (VCLK < 234))   data = 0x02;
+     }
+
+     if(HwInfo->jChipType < SIS_315H) {
+        SiS_SetRegANDOR(SiS_Pr->SiS_P3c4,0x07,0xFC,data);
+     } else {
+        if(HwInfo->jChipType > SIS_315PRO) {
+           if(ModeNo > 0x13) data &= 0xfc;
+        }
+        SiS_SetRegANDOR(SiS_Pr->SiS_P3c4,0x07,0xF8,data);
      }
-     SiS_SetRegANDOR(SiS_Pr->SiS_P3c4,0x07,0xF8,data2);  	/* DAC speed */
+
   }
 }
 
@@ -3022,75 +2933,51 @@
 SiS_SetCRT1ModeRegs(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo,
                     USHORT ModeNo,USHORT ModeIdIndex,USHORT RefreshRateTableIndex)
 {
-  USHORT data,data2;
-  USHORT infoflag=0,modeflag;
+  USHORT data,infoflag=0,modeflag;
   USHORT resindex,xres;
 #ifdef SIS315H
-  USHORT data3;
+  USHORT data2,data3;
   ULONG  longdata;
-#if 0
-  resinfo = 0;
-#endif
+  UCHAR  *ROMAddr  = HwInfo->pjVirtualRomBase;
 #endif
 
   if(SiS_Pr->UseCustomMode) {
      modeflag = SiS_Pr->CModeFlag;
      infoflag = SiS_Pr->CInfoFlag;
+     xres = SiS_Pr->CHDisplay;
   } else {
+     resindex = SiS_GetResInfo(SiS_Pr,ModeNo,ModeIdIndex);
      if(ModeNo > 0x13) {
     	modeflag = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag;
     	infoflag = SiS_Pr->SiS_RefIndex[RefreshRateTableIndex].Ext_InfoFlag;
-#ifdef SIS315H
-#if 0
-	resinfo = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_RESINFO;
-#endif
-#endif
+	xres = SiS_Pr->SiS_ModeResInfo[resindex].HTotal;
      } else {
     	modeflag = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_ModeFlag;
+	xres = SiS_Pr->SiS_StResInfo[resindex].HTotal;
      }
   }
 
   /* Disable DPMS */
   SiS_SetRegAND(SiS_Pr->SiS_P3c4,0x1F,0x3F);
 
-  if(ModeNo > 0x13) data = infoflag;
-  else data = 0;
-
-  data2 = 0;
+  data = 0;
   if(ModeNo > 0x13) {
-     if(SiS_Pr->SiS_ModeType > 0x02) {
-        data2 |= 0x02;
-        data2 |= ((SiS_Pr->SiS_ModeType - ModeVGA) << 2);
-     }
-  }
-
-#ifdef TWDEBUG
-  xf86DrvMsg(0, X_INFO, "Debug: Mode infoflag = %x, Chiptype %d\n",
-  	data, HwInfo->jChipType);
-#endif
-
-  if(data & InterlaceMode) data2 |= 0x20;
-  SiS_SetRegANDOR(SiS_Pr->SiS_P3c4,0x06,0xC0,data2);
-
-  if(SiS_Pr->UseCustomMode) {
-     xres = SiS_Pr->CHDisplay;
-  } else {
-     resindex = SiS_GetResInfo(SiS_Pr,ModeNo,ModeIdIndex);
-     if(ModeNo <= 0x13) {
-      	xres = SiS_Pr->SiS_StResInfo[resindex].HTotal;
-     } else {
-      	xres = SiS_Pr->SiS_ModeResInfo[resindex].HTotal;
+     if(SiS_Pr->SiS_ModeType > ModeEGA) {
+        data |= 0x02;
+        data |= ((SiS_Pr->SiS_ModeType - ModeVGA) << 2);
      }
+     if(infoflag & InterlaceMode) data |= 0x20;
   }
+  SiS_SetRegANDOR(SiS_Pr->SiS_P3c4,0x06,0xC0,data);
 
   if(HwInfo->jChipType != SIS_300) {
-     data = 0x0000;
+     data = 0;
      if(infoflag & InterlaceMode) {
-        if(xres <= 800) data = 0x0020;
+        if(xres <= 800)       data = 0x0020;
         else if(xres <= 1024) data = 0x0035;
-        else data = 0x0048;
+        else                  data = 0x0048;
      }
-     SiS_SetReg(SiS_Pr->SiS_P3d4,0x19,(data & 0x00FF));
+     SiS_SetReg(SiS_Pr->SiS_P3d4,0x19,(data & 0xFF));
      SiS_SetRegANDOR(SiS_Pr->SiS_P3d4,0x1a,0xFC,(data >> 8));
   }
 
@@ -3098,18 +2985,12 @@
      SiS_SetRegOR(SiS_Pr->SiS_P3c4,0x01,0x08);
   }
 
+  data = 0;
+  if(modeflag & LineCompareOff) data = 0x08;
   if(HwInfo->jChipType == SIS_300) {
-     if(modeflag & LineCompareOff) {
-        SiS_SetRegOR(SiS_Pr->SiS_P3c4,0x0F,0x08);
-     } else {
-        SiS_SetRegAND(SiS_Pr->SiS_P3c4,0x0F,0xF7);
-     }
+     SiS_SetRegANDOR(SiS_Pr->SiS_P3c4,0x0F,0xF7,data);
   } else {
-     if(modeflag & LineCompareOff) {
-        SiS_SetRegANDOR(SiS_Pr->SiS_P3c4,0x0F,0xB7,0x08);
-     } else {
-        SiS_SetRegAND(SiS_Pr->SiS_P3c4,0x0F,0xB7);
-     }
+     SiS_SetRegANDOR(SiS_Pr->SiS_P3c4,0x0F,0xB7,data);
      if(SiS_Pr->SiS_ModeType == ModeEGA) {
         if(ModeNo > 0x13) {
   	   SiS_SetRegOR(SiS_Pr->SiS_P3c4,0x0F,0x40);
@@ -3117,9 +2998,13 @@
      }
   }
 
+  if(HwInfo->jChipType >= SIS_661) {
+     SiS_SetRegAND(SiS_Pr->SiS_P3c4,0x31,0xfb);
+  }
+
 #ifdef SIS315H
-  /* 315 BIOS sets SR17 at this point */
   if(HwInfo->jChipType == SIS_315PRO) {
+
      data = SiS_Get310DRAMType(SiS_Pr, HwInfo);
      data = SiS_Pr->SiS_SR15[2][data];
      if(SiS_Pr->SiS_ModeType == ModeText) {
@@ -3138,12 +3023,18 @@
 	}
      }
      SiS_SetReg(SiS_Pr->SiS_P3c4,0x17,data);
-  }
 
-  /* 330 BIOS sets SR17 at this point */
-  if(HwInfo->jChipType == SIS_330) {
+  } else if( (HwInfo->jChipType == SIS_330) ||
+             ((HwInfo->jChipType == SIS_760) && (SiS_Pr->SiS_SysFlags & SF_760LFB))) {
+
      data = SiS_Get310DRAMType(SiS_Pr, HwInfo);
-     data = SiS_Pr->SiS_SR15[2][data];
+     if(HwInfo->jChipType == SIS_330) {
+        data = SiS_Pr->SiS_SR15[2][data];
+     } else {
+        if(SiS_Pr->SiS_ROMNew) 	    data = ROMAddr[0xf6];
+        else if(SiS_Pr->SiS_UseROM) data = ROMAddr[0x100 + data];
+	else                        data = 0xba;
+     }
      if(SiS_Pr->SiS_ModeType <= ModeEGA) {
         data &= 0xc7;
      } else {
@@ -3156,31 +3047,38 @@
 	}
 
 	data3 = SiS_GetColorDepth(SiS_Pr,ModeNo,ModeIdIndex) >> 1;
-	if(!data3) data3++;
-
-	data2 *= data3;
+	if(data3) data2 *= data3;
 
 	longdata = SiS_GetMCLK(SiS_Pr, HwInfo) * 1024;
 
 	data2 = longdata / data2;
 
-	if(SiS_Pr->SiS_ModeType != Mode16Bpp) {
-           if(data2 >= 0x19c)      data = 0xba;
-	   else if(data2 >= 0x140) data = 0x7a;
-	   else if(data2 >= 0x101) data = 0x3a;
-	   else if(data2 >= 0xf5)  data = 0x32;
-	   else if(data2 >= 0xe2)  data = 0x2a;
-	   else if(data2 >= 0xc4)  data = 0x22;
-	   else if(data2 >= 0xac)  data = 0x1a;
-	   else if(data2 >= 0x9e)  data = 0x12;
-	   else if(data2 >= 0x8e)  data = 0x0a;
+	if(HwInfo->jChipType == SIS_330) {
+	   if(SiS_Pr->SiS_ModeType != Mode16Bpp) {
+              if     (data2 >= 0x19c) data = 0xba;
+	      else if(data2 >= 0x140) data = 0x7a;
+	      else if(data2 >= 0x101) data = 0x3a;
+	      else if(data2 >= 0xf5)  data = 0x32;
+	      else if(data2 >= 0xe2)  data = 0x2a;
+	      else if(data2 >= 0xc4)  data = 0x22;
+	      else if(data2 >= 0xac)  data = 0x1a;
+	      else if(data2 >= 0x9e)  data = 0x12;
+	      else if(data2 >= 0x8e)  data = 0x0a;
+	      else                    data = 0x02;
+	   } else {
+	      if(data2 >= 0x127)      data = 0xba;
+	      else                    data = 0x7a;
+	   }
+	} else {  /* 760+LFB */
+	   if     (data2 >= 0x190) data = 0xba;
+	   else if(data2 >= 0xff)  data = 0x7a;
+	   else if(data2 >= 0xd3)  data = 0x3a;
+	   else if(data2 >= 0xa9)  data = 0x1a;
+	   else if(data2 >= 0x93)  data = 0x0a;
 	   else                    data = 0x02;
-	 } else {
-	   if(data2 >= 0x127)      data = 0xba;
-	   else                    data = 0x7a;
-	 }
-      }
-      SiS_SetReg(SiS_Pr->SiS_P3c4,0x17,data);
+	}
+     }
+     SiS_SetReg(SiS_Pr->SiS_P3c4,0x17,data);
   }
 #endif
 
@@ -3202,46 +3100,6 @@
      } else {
         SiS_SetReg(SiS_Pr->SiS_P3d4,0x52,0x6c);
      }
-#if 0   /* What is SR0E[D5:6]? */
-     if(HwInfo->jChipType >= SIS_661) {
-        data = 0;
-        if((ModeNo == 6) || ((ModeNo >= 0x0e) && (ModeNo <= 0x13))) {
-	   data |= 0x20;
-	}
-	if(SiS_Pr->SiS_ModeType != ModeVGA) {
-	   if(SiS_Pr->UseCustomMode) {
-              if((xres >= 640) && (SiS_Pr->CVDisplay >= 480)) {
-	         data |= 0x40;
-	      }
-	      if((xres > 1280) && (SiS_Pr->CVDisplay > 1024)) {
-	         data |= 0x60;
-	      }
-	   }
-	} else if(ModeNo > 0x13) {   /* These are in the CRT1 table, and set by CRT1CRTC */
-	   if(resinfo >= SIS_RI_640x480) {
-	      if(resinfo <= SIS_RI_2048x1536) {
-	         data |= 0x40;
-		 if(resinfo > SIS_RI_1280x1024) {
-		    data |= 0x60;
-		    if(resinfo != SIS_RI_1600x1200) {
-		       data = SiS_GetReg(SiS_Pr->SiS_P3c4,0x0e);
-		       data += 0x60;
-		       SiS_SetReg(SiS_Pr->SiS_P3c4,0x0e);
-		       data = 0;
-		    }
-		 }
-	      }
-	      if(resinfo == SIS_RI_1152x864) {
-		 data = 0x40;
-	      }
-	      if(resinfo == SIS_RI_1400x1050) { /* TW */
-		 data = 0x60;
-	      }
-	   }
-	}
-	SiS_SetRegOR(SiS_Pr->SiS_P3c4,0x0e,data);
-     }
-#endif
   }
 #endif
 }
@@ -3416,7 +3274,7 @@
   SiS_SetCRTCRegs(SiS_Pr, HwInfo, StandTableIndex);
   SiS_SetATTRegs(SiS_Pr, StandTableIndex, HwInfo);
   SiS_SetGRCRegs(SiS_Pr, StandTableIndex);
-  SiS_ClearExt1Regs(SiS_Pr,HwInfo);
+  SiS_ClearExt1Regs(SiS_Pr, HwInfo, ModeNo);
   SiS_ResetCRT1VCLK(SiS_Pr, HwInfo);
 
   SiS_Pr->SiS_SelectCRT2Rate = 0;
@@ -3482,21 +3340,28 @@
 }
 
 /*********************************************/
-/*            HELPER: ENABLE CRT1            */
+/*         HELPER: RESET VIDEO BRIDGE        */
 /*********************************************/
 
 static void
-SiS_HandleCRT1(SiS_Private *SiS_Pr)
+SiS_ResetVB(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo)
 {
-  SiS_SetRegAND(SiS_Pr->SiS_P3d4,SiS_Pr->SiS_MyCR63,0xbf);
-#if 0
-  if(!(SiS_GetReg(SiS_Pr->SiS_P3c4,0x15) & 0x01)) {
-     if((SiS_GetReg(SiS_Pr->SiS_P3c4,0x15) & 0x0a) ||
-        (SiS_GetReg(SiS_Pr->SiS_P3c4,0x16) & 0x01)) {
-        SiS_SetRegOR(SiS_Pr->SiS_P3d4,SiS_Pr->SiS_MyCR63,0x40);
-     }
-  }
-#endif
+   UCHAR  *ROMAddr  = HwInfo->pjVirtualRomBase;
+   USHORT temp;
+
+   if(SiS_Pr->SiS_UseROM) {
+      if(HwInfo->jChipType < SIS_330) {
+         temp = ROMAddr[VB310Data_1_2_Offset] | 0x40;
+	 if(SiS_Pr->SiS_ROMNew) temp = ROMAddr[0x80] | 0x40;
+         SiS_SetReg(SiS_Pr->SiS_Part1Port,0x02,temp);
+      } else if(HwInfo->jChipType >= SIS_661) {
+         temp = ROMAddr[0x7e];
+         if(SiS_Pr->SiS_ROMNew) temp = ROMAddr[0x80];
+         if(HwInfo->jChipType >= SIS_660)                  temp |= 0x40;
+         else if(SiS_GetReg(SiS_Pr->SiS_P3d4,0x7b) >= 100) temp |= 0x40;
+         SiS_SetReg(SiS_Pr->SiS_Part1Port,0x02,temp);
+      }
+   }
 }
 
 /*********************************************/
@@ -3585,13 +3450,12 @@
 SiSSetMode(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo,USHORT ModeNo)
 #endif
 {
-   ULONG   temp;
    USHORT  ModeIdIndex;
-   UCHAR  *ROMAddr  = HwInfo->pjVirtualRomBase;
    SISIOADDRESS BaseAddr = HwInfo->ulIOAddress;
    unsigned char backupreg=0;
 #ifndef LINUX_XF86
    USHORT  KeepLockReg;
+   ULONG   temp;
 
    SiS_Pr->UseCustomMode = FALSE;
    SiS_Pr->CRT1UsesCustomMode = FALSE;
@@ -3605,7 +3469,7 @@
    SiSRegInit(SiS_Pr, BaseAddr);
    SiS_GetSysFlags(SiS_Pr, HwInfo);
 
-#ifdef LINUX_XF86
+#if defined(LINUX_XF86) && (defined(i386) || defined(__i386) || defined(__i386__) || defined(__AMD64__))
    if(pScrn) SiS_Pr->SiS_VGAINFO = SiS_GetSetBIOSScratch(pScrn, 0x489, 0xff);
    else
 #endif
@@ -3615,20 +3479,13 @@
    SiSSetLVDSetc(SiS_Pr, HwInfo);
    SiSDetermineROMUsage(SiS_Pr, HwInfo);
 
-   if(!SiS_Pr->UseCustomMode) {
-      ModeNo = ((ModeNo & 0x80) << 8) | (ModeNo & 0x7f);
-   }
+   SiS_Pr->SiS_flag_clearbuffer = 0;
 
-#ifdef LINUX_XF86
-   /* We never clear the buffer in X */
-   ModeNo |= 0x8000;
+   if(!SiS_Pr->UseCustomMode) {
+#ifndef LINUX_XF86
+      if(!(ModeNo & 0x80)) SiS_Pr->SiS_flag_clearbuffer = 1;
 #endif
-
-   if(ModeNo & 0x8000) {
-     	ModeNo &= 0x7fff;
-     	SiS_Pr->SiS_flag_clearbuffer = 0;
-   } else {
-     	SiS_Pr->SiS_flag_clearbuffer = 1;
+      ModeNo &= 0x7f;
    }
 
 #ifndef LINUX_XF86
@@ -3650,23 +3507,9 @@
 
    if(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) {
       if(HwInfo->jChipType >= SIS_315H) {
-         SiS_UnLockCRT2(SiS_Pr,HwInfo);
-	 if(ROMAddr && SiS_Pr->SiS_UseROM) {
-	    if(HwInfo->jChipType < SIS_330) {
-               temp = ROMAddr[VB310Data_1_2_Offset];
-	       temp |= 0x40;
-	       SiS_SetReg(SiS_Pr->SiS_Part1Port,0x02,temp);
-            }
-	    if(HwInfo->jChipType > SIS_330) {
-	       temp = ROMAddr[0x7e];
-	       if(SiS_GetReg(SiS_Pr->SiS_P3d4,0x7b) >= 100) temp |= 0x40;
-	       SiS_SetReg(SiS_Pr->SiS_Part1Port,0x02,temp);
-	    }
-	 }
+         SiS_ResetVB(SiS_Pr, HwInfo);
 	 SiS_SetRegOR(SiS_Pr->SiS_P3c4,0x32,0x10);
-
 	 SiS_SetRegOR(SiS_Pr->SiS_Part2Port,0x00,0x0c);
-
          backupreg = SiS_GetReg(SiS_Pr->SiS_P3d4,0x38);
       } else {
          backupreg = SiS_GetReg(SiS_Pr->SiS_P3d4,0x35);
@@ -3687,27 +3530,7 @@
 #endif
 
    if(HwInfo->jChipType >= SIS_315H) {
-#if 0
-      if(SiS_GetReg(SiS_Pr->SiS_P3c4,0x17) & 0x08)  {
-         if(SiS_Pr->SiS_IF_DEF_LVDS == 1) {
-            if(ModeNo != 0x10)  SiS_Pr->SiS_SetFlag |= SetDOSMode;
-         } else if((IS_SIS651) && (SiS_Pr->SiS_VBType & VB_NoLCD)) {
-            SiS_Pr->SiS_SetFlag |= SetDOSMode;
-         }
-      }
-#endif
-
-      if(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) {
-         if(IS_SIS650) {
-	    SiS_SetRegAND(SiS_Pr->SiS_P3d4,0x51,0x1f);
-	    if(IS_SIS651) SiS_SetRegOR(SiS_Pr->SiS_P3d4,0x51,0x20);
-	    SiS_SetRegAND(SiS_Pr->SiS_P3d4,0x56,0xe7);
-	 } else if(IS_SIS661741660760) {
-	    SiS_SetRegAND(SiS_Pr->SiS_P3d4,0x51,0x1f);
-	    SiS_SetRegAND(SiS_Pr->SiS_P3d4,0x56,0xe7);
-	    SiS_SetRegAND(SiS_Pr->SiS_P3d4,0x3a,0xef);
-	 }
-      }
+      SiS_SetupCR5x(SiS_Pr, HwInfo);
    }
 
    if(SiS_Pr->UseCustomMode) {
@@ -3751,7 +3574,7 @@
 
    if(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) {
       if(HwInfo->jChipType >= SIS_315H) {
-         if(HwInfo->jChipType < SIS_661) {
+         if(!SiS_Pr->SiS_ROMNew) {
 	    if(SiS_IsVAMode(SiS_Pr,HwInfo)) {
 	       SiS_SetRegOR(SiS_Pr->SiS_P3d4,0x35,0x01);
 	    } else {
@@ -3840,9 +3663,7 @@
 SiSBIOSSetModeCRT2(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo, ScrnInfoPtr pScrn,
                DisplayModePtr mode, BOOLEAN IsCustom)
 {
-   ULONG   temp;
    USHORT  ModeIdIndex;
-   UCHAR  *ROMAddr  = HwInfo->pjVirtualRomBase;
    SISIOADDRESS BaseAddr = HwInfo->ulIOAddress;
    UShort  ModeNo   = 0;
    unsigned char backupreg=0;
@@ -3879,7 +3700,11 @@
    SiSRegInit(SiS_Pr, BaseAddr);
    SiSInitPtr(SiS_Pr, HwInfo);
    SiS_GetSysFlags(SiS_Pr, HwInfo);
+#if (defined(i386) || defined(__i386) || defined(__i386__) || defined(__AMD64__))
    SiS_Pr->SiS_VGAINFO = SiS_GetSetBIOSScratch(pScrn, 0x489, 0xff);
+#else
+   SiS_Pr->SiS_VGAINFO = 0x11;
+#endif
    SiSInitPCIetc(SiS_Pr, HwInfo);
    SiSSetLVDSetc(SiS_Pr, HwInfo);
    SiSDetermineROMUsage(SiS_Pr, HwInfo);
@@ -3941,23 +3766,9 @@
 
    if(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) {
       if(HwInfo->jChipType >= SIS_315H) {
-         SiS_UnLockCRT2(SiS_Pr,HwInfo);
-         if(ROMAddr && SiS_Pr->SiS_UseROM) {
-	    if(HwInfo->jChipType < SIS_330) {
-               temp = ROMAddr[VB310Data_1_2_Offset];
-	       temp |= 0x40;
-               SiS_SetReg(SiS_Pr->SiS_Part1Port,0x02,temp);
-            }
-	    if(HwInfo->jChipType > SIS_330) {
-	       temp = ROMAddr[0x7e];
-	       if(SiS_GetReg(SiS_Pr->SiS_P3d4,0x7b) >= 100) temp |= 0x40;
-	       SiS_SetReg(SiS_Pr->SiS_Part1Port,0x02,temp);
-	    }
-	 }
+	 SiS_ResetVB(SiS_Pr, HwInfo);
 	 SiS_SetRegOR(SiS_Pr->SiS_P3c4,0x32,0x10);
-
 	 SiS_SetRegOR(SiS_Pr->SiS_Part2Port,0x00,0x0c);
-
          backupreg = SiS_GetReg(SiS_Pr->SiS_P3d4,0x38);
       } else {
          backupreg = SiS_GetReg(SiS_Pr->SiS_P3d4,0x35);
@@ -3999,7 +3810,7 @@
 
    if(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) {
       if(HwInfo->jChipType >= SIS_315H) {
-         if(HwInfo->jChipType < SIS_661) {
+         if(!SiS_Pr->SiS_ROMNew) {
 	    if(SiS_IsVAMode(SiS_Pr,HwInfo)) {
 	       SiS_SetRegOR(SiS_Pr->SiS_P3d4,0x35,0x01);
 	    } else {
@@ -4069,7 +3880,11 @@
    SiSInitPtr(SiS_Pr, HwInfo);
    SiSRegInit(SiS_Pr, BaseAddr);
    SiS_GetSysFlags(SiS_Pr, HwInfo);
+#if (defined(i386) || defined(__i386) || defined(__i386__) || defined(__AMD64__))
    SiS_Pr->SiS_VGAINFO = SiS_GetSetBIOSScratch(pScrn, 0x489, 0xff);
+#else
+   SiS_Pr->SiS_VGAINFO = 0x11;
+#endif
    SiSInitPCIetc(SiS_Pr, HwInfo);
    SiSSetLVDSetc(SiS_Pr, HwInfo);
    SiSDetermineROMUsage(SiS_Pr, HwInfo);
@@ -4107,27 +3922,7 @@
    SiS_SetLowModeTest(SiS_Pr, ModeNo, HwInfo);
 
    if(HwInfo->jChipType >= SIS_315H) {
-#if 0
-      if(SiS_GetReg(SiS_Pr->SiS_P3c4,0x17) & 0x08)  {
-         if(SiS_Pr->SiS_IF_DEF_LVDS == 1) {
-            if(ModeNo != 0x10)  SiS_Pr->SiS_SetFlag |= SetDOSMode;
-         } else if((IS_SIS651) && (SiS_Pr->SiS_VBType & VB_NoLCD)) {
-            SiS_Pr->SiS_SetFlag |= SetDOSMode;
-         }
-      }
-#endif
-
-      if(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) {
-         if(IS_SIS650) {
-	    SiS_SetRegAND(SiS_Pr->SiS_P3d4,0x51,0x1f);
-	    if(IS_SIS651) SiS_SetRegOR(SiS_Pr->SiS_P3d4,0x51,0x20);
-	    SiS_SetRegAND(SiS_Pr->SiS_P3d4,0x56,0xe7);
-	 } else if(IS_SIS661741660760) {
-	    SiS_SetRegAND(SiS_Pr->SiS_P3d4,0x51,0x1f);
-	    SiS_SetRegAND(SiS_Pr->SiS_P3d4,0x56,0xe7);
-	    SiS_SetRegAND(SiS_Pr->SiS_P3d4,0x3a,0xef);
-	 }
-      }
+      SiS_SetupCR5x(SiS_Pr, HwInfo);
    }
 
    /* Set mode on CRT1 */
@@ -4296,12 +4091,188 @@
 }
 #endif
 
+#ifndef GETBITSTR
+#define BITMASK(h,l)    	(((unsigned)(1U << ((h)-(l)+1))-1)<<(l))
+#define GENMASK(mask)   	BITMASK(1?mask,0?mask)
+#define GETBITS(var,mask)   	(((var) & GENMASK(mask)) >> (0?mask))
+#define GETBITSTR(val,from,to)  ((GETBITS(val,from)) << (0?to))
+#endif
+
+static void
+SiS_CalcCRRegisters(SiS_Private *SiS_Pr, int depth)
+{
+   SiS_Pr->CCRT1CRTC[0]  =  ((SiS_Pr->CHTotal >> 3) - 5) & 0xff;		/* CR0 */
+   SiS_Pr->CCRT1CRTC[1]  =  (SiS_Pr->CHDisplay >> 3) - 1;			/* CR1 */
+   SiS_Pr->CCRT1CRTC[2]  =  (SiS_Pr->CHBlankStart >> 3) - 1;			/* CR2 */
+   SiS_Pr->CCRT1CRTC[3]  =  (((SiS_Pr->CHBlankEnd >> 3) - 1) & 0x1F) | 0x80;	/* CR3 */
+   SiS_Pr->CCRT1CRTC[4]  =  (SiS_Pr->CHSyncStart >> 3) + 3;			/* CR4 */
+   SiS_Pr->CCRT1CRTC[5]  =  ((((SiS_Pr->CHBlankEnd >> 3) - 1) & 0x20) << 2) |	/* CR5 */
+       			    (((SiS_Pr->CHSyncEnd >> 3) + 3) & 0x1F);
+
+   SiS_Pr->CCRT1CRTC[6]  =  (SiS_Pr->CVTotal - 2) & 0xFF;			/* CR6 */
+   SiS_Pr->CCRT1CRTC[7]  =  (((SiS_Pr->CVTotal - 2) & 0x100) >> 8)		/* CR7 */
+ 	 		  | (((SiS_Pr->CVDisplay - 1) & 0x100) >> 7)
+	 		  | ((SiS_Pr->CVSyncStart & 0x100) >> 6)
+	 	  	  | (((SiS_Pr->CVBlankStart - 1) & 0x100) >> 5)
+			  | 0x10
+	 		  | (((SiS_Pr->CVTotal - 2) & 0x200)   >> 4)
+	 		  | (((SiS_Pr->CVDisplay - 1) & 0x200) >> 3)
+	 		  | ((SiS_Pr->CVSyncStart & 0x200) >> 2);
+
+   SiS_Pr->CCRT1CRTC[16] = ((((SiS_Pr->CVBlankStart - 1) & 0x200) >> 4) >> 5); 	/* CR9 */
+
+   if(depth != 8) {
+      if(SiS_Pr->CHDisplay >= 1600)      SiS_Pr->CCRT1CRTC[16] |= 0x60;		/* SRE */
+      else if(SiS_Pr->CHDisplay >= 640)  SiS_Pr->CCRT1CRTC[16] |= 0x40;
+   }
+
+#if 0
+   if (mode->VScan >= 32)
+	regp->CRTC[9] |= 0x1F;
+   else if (mode->VScan > 1)
+	regp->CRTC[9] |= mode->VScan - 1;
+#endif
+
+   SiS_Pr->CCRT1CRTC[8] =  (SiS_Pr->CVSyncStart     ) & 0xFF;			/* CR10 */
+   SiS_Pr->CCRT1CRTC[9] =  ((SiS_Pr->CVSyncEnd      ) & 0x0F) | 0x80;		/* CR11 */
+   SiS_Pr->CCRT1CRTC[10] = (SiS_Pr->CVDisplay    - 1) & 0xFF;			/* CR12 */
+   SiS_Pr->CCRT1CRTC[11] = (SiS_Pr->CVBlankStart - 1) & 0xFF;			/* CR15 */
+   SiS_Pr->CCRT1CRTC[12] = (SiS_Pr->CVBlankEnd   - 1) & 0xFF;			/* CR16 */
+
+   SiS_Pr->CCRT1CRTC[13] =							/* SRA */
+                        GETBITSTR((SiS_Pr->CVTotal     -2), 10:10, 0:0) |
+                        GETBITSTR((SiS_Pr->CVDisplay   -1), 10:10, 1:1) |
+                        GETBITSTR((SiS_Pr->CVBlankStart-1), 10:10, 2:2) |
+                        GETBITSTR((SiS_Pr->CVSyncStart   ), 10:10, 3:3) |
+                        GETBITSTR((SiS_Pr->CVBlankEnd  -1),   8:8, 4:4) |
+                        GETBITSTR((SiS_Pr->CVSyncEnd     ),   4:4, 5:5) ;
+
+   SiS_Pr->CCRT1CRTC[14] =							/* SRB */
+                        GETBITSTR((SiS_Pr->CHTotal      >> 3) - 5, 9:8, 1:0) |
+                        GETBITSTR((SiS_Pr->CHDisplay    >> 3) - 1, 9:8, 3:2) |
+                        GETBITSTR((SiS_Pr->CHBlankStart >> 3) - 1, 9:8, 5:4) |
+                        GETBITSTR((SiS_Pr->CHSyncStart  >> 3) + 3, 9:8, 7:6) ;
+
+
+   SiS_Pr->CCRT1CRTC[15] =							/* SRC */
+                        GETBITSTR((SiS_Pr->CHBlankEnd >> 3) - 1, 7:6, 1:0) |
+                        GETBITSTR((SiS_Pr->CHSyncEnd  >> 3) + 3, 5:5, 2:2) ;
+}
+
+void
+SiS_CalcLCDACRT1Timing(SiS_Private *SiS_Pr,USHORT ModeNo,USHORT ModeIdIndex)
+{
+   USHORT modeflag, tempax, tempbx, VGAHDE = SiS_Pr->SiS_VGAHDE;
+   int i,j;
+
+   /* 1:1 data: use data set by setcrt1crtc() */
+   if(SiS_Pr->SiS_LCDInfo & LCDPass11) return;
+
+   if(ModeNo <= 0x13) {
+     modeflag = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_ModeFlag;
+   } else if(SiS_Pr->UseCustomMode) {
+     modeflag = SiS_Pr->CModeFlag;
+   } else {
+     modeflag = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag;
+   }
+
+   if(modeflag & HalfDCLK) VGAHDE >>= 1;
+
+   SiS_Pr->CHDisplay = VGAHDE;
+   SiS_Pr->CHBlankStart = VGAHDE;
+
+   SiS_Pr->CVDisplay = SiS_Pr->SiS_VGAVDE;
+   SiS_Pr->CVBlankStart = SiS_Pr->SiS_VGAVDE;
+
+   tempbx = SiS_Pr->PanelHT - SiS_Pr->PanelXRes;
+   tempax = SiS_Pr->SiS_VGAHDE;  /* not /2 ! */
+   if(SiS_Pr->SiS_LCDInfo & DontExpandLCD) {
+      tempax = SiS_Pr->PanelXRes;
+   }
+   tempbx += tempax;
+   if(modeflag & HalfDCLK) tempbx -= VGAHDE;
+   SiS_Pr->CHTotal = SiS_Pr->CHBlankEnd = tempbx;
+
+   tempax = VGAHDE;
+   tempbx = SiS_Pr->CHTotal;
+   if(SiS_Pr->SiS_LCDInfo & DontExpandLCD) {
+      tempbx = SiS_Pr->PanelXRes;
+      if(modeflag & HalfDCLK) tempbx >>= 1;
+      tempax += ((tempbx - tempax) >> 1);
+   }
+
+   tempax += SiS_Pr->PanelHRS;
+   SiS_Pr->CHSyncStart = tempax;
+   tempax += SiS_Pr->PanelHRE;
+   SiS_Pr->CHSyncEnd = tempax;
+
+   tempbx = SiS_Pr->PanelVT - SiS_Pr->PanelYRes;
+   tempax = SiS_Pr->SiS_VGAVDE;
+   if(SiS_Pr->SiS_LCDInfo & DontExpandLCD) {
+      tempax = SiS_Pr->PanelYRes;
+   }
+   SiS_Pr->CVTotal = SiS_Pr->CVBlankEnd = tempbx + tempax;
+
+   tempax = SiS_Pr->SiS_VGAVDE;
+   if(SiS_Pr->SiS_LCDInfo & DontExpandLCD) {
+      tempax += (SiS_Pr->PanelYRes - tempax) >> 1;
+   }
+   tempax += SiS_Pr->PanelVRS;
+   SiS_Pr->CVSyncStart = tempax;
+   tempax += SiS_Pr->PanelVRE;
+   SiS_Pr->CVSyncEnd = tempax;
+
+   SiS_CalcCRRegisters(SiS_Pr, 8);
+   SiS_Pr->CCRT1CRTC[16] &= ~0xE0;
+
+   SiS_SetRegAND(SiS_Pr->SiS_P3d4,0x11,0x7f);
+
+   for(i=0,j=0;i<=7;i++,j++) {
+      SiS_SetReg(SiS_Pr->SiS_P3d4,j,SiS_Pr->CCRT1CRTC[i]);
+   }
+   for(j=0x10;i<=10;i++,j++) {
+      SiS_SetReg(SiS_Pr->SiS_P3d4,j,SiS_Pr->CCRT1CRTC[i]);
+   }
+   for(j=0x15;i<=12;i++,j++) {
+      SiS_SetReg(SiS_Pr->SiS_P3d4,j,SiS_Pr->CCRT1CRTC[i]);
+   }
+   for(j=0x0A;i<=15;i++,j++) {
+      SiS_SetReg(SiS_Pr->SiS_P3c4,j,SiS_Pr->CCRT1CRTC[i]);
+   }
+
+   tempax = SiS_Pr->CCRT1CRTC[16] & 0xE0;
+   SiS_SetRegANDOR(SiS_Pr->SiS_P3c4,0x0E,0x1F,tempax);
+
+   tempax = (SiS_Pr->CCRT1CRTC[16] & 0x01) << 5;
+   if(modeflag & DoubleScanMode) tempax |= 0x80;
+   SiS_SetRegANDOR(SiS_Pr->SiS_P3d4,0x09,0x5F,tempax);
+
+#ifdef TWDEBUG
+   xf86DrvMsg(0, X_INFO, "%d %d %d %d  %d %d %d %d  (%d %d %d %d)\n",
+       	SiS_Pr->CHDisplay, SiS_Pr->CHSyncStart, SiS_Pr->CHSyncEnd, SiS_Pr->CHTotal,
+	SiS_Pr->CVDisplay, SiS_Pr->CVSyncStart, SiS_Pr->CVSyncEnd, SiS_Pr->CVTotal,
+	SiS_Pr->CHBlankStart, SiS_Pr->CHBlankEnd, SiS_Pr->CVBlankStart, SiS_Pr->CVBlankEnd);
+
+   xf86DrvMsg(0, X_INFO, " {{0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,\n",
+   	SiS_Pr->CCRT1CRTC[0], SiS_Pr->CCRT1CRTC[1],
+	SiS_Pr->CCRT1CRTC[2], SiS_Pr->CCRT1CRTC[3],
+	SiS_Pr->CCRT1CRTC[4], SiS_Pr->CCRT1CRTC[5],
+	SiS_Pr->CCRT1CRTC[6], SiS_Pr->CCRT1CRTC[7]);
+   xf86DrvMsg(0, X_INFO, "   0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,\n",
+   	SiS_Pr->CCRT1CRTC[8], SiS_Pr->CCRT1CRTC[9],
+	SiS_Pr->CCRT1CRTC[10], SiS_Pr->CCRT1CRTC[11],
+	SiS_Pr->CCRT1CRTC[12], SiS_Pr->CCRT1CRTC[13],
+	SiS_Pr->CCRT1CRTC[14], SiS_Pr->CCRT1CRTC[15]);
+   xf86DrvMsg(0, X_INFO, "   0x%02x}},\n", SiS_Pr->CCRT1CRTC[16]);
+#endif
+}
 
 /* ================ XFREE86 ================= */
 
 /* Helper functions */
 
 #ifdef LINUX_XF86
+
 USHORT
 SiS_CheckBuildCustomMode(ScrnInfoPtr pScrn, DisplayModePtr mode, int VBFlags)
 {
@@ -4382,73 +4353,16 @@
 
    pSiS->SiS_Pr->CSRClock = (pSiS->SiS_Pr->CDClock / 1000) + 1;
 
-   pSiS->SiS_Pr->CCRT1CRTC[0]  =  ((pSiS->SiS_Pr->CHTotal >> 3) - 5) & 0xff;
-   pSiS->SiS_Pr->CCRT1CRTC[1]  =  (pSiS->SiS_Pr->CHDisplay >> 3) - 1;
-   pSiS->SiS_Pr->CCRT1CRTC[2]  =  (pSiS->SiS_Pr->CHBlankStart >> 3) - 1;
-   pSiS->SiS_Pr->CCRT1CRTC[3]  =  (((pSiS->SiS_Pr->CHBlankEnd >> 3) - 1) & 0x1F) | 0x80;
-   pSiS->SiS_Pr->CCRT1CRTC[4]  =  (pSiS->SiS_Pr->CHSyncStart >> 3) + 3;
-   pSiS->SiS_Pr->CCRT1CRTC[5]  =  ((((pSiS->SiS_Pr->CHBlankEnd >> 3) - 1) & 0x20) << 2) |
-       				  (((pSiS->SiS_Pr->CHSyncEnd >> 3) + 3) & 0x1F);
-
-   pSiS->SiS_Pr->CCRT1CRTC[6]  =  (pSiS->SiS_Pr->CVTotal - 2) & 0xFF;
-   pSiS->SiS_Pr->CCRT1CRTC[7]  =  (((pSiS->SiS_Pr->CVTotal - 2) & 0x100) >> 8)
- 	 			| (((pSiS->SiS_Pr->CVDisplay - 1) & 0x100) >> 7)
-	 			| ((pSiS->SiS_Pr->CVSyncStart & 0x100) >> 6)
-	 			| (((pSiS->SiS_Pr->CVBlankStart - 1) & 0x100) >> 5)
-	 			| 0x10
-	 			| (((pSiS->SiS_Pr->CVTotal - 2) & 0x200)   >> 4)
-	 			| (((pSiS->SiS_Pr->CVDisplay - 1) & 0x200) >> 3)
-	 			| ((pSiS->SiS_Pr->CVSyncStart & 0x200) >> 2);
-
-   pSiS->SiS_Pr->CCRT1CRTC[16] = ((((pSiS->SiS_Pr->CVBlankStart - 1) & 0x200) >> 4) >> 5); 	/* cr9 */
-
-#if 0
-   if (mode->VScan >= 32)
-	regp->CRTC[9] |= 0x1F;
-   else if (mode->VScan > 1)
-	regp->CRTC[9] |= mode->VScan - 1;
-#endif
-
-   pSiS->SiS_Pr->CCRT1CRTC[8] =  (pSiS->SiS_Pr->CVSyncStart     ) & 0xFF;		/* cr10 */
-   pSiS->SiS_Pr->CCRT1CRTC[9] =  ((pSiS->SiS_Pr->CVSyncEnd      ) & 0x0F) | 0x80;	/* cr11 */
-   pSiS->SiS_Pr->CCRT1CRTC[10] = (pSiS->SiS_Pr->CVDisplay    - 1) & 0xFF;		/* cr12 */
-   pSiS->SiS_Pr->CCRT1CRTC[11] = (pSiS->SiS_Pr->CVBlankStart - 1) & 0xFF;		/* cr15 */
-   pSiS->SiS_Pr->CCRT1CRTC[12] = (pSiS->SiS_Pr->CVBlankEnd   - 1) & 0xFF;		/* cr16 */
-
-   pSiS->SiS_Pr->CCRT1CRTC[13] =
-                        GETBITSTR((pSiS->SiS_Pr->CVTotal     -2), 10:10, 0:0) |
-                        GETBITSTR((pSiS->SiS_Pr->CVDisplay   -1), 10:10, 1:1) |
-                        GETBITSTR((pSiS->SiS_Pr->CVBlankStart-1), 10:10, 2:2) |
-                        GETBITSTR((pSiS->SiS_Pr->CVSyncStart   ), 10:10, 3:3) |
-                        GETBITSTR((pSiS->SiS_Pr->CVBlankEnd  -1),   8:8, 4:4) |
-                        GETBITSTR((pSiS->SiS_Pr->CVSyncEnd     ),   4:4, 5:5) ;
-
-   pSiS->SiS_Pr->CCRT1CRTC[14] =
-                        GETBITSTR((pSiS->SiS_Pr->CHTotal      >> 3) - 5, 9:8, 1:0) |
-                        GETBITSTR((pSiS->SiS_Pr->CHDisplay    >> 3) - 1, 9:8, 3:2) |
-                        GETBITSTR((pSiS->SiS_Pr->CHBlankStart >> 3) - 1, 9:8, 5:4) |
-                        GETBITSTR((pSiS->SiS_Pr->CHSyncStart  >> 3) + 3, 9:8, 7:6) ;
-
-
-   pSiS->SiS_Pr->CCRT1CRTC[15] =
-                        GETBITSTR((pSiS->SiS_Pr->CHBlankEnd >> 3) - 1, 7:6, 1:0) |
-                        GETBITSTR((pSiS->SiS_Pr->CHSyncEnd  >> 3) + 3, 5:5, 2:2) ;
+   SiS_CalcCRRegisters(pSiS->SiS_Pr, depth);
 
    switch(depth) {
-   case 8:
-      	pSiS->SiS_Pr->CModeFlag |= 0x223b;
-	break;
-   case 16:
-      	pSiS->SiS_Pr->CModeFlag |= 0x227d;
-	break;
-   case 32:
-      	pSiS->SiS_Pr->CModeFlag |= 0x22ff;
-	break;		
-   default: 
-   	return 0;	
-   }	
-   
-   if(pSiS->SiS_Pr->CFlags & V_DBLSCAN) 
+   case 8:  pSiS->SiS_Pr->CModeFlag |= 0x223b; break;
+   case 16: pSiS->SiS_Pr->CModeFlag |= 0x227d; break;
+   case 32: pSiS->SiS_Pr->CModeFlag |= 0x22ff; break;
+   default: return 0;
+   }
+
+   if(pSiS->SiS_Pr->CFlags & V_DBLSCAN)
       pSiS->SiS_Pr->CModeFlag |= DoubleScanMode;
 
    if((pSiS->SiS_Pr->CVDisplay >= 1024)	||
@@ -4472,33 +4386,23 @@
 
    pSiS->SiS_Pr->UseCustomMode = TRUE;
 #ifdef TWDEBUG
-   xf86DrvMsg(0, X_INFO, "Custom mode %dx%d:\n", 
+   xf86DrvMsg(0, X_INFO, "Custom mode %dx%d:\n",
    	pSiS->SiS_Pr->CHDisplay,pSiS->SiS_Pr->CVDisplay);
    xf86DrvMsg(0, X_INFO, "Modeflag %04x, Infoflag %04x\n",
    	pSiS->SiS_Pr->CModeFlag, pSiS->SiS_Pr->CInfoFlag);
    xf86DrvMsg(0, X_INFO, " {{0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,\n",
-   	pSiS->SiS_Pr->CCRT1CRTC[0],
-	pSiS->SiS_Pr->CCRT1CRTC[1],
-	pSiS->SiS_Pr->CCRT1CRTC[2],
-	pSiS->SiS_Pr->CCRT1CRTC[3],
-	pSiS->SiS_Pr->CCRT1CRTC[4],
-	pSiS->SiS_Pr->CCRT1CRTC[5],
-	pSiS->SiS_Pr->CCRT1CRTC[6],
-	pSiS->SiS_Pr->CCRT1CRTC[7]);
+   	pSiS->SiS_Pr->CCRT1CRTC[0], pSiS->SiS_Pr->CCRT1CRTC[1],
+	pSiS->SiS_Pr->CCRT1CRTC[2], pSiS->SiS_Pr->CCRT1CRTC[3],
+	pSiS->SiS_Pr->CCRT1CRTC[4], pSiS->SiS_Pr->CCRT1CRTC[5],
+	pSiS->SiS_Pr->CCRT1CRTC[6], pSiS->SiS_Pr->CCRT1CRTC[7]);
    xf86DrvMsg(0, X_INFO, "  0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,\n",
-   	pSiS->SiS_Pr->CCRT1CRTC[8],
-	pSiS->SiS_Pr->CCRT1CRTC[9],
-	pSiS->SiS_Pr->CCRT1CRTC[10],
-	pSiS->SiS_Pr->CCRT1CRTC[11],
-	pSiS->SiS_Pr->CCRT1CRTC[12],
-	pSiS->SiS_Pr->CCRT1CRTC[13],
-	pSiS->SiS_Pr->CCRT1CRTC[14],
-	pSiS->SiS_Pr->CCRT1CRTC[15]);
+   	pSiS->SiS_Pr->CCRT1CRTC[8], pSiS->SiS_Pr->CCRT1CRTC[9],
+	pSiS->SiS_Pr->CCRT1CRTC[10], pSiS->SiS_Pr->CCRT1CRTC[11],
+	pSiS->SiS_Pr->CCRT1CRTC[12], pSiS->SiS_Pr->CCRT1CRTC[13],
+	pSiS->SiS_Pr->CCRT1CRTC[14], pSiS->SiS_Pr->CCRT1CRTC[15]);
    xf86DrvMsg(0, X_INFO, "  0x%02x}},\n", pSiS->SiS_Pr->CCRT1CRTC[16]);
    xf86DrvMsg(0, X_INFO, "Clock: 0x%02x, 0x%02x, %d\n",
-   	pSiS->SiS_Pr->CSR2B,
-	pSiS->SiS_Pr->CSR2C,
-	pSiS->SiS_Pr->CSRClock);
+   	pSiS->SiS_Pr->CSR2B, pSiS->SiS_Pr->CSR2C, pSiS->SiS_Pr->CSRClock);
 #endif
    return 1;
 }
@@ -4615,7 +4519,7 @@
       /* Horizontal display enable end */
       HDE = (cr_data & 0xff) |
             ((unsigned short) (sr_data & 0x0C) << 6);
-      E = HDE + 1;
+      E = HDE + 1;  /* 0x80 0x64 */
 
       cr_data = pSiS->SiS_Pr->SiS_CRT1Table[index].CR[4];
 	/* inSISIDXREG(SISCR, 0x04, cr_data); */
@@ -4623,7 +4527,7 @@
       /* Horizontal retrace (=sync) start */
       HRS = (cr_data & 0xff) |
             ((unsigned short) (sr_data & 0xC0) << 2);
-      F = HRS - E - 3;
+      F = HRS - E - 3;  /* 0x06 0x06 */
 
       cr_data = pSiS->SiS_Pr->SiS_CRT1Table[index].CR[2];
 	/* inSISIDXREG(SISCR, 0x02, cr_data); */
@@ -4653,7 +4557,7 @@
       B = (temp > 0) ? temp : (temp + 256);
 
       temp = HRE - ((E + F + 3) & 63);
-      C = (temp > 0) ? temp : (temp + 64);
+      C = (temp > 0) ? temp : (temp + 64); /* 0x0b 0x0b */
 
       D = B - F - C;
 
@@ -5159,10 +5063,7 @@
 int
 sisfb_mode_rate_to_ddata(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo,
 			 unsigned char modeno, unsigned char rateindex,
-			 ULONG *left_margin, ULONG *right_margin, 
-			 ULONG *upper_margin, ULONG *lower_margin,
-			 ULONG *hsync_len, ULONG *vsync_len,
-			 ULONG *sync, ULONG *vmode)
+			 struct fb_var_screeninfo *var)
 {
     USHORT ModeNo = modeno;
     USHORT ModeIdIndex = 0, index = 0;
@@ -5185,7 +5086,7 @@
        return 0;
 #endif
     }
-    
+
     if(!(SiS_SearchModeID(SiS_Pr, &ModeNo, &ModeIdIndex))) return 0;
 
     RefreshRateTableIndex = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].REFindex;
@@ -5250,15 +5151,15 @@
 	 /* Terrible hack, but the correct CRTC data for
 	  * these modes only produces a black screen...
 	  */
-       *left_margin = (400 - 376);
-       *right_margin = (328 - 320);
-       *hsync_len = (376 - 328);
+       var->left_margin = (400 - 376);
+       var->right_margin = (328 - 320);
+       var->hsync_len = (376 - 328);
 
     } else {
 
-       *left_margin = D * 8;
-       *right_margin = F * 8;
-       *hsync_len = C * 8;
+       var->left_margin = D * 8;
+       var->right_margin = F * 8;
+       var->hsync_len = C * 8;
 
     }
 
@@ -5320,47 +5221,47 @@
 
     D = B - F - C;
       
-    *upper_margin = D;
-    *lower_margin = F;
-    *vsync_len = C;
+    var->upper_margin = D;
+    var->lower_margin = F;
+    var->vsync_len = C;
 
     if(SiS_Pr->SiS_RefIndex[RefreshRateTableIndex].Ext_InfoFlag & 0x8000)
-       *sync &= ~FB_SYNC_VERT_HIGH_ACT;
+       var->sync &= ~FB_SYNC_VERT_HIGH_ACT;
     else
-       *sync |= FB_SYNC_VERT_HIGH_ACT;
+       var->sync |= FB_SYNC_VERT_HIGH_ACT;
 
     if(SiS_Pr->SiS_RefIndex[RefreshRateTableIndex].Ext_InfoFlag & 0x4000)       
-       *sync &= ~FB_SYNC_HOR_HIGH_ACT;
+       var->sync &= ~FB_SYNC_HOR_HIGH_ACT;
     else
-       *sync |= FB_SYNC_HOR_HIGH_ACT;
+       var->sync |= FB_SYNC_HOR_HIGH_ACT;
 		
-    *vmode = FB_VMODE_NONINTERLACED;
+    var->vmode = FB_VMODE_NONINTERLACED;
     if(SiS_Pr->SiS_RefIndex[RefreshRateTableIndex].Ext_InfoFlag & 0x0080)
-       *vmode = FB_VMODE_INTERLACED;
+       var->vmode = FB_VMODE_INTERLACED;
     else {
-      j = 0;
-      while(SiS_Pr->SiS_EModeIDTable[j].Ext_ModeID != 0xff) {
+       j = 0;
+       while(SiS_Pr->SiS_EModeIDTable[j].Ext_ModeID != 0xff) {
           if(SiS_Pr->SiS_EModeIDTable[j].Ext_ModeID ==
 	                  SiS_Pr->SiS_RefIndex[RefreshRateTableIndex].ModeID) {
               if(SiS_Pr->SiS_EModeIDTable[j].Ext_ModeFlag & DoubleScanMode) {
-	      	  *vmode = FB_VMODE_DOUBLE;
+	      	  var->vmode = FB_VMODE_DOUBLE;
               }
 	      break;
           }
 	  j++;
-      }
+       }
     }       
 
-    if((*vmode & FB_VMODE_MASK) == FB_VMODE_INTERLACED) {
+    if((var->vmode & FB_VMODE_MASK) == FB_VMODE_INTERLACED) {
 #if 0  /* Do this? */
-       *upper_margin <<= 1;
-       *lower_margin <<= 1;
-       *vsync_len <<= 1;
-#endif
-    } else if((*vmode & FB_VMODE_MASK) == FB_VMODE_DOUBLE) {
-       *upper_margin >>= 1;
-       *lower_margin >>= 1;
-       *vsync_len >>= 1;
+       var->upper_margin <<= 1;
+       var->lower_margin <<= 1;
+       var->vsync_len <<= 1;
+#endif
+    } else if((var->vmode & FB_VMODE_MASK) == FB_VMODE_DOUBLE) {
+       var->upper_margin >>= 1;
+       var->lower_margin >>= 1;
+       var->vsync_len >>= 1;
     }
 
     return 1;       
--- diff/drivers/video/sis/init.h	2004-05-19 22:12:23.000000000 +0100
+++ source/drivers/video/sis/init.h	2004-06-11 19:22:05.000000000 +0100
@@ -1,4 +1,5 @@
 /* $XFree86$ */
+/* $XdotOrg$ */
 /*
  * Data and prototypes for init.c
  *
@@ -31,13 +32,10 @@
  * * 2) Redistributions in binary form must reproduce the above copyright
  * *    notice, this list of conditions and the following disclaimer in the
  * *    documentation and/or other materials provided with the distribution.
- * * 3) All advertising materials mentioning features or use of this software
- * *    must display the following acknowledgement: "This product includes
- * *    software developed by Thomas Winischhofer, Vienna, Austria."
- * * 4) The name of the author may not be used to endorse or promote products
+ * * 3) The name of the author may not be used to endorse or promote products
  * *    derived from this software without specific prior written permission.
  * *
- * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESSED OR
  * * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
  * * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
  * * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
@@ -101,6 +99,7 @@
 const USHORT  ModeIndex_800x600[]      = {0x30, 0x47, 0x00, 0x63};
 const USHORT  ModeIndex_848x480[]      = {0x39, 0x3b, 0x00, 0x3e};
 const USHORT  ModeIndex_856x480[]      = {0x3f, 0x42, 0x00, 0x45};
+const USHORT  ModeIndex_960x540[]      = {0x1d, 0x1e, 0x00, 0x1f};  /* 315 series only */
 const USHORT  ModeIndex_1024x768[]     = {0x38, 0x4a, 0x00, 0x64};
 const USHORT  ModeIndex_1024x576[]     = {0x71, 0x74, 0x00, 0x77};
 const USHORT  ModeIndex_1024x600[]     = {0x20, 0x21, 0x00, 0x22};  /* 300 series only */
@@ -111,10 +110,13 @@
 const USHORT  ModeIndex_300_1280x768[] = {0x55, 0x5a, 0x00, 0x5b};
 const USHORT  ModeIndex_310_1280x768[] = {0x23, 0x24, 0x00, 0x25};
 const USHORT  ModeIndex_1280x720[]     = {0x79, 0x75, 0x00, 0x78};
+const USHORT  ModeIndex_1280x800[]     = {0x14, 0x15, 0x00, 0x16};
 const USHORT  ModeIndex_1360x768[]     = {0x48, 0x4b, 0x00, 0x4e};
 const USHORT  ModeIndex_300_1360x1024[]= {0x67, 0x6f, 0x00, 0x72};  /* 300 series, BARCO only */
 const USHORT  ModeIndex_1400x1050[]    = {0x26, 0x27, 0x00, 0x28};  /* 315 series only */
+const USHORT  ModeIndex_1680x1050[]    = {0x17, 0x18, 0x00, 0x19};  /* 315 series only */
 const USHORT  ModeIndex_1600x1200[]    = {0x3c, 0x3d, 0x00, 0x66};
+const USHORT  ModeIndex_1920x1080[]    = {0x2c, 0x2d, 0x00, 0x73};  /* 315 series only */
 const USHORT  ModeIndex_1920x1440[]    = {0x68, 0x69, 0x00, 0x6b};
 const USHORT  ModeIndex_300_2048x1536[]= {0x6c, 0x6d, 0x00, 0x00};
 const USHORT  ModeIndex_310_2048x1536[]= {0x6c, 0x6d, 0x00, 0x6e};
@@ -253,9 +255,14 @@
 	{ 1024, 600, 8,16},   /* 0x19 */
 	{ 1152, 768, 8,16},   /* 0x1a */
 	{  768, 576, 8,16},   /* 0x1b */
-	{ 1360,1024, 8,16}    /* 0x1c */
+	{ 1360,1024, 8,16},   /* 0x1c */
+	{ 1680,1050, 8,16},   /* 0x1d */
+	{ 1280, 800, 8,16},   /* 0x1e */
+	{ 1920,1080, 8,16},   /* 0x1f */
+	{  960, 540, 8,16}    /* 0x20 */
 };
 
+#if defined(SIS300) || defined(SIS315H)
 static SiS_StandTableStruct SiS_StandTable[]=
 {
 /* 0x00: MD_0_200 */
@@ -694,6 +701,7 @@
    0xff}
  }
 };
+#endif
 
 /**************************************************************/
 /* SIS VIDEO BRIDGE ----------------------------------------- */
@@ -839,7 +847,8 @@
  {   36,  25,1060, 648,1270, 530, 438,   0, 438,0xeb,0x05,0x25,0x16},  /* 800x600, 400x300 - better */
  {    3,   2,1080, 619,1270, 540, 438,   0, 438,0xf3,0x00,0x1d,0x20},  /* 720x576 */
  {    1,   1,1170, 821,1270, 520, 686,   0, 686,0xF3,0x00,0x1D,0x20},  /* 1024x768 */
- {    1,   1,1170, 821,1270, 520, 686,   0, 686,0xF3,0x00,0x1D,0x20}   /* 1024x768 (for NTSC equ) */
+ {    1,   1,1170, 821,1270, 520, 686,   0, 686,0xF3,0x00,0x1D,0x20},  /* 1024x768 (for NTSC equ) */
+ {    9,   4, 848, 528,1270, 530,   0,   0,  50,0xf5,0xfb,0x1b,0x2a}   /* 720x480 test */
 };
 
 static const SiS_TVDataStruct  SiS_StNTSCData[] =
@@ -921,6 +930,22 @@
 
 static const SiS_TVDataStruct  SiS_Ext750pData[] =
 {
+#if 1
+ {  143,  65, 0x35a,0x1bb,0x4f6,0x1b8,0x0ab,  0, 0x0ab, 0x00,0x00,0x00,0x00},
+ {   88,  35, 0x35a,0x189,0x4f6,0x1b8,0x0ab,  0, 0x0ab, 0x00,0x00,0x00,0x00},
+ {   18,   5, 0x339,0x1ae,0x500,0x2d0,0x05c,  0, 0x05c, 0x00,0x00,0x00,0x00},
+ {  143,  70, 0x39c,0x189,0x4f6,0x1b8,0x05c,  0, 0x05c, 0x00,0x00,0x00,0x00},
+ {   99,  32, 0x320,0x1fe,0x500,0x2d0,   50,  0,     0, 0x00,0x00,0x00,0x00},  /* 640x480  */
+ {    5,   4, 0x5d8,0x29e,0x500,0x2a8,   50,  0,     0, 0x00,0x00,0x00,0x00},  /* 800x600  */
+#if 0
+ {    2,   1, 0x35a,0x1f7,0x4f6,0x1e0,    0,128,     0, 0x00,0x00,0x00,0x00},  /* 720x480  */
+#endif
+ {   99,  32, 0x320,0x1fe,0x500,0x2d0,   50,  0,     0, 0x00,0x00,0x00,0x00},  /* 720x480 test WORKS */
+ {   68,  64, 0x55f,0x346,0x500,0x2a8,0x27e,  0,     0, 0x00,0x00,0x00,0x00},  /* 1024x768 */
+ {    5,   2, 0x3a7,0x226,0x500,0x2a8,    0,128,     0, 0x00,0x00,0x00,0x00},  /* 720x576  */
+ {   25,  24, 0x5d8,0x2f3,0x460,0x2a8,   50,  0,     0, 0x00,0x00,0x00,0x00}   /* 1280x720 WORKS */
+#endif
+#if 0
  {    3,   1, 0x3a7,0x1d6,0x500,0x2a8,   50,  0,     0, 0x00,0x00,0x00,0x00},
  {   24,   7, 0x3a7,0x1a4,0x500,0x2a8,   50,  0,     0, 0x00,0x00,0x00,0x00},
  {    3,   1, 0x3a7,0x1d6,0x500,0x2a8,   50,  0,     0, 0x00,0x00,0x00,0x00},
@@ -929,63 +954,105 @@
  {    5,   4, 0x5d8,0x29e,0x500,0x2a8,   50,  0,     0, 0x00,0x00,0x00,0x00},  /* 800x600   */
  {    2,   1, 0x35a,0x1f7,0x4f6,0x1e0,    0,128,     0, 0x00,0x00,0x00,0x00},  /* 720x480   */
  {   68,  64, 0x55f,0x346,0x500,0x2a8,0x27e,  0,     0, 0x00,0x00,0x00,0x00},  /* 1024x768  */
+ {   25,  24, 0x5d8,0x2f3,0x460,0x2a8,   50,  0,     0, 0x00,0x00,0x00,0x00}   /* 1280x720  */
+#endif
+#if 0
+ {  136,  35, 0x339,0x181,0x460,0x2a8,   50,  0,     0, 0x00,0x00,0x00,0x00},  /* TEST (0.93) BAD */
+ {   17,   6, 0x339,0x203,0x460,0x2a8,   50,  0,    50, 0x00,0x00,0x00,0x00},
+ {  136,  35, 0x339,0x181,0x460,0x2a8,   50,  0,    50, 0x00,0x00,0x00,0x00},
+ {   17,   6, 0x339,0x203,0x460,0x2a8,   50,  0,    50, 0x00,0x00,0x00,0x00},
+ {   85,  46, 0x3f4,0x27b,0x460,0x2a8,   50,  0,     0, 0x00,0x00,0x00,0x00},  /* 640x480   */
+ {   17,  16, 0x55f,0x323,0x460,0x2a8,0x2b6,  0,     0, 0x00,0x00,0x00,0x00},  /* 800x600   */
+ {  136,  35, 0x339,0x181,0x460,0x2a8,   50,  0,     0, 0x00,0x00,0x00,0x00},  /* 720x480   */
+ {  187,  74, 0x39d,0x203,0x460,0x2a8,   50,  0,     0, 0x00,0x00,0x00,0x00},  /* 1024x768  */
+ {   25,  24, 0x5d8,0x2f3,0x460,0x2a8,   50,  0,    50, 0x00,0x00,0x00,0x00}   /* 1280x720  */
+#endif
 };
 
-static const SiS_LCDDataStruct  SiS_LCD1280x960Data[] =
+static const SiS_LCDDataStruct  SiS_LCD1280x720Data[] =
 {
-	{    9,   2, 800, 500,1800,1000},
-	{    9,   2, 800, 500,1800,1000},
-	{    4,   1, 900, 500,1800,1000},
-	{    4,   1, 900, 500,1800,1000},
-	{    9,   2, 800, 500,1800,1000},
-	{   30,  11,1056, 625,1800,1000},
-	{    5,   3,1350, 800,1800,1000},
-	{    1,   1,1576,1050,1576,1050},
-	{    1,   1,1800,1000,1800,1000}
-};
-
-/* 1280x768 panel data from Fujitsu 7911 (VL-17WDX8).
- * Other 1280x768 panels (with clock != 81000, HTxVT != 1688x802)
- * will be treated as custom panels.
+	{  14,    5,  864,  432, 1344,  806 }, /* 640x400 */
+	{  16,    5,  864,  378, 1344,  806 },
+	{  14,    5,  864,  432, 1344,  806 },
+	{  16,    5,  864,  378, 1344,  806 },
+	{  24,   11,  924,  523, 1344,  806 }, /* 640x480 */
+	{   7,    5, 1152,  664, 1344,  806 }, /* 800x600 */
+	{   0,    0,    0,    0,    0,    0 },
+	{   0,    0,    0,    0,    0,    0 },
+	{   0,    0,    0,    0,    0,    0 },
+	{   0,    0,    0,    0,    0,    0 },
+	{   1,    1, 1344,  806, 1344,  806 }  /* 1280x720 */
+};
+
+/* About 1280x768: For TMDS, Panel_1280x768 will only be set if
+ * the panel is a Fujitsu 7911 (VL-17WDX8) (with clock 81, 1688x802)
+ * Other TMDS panels of this resolution will be treated as custom.
+ * For LVDS, we know two types. Data follows:
  */
 
-static const SiS_LCDDataStruct  SiS_StLCD1280x768Data[] =
+static const SiS_LCDDataStruct  SiS_StLCD1280x768_2Data[] =
 {
-	{ 211,  100, 2100,  408, 1688,  802 }, /* These values are *wrong* */
-	{ 211,   64, 1536,  358, 1688,  802 }, /* (which is why they aren't used yet) */
-	{ 211,  100, 2100,  408, 1688,  802 },
-	{ 211,   64, 1536,  358, 1688,  802 },
-	{ 211,   48,  840,  488, 1688,  802 },
-	{ 211,   72, 1008,  609, 1688,  802 },
-	{ 211,  128, 1400,  776, 1688,  802 },
-	{ 211,  205, 1680, 1041, 1688,  802 },
-	{ 1,      1, 1688,  802, 1688,  802 }  /* That's the only one that is correct */
-};
-
-static const SiS_LCDDataStruct  SiS_ExtLCD1280x768Data[] =
-{
-	{ 211,  100, 2100,  408, 1688,  802 }, /* These values are *wrong* */
-	{ 211,   64, 1536,  358, 1688,  802 }, /* (which is why they aren't used yet) */
-	{ 211,  100, 2100,  408, 1688,  802 },
-	{ 211,   64, 1536,  358, 1688,  802 },
-	{ 211,   48,  840,  488, 1688,  802 },
-	{ 211,   72, 1008,  609, 1688,  802 },
-	{ 211,  128, 1400,  776, 1688,  802 },
-	{ 211,  205, 1680, 1041, 1688,  802 },
-	{ 1,      1, 1688,  802, 1688,  802 }  /* That's the only one that is correct */
-};
-
-static const SiS_LCDDataStruct  SiS_NoScaleData1280x768[] =
-{
-        { 1, 1, 1688,  802, 1688,  802},
-	{ 1, 1, 1688,  802, 1688,  802},
-	{ 1, 1, 1688,  802, 1688,  802},
-	{ 1, 1, 1688,  802, 1688,  802},
-	{ 1, 1, 1688,  802, 1688,  802},
-	{ 1, 1, 1688,  802, 1688,  802},
-	{ 1, 1, 1688,  802, 1688,  802},
-	{ 1, 1, 1688,  802, 1688,  802},
-	{ 1, 1, 1688,  802, 1688,  802}
+	{  64,   21,  858,  434, 1408,  806 }, /* 640x400 */
+	{  32,    9,  858,  372, 1408,  806 },
+	{  64,   21,  858,  434, 1408,  806 },
+	{  32,    9,  858,  372, 1408,  806 },
+	{ 143,   68, 1024,  527, 1408,  806 }, /* 640x480 */
+	{  64,   51, 1364,  663, 1408,  806 }, /* 800x600 */
+	{  88,   81, 1296,  806, 1408,  806 }, /* 1024x768 */
+	{   0,    0,    0,    0,    0,    0 },
+	{   1,    1, 1408,  806, 1408,  806 }  /* 1280x768 */
+};
+
+static const SiS_LCDDataStruct  SiS_ExtLCD1280x768_2Data[] =
+{
+	{  64,   25, 1056,  422, 1408,  806 }, /*, 664 */
+	{ 128,   39,  884,  396, 1408,  806 }, /*, 640 */
+	{  64,   25, 1056,  422, 1408,  806 }, /*, 664 */
+	{ 128,   39,  884,  396, 1408,  806 }, /*, 640 */
+	{  32,   15, 1056,  513, 1408,  806 }, /*, 664 */
+	{ 176,  125, 1280,  640, 1408,  806 }, /*, 768 */
+	{  88,   81, 1296,  806, 1408,  806 },
+	{   0,    0,    0,    0,    0,    0 },
+	{   1,    1, 1408,  806, 1408,  806 }
+};
+
+static const SiS_LCDDataStruct  SiS_LCD1280x768_3Data[] =
+{
+	{  64,   25, 1056,  422, 1664,  798 },			/* 640x400 */
+	{ 128,   39,  884,  396, 1408,  806 }, /* ,640 */
+	{  64,   25, 1056,  422, 1664,  798 },			/* 640x400 */
+	{ 128,   39,  884,  396, 1408,  806 }, /* ,640 */
+	{  32,   15, 1056,  513, 1408,  806 }, /* ,664 */	/* 640x480 */
+	{ 176,  125, 1280,  640, 1408,  806 }, /* ,768 */	/* 800x600 */
+	{  64,   61, 1342,  806, 1408,  806 },			/* 1024x768 */
+	{   0,    0,    0,    0,    0,    0 },
+	{   1,    1, 1408,  806, 1408,  806 }			/* 1280x768 */
+};
+
+static const SiS_LCDDataStruct  SiS_LCD1280x800Data[] =
+{
+	{ 128,   51, 1122,  412, 1408,  816 }, /* 640x400 */
+	{ 128,   49, 1232,  361, 1408,  816 },
+	{ 128,   51, 1122,  412, 1408,  816 },
+	{ 128,   49, 1232,  361, 1408,  816 },
+	{   8,    3,  880,  491, 1408,  816 }, /* 640x480 */
+	{  11,    6, 1024,  612, 1408,  816 }, /* 800x600 */
+	{  22,   21, 1400,  784, 1408,  816 }, /* 1024x768 */
+	{   0,    0,    0,    0,    0,    0 },
+	{   1,    1, 1408,  816, 1408,  816 }  /* 1280x800 */
+};
+
+static const SiS_LCDDataStruct  SiS_LCD1280x960Data[] =
+{
+	{    9,   2,  800,  500, 1800, 1000 },
+	{    9,   2,  800,  500, 1800, 1000 },
+	{    4,   1,  900,  500, 1800, 1000 },
+	{    4,   1,  900,  500, 1800, 1000 },
+	{    9,   2,  800,  500, 1800, 1000 },
+	{   30,  11, 1056,  625, 1800, 1000 },
+	{    5,   3, 1350,  800, 1800, 1000 },
+	{    1,   1, 1576, 1050, 1576, 1050 },
+	{    1,   1, 1800, 1000, 1800, 1000 }
 };
 
 static const SiS_LCDDataStruct  SiS_StLCD1400x1050Data[] =
@@ -1003,28 +1070,37 @@
 
 static const SiS_LCDDataStruct  SiS_ExtLCD1400x1050Data[] =
 {
-	{ 211,  100, 2100,  408, 1688, 1066 },
+/*	{ 211,   60, 1260,  410, 1688, 1066 },    640x400 (6330) */
+	{ 211,  100, 2100,  408, 1688, 1066 }, /* 640x400 (6325) WORKS */
 	{ 211,   64, 1536,  358, 1688, 1066 },
 	{ 211,  100, 2100,  408, 1688, 1066 },
 	{ 211,   64, 1536,  358, 1688, 1066 },
-	{ 211,   48,  840,  488, 1688, 1066 },
-	{ 211,   72, 1008,  609, 1688, 1066 },
-	{ 211,  128, 1400,  776, 1688, 1066 },
-	{ 211,  205, 1680, 1041, 1688, 1066 },
-	{   1,    1, 1688, 1066, 1688, 1066 }
-};
-
-static const SiS_LCDDataStruct  SiS_NoScaleData1400x1050[] =
-{
-	{ 1, 1, 1688, 1066, 1688, 1066 },
-	{ 1, 1, 1688, 1066, 1688, 1066 },
-	{ 1, 1, 1688, 1066, 1688, 1066 },
-	{ 1, 1, 1688, 1066, 1688, 1066 },
-	{ 1, 1, 1688, 1066, 1688, 1066 },
-	{ 1, 1, 1688, 1066, 1688, 1066 },
-	{ 1, 1, 1688, 1066, 1688, 1066 },
-	{ 1, 1, 1688, 1066, 1688, 1066 },
-	{ 1, 1, 1688, 1066, 1688, 1066 }
+/*	{ 211,   80, 1400,  490, 1688, 1066 },    640x480 (6330) */
+	{ 211,   48,  840,  488, 1688, 1066 }, /* 640x480 (6325) WORKS */
+/*	{ 211,  117, 1638,  613, 1688, 1066 },    800x600 (6330) */
+	{ 211,   72, 1008,  609, 1688, 1066 }, /* 800x600 (6325) WORKS */
+	{ 211,  128, 1400,  776, 1688, 1066 }, /* 1024x768 */
+	{ 211,  205, 1680, 1041, 1688, 1066 }, /* 1280x1024 - not used (always unscaled) */
+	{   1,    1, 1688, 1066, 1688, 1066 }, /* 1400x1050 */
+	{   0,    0,    0,    0,    0,    0 }, /* kludge */
+	{ 211,  120, 1400,  730, 1688, 1066 }  /* 1280x720 */
+};
+
+static const SiS_LCDDataStruct  SiS_LCD1680x1050Data[] =
+{
+	{  95,   24, 1260,  410, 1900, 1066 }, /*  0 640x400 */
+	{  10,    3, 1710,  362, 1900, 1066 },
+	{  95,   24, 1260,  410, 1900, 1066 },
+	{  10,    3, 1710,  362, 1900, 1066 },
+	{  95,   32, 1400,  490, 1900, 1066 }, /*  4 640x480 */
+	{  95,   42, 1470,  610, 1900, 1066 }, /*  5 800x600 */
+	{  95,   64, 1750,  784, 1900, 1066 }, /*  6 1024x768 */
+	{  95,   94, 1900, 1055, 1900, 1066 }, /*  7 1280x1024 */
+	{  41,   31, 1900,  806, 1900, 1066 }, /*  8 1280x768 */
+	{  95,   69, 1800,  817, 1900, 1066 }, /*  9 1280x800 patch */
+	{  13,    9, 1900,  739, 1900, 1066 }, /* 10 1280x720 */
+	{  95,   94, 1880, 1066, 1900, 1066 }, /* 11 1400x1050 patch */
+	{   1,    1, 1900, 1066, 1900, 1066 }  /* 12 1680x1050 */
 };
 
 static const SiS_LCDDataStruct  SiS_StLCD1600x1200Data[] =
@@ -1037,440 +1113,59 @@
 	{ 4,  1,1080, 625, 2160, 1250 },
 	{ 5,  2,1350, 800, 2160, 1250 },
 	{135,88,1600,1100, 2160, 1250 },
-	{135,88,1600,1100, 2160, 1250 },
+	{72, 49,1680,1092, 2160, 1250 },
 	{ 1,  1,2160,1250, 2160, 1250 }
 };
 
 static const SiS_LCDDataStruct  SiS_ExtLCD1600x1200Data[] =
 {
-	{27, 4, 800, 500, 2160, 1250 },
+	{72,11, 990, 422, 2160, 1250 }, /* 640x400 (6330) WORKS */
+/*	{27, 4, 800, 500, 2160, 1250 },    640x400 (6235) */
 	{27, 4, 800, 500, 2160, 1250 },
 	{ 6, 1, 900, 500, 2160, 1250 },
 	{ 6, 1, 900, 500, 2160, 1250 },
-	{27, 1, 800, 500, 2160, 1250 },
+	{45, 8, 960, 505, 2160, 1250 }, /* 640x480 (6330) WORKS */
+/*	{27, 1, 800, 500, 2160, 1250 },    640x480 (6325) */
 	{ 4, 1,1080, 625, 2160, 1250 },
 	{ 5, 2,1350, 800, 2160, 1250 },
-	{27,16,1500,1064, 2160, 1250 },
-	{27,16,1500,1064, 2160, 1250 },
+	{27,16,1500,1064, 2160, 1250 }, /* 1280x1024 */
+	{72,49,1680,1092, 2160, 1250 }, /* 1400x1050 (6330, was not supported on 6325) */
 	{ 1, 1,2160,1250, 2160, 1250 }
 };
 
-static const SiS_LCDDataStruct  SiS_NoScaleData1600x1200[] =
-{
-        {1,  1, 2160, 1250, 2048, 1250},
-	{1,  1, 2160, 1250, 2048, 1250},
-	{1,  1, 2160, 1250, 2048, 1250},
-	{1,  1, 2160, 1250, 2048, 1250},
-	{1,  1, 2160, 1250, 2048, 1250},
-	{1,  1, 2160, 1250, 2048, 1250},
-	{1,  1, 2160, 1250, 2048, 1250},
-	{1,  1, 2160, 1250, 2048, 1250},
-	{1,  1, 2160, 1250, 2048, 1250},
-	{1,  1, 2160, 1250, 2048, 1250},
-};
-
 static const SiS_LCDDataStruct  SiS_NoScaleData[] =
 {
-	{ 1, 1, 800, 449, 800, 449 },
+	{ 1, 1, 800, 449, 800, 449 },  /* 0x00: 320x200, 640x400 */
 	{ 1, 1, 800, 449, 800, 449 },
 	{ 1, 1, 900, 449, 900, 449 },
 	{ 1, 1, 900, 449, 900, 449 },
-	{ 1, 1, 800, 525, 800, 525 },
-	{ 1, 1,1056, 628,1056, 628 },
-	{ 1, 1,1344, 806,1344, 806 },
-	{ 1, 1,1688,1066,1688,1066 },
-        { 1, 1,1688, 802,1688, 802 },  /* 1280x768: 802 was 806 in both cases */
-        { 1, 1,2160,1250,2160,1250 },  /* 1600x1200 */
-	{ 1, 1,1800,1000,1800,1000 }   /* 1280x960 */
-};
-
-/* *** LCDA *** */
-
-static const SiS_LVDSDataStruct  SiS_LCDA1024x768Data_1[]=
-{
-	{  960, 438,1344, 806},
-	{  960, 388,1344, 806},
-	{ 1040, 438,1344, 806},
-	{ 1040, 388,1344, 806},
-	{  960, 518,1344, 806},   /* 640x480 */
-	{ 1120, 638,1344, 806},   /* 800x600 */
-	{ 1344, 806,1344, 806},   /* 1024x768 */
-#if 0
-	{ 840, 438,1344, 806},
-	{ 840, 409,1344, 806},
-	{ 840, 438,1344, 806},
-	{ 840, 409,1344, 806},
-	{ 840, 518,1344, 806},   /* 640x480 */
-	{1050, 638,1344, 806},   /* 800x600 */
-	{1344, 806,1344, 806},   /* 1024x768 */
-#endif
-};
-
-static const SiS_LVDSDataStruct  SiS_LCDA1024x768Data_2[]=
-{
-	{1344, 806,1344, 806},
-	{1344, 806,1344, 806},
-	{1344, 806,1344, 806},
-	{1344, 806,1344, 806},
-	{1344, 806,1344, 806},
-	{1344, 806,1344, 806},
-	{1344, 806,1344, 806},
-};
-
-static const SiS_LVDSDataStruct  SiS_LCDA1280x1024Data_1[]=
-{ /* Acer, Compaq */
-	{1048, 442,1688,1066},
-	{1048, 392,1688,1066},
-	{1128, 442,1688,1066},
-	{1128, 392,1688,1066},
-	{1048, 522,1688,1066},
-	{1208, 642,1688,1066},
-	{1432, 810,1688,1066},
-	{1688,1066,1688,1066}
-};
-
-static const SiS_LVDSDataStruct  SiS_LCDA1280x1024Data_2[]=
-{ /* Corrected (illegal in Acer, correct in Compaq) */
-	{1688,1066,1688,1066},
-	{1688,1066,1688,1066},
-	{1688,1066,1688,1066},
-	{1688,1066,1688,1066},
-	{1688,1066,1688,1066},
-	{1688,1066,1688,1066},
-	{1688,1066,1688,1066},
-	{1688,1066,1688,1066}
-};
-
-static const SiS_LVDSDataStruct  SiS_LCDA1400x1050Data_1[]=
-{ /* Clevo */
-        { 928, 416, 1688,1066},
-	{ 928, 366, 1688,1066},
-	{1008, 416, 1688,1066},
-	{1008, 366, 1688,1066},
-	{1200, 530, 1688,1066},
-	{1088, 616, 1688,1066},
-	{1312, 784, 1688,1066},
-	{1568,1040, 1688,1066},
-	{1688,1066, 1688,1066}
-};
-
-static const SiS_LVDSDataStruct  SiS_LCDA1400x1050Data_2[]=
-{ /* Clevo */
-    	{1688,1066, 1688,1066},
-	{1688,1066, 1688,1066},
-	{1688,1066, 1688,1066},
-	{1688,1066, 1688,1066},
-	{1688,1066, 1688,1066},
-	{1688,1066, 1688,1066},
-	{1688,1066, 1688,1066},
-	{1688,1066, 1688,1066},
-	{1688,1066, 1688,1066}
-};
-
-static const SiS_LVDSDataStruct  SiS_LCDA1600x1200Data_1[]=
-{ /* Clevo (Temporary data)  */
-	{1200, 450, 2048,1250},
-	{1200, 400, 2048,1250},
-	{1280, 450, 2048,1250},
-	{1280, 400, 2048,1250},
-	{1200, 530, 2048,1250},
-	{1360, 650, 2048,1250},
-	{1584, 818, 2048,1250},
-	{1688,1066, 2048,1250},
-	{1688,1066, 2048,1250},
-	{2048,1250, 2048,1250}   /* this should be correct */
-#if 0
-	{2160,1250, 2048,1250}   /* ? */
-#endif
-};
-
-static const SiS_LVDSDataStruct  SiS_LCDA1600x1200Data_2[]=
-{ /* Clevo (Temporary data. Seems invalid.) */
-	{2160,1250, 2160,1250},
-	{2160,1250, 2160,1250},
-	{2160,1250, 2160,1250},
-	{2160,1250, 2160,1250},
-	{2160,1250, 2160,1250},
-	{2160,1250, 2160,1250},
-	{2160,1250, 2160,1250},
-	{2160,1250, 2160,1250},
-	{2160,1250, 2160,1250},
-	{2160,1250, 2160,1250}
-};
-
-/* LVDS SKEW for LCDA */
-
-static const SiS_LVDSDesStruct SiS_PanelType1076_1[]=
-{  /* 1024x768 */
-	{ 0 , 0},
-	{ 0 , 0},
-	{ 0 , 0},
-	{ 0 , 0},
-	{ 0 , 0},
-	{ 0 , 0},
-	{ 0 , 0},   /* 805; was 0, 0 -> top line cut away (26/09/03) */
-};
-
-static const SiS_LVDSDesStruct SiS_PanelType1076_2[]=
-{  /* 1024x768; not expanded */
-	{ 1184, 622 },
-	{ 1184, 597 },
-	{ 1184, 622 },
-	{ 1184, 597 },
-	{ 1152, 650 },  /* 622 */
-	{ 1232, 722 },
-	{    0, 0   },  /* 805; was 0, 0 -> top line cut away (26/09/03) */
-};
-
-static const SiS_LVDSDesStruct SiS_PanelType1210_1[]=
-{  /* 1280x1024 */
-	{ 0 ,    0},
-	{ 0 ,    0},
-	{ 0 ,    0},
-	{ 0 ,    0},
-	{ 0 ,    0},
-	{ 0 ,    0},
-	{ 0 ,    0},
-	{ 0 , 1065},  /* Acer */
-	{ 0 ,    0}
-};
-
-static const SiS_LVDSDesStruct SiS_PanelType1210_2[]=
-{  /* 1280x1024; not expanded */
-	{ 0 , 0},
-	{ 0 , 0},
-	{ 0 , 0},
-	{ 0 , 0},
-	{ 0 , 0},
-	{ 0 , 0},
-	{ 0 , 0},
-	{ 0 , 0},
-	{ 0 , 0}
-};
-
-static const SiS_LVDSDesStruct SiS_PanelType1296_1[]=
-{  /* 1400x1050 */
-	{ 0 , 0},
-	{ 0 , 0},
-	{ 0 , 0},
-	{ 0 , 0},
-	{ 0 , 0},
-	{ 0 , 0},
-	{ 0 , 0},
-	{ 0 , 0},
-	{ 0 , 1065}   /* Was 0,0 */
-};
-
-static const SiS_LVDSDesStruct SiS_PanelType1296_2[]=
-{  /* 1400x1050; not expanded */
-	{ 1308, 741 },
-	{ 1308, 716 },
-	{ 1308, 741 },
-	{ 1308, 716 },
-	{ 1308, 781 },
-	{ 1388, 841 },
-	{ 1500, 925 },
-	{ 1628,1053 },
-	{    0,1065 }
-#if 0
-	{ 808 , 740},
-	{ 0   , 715},
-	{ 632 , 740},
-	{ 632 , 715},
-	{ 1307, 780},
-	{ 1387,1157},
-	{ 1499, 924},
-	{ 1627,1052},
-	{ 0 , 0}
-#endif
-};
-
-static const SiS_LVDSDesStruct SiS_PanelType1600_1[]=
-{  /* 1600x1200 */
-	{ 0 , 0},
-	{ 0 , 0},
-	{ 0 , 0},
-	{ 0 , 0},
-	{ 0 , 0},
-	{ 0 , 0},
-	{ 0 , 0},
-	{ 0 , 0},
-	{ 0 , 0},
-	{ 0 , 0}
-};
-
-static const SiS_LVDSDesStruct SiS_PanelType1600_2[]=
-{  /* 1600x1200; not expanded */
-	{ 0 , 0},
-	{ 0 , 0},
-	{ 0 , 0},
-	{ 0 , 0},
-	{ 0 , 0},
-	{ 0 , 0},
-	{ 0 , 0},
-	{ 0 , 0},
-	{ 0 , 0},
-	{ 0 , 0}
-};
-
-#ifdef SIS315H
-
-/* LCDA CRT1 custom data */
-
-static const SiS_LCDACRT1DataStruct  Compaq1280x1024_LCDACRT1_1[]=
-{
- {{0x7e,0x4f,0x4f,0x82,0x58,0x06,0xb8,0x1f,
-   0x90,0x84,0x8f,0x8f,0xb9,0x30,0x00,0x06,
-   0x00}},
- {{0x7e,0x4f,0x4f,0x82,0x58,0x06,0x86,0x1f,
-   0x5e,0x82,0x5d,0x5d,0x87,0x10,0x00,0x06,
-   0x00}},
- {{0x7e,0x4f,0x4f,0x82,0x58,0x06,0xb8,0x1f,
-   0x90,0x84,0x8f,0x8f,0xb9,0x30,0x00,0x06,
-   0x00}},
- {{0x7e,0x4f,0x4f,0x82,0x58,0x06,0x86,0x1f,
-   0x5e,0x82,0x5d,0x5d,0x87,0x10,0x00,0x06,
-   0x00}},
- {{0x7e,0x4f,0x4f,0x82,0x58,0x06,0x08,0x3e,
-   0xe0,0x84,0xdf,0xdf,0x09,0x00,0x00,0x06,
-   0x00}},
- {{0x92,0x63,0x63,0x96,0x6c,0x1a,0x80,0xf0,
-   0x58,0x8c,0x57,0x57,0x81,0x20,0x00,0x06,
-   0x01}},
- {{0xae,0x7f,0x7f,0x92,0x88,0x96,0x28,0xf5,
-   0x00,0x84,0xff,0xff,0x29,0x10,0x00,0x02,
-   0x01}},
- {{0xce,0x9f,0x9f,0x92,0xa8,0x16,0x28,0x5a,
-   0x00,0x84,0xff,0xff,0x29,0x01,0x00,0x07,
-   0x01}}
-};
-
-static const SiS_LCDACRT1DataStruct  Compaq1280x1024_LCDACRT1_1_H[]=
-{
- {{0x56,0x27,0x27,0x9a,0x30,0x1e,0xb8,0x1f,
-   0x90,0x84,0x8f,0x8f,0xb9,0x30,0x00,0x05,
-   0x00}},
- {{0x3c,0x4f,0x4f,0x82,0x58,0x06,0x86,0xd1,
-   0xbc,0x80,0xbb,0xbb,0xe5,0x00,0x00,0x06,
-   0x01}},
- {{0x56,0x27,0x27,0x9a,0x30,0x1e,0xb8,0x1f,
-   0x90,0x84,0x8f,0x8f,0xb9,0x30,0x00,0x05,
-   0x00}},
- {{0x3c,0x4f,0x4f,0x82,0x58,0x06,0x86,0xd1,
-   0xbc,0x80,0xbb,0xbb,0xe5,0x00,0x00,0x06,
-   0x01}},
- {{0x56,0x27,0x27,0x9a,0x30,0x1e,0x08,0x3e,
-   0xe0,0x84,0xdf,0xdf,0x09,0x00,0x00,0x05,
-   0x00}},
- {{0x60,0x31,0x31,0x84,0x3a,0x88,0x80,0xf0,
-   0x58,0x8c,0x57,0x57,0x81,0x20,0x00,0x01,
-   0x01}},
- {{0x6e,0x3f,0x3f,0x92,0x48,0x96,0x28,0xf5,
-   0x00,0x84,0xff,0xff,0x29,0x10,0x00,0x01,
-   0x01}}
+	{ 1, 1, 800, 525, 800, 525 },  /* 0x04: 320x240, 640x480  */
+	{ 1, 1,1056, 628,1056, 628 },  /* 0x05: 400x300, 800x600  */
+	{ 1, 1,1344, 806,1344, 806 },  /* 0x06: 512x384, 1024x768 */
+	{ 1, 1,1688,1066,1688,1066 },  /* 0x07: 1280x1024 */
+        { 1, 1,1688, 802,1688, 802 },  /* 0x08: 1280x768: Fujitsu, TMDS only */
+        { 1, 1,2160,1250,2160,1250 },  /* 0x09: 1600x1200 */
+	{ 1, 1,1800,1000,1800,1000 },  /* 0x0a: 1280x960  */
+	{ 1, 1,1688,1066,1688,1066 },  /* 0x0b: 1400x1050 */
+	{ 1, 1,1650, 750,1650, 750 },  /* 0x0c: 1280x720 (TMDS, projector)  */
+	{ 1, 1,1656, 841,1656, 841 },  /* 0x0d: 1280x800 (was: 1408, 816) */
+	{ 1, 1,1900,1066,1900,1066 },  /* 0x0e: 1680x1050 (LVDS) */
+	{ 1, 1,1408, 806,1408, 806 },  /* 0x0f: 1280x768_2 */
+	{ 1, 1,1664, 798,1664, 798 },  /* 0x10: 1280x768_3 */
+	{ 1, 1,1688, 802,1688, 802 },  /* 0x11: 1280x768: Std, TMDS only */
+	{ 1, 1,1344, 806,1344, 806 },  /* 0x12: 1280x720 (LVDS)  */
+	{ 1, 1, 896, 497, 896, 497 },  /* 0x13: 720x480 */
+	{ 1, 1, 912, 597, 912, 597 },  /* 0x14: 720x576 */
+	{ 1, 1, 912, 597, 912, 597 },  /* 0x15: 768x576 */
+	{ 1, 1,1056, 497,1056, 497 },  /* 0x16: 848x480 */
+	{ 1, 1,1064, 497,1064, 497 },  /* 0x17: 856x480 */
+	{ 1, 1,1056, 497,1056, 497 },  /* 0x18: 800x480 */
+	{ 1, 1,1328, 739,1328, 739 },  /* 0x19: 1024x576 */
+	{ 1, 1,1680, 892,1680, 892 },  /* 0x1a: 1152x864 */
+	{ 1, 1,1808, 808,1808, 808 },  /* 0x1b: 1360x768 */
+	{ 1, 1,1104, 563,1104, 563 }   /* 0x1c: 960x540 */
 };
 
-static const SiS_LCDACRT1DataStruct  Clevo1024x768_LCDACRT1_1[]=
-{
- {{0x73,0x4f,0x4f,0x97,0x55,0x86,0xc4,0x1f,
-   0x92,0x89,0x8f,0x8f,0xb5,0x30,0x00,0x05,
-   0x00}},
- {{0x73,0x4f,0x4f,0x97,0x55,0x86,0x97,0x1f,
-   0x60,0x87,0x5d,0x5d,0x83,0x10,0x00,0x05,
-   0x00}},
- {{0x73,0x4f,0x4f,0x97,0x55,0x86,0xc4,0x1f,
-   0x92,0x89,0x8f,0x8f,0xb5,0x30,0x00,0x05,
-   0x00}},
- {{0x73,0x4f,0x4f,0x97,0x55,0x86,0x97,0x1f,
-   0x60,0x87,0x5d,0x5d,0x83,0x10,0x00,0x05,
-   0x00}},
- {{0x73,0x4f,0x4f,0x97,0x55,0x86,0x04,0x3e,
-   0xE2,0x89,0xDf,0xDf,0x05,0x00,0x00,0x05,
-   0x00}},
- {{0x87,0x63,0x63,0x8B,0x69,0x1A,0x7c,0xf0,
-   0x5A,0x8F,0x57,0x57,0x7D,0x20,0x00,0x26,
-   0x01}},
- {{0xA3,0x7f,0x7f,0x87,0x86,0x97,0x24,0xf5,
-   0x02,0x88,0xFf,0xFf,0x25,0x10,0x00,0x02,
-   0x01}}
-};
-
-static const SiS_LCDACRT1DataStruct  Clevo1024x768_LCDACRT1_1_H[]=
-{
- {{0x4b,0x27,0x27,0x8f,0x2b,0x03,0xc4,0x1f,
-   0x92,0x89,0x8f,0x8f,0xb5,0x30,0x00,0x44,
-   0x00}},
- {{0x4b,0x27,0x27,0x8f,0x2b,0x03,0x97,0x1f,
-   0x60,0x87,0x5D,0x5D,0x83,0x01,0x00,0x44,
-   0x00}},
- {{0x4b,0x27,0x27,0x8f,0x2b,0x03,0xc4,0x1f,
-   0x92,0x89,0x8f,0x8f,0xb5,0x30,0x00,0x44,
-   0x00}},
- {{0x4b,0x27,0x27,0x8f,0x2b,0x03,0x97,0x1f,
-   0x60,0x87,0x5D,0x5D,0x83,0x01,0x00,0x44,
-   0x00}},
- {{0x4b,0x27,0x27,0x8f,0x32,0x1b,0x04,0x3e,
-   0xE2,0x89,0xDf,0xDf,0x05,0x00,0x00,0x45,
-   0x00}},
- {{0x55,0x31,0x31,0x99,0x46,0x1d,0x7c,0xf0,
-   0x5A,0x8F,0x57,0x57,0x7D,0x20,0x00,0x55,
-   0x01}},
- {{0x63,0x3F,0x3F,0x87,0x4A,0x93,0x24,0xF5,
-   0x02,0x88,0xFF,0xFF,0x25,0x10,0x00,0x01,
-   0x01}}
-};
-
-static const SiS_LCDACRT1DataStruct  Clevo1024x768_LCDACRT1_2[]=
-{
- {{0xa3,0x4f,0x4f,0x87,0x6e,0x9f,0x24,0xbb,
-   0x4a,0x80,0x8f,0x8f,0x25,0x30,0x00,0x06,
-   0x00}},
- {{0xa3,0x4f,0x4f,0x87,0x6e,0x9f,0x24,0xbb,
-   0x31,0x87,0x5d,0x5d,0x25,0x30,0x00,0x06,
-   0x00}},
- {{0xa3,0x4f,0x4f,0x87,0x6e,0x9f,0x24,0xbb,
-   0x4a,0x80,0x8f,0x8f,0x25,0x30,0x00,0x06,
-   0x00}},
- {{0xa3,0x4f,0x4f,0x87,0x6e,0x9f,0x24,0xbb,
-   0x31,0x87,0x5d,0x5d,0x25,0x30,0x00,0x06,
-   0x00}},
- {{0xa3,0x4f,0x4f,0x87,0x6e,0x9f,0x24,0xbb,
-   0x72,0x88,0xdf,0xdf,0x25,0x30,0x00,0x06,
-   0x00}},
- {{0xa3,0x63,0x63,0x87,0x78,0x89,0x24,0xf1,
-   0xae,0x84,0x57,0x57,0x25,0x30,0x00,0x02,
-   0x01}},
- {{0xa3,0x7f,0x7f,0x87,0x86,0x97,0x24,0xf5,
-   0x02,0x88,0xff,0xff,0x25,0x10,0x00,0x02,
-   0x01}}
-};
-
-static const SiS_LCDACRT1DataStruct  Clevo1024x768_LCDACRT1_2_H[]=
-{
- {{0x7b,0x27,0x27,0x9f,0x46,0x97,0x24,0xbb,
-   0x57,0x8e,0x8f,0x8f,0x25,0x30,0x00,0x01,
-   0x00 }},
- {{0x7b,0x27,0x27,0x9f,0x46,0x97,0x24,0xbb,
-   0x3e,0x85,0x5d,0x5d,0x25,0x10,0x00,0x01,
-   0x00 }},
- {{0x7b,0x27,0x27,0x9f,0x46,0x97,0x24,0xbb,
-   0x57,0x8e,0x8f,0x8f,0x25,0x30,0x00,0x01,
-   0x00 }},
- {{0x7b,0x27,0x27,0x9f,0x46,0x97,0x24,0xbb,
-   0x3e,0x85,0x5d,0x5d,0x25,0x10,0x00,0x01,
-   0x00 }},
- {{0x7b,0x27,0x27,0x9f,0x46,0x97,0x24,0xbb,
-   0x7f,0x86,0xdf,0xdf,0x25,0x10,0x00,0x01,
-   0x00 }},
- {{0x71,0x31,0x31,0x95,0x46,0x97,0x24,0xf1,
-   0xbb,0x82,0x57,0x57,0x25,0x10,0x00,0x01,
-   0x01 }},
- {{0x63,0x3f,0x3f,0x87,0x46,0x97,0x24,0xf5,
-   0x0f,0x86,0xff,0xff,0x25,0x30,0x00,0x01,
-   0x01 }}
-};
-
-#endif  /* 315 */
 
 /**************************************************************/
 /* LVDS ----------------------------------------------------- */
@@ -1521,9 +1216,7 @@
 	{ 848, 389,1060, 629},
 	{ 848, 518,1060, 629},
 	{1056, 628,1056, 628},
-	{1056, 628,1056, 628},
-	{ 800, 449,1000, 644},
-	{ 800, 525,1000, 635}
+	{1056, 628,1056, 628}
 };
 
 static const SiS_LVDSDataStruct  SiS_LVDS800x600Data_2[]=
@@ -1534,9 +1227,7 @@
 	{1056, 628,1056, 628},
 	{1056, 628,1056, 628},
 	{1056, 628,1056, 628},
-	{1056, 628,1056, 628},
-	{ 800, 449,1000, 644},
-	{ 800, 525,1000, 635}
+	{1056, 628,1056, 628}
 };
 
 static const SiS_LVDSDataStruct  SiS_LVDS1024x768Data_1[]=
@@ -1548,8 +1239,6 @@
 	{ 840, 518,1344, 806},   /* 640x480 */
 	{1050, 638,1344, 806},   /* 800x600 */
 	{1344, 806,1344, 806},   /* 1024x768 */
-	{ 800, 449,1280, 801},
-	{ 800, 525,1280, 813}
 };
 
 static const SiS_LVDSDataStruct  SiS_LVDS1024x768Data_2[]=
@@ -1561,11 +1250,8 @@
 	{1344, 806,1344, 806},
 	{1344, 806,1344, 806},
 	{1344, 806,1344, 806},
-	{ 800, 449,1280, 801},
-	{ 800, 525,1280, 813}
 };
 
-
 static const SiS_LVDSDataStruct  SiS_LVDS1280x1024Data_1[]=
 {
 	{1048, 442,1688,1066},
@@ -1716,9 +1402,7 @@
 	{ 840, 560,1344, 800},
 	{ 840, 689,1344, 800},
 	{1050, 800,1344, 800},
-	{1344, 800,1344, 800},
-	{ 800, 449,1280, 789},
-	{ 800, 525,1280, 785}
+	{1344, 800,1344, 800}
 };
 
 static const SiS_LVDSDataStruct  SiS_LVDS1024x600Data_2[] =
@@ -1729,9 +1413,7 @@
 	{1344, 800,1344, 800},
 	{1344, 800,1344, 800},
 	{1344, 800,1344, 800},
-	{1344, 800,1344, 800},
-	{ 800, 449,1280, 801},
-	{ 800, 525,1280, 813}
+	{1344, 800,1344, 800}
 };
 
 static const SiS_LVDSDataStruct  SiS_LVDS1152x768Data_1[] =
@@ -1742,9 +1424,7 @@
 	{ 840, 409,1344, 806},
 	{ 840, 518,1344, 806},
 	{1050, 638,1344, 806},
-	{1344, 806,1344, 806},
-	{ 800, 449,1280, 801},
-	{ 800, 525,1280, 813}
+	{1344, 806,1344, 806}
 };
 
 static const SiS_LVDSDataStruct  SiS_LVDS1152x768Data_2[] =
@@ -1755,9 +1435,7 @@
 	{1344, 806,1344, 806},
 	{1344, 806,1344, 806},
 	{1344, 806,1344, 806},
-	{1344, 806,1344, 806},
-	{ 800, 449,1280, 801},
-	{ 800, 525,1280, 813}
+	{1344, 806,1344, 806}
 };
 
 /* Pass 1:1 data */
@@ -1770,7 +1448,7 @@
 	{ 800, 525,  800, 525},  /*  640x480   */
 	{1056, 628, 1056, 628},  /*  800x600   */
 	{1344, 806, 1344, 806},  /* 1024x768   */
-	{1344,1066, 1344,1066},  /* 1280x1024  */  /* INSERTED ! */
+	{1688,1066, 1688,1066},  /* 1280x1024  */  /* INSERTED ! */
  	{1688, 806, 1688, 806},  /* 1280x768   */
 	/* No other panels ! */
 };
@@ -1885,36 +1563,6 @@
         {1160, 840,1160, 840}
 };
 
-/* LVDS Skew */
-
-static const SiS_LVDSDesStruct  SiS_PanelTypeNS_1[]=
-{
-	{ 8,   0},
-	{ 8,   0},
-	{ 8,   0},
-	{ 8,   0},
-	{ 8,   0},
-	{ 0,   0},
-	{ 0,   0},
-	{ 0,   0},
-	{ 0, 806},
-	{ 0,   0}
-};
-
-static const SiS_LVDSDesStruct  SiS_PanelTypeNS_2[] =
-{
-	{ 0 , 0},
-	{ 0 , 0},
-	{ 0 , 0},
-	{ 0 , 0},
-	{ 0 , 0},
-	{ 0 , 0},
-	{ 0 , 0},
-	{ 0 , 0},
-	{ 0 , 0},
-	{ 0 , 0}
-};
-
 /* Chrontel TV Skew */
 
 static const SiS_LVDSDesStruct  SiS_CHTVUNTSCDesData[]=
@@ -2453,63 +2101,6 @@
    0x01}}
 };
 
-static const SiS_LVDSCRT1DataStruct  SiS_LVDSCRT1XXXxXXX_1[] =
-{
- {{0x5f,0x4f,0x82,0x55,0x81,0xbf,0x1f,
-   0x9c,0x8e,0x96,0xb9,0x30,0x00,0x05,
-   0x00}},
- {{0x5f,0x4f,0x82,0x55,0x81,0xbf,0x1f,
-   0x9c,0x8e,0x96,0xb9,0x30,0x00,0x05,
-   0x00}},
- {{0x5f,0x4f,0x82,0x55,0x81,0xbf,0x1f,
-   0x9c,0x8e,0x96,0xb9,0x30,0x00,0x05,
-   0x00}},
- {{0x5f,0x4f,0x82,0x55,0x81,0xbf,0x1f,
-   0x9c,0x8e,0x96,0xb9,0x30,0x00,0x05,
-   0x00}},
- {{0x5f,0x4f,0x82,0x55,0x81,0x0b,0x3e,
-   0xe9,0x8b,0xe7,0x04,0x00,0x00,0x05,
-   0x00}},
- {{0x7f,0x63,0x83,0x6c,0x1c,0x72,0xf0,
-   0x58,0x8c,0x57,0x73,0x20,0x00,0x06,
-   0x01}},
- {{0xa3,0x7f,0x87,0x86,0x97,0x24,0xf5,
-   0x02,0x88,0xff,0x25,0x10,0x00,0x02,
-   0x01}},
- {{0xce,0x9f,0x92,0xa8,0x14,0x28,0x5a,
-   0x00,0x84,0xff,0x29,0x09,0x00,0x07,
-   0x01}},
- {{0xce,0x9f,0x92,0xa9,0x17,0x24,0xf5,
-   0x02,0x88,0xff,0x25,0x10,0x00,0x07,
-   0x01}}
-};
-
-static const SiS_LVDSCRT1DataStruct  SiS_LVDSCRT1XXXxXXX_1_H[] =
-{
- {{0x38,0x27,0x9c,0x2c,0x80,0xbf,0x1f,
-   0x9c,0x8e,0x96,0xb9,0x30,0x00,0x00,
-   0x00}},
- {{0x38,0x27,0x9c,0x2c,0x80,0xbf,0x1f,
-   0x9c,0x8e,0x96,0xb9,0x30,0x00,0x00,
-   0x00}},
- {{0x38,0x27,0x9c,0x2c,0x80,0xbf,0x1f,
-   0x9c,0x8e,0x96,0xb9,0x30,0x00,0x00,
-   0x00}},
- {{0x38,0x27,0x9c,0x2c,0x80,0xbf,0x1f,
-   0x9c,0x8e,0x96,0xb9,0x30,0x00,0x00,
-   0x00}},
- {{0x38,0x27,0x9c,0x2c,0x80,0x0b,0x3e,
-   0xe9,0x8b,0xe7,0x04,0x00,0x00,0x00,
-   0x00}},
- {{0x4d,0x31,0x91,0x3b,0x03,0x72,0xf0,
-   0x58,0x8c,0x57,0x73,0x20,0x00,0x01,
-   0x01}},
- {{0x63,0x3f,0x87,0x4a,0x92,0x24,0xf5,
-   0x02,0x88,0xff,0x25,0x10,0x00,0x01,
-   0x01}}
-};
-
-
 /**************************************************************/
 /* COMMON --------------------------------------------------- */
 /**************************************************************/
@@ -2770,7 +2361,8 @@
    { 0x0000 }
 };
 
-USHORT  SiS_GetModeID(int VGAEngine, ULONG VBFlags, int HDisplay, int VDisplay, int Depth, BOOLEAN FSTN);
+USHORT  SiS_GetModeID(int VGAEngine, ULONG VBFlags, int HDisplay, int VDisplay,
+			  int Depth, BOOLEAN FSTN, int LCDwith, int LCDheight);
 USHORT  SiS_GetModeID_LCD(int VGAEngine, ULONG VBFlags, int HDisplay, int VDisplay, int Depth, BOOLEAN FSTN,
                           USHORT CustomT, int LCDwith, int LCDheight);
 USHORT  SiS_GetModeID_TV(int VGAEngine, ULONG VBFlags, int HDisplay, int VDisplay, int Depth);
@@ -2791,6 +2383,7 @@
 void	SiS_DisplayOff(SiS_Private *SiS_Pr);
 void	SiSRegInit(SiS_Private *SiS_Pr, SISIOADDRESS BaseAddr);
 void	SiSSetLVDSetc(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo);
+BOOLEAN SiSDetermineROMLayout661(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo);
 void	SiS_SetEnableDstn(SiS_Private *SiS_Pr, int enable);
 void	SiS_SetEnableFstn(SiS_Private *SiS_Pr, int enable);
 void	SiS_GetVBType(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo);
@@ -2801,6 +2394,7 @@
 USHORT	SiS_GetOffset(SiS_Private *SiS_Pr,USHORT ModeNo,USHORT ModeIdIndex,
               USHORT RefreshRateTableIndex,PSIS_HW_INFO HwInfo);
 void	SiS_LoadDAC(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo, USHORT ModeNo, USHORT ModeIdIndex);
+void	SiS_CalcLCDACRT1Timing(SiS_Private *SiS_Pr,USHORT ModeNo,USHORT ModeIdIndex);
 #ifdef LINUX_XF86
 BOOLEAN	SiSSetMode(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo,ScrnInfoPtr pScrn,USHORT ModeNo, BOOLEAN dosetpitch);
 BOOLEAN	SiSBIOSSetMode(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo, ScrnInfoPtr pScrn,
@@ -2821,10 +2415,7 @@
 			      unsigned char modeno, unsigned char rateindex);
 int    sisfb_mode_rate_to_ddata(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo,
 			 unsigned char modeno, unsigned char rateindex,
-			 ULONG *left_margin, ULONG *right_margin,
-			 ULONG *upper_margin, ULONG *lower_margin,
-			 ULONG *hsync_len, ULONG *vsync_len,
-			 ULONG *sync, ULONG *vmode);
+			 struct fb_var_screeninfo *var);
 BOOLEAN sisfb_gettotalfrommode(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo,
 		       unsigned char modeno, int *htotal, int *vtotal, unsigned char rateindex);
 #endif
--- diff/drivers/video/sis/init301.c	2004-05-19 22:12:23.000000000 +0100
+++ source/drivers/video/sis/init301.c	2004-06-11 19:22:05.000000000 +0100
@@ -1,9 +1,10 @@
 /* $XFree86$ */
+/* $XdotOrg$ */
 /*
  * Mode initializing code (CRT2 section)
  * for SiS 300/305/540/630/730 and
- *     SiS 315/550/650/M650/651/661FX/M661xX/740/741/M741/330/660/M660/760/M760
- * (Universal module for Linux kernel framebuffer and XFree86 4.x)
+ *     SiS 315/550/650/M650/651/661FX/M661xX/740/741(GX)/M741/330/660/M660/760/M760
+ * (Universal module for Linux kernel framebuffer and XFree86/X.org 4.x)
  *
  * Copyright (C) 2001-2004 by Thomas Winischhofer, Vienna, Austria
  *
@@ -34,13 +35,10 @@
  * * 2) Redistributions in binary form must reproduce the above copyright
  * *    notice, this list of conditions and the following disclaimer in the
  * *    documentation and/or other materials provided with the distribution.
- * * 3) All advertising materials mentioning features or use of this software
- * *    must display the following acknowledgement: "This product includes
- * *    software developed by Thomas Winischhofer, Vienna, Austria."
- * * 4) The name of the author may not be used to endorse or promote products
+ * * 3) The name of the author may not be used to endorse or promote products
  * *    derived from this software without specific prior written permission.
  * *
- * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESSED OR
  * * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
  * * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
  * * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
@@ -76,10 +74,6 @@
 
 #include "init301.h"
 
-#if 0
-#define TWNEWPANEL
-#endif
-
 #ifdef SIS300
 #include "oem300.h"
 #endif
@@ -91,6 +85,8 @@
 #define SiS_I2CDELAY      1000
 #define SiS_I2CDELAYSHORT  150
 
+static USHORT SiS_GetBIOSLCDResInfo(SiS_Private *SiS_Pr);
+
 /*********************************************/
 /*         HELPER: Lock/Unlock CRT2          */
 /*********************************************/
@@ -98,29 +94,19 @@
 void
 SiS_UnLockCRT2(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo)
 {
-  if(HwInfo->jChipType >= SIS_315H)
-     SiS_SetRegOR(SiS_Pr->SiS_Part1Port,0x2f,0x01);
-  else
-     SiS_SetRegOR(SiS_Pr->SiS_Part1Port,0x24,0x01);
+   if(HwInfo->jChipType >= SIS_315H)
+      SiS_SetRegOR(SiS_Pr->SiS_Part1Port,0x2f,0x01);
+   else
+      SiS_SetRegOR(SiS_Pr->SiS_Part1Port,0x24,0x01);
 }
 
 void
 SiS_LockCRT2(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo)
 {
-  if(HwInfo->jChipType >= SIS_315H)
-     SiS_SetRegAND(SiS_Pr->SiS_Part1Port,0x2F,0xFE);
-  else
-     SiS_SetRegAND(SiS_Pr->SiS_Part1Port,0x24,0xFE);
-}
-
-/*********************************************/
-/*            HELPER: Enable CRT2            */
-/*********************************************/
-
-void
-SiS_EnableCRT2(SiS_Private *SiS_Pr)
-{
-  SiS_SetRegOR(SiS_Pr->SiS_P3c4,0x1E,0x20);
+   if(HwInfo->jChipType >= SIS_315H)
+      SiS_SetRegAND(SiS_Pr->SiS_Part1Port,0x2F,0xFE);
+   else
+      SiS_SetRegAND(SiS_Pr->SiS_Part1Port,0x24,0xFE);
 }
 
 /*********************************************/
@@ -130,7 +116,10 @@
 static void
 SiS_SetRegSR11ANDOR(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo, USHORT DataAND, USHORT DataOR)
 {
-   if(HwInfo->jChipType >= SIS_661) DataAND &= 0x0f;
+   if(HwInfo->jChipType >= SIS_661) {
+      DataAND &= 0x0f;
+      DataOR  &= 0x0f;
+   }
    SiS_SetRegANDOR(SiS_Pr->SiS_P3c4,0x11,DataAND,DataOR);
 }
 
@@ -138,117 +127,45 @@
 /*    HELPER: Get Pointer to LCD structure   */
 /*********************************************/
 
-/* For 661 series only */
 #ifdef SIS315H
-#if 0   /* Need to wait until hardware using this really exists */
 static UCHAR *
-GetLCDPtr661(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo, int tabletype,
-             USHORT ModeNo, USHORT ModeIdIndex, USHORT RRTI)
+GetLCDStructPtr661(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo)
 {
-  UCHAR *ROMAddr =  HwInfo->pjVirtualRomBase;
-  UCHAR *tableptr = NULL;
-  UCHAR tablelengths[] = { 8, 7, 6, 6, 8, 6, 0, 0, 0 };
-  USHORT modeflag, CRT2Index, tablelength, lcdid, myid, tableptri;
-
-  if(ModeNo <= 0x13) {
-     modeflag = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_ModeFlag;
-     CRT2Index = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_CRT2CRTC;
-  } else {
-     modeflag = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag;
-     CRT2Index = SiS_Pr->SiS_RefIndex[RRTI].Ext_CRT2CRTC;
-     /* This is total bullshit: */
-     if(SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_RESINFO == SIS_RI_720x576) CRT2Index = 10;
-  }
-
-  if(tabletype <= 1) {
-#if 0	/* Not yet implemented */
-     if(ModeNo <= 0x13) {
-        CRT2Index = SiS_Pr->SiS_SModeIDTable[ModeIdIndex]. + 5;
-     } else {
-        CRT2Index = SiS_Pr->SiS_RefIndex[RRTI]. + 5;
-     }
-     if(tabletype & 1) CRT2Index >>= 4;
-#endif
-  }
-
-  CRT2Index &= 0x0f;
-
-  tablelength = tablelengths[tabletype];
-  if(SiS_Pr->SiS_LCDInfo & LCDPass11) {
-     if((tabletype == 5) || (tabletype == 7)) tablelength = 8;
-     if((tabletype == 3) || (tabletype == 8)) tablelength = 8;
-  }
-
-  if(!tablelength) return NULL;
-
-  tableptri = ROMAddr[0x222] | (ROMAddr[0x223] << 8);
-  tableptri += (tabletype << 1);
-  if(!tableptri) return NULL;
-  tableptr = &ROMAddr[tableptri];
+   UCHAR  *ROMAddr = HwInfo->pjVirtualRomBase;
+   UCHAR  *myptr = NULL;
+   USHORT romindex = 0;
 
-  do {
-     lcdid = tableptr[0];
-     if(lcdid == 0xff) break;
-     myid = SiS_Pr->SiS_LCDResInfo;
-     if((lcdid & 0x80) && (lcdid != 0x80)) {
-        lcdid &= 0x7f;
-	myid = SiS_Pr->SiS_LCDTypeInfo;
-     }
-     if(SiS_Pr->SiS_LCDInfo & LCDPass11) myid &= ~0x1f;
-
-     if(myid == lcdid) {
-	lcdid = tableptr[1] | (tableptr[2] << 8);
-	myid = SiS_Pr->SiS_LCDInfo661;
-	if(modeflag & HalfDCLK) myid |= 0x200;
-	if(ModeNo <= 0x13)      myid |= 0x400;
-	lcdid &= myid;
-	myid = tableptr[3] | (tableptr[4] << 8);
-	if(lcdid == myid) break;
-     }
-     tableptr += 7;
-  } while (1);
-
-  if(lcdid == myid) {
-     lcdid = tableptr[5] | (tableptr[6] << 8);
-     lcdid += (tablelength * CRT2Index);
-     return((UCHAR *)&ROMAddr[lcdid]);
-  }
+   /* Use the BIOS tables only for LVDS panels; DVI is unreliable
+    * due to the variaty of panels the BIOS doesn't know about.
+    */
 
-  return NULL;
+   if((SiS_Pr->SiS_ROMNew) && (SiS_Pr->SiS_VBType & VB_SIS301LV302LV)) {
+      myptr = (UCHAR *)SiS_LCDStruct661;
+      romindex = SISGETROMW(0x100);
+      if(romindex) {
+         romindex += ((SiS_GetReg(SiS_Pr->SiS_P3d4,0x7d) & 0x1f) * 26);
+         myptr = &ROMAddr[romindex];
+      }
+   }
+   return myptr;
 }
-#endif
 
-static UCHAR *
-GetLCDStructPtr661(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo)
+static USHORT
+GetLCDStructPtr661_2(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo)
 {
    UCHAR  *ROMAddr = HwInfo->pjVirtualRomBase;
-   USHORT lcdres = SiS_Pr->SiS_LCDResInfo;
-   USHORT lcdtype = SiS_Pr->SiS_LCDTypeInfo;
-   USHORT romindex=0;
-   UCHAR  *myptr = NULL;
-   UCHAR  lcdid;
+   USHORT romptr = 0;
 
-   if((ROMAddr) && SiS_Pr->SiS_UseROM) {
-      romindex = ROMAddr[0x256] | (ROMAddr[0x257] << 8);
-   }
-   if(romindex) {
-      myptr = &ROMAddr[romindex];
-   } else {
-      myptr = (UCHAR *)SiS_LCDStruct661;
-   }
+   /* Use the BIOS tables only for LVDS panels; DVI is unreliable
+    * due to the variaty of panels the BIOS doesn't know about.
+    */
 
-   while(myptr[0] != 0xff) {
-      lcdid = myptr[0];
-      if((lcdid & 0x80) && (lcdid != 0x80)) {
-         lcdres = lcdtype;
-	 lcdid &= 0x7f;
-      }
-      if(lcdid == lcdres) break;
-      myptr += 26;
+   if((SiS_Pr->SiS_ROMNew) && (SiS_Pr->SiS_VBType & VB_SIS301LV302LV)) {
+      romptr = SISGETROMW(0x102);
+      romptr += ((SiS_GetReg(SiS_Pr->SiS_P3d4,0x36) >> 4) * SiS_Pr->SiS661LCD2TableSize);
    }
-   if(myptr[0] == 0xff) return NULL;
 
-   return myptr;
+   return(romptr);
 }
 #endif
 
@@ -261,71 +178,72 @@
                    USHORT RefreshRateTableIndex, USHORT *i,
 		   PSIS_HW_INFO HwInfo)
 {
-  USHORT tempax,tempbx,infoflag;
-
-  tempbx = SiS_Pr->SiS_RefIndex[RefreshRateTableIndex + (*i)].ModeID;
+  USHORT checkmask=0,modeid,infoflag;
 
-  tempax = 0;
+  modeid = SiS_Pr->SiS_RefIndex[RefreshRateTableIndex + (*i)].ModeID;
 
   if(SiS_Pr->SiS_VBType & VB_SISVB) {
 
      if(SiS_Pr->SiS_VBInfo & SetCRT2ToRAMDAC) {
 
-      	tempax |= SupportRAMDAC2;
+      	checkmask |= SupportRAMDAC2;
 	if(HwInfo->jChipType >= SIS_315H) {
-	   tempax |= SupportRAMDAC2_135;
+	   checkmask |= SupportRAMDAC2_135;
 	   if(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) {
-	      tempax |= SupportRAMDAC2_162;
+	      checkmask |= SupportRAMDAC2_162;
 	      if(SiS_Pr->SiS_VBType & VB_SIS301C) {
-		 tempax |= SupportRAMDAC2_202;
+		 checkmask |= SupportRAMDAC2_202;
 	      }
 	   }
 	}
 
      } else if(SiS_Pr->SiS_VBInfo & (SetCRT2ToLCD | SetCRT2ToLCDA)) {
 
-     	tempax |= SupportLCD;
+     	checkmask |= SupportLCD;
 	if(HwInfo->jChipType >= SIS_315H) {
-	   if(SiS_Pr->SiS_VBType & VB_SIS301B302B) {
-	      if(SiS_Pr->SiS_LCDInfo & DontExpandLCD) {
-	         if(tempbx == 0x2e) {  /* 640x480 */
-		    tempax |= Support64048060Hz;
-		 }
+	   if(SiS_Pr->SiS_VBType & VB_SISVB) {
+	      if((SiS_Pr->SiS_LCDInfo & DontExpandLCD) && (SiS_Pr->SiS_LCDInfo & LCDPass11)) {
+	         if(modeid == 0x2e) checkmask |= Support64048060Hz;
 	      }
 	   }
 	}
 
      } else if(SiS_Pr->SiS_VBInfo & SetCRT2ToHiVision) {
 
-      	tempax |= SupportHiVision;
+      	checkmask |= SupportHiVision;
 
      } else if(SiS_Pr->SiS_VBInfo & (SetCRT2ToYPbPr525750|SetCRT2ToAVIDEO|SetCRT2ToSVIDEO|SetCRT2ToSCART)) {
 
-        tempax |= SupportTV;
+        checkmask |= SupportTV;
 	if(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) {
-	   tempax |= SupportTV1024;
+	   checkmask |= SupportTV1024;
+	   if(SiS_Pr->SiS_VBInfo & SetCRT2ToYPbPr525750) {
+	      if(SiS_Pr->SiS_TVMode & TVSetYPbPr750p) {
+	         checkmask |= SupportYPbPr750p;
+	      }
+	   }
 	}
 
      }
 
-  } else {	/* for LVDS  */
+  } else {	/* LVDS */
 
      if(SiS_Pr->SiS_IF_DEF_CH70xx != 0) {
      	if(SiS_Pr->SiS_VBInfo & SetCRT2ToTV) {
-           tempax |= SupportCHTV;
+           checkmask |= SupportCHTV;
       	}
      }
 
      if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCD) {
-     	tempax |= SupportLCD;
+     	checkmask |= SupportLCD;
      }
 
   }
 
   /* Look backwards in table for matching CRT2 mode */
-  for(; SiS_Pr->SiS_RefIndex[RefreshRateTableIndex+(*i)].ModeID == tempbx; (*i)--) {
+  for(; SiS_Pr->SiS_RefIndex[RefreshRateTableIndex+(*i)].ModeID == modeid; (*i)--) {
      infoflag = SiS_Pr->SiS_RefIndex[RefreshRateTableIndex + (*i)].Ext_InfoFlag;
-     if(infoflag & tempax) return(1);
+     if(infoflag & checkmask) return TRUE;
      if((*i) == 0) break;
   }
 
@@ -333,17 +251,17 @@
    * for a matching CRT2 mode if no mode was found yet.
    */
   for((*i) = 0; ; (*i)++) {
-     if(SiS_Pr->SiS_RefIndex[RefreshRateTableIndex + (*i)].ModeID != tempbx) {
-     	return(0);
+     if(SiS_Pr->SiS_RefIndex[RefreshRateTableIndex + (*i)].ModeID != modeid) {
+     	return FALSE;
      }
      infoflag = SiS_Pr->SiS_RefIndex[RefreshRateTableIndex + (*i)].Ext_InfoFlag;
-     if(infoflag & tempax) return(1);
+     if(infoflag & checkmask) return TRUE;
   }
-  return(1);
+  return TRUE;
 }
 
 /*********************************************/
-/*              Get rate pointer             */
+/*              Get rate index               */
 /*********************************************/
 
 USHORT
@@ -361,20 +279,19 @@
   /* Do NOT check for UseCustomMode here, will skrew up FIFO */
   if(ModeNo == 0xfe) return 0;
 
-  if(ModeNo <= 0x13)
+  if(ModeNo <= 0x13) {
      modeflag = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_ModeFlag;
-  else
+  } else {
      modeflag = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag;
+  }
 
   if(SiS_Pr->SiS_IF_DEF_CH70xx != 0) {
      if(SiS_Pr->SiS_VBInfo & SetCRT2ToTV) {
-     	if(modeflag & HalfDCLK) return(0);
+     	if(modeflag & HalfDCLK) return 0;
      }
   }
 
-  if(ModeNo < 0x14) return(0xFFFF);
-
-  /* CR33 holds refresh rate index for CRT1 [3:0] and CRT2 [7:4]. */
+  if(ModeNo < 0x14) return 0xFFFF;
 
   index = (SiS_GetReg(SiS_Pr->SiS_P3d4,0x33) >> SiS_Pr->SiS_SelectCRT2Rate) & 0x0F;
   backupindex = index;
@@ -389,7 +306,7 @@
 	}
 	if(SiS_Pr->SiS_VBInfo & (SetCRT2ToLCD | SetCRT2ToLCDA)) {
 	   if(!(SiS_Pr->SiS_VBType & VB_NoLCD)) {
-              temp = LCDRefreshIndex[SiS_Pr->SiS_LCDResInfo];
+              temp = LCDRefreshIndex[SiS_GetBIOSLCDResInfo(SiS_Pr)];
               if(index > temp) index = temp;
 	   }
 	}
@@ -462,37 +379,39 @@
 /*    HELPER: GET SOME DATA FROM BIOS ROM    */
 /*********************************************/
 
+#ifdef SIS300
 static BOOLEAN
 SiS_CR36BIOSWord23b(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo)
 {
+  UCHAR *ROMAddr = (UCHAR *)HwInfo->pjVirtualRomBase;
   USHORT temp,temp1;
-  UCHAR *ROMAddr;
 
-  if((ROMAddr = (UCHAR *)HwInfo->pjVirtualRomBase) && SiS_Pr->SiS_UseROM) {
+  if(SiS_Pr->SiS_UseROM) {
      if((ROMAddr[0x233] == 0x12) && (ROMAddr[0x234] == 0x34)) {
         temp = 1 << ((SiS_GetReg(SiS_Pr->SiS_P3d4,0x36) & 0xff) >> 4);
-        temp1 = (ROMAddr[0x23c] << 8) | ROMAddr[0x23b];
-        if(temp1 & temp) return(1);
+        temp1 = SISGETROMW(0x23b);
+        if(temp1 & temp) return TRUE;
      }
   }
-  return(0);
+  return FALSE;
 }
 
 static BOOLEAN
 SiS_CR36BIOSWord23d(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo)
 {
+  UCHAR *ROMAddr = (UCHAR *)HwInfo->pjVirtualRomBase;
   USHORT temp,temp1;
-  UCHAR *ROMAddr;
 
-  if((ROMAddr = (UCHAR *)HwInfo->pjVirtualRomBase) && SiS_Pr->SiS_UseROM) {
+  if(SiS_Pr->SiS_UseROM) {
      if((ROMAddr[0x233] == 0x12) && (ROMAddr[0x234] == 0x34)) {
         temp = 1 << ((SiS_GetReg(SiS_Pr->SiS_P3d4,0x36) & 0xff) >> 4);
-        temp1 = (ROMAddr[0x23e] << 8) | ROMAddr[0x23d];
-        if(temp1 & temp) return(1);
+        temp1 = SISGETROMW(0x23d);
+        if(temp1 & temp) return TRUE;
      }
   }
-  return(0);
+  return FALSE;
 }
+#endif
 
 /*********************************************/
 /*          HELPER: DELAY FUNCTIONS          */
@@ -508,6 +427,7 @@
   }
 }
 
+#if defined(SIS300) || defined(SIS315H)
 static void
 SiS_GenericDelay(SiS_Private *SiS_Pr, USHORT delay)
 {
@@ -522,6 +442,7 @@
      delay--;
   }
 }
+#endif
 
 #ifdef SIS315H
 static void
@@ -533,6 +454,7 @@
 }
 #endif
 
+#if defined(SIS300) || defined(SIS315H)
 static void
 SiS_ShortDelay(SiS_Private *SiS_Pr, USHORT delay)
 {
@@ -540,12 +462,15 @@
      SiS_GenericDelay(SiS_Pr,0x42);
   }
 }
+#endif
 
 static void
 SiS_PanelDelay(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo, USHORT DelayTime)
 {
+#if defined(SIS300) || defined(SIS315H)
   UCHAR  *ROMAddr = HwInfo->pjVirtualRomBase;
   USHORT PanelID, DelayIndex, Delay=0;
+#endif
 
   if(HwInfo->jChipType < SIS_315H) {
 
@@ -560,23 +485,19 @@
          Delay = 3;
       } else {
          if(DelayTime >= 2) DelayTime -= 2;
-
          if(!(DelayTime & 0x01)) {
        	    Delay = SiS_Pr->SiS_PanelDelayTbl[DelayIndex].timer[0];
          } else {
        	    Delay = SiS_Pr->SiS_PanelDelayTbl[DelayIndex].timer[1];
          }
-	 if((ROMAddr) && (SiS_Pr->SiS_UseROM)) {
+	 if(SiS_Pr->SiS_UseROM) {
             if(ROMAddr[0x220] & 0x40) {
-               if(!(DelayTime & 0x01)) {
-	          Delay = (USHORT)ROMAddr[0x225];
-               } else {
-	    	  Delay = (USHORT)ROMAddr[0x226];
-               }
+               if(!(DelayTime & 0x01)) Delay = (USHORT)ROMAddr[0x225];
+               else 	    	       Delay = (USHORT)ROMAddr[0x226];
             }
          }
       }
-      SiS_ShortDelay(SiS_Pr,Delay);
+      SiS_ShortDelay(SiS_Pr, Delay);
 
 #endif  /* SIS300 */
 
@@ -584,11 +505,19 @@
 
 #ifdef SIS315H
 
-      if(HwInfo->jChipType >= SIS_330) return;
+      if((HwInfo->jChipType >= SIS_661)    ||
+         (HwInfo->jChipType <= SIS_315PRO) ||
+	 (HwInfo->jChipType == SIS_330)) {
+
+         if(!(DelayTime & 0x01)) {
+	    SiS_DDC2Delay(SiS_Pr, 0x1000);
+         } else {
+	    SiS_DDC2Delay(SiS_Pr, 0x4000);
+         }
 
-      if((SiS_Pr->SiS_IF_DEF_LVDS == 1) ||
+      } else if((SiS_Pr->SiS_IF_DEF_LVDS == 1) /* ||
          (SiS_Pr->SiS_CustomT == CUT_COMPAQ1280) ||
-	 (SiS_Pr->SiS_CustomT == CUT_CLEVO1400)) {			/* 315 series, LVDS; Special */
+	 (SiS_Pr->SiS_CustomT == CUT_CLEVO1400) */ ) {			/* 315 series, LVDS; Special */
 
          if(SiS_Pr->SiS_IF_DEF_CH70xx == 0) {
             PanelID = SiS_GetReg(SiS_Pr->SiS_P3d4,0x36);
@@ -609,7 +538,7 @@
                } else {
        		  Delay = SiS_Pr->SiS_PanelDelayTblLVDS[DelayIndex].timer[1];
                }
-	       if((ROMAddr) && (SiS_Pr->SiS_UseROM)) {
+	       if((SiS_Pr->SiS_UseROM) && (!(SiS_Pr->SiS_ROMNew))) {
                   if(ROMAddr[0x13c] & 0x40) {
                      if(!(DelayTime & 0x01)) {
 	    	        Delay = (USHORT)ROMAddr[0x17e];
@@ -619,7 +548,7 @@
                   }
                }
             }
-	    SiS_ShortDelay(SiS_Pr,Delay);
+	    SiS_ShortDelay(SiS_Pr, Delay);
 	 }
 
       } else if(SiS_Pr->SiS_VBType & VB_SISVB) {			/* 315 series, all bridges */
@@ -662,7 +591,6 @@
   USHORT watchdog;
 
   if(SiS_GetReg(SiS_Pr->SiS_P3c4,0x1f) & 0xc0) return;
-
   if(!(SiS_GetReg(SiS_Pr->SiS_P3d4,0x17) & 0x80)) return;
 
   watchdog = 65535;
@@ -671,6 +599,7 @@
   while((!(SiS_GetRegByte(SiS_Pr->SiS_P3da) & 0x08)) && --watchdog);
 }
 
+#if defined(SIS300) || defined(SIS315H)
 static void
 SiS_WaitRetrace2(SiS_Private *SiS_Pr, USHORT reg)
 {
@@ -681,6 +610,7 @@
   watchdog = 65535;
   while((!(SiS_GetReg(SiS_Pr->SiS_Part1Port,reg) & 0x02)) && --watchdog);
 }
+#endif
 
 static void
 SiS_WaitVBRetrace(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo)
@@ -718,10 +648,10 @@
        tempal = SiS_GetRegByte(SiS_Pr->SiS_P3da);
        if(temp & 0x01) {
           if((tempal & 0x08))  continue;
-          if(!(tempal & 0x08)) break;
+          else break;
        } else {
           if(!(tempal & 0x08)) continue;
-          if((tempal & 0x08))  break;
+          else break;
        }
     }
     temp ^= 0x01;
@@ -742,15 +672,14 @@
 /*               HELPER: MISC                */
 /*********************************************/
 
+#ifdef SIS300
 static BOOLEAN
 SiS_Is301B(SiS_Private *SiS_Pr)
 {
-  USHORT flag;
-
-  flag = SiS_GetReg(SiS_Pr->SiS_Part4Port,0x01);
-  if(flag >= 0xb0) return TRUE;
+  if(SiS_GetReg(SiS_Pr->SiS_Part4Port,0x01) >= 0xb0) return TRUE;
   return FALSE;
 }
+#endif
 
 static BOOLEAN
 SiS_CRT2IsLCD(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo)
@@ -796,6 +725,16 @@
   return FALSE;
 }
 
+#ifdef SIS315H
+static BOOLEAN
+SiS_IsVAorLCD(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo)
+{
+  if(SiS_IsVAMode(SiS_Pr,HwInfo))   return TRUE;
+  if(SiS_CRT2IsLCD(SiS_Pr, HwInfo)) return TRUE;
+  return FALSE;
+}
+#endif
+
 static BOOLEAN
 SiS_IsDualLink(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo)
 {
@@ -815,7 +754,7 @@
 SiS_TVEnabled(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo)
 {
   if((SiS_GetReg(SiS_Pr->SiS_Part2Port,0x00) & 0x0f) != 0x0c) return TRUE;
-  if(SiS_Pr->SiS_VBType & (VB_301C | VB_SIS301LV302LV)) {
+  if(SiS_Pr->SiS_VBType & (VB_SIS301C | VB_SIS301LV302LV)) {
      if(SiS_GetReg(SiS_Pr->SiS_Part2Port,0x4d) & 0x10) return TRUE;
   }
   return FALSE;
@@ -835,11 +774,8 @@
 static BOOLEAN
 SiS_WeHaveBacklightCtrl(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo)
 {
-  USHORT flag;
-
   if((HwInfo->jChipType >= SIS_315H) && (HwInfo->jChipType < SIS_661)) {
-     flag = SiS_GetReg(SiS_Pr->SiS_P3d4,0x79);
-     if(flag & 0x10) return TRUE;
+     if(SiS_GetReg(SiS_Pr->SiS_P3d4,0x79) & 0x10) return TRUE;
   }
   return FALSE;
 }
@@ -935,12 +871,12 @@
   USHORT flag;
 
   if(SiS_Pr->SiS_IF_DEF_LVDS == 1) {
-     return FALSE;
+     return TRUE;
   } else if(SiS_Pr->SiS_VBType & VB_SISVB) {
      flag = SiS_GetReg(SiS_Pr->SiS_Part4Port,0x00);
-     if((flag == 1) || (flag == 2)) return FALSE;
+     if((flag == 1) || (flag == 2)) return TRUE;
   }
-  return TRUE;
+  return FALSE;
 }
 
 static BOOLEAN
@@ -948,21 +884,21 @@
 {
   USHORT flag;
 
-  if(!(SiS_BridgeIsOn(SiS_Pr))) {
+  if(SiS_BridgeIsOn(SiS_Pr)) {
      flag = SiS_GetReg(SiS_Pr->SiS_Part1Port,0x00);
      if(HwInfo->jChipType < SIS_315H) {
        flag &= 0xa0;
-       if((flag == 0x80) || (flag == 0x20)) return FALSE;
+       if((flag == 0x80) || (flag == 0x20)) return TRUE;
      } else {
        flag &= 0x50;
-       if((flag == 0x40) || (flag == 0x10)) return FALSE;
+       if((flag == 0x40) || (flag == 0x10)) return TRUE;
      }
   }
-  return TRUE;
+  return FALSE;
 }
 
 static BOOLEAN
-SiS_BridgeInSlave(SiS_Private *SiS_Pr)
+SiS_BridgeInSlavemode(SiS_Private *SiS_Pr)
 {
   USHORT flag1;
 
@@ -985,7 +921,7 @@
    if(!(SiS_Pr->SiS_ChSW)) return;
 
 #ifndef LINUX_XF86
-   SiS_SetRegLong(0xcf8,0x80000874);		   /* get ACPI base */
+   SiS_SetRegLong(0xcf8,0x80000874);		       /* get ACPI base */
    acpibase = SiS_GetRegLong(0xcfc);
 #else
    acpibase = pciReadLong(0x00000800, 0x74);
@@ -1003,22 +939,19 @@
 }
 
 void
-SiS_GetVBInfo(SiS_Private *SiS_Pr, USHORT ModeNo,
-              USHORT ModeIdIndex,PSIS_HW_INFO HwInfo,
-	      int checkcrt2mode)
+SiS_GetVBInfo(SiS_Private *SiS_Pr, USHORT ModeNo, USHORT ModeIdIndex,
+              PSIS_HW_INFO HwInfo, int checkcrt2mode)
 {
   USHORT tempax,tempbx,temp;
   USHORT modeflag, resinfo=0;
 
   if(ModeNo <= 0x13) {
      modeflag = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_ModeFlag;
+  } else if(SiS_Pr->UseCustomMode) {
+     modeflag = SiS_Pr->CModeFlag;
   } else {
-     if(SiS_Pr->UseCustomMode) {
-        modeflag = SiS_Pr->CModeFlag;
-     } else {
-   	modeflag = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag;
-	resinfo = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_RESINFO;
-     }
+     modeflag = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag;
+     resinfo = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_RESINFO;
   }
 
   SiS_Pr->SiS_SetFlag = 0;
@@ -1026,7 +959,7 @@
   SiS_Pr->SiS_ModeType = modeflag & ModeInfoFlag;
 
   tempbx = 0;
-  if(SiS_BridgeIsOn(SiS_Pr) == 0) {
+  if(SiS_BridgeIsOn(SiS_Pr)) {
     	temp = SiS_GetReg(SiS_Pr->SiS_P3d4,0x30);
 #if 0
    	if(HwInfo->jChipType < SIS_661) {
@@ -1054,7 +987,7 @@
 		 SiS_SetRegAND(SiS_Pr->SiS_P3d4,0x31,0xbf);
 	      }
 	      if(!(SiS_GetReg(SiS_Pr->SiS_P3d4,0x31) & (DriverMode >> 8))) {
-	         /* Reset LCDA setting */
+	         /* Reset LCDA setting if not driver mode */
 		 SiS_SetRegAND(SiS_Pr->SiS_P3d4,0x38,0xfc);
 	      }
 	      if(IS_SIS650) {
@@ -1071,6 +1004,11 @@
           	 tempbx |= SetCRT2ToLCDA;
 	      }
 	   }
+
+	   if(SiS_Pr->SiS_VBType & (VB_SIS301LV|VB_SIS302LV|VB_SIS302ELV)) {
+	      tempbx &= ~(SetCRT2ToRAMDAC);
+	   }
+
 	   if(HwInfo->jChipType >= SIS_661) {
 	      tempbx &= ~(SetCRT2ToYPbPr525750 | SetCRT2ToHiVision);
 	      temp = SiS_GetReg(SiS_Pr->SiS_P3d4,0x38);
@@ -1148,24 +1086,12 @@
 				SetPALTV 	   |
 				SwitchCRT2	   |
 				SetSimuScanMode );
-      	   if(tempbx & SetCRT2ToLCDA) {
-              tempbx &= (clearmask | SetCRT2ToLCDA);
-      	   }
-	   if(tempbx & SetCRT2ToRAMDAC) {
-              tempbx &= (clearmask | SetCRT2ToRAMDAC);
-      	   }
-	   if(tempbx & SetCRT2ToLCD) {
-              tempbx &= (clearmask | SetCRT2ToLCD);
-      	   }
-	   if(tempbx & SetCRT2ToSCART) {
-              tempbx &= (clearmask | SetCRT2ToSCART);
-      	   }
-	   if(tempbx & SetCRT2ToHiVision) {
-              tempbx &= (clearmask | SetCRT2ToHiVision);
-      	   }
-	   if(tempbx & SetCRT2ToYPbPr525750) {
-	      tempbx &= (clearmask | SetCRT2ToYPbPr525750);
-	   }
+      	   if(tempbx & SetCRT2ToLCDA)        tempbx &= (clearmask | SetCRT2ToLCDA);
+	   if(tempbx & SetCRT2ToRAMDAC)      tempbx &= (clearmask | SetCRT2ToRAMDAC);
+	   if(tempbx & SetCRT2ToLCD)         tempbx &= (clearmask | SetCRT2ToLCD);
+	   if(tempbx & SetCRT2ToSCART)       tempbx &= (clearmask | SetCRT2ToSCART);
+	   if(tempbx & SetCRT2ToHiVision)    tempbx &= (clearmask | SetCRT2ToHiVision);
+	   if(tempbx & SetCRT2ToYPbPr525750) tempbx &= (clearmask | SetCRT2ToYPbPr525750);
    	} else {
 	   if(HwInfo->jChipType >= SIS_315H) {
 	      if(tempbx & SetCRT2ToLCDA) {
@@ -1193,14 +1119,12 @@
       	   }
     	}
 
-    	if(!(tempbx & DriverMode)){
-      	   tempbx |= SetSimuScanMode;
-    	}
+    	if(!(tempbx & DriverMode)) tempbx |= SetSimuScanMode;
 
 	/* LVDS/CHRONTEL (LCD/TV) and 301BDH (LCD) can only be slave in 8bpp modes */
 	if(SiS_Pr->SiS_ModeType <= ModeVGA) {
 	   if( (SiS_Pr->SiS_IF_DEF_LVDS == 1) ||
-	       ((tempbx & SetCRT2ToLCD) && (SiS_Pr->SiS_VBType & VB_NoLCD)) ) {
+	       ((SiS_Pr->SiS_VBType & VB_NoLCD) && (tempbx & SetCRT2ToLCD)) ) {
 	       modeflag &= (~CRT2Mode);
 	   }
 	}
@@ -1218,9 +1142,9 @@
 	         }
               }
       	   } else {
-              if(!(SiS_BridgeIsEnabled(SiS_Pr,HwInfo))) {
+              if(SiS_BridgeIsEnabled(SiS_Pr,HwInfo)) {
           	 if(!(tempbx & DriverMode)) {
-            	    if(SiS_BridgeInSlave(SiS_Pr)) {
+            	    if(SiS_BridgeInSlavemode(SiS_Pr)) {
 		       tempbx |= SetSimuScanMode;
             	    }
                  }
@@ -1346,7 +1270,7 @@
 	   if(HwInfo->jChipType >= SIS_330) romindex = 0x11b;
         }
         if(temp) {
-           if(romindex && ROMAddr && SiS_Pr->SiS_UseROM) {
+           if(romindex && SiS_Pr->SiS_UseROM && (!(SiS_Pr->SiS_ROMNew))) {
 	      OutputSelect = ROMAddr[romindex];
 	      if(!(OutputSelect & EnablePALMN)) {
                  SiS_SetRegAND(SiS_Pr->SiS_P3d4,temp,0x3F);
@@ -1443,6 +1367,22 @@
 	} else if(SiS_Pr->SiS_VBInfo & SetCRT2ToHiVision) {
 	   SiS_Pr->SiS_TVMode |= (TVSetHiVision | TVSetPAL);
 	}
+	if(SiS_Pr->SiS_VBInfo & (SetCRT2ToYPbPr525750 | SetCRT2ToHiVision)) {
+	   if(resinfo == SIS_RI_800x480 || resinfo == SIS_RI_1024x576 || resinfo == SIS_RI_1280x720) {
+	      SiS_Pr->SiS_TVMode |= TVAspect169;
+	   } else {
+	      temp1 = SiS_GetReg(SiS_Pr->SiS_P3d4,0x39);
+	      if(temp1 & 0x02) {
+		 if(SiS_Pr->SiS_TVMode & (TVSetYPbPr750p | TVSetHiVision)) {
+		    SiS_Pr->SiS_TVMode |= TVAspect169;
+		 } else {
+		    SiS_Pr->SiS_TVMode |= TVAspect43LB;
+		 }
+	      } else {
+		 SiS_Pr->SiS_TVMode |= TVAspect43;
+	      }
+	   }
+	}
      }
   }
 
@@ -1493,13 +1433,74 @@
 #ifdef TWDEBUG
   xf86DrvMsg(0, X_INFO, "(init301: TVMode %x, VBInfo %x)\n", SiS_Pr->SiS_TVMode, SiS_Pr->SiS_VBInfo);
 #endif
-
 }
 
 /*********************************************/
 /*               GET LCD INFO                */
 /*********************************************/
 
+static USHORT
+SiS_GetBIOSLCDResInfo(SiS_Private *SiS_Pr)
+{
+   USHORT temp = SiS_Pr->SiS_LCDResInfo;
+   /* Translate my LCDResInfo to BIOS value */
+   if(temp == Panel_1280x768_2)  temp = Panel_1280x768;
+   if(temp == Panel_1280x768_3)  temp = Panel_1280x768;
+   return temp;
+}
+
+static void
+SiS_GetLCDInfoBIOS(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo)
+{
+#ifdef SIS315H
+   UCHAR  *ROMAddr;
+   USHORT temp;
+
+#ifdef TWDEBUG
+   xf86DrvMsg(0, X_INFO, "Paneldata driver: [%d %d] [H %d %d] [V %d %d] [C %d 0x%02x 0x%02x]\n",
+      	SiS_Pr->PanelHT, SiS_Pr->PanelVT,
+	SiS_Pr->PanelHRS, SiS_Pr->PanelHRE,
+	SiS_Pr->PanelVRS, SiS_Pr->PanelVRE,
+	SiS_Pr->SiS_VBVCLKData[SiS_Pr->PanelVCLKIdx315].CLOCK,
+	SiS_Pr->SiS_VBVCLKData[SiS_Pr->PanelVCLKIdx315].Part4_A,
+	SiS_Pr->SiS_VBVCLKData[SiS_Pr->PanelVCLKIdx315].Part4_B);
+#endif
+
+   if((ROMAddr = GetLCDStructPtr661(SiS_Pr, HwInfo))) {
+      if((temp = SISGETROMW(6)) != SiS_Pr->PanelHT) {
+         SiS_Pr->SiS_NeedRomModeData = TRUE;
+	 SiS_Pr->PanelHT  = temp;
+      }
+      if((temp = SISGETROMW(8)) != SiS_Pr->PanelVT) {
+         SiS_Pr->SiS_NeedRomModeData = TRUE;
+         SiS_Pr->PanelVT  = temp;
+      }
+      SiS_Pr->PanelHRS = SISGETROMW(10);
+      SiS_Pr->PanelHRE = SISGETROMW(12);
+      SiS_Pr->PanelVRS = SISGETROMW(14);
+      SiS_Pr->PanelVRE = SISGETROMW(16);
+      SiS_Pr->PanelVCLKIdx315 = VCLK_CUSTOM_315;
+      SiS_Pr->SiS_VCLKData[VCLK_CUSTOM_315].CLOCK =
+	 SiS_Pr->SiS_VBVCLKData[VCLK_CUSTOM_315].CLOCK = (USHORT)((UCHAR)ROMAddr[18]);
+      SiS_Pr->SiS_VCLKData[VCLK_CUSTOM_315].SR2B =
+	 SiS_Pr->SiS_VBVCLKData[VCLK_CUSTOM_315].Part4_A = ROMAddr[19];
+      SiS_Pr->SiS_VCLKData[VCLK_CUSTOM_315].SR2C =
+	 SiS_Pr->SiS_VBVCLKData[VCLK_CUSTOM_315].Part4_B = ROMAddr[20];
+
+#ifdef TWDEBUG
+      xf86DrvMsg(0, X_INFO, "Paneldata BIOS:  [%d %d] [H %d %d] [V %d %d] [C %d 0x%02x 0x%02x]\n",
+      	SiS_Pr->PanelHT, SiS_Pr->PanelVT,
+	SiS_Pr->PanelHRS, SiS_Pr->PanelHRE,
+	SiS_Pr->PanelVRS, SiS_Pr->PanelVRE,
+	SiS_Pr->SiS_VBVCLKData[SiS_Pr->PanelVCLKIdx315].CLOCK,
+	SiS_Pr->SiS_VBVCLKData[SiS_Pr->PanelVCLKIdx315].Part4_A,
+	SiS_Pr->SiS_VBVCLKData[SiS_Pr->PanelVCLKIdx315].Part4_B);
+#endif
+
+   }
+#endif
+}
+
 void
 SiS_GetLCDResInfo(SiS_Private *SiS_Pr, USHORT ModeNo, USHORT ModeIdIndex,
 		  PSIS_HW_INFO HwInfo)
@@ -1515,50 +1516,60 @@
          { 0,  1,  2,  3,  7,  4,  5,  8,
 	   0,  0, 10,  0,  0,  0,  0, 15 };
 
-  SiS_Pr->SiS_LCDResInfo = 0;
+  SiS_Pr->SiS_LCDResInfo  = 0;
   SiS_Pr->SiS_LCDTypeInfo = 0;
-  SiS_Pr->SiS_LCDInfo = 0;
+  SiS_Pr->SiS_LCDInfo     = 0;
+  SiS_Pr->PanelHRS        = 999; /* HSync start */
+  SiS_Pr->PanelHRE        = 999; /* HSync end */
+  SiS_Pr->PanelVRS        = 999; /* VSync start */
+  SiS_Pr->PanelVRE        = 999; /* VSync end */
+  SiS_Pr->SiS_NeedRomModeData = FALSE;
 
-  if(SiS_Pr->UseCustomMode) {
+  if(!(SiS_Pr->SiS_VBInfo & (SetCRT2ToLCD | SetCRT2ToLCDA))) return;
+
+  if(ModeNo <= 0x13) {
+     modeflag = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_ModeFlag;
+  } else if(SiS_Pr->UseCustomMode) {
      modeflag = SiS_Pr->CModeFlag;
   } else {
-     if(ModeNo <= 0x13) {
-    	modeflag = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_ModeFlag;
-     } else {
-    	modeflag = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag;
-    	resinfo = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_RESINFO;
-     }
+     modeflag = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag;
+     resinfo = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_RESINFO;
   }
 
-  if(!(SiS_Pr->SiS_VBInfo & (SetCRT2ToLCD | SetCRT2ToLCDA))) return;
-
   temp = SiS_GetReg(SiS_Pr->SiS_P3d4,0x36);
+  if(!temp) return;
 
-  if((HwInfo->jChipType < SIS_315H) || (HwInfo->jChipType >= SIS_661)) {
+  if((HwInfo->jChipType >= SIS_661) || (SiS_Pr->SiS_ROMNew)) {
+     SiS_Pr->SiS_LCDTypeInfo = (SiS_GetReg(SiS_Pr->SiS_P3d4,0x39) & 0x7c) >> 2;
+  } else if((HwInfo->jChipType < SIS_315H) || (HwInfo->jChipType >= SIS_661)) {
      SiS_Pr->SiS_LCDTypeInfo = temp >> 4;
   } else {
      SiS_Pr->SiS_LCDTypeInfo = (temp & 0x0F) - 1;
   }
   temp &= 0x0f;
   if(HwInfo->jChipType < SIS_315H) {
-      /* Translate 300 series LCDRes to 315 series for unified usage */
-      temp = SiS300SeriesLCDRes[temp];
+     /* Translate 300 series LCDRes to 315 series for unified usage */
+     temp = SiS300SeriesLCDRes[temp];
   }
-  SiS_Pr->SiS_LCDResInfo = temp;
 
-  if(SiS_Pr->SiS_VBType & VB_SISVB) {
-     if(SiS_Pr->SiS_LCDResInfo < SiS_Pr->SiS_PanelMin301)
-	SiS_Pr->SiS_LCDResInfo = SiS_Pr->SiS_PanelMin301;
-  } else {
-     if(SiS_Pr->SiS_LCDResInfo < SiS_Pr->SiS_PanelMinLVDS)
-	SiS_Pr->SiS_LCDResInfo = SiS_Pr->SiS_PanelMinLVDS;
+  if(HwInfo->jChipType == SIS_550) {
+     if(temp == Panel310_640x480_2) temp = Panel_640x480_2;
+     if(temp == Panel310_640x480_3) temp = Panel_640x480_3;
   }
 
-  if((!SiS_Pr->CP_HaveCustomData) || (SiS_Pr->SiS_LCDResInfo != SiS_Pr->SiS_PanelCustom)) {
-     if(SiS_Pr->SiS_LCDResInfo > SiS_Pr->SiS_PanelMax)
-  	SiS_Pr->SiS_LCDResInfo = SiS_Pr->SiS_Panel1024x768;
+  if(SiS_Pr->SiS_VBType & VB_SIS301LV302LV) {	/* SiS LVDS */
+     if(temp == Panel310_1280x768) {
+        temp = Panel_1280x768_2;
+#ifdef SIS315H
+	if((myptr = GetLCDStructPtr661(SiS_Pr, HwInfo))) {
+	   if((myptr[8] | (myptr[9] << 8)) == 798) temp = Panel_1280x768_3;
+	}
+#endif
+     }
   }
 
+  SiS_Pr->SiS_LCDResInfo = temp;
+
   if(SiS_Pr->SiS_IF_DEF_LVDS == 1) {
      if(SiS_Pr->SiS_CustomT == CUT_BARCO1366) {
         SiS_Pr->SiS_LCDResInfo = Panel_Barco1366;
@@ -1567,113 +1578,306 @@
      }
   }
 
+  if(SiS_Pr->SiS_VBType & VB_SISVB) {
+     if(SiS_Pr->SiS_LCDResInfo < SiS_Pr->SiS_PanelMin301)
+	SiS_Pr->SiS_LCDResInfo = SiS_Pr->SiS_PanelMin301;
+  } else {
+     if(SiS_Pr->SiS_LCDResInfo < SiS_Pr->SiS_PanelMinLVDS)
+	SiS_Pr->SiS_LCDResInfo = SiS_Pr->SiS_PanelMinLVDS;
+  }
+
+  SiS_Pr->PanelVCLKIdx300 = VCLK65_300;
+  SiS_Pr->PanelVCLKIdx315 = VCLK108_2_315;
+
   switch(SiS_Pr->SiS_LCDResInfo) {
-     case Panel_800x600:   SiS_Pr->PanelXRes =  800; SiS_Pr->PanelYRes =  600; break;
-     case Panel_1024x768:  SiS_Pr->PanelXRes = 1024; SiS_Pr->PanelYRes =  768; break;
-     case Panel_1280x1024: SiS_Pr->PanelXRes = 1280; SiS_Pr->PanelYRes = 1024; break;
-     case Panel_640x480_3:
+     case Panel_320x480:    SiS_Pr->PanelXRes =  320; SiS_Pr->PanelYRes =  480;
+     			    SiS_Pr->PanelHT   =  400; SiS_Pr->PanelVT   =  525;
+			    SiS_Pr->PanelVCLKIdx300 = VCLK28;
+			    SiS_Pr->PanelVCLKIdx315 = VCLK28;
+			    break;
      case Panel_640x480_2:
-     case Panel_640x480:   SiS_Pr->PanelXRes =  640; SiS_Pr->PanelYRes =  480; break;
-     case Panel_1024x600:  SiS_Pr->PanelXRes = 1024; SiS_Pr->PanelYRes =  600; break;
-     case Panel_1152x864:  SiS_Pr->PanelXRes = 1152; SiS_Pr->PanelYRes =  864; break;
-     case Panel_1280x960:  SiS_Pr->PanelXRes = 1280; SiS_Pr->PanelYRes =  960; break;
-     case Panel_1152x768:  SiS_Pr->PanelXRes = 1152; SiS_Pr->PanelYRes =  768; break;
-     case Panel_1400x1050: SiS_Pr->PanelXRes = 1400; SiS_Pr->PanelYRes = 1050; break;
-     case Panel_1280x768:  SiS_Pr->PanelXRes = 1280; SiS_Pr->PanelYRes =  768; break;
-     case Panel_1600x1200: SiS_Pr->PanelXRes = 1600; SiS_Pr->PanelYRes = 1200; break;
-     case Panel_320x480:   SiS_Pr->PanelXRes =  320; SiS_Pr->PanelYRes =  480; break;
-     case Panel_Custom:    SiS_Pr->PanelXRes = SiS_Pr->CP_MaxX;
-    			   SiS_Pr->PanelYRes = SiS_Pr->CP_MaxY;
-			   break;
-     case Panel_Barco1366: SiS_Pr->PanelXRes = 1360; SiS_Pr->PanelYRes = 1024; break;
-     case Panel_848x480:   SiS_Pr->PanelXRes =  848; SiS_Pr->PanelYRes =  480; break;
-     default:		   SiS_Pr->PanelXRes = 1024; SiS_Pr->PanelYRes =  768; break;
+     case Panel_640x480_3:  SiS_Pr->PanelXRes =  640; SiS_Pr->PanelYRes =  480;
+     			    SiS_Pr->PanelVRS  =   24; SiS_Pr->PanelVRE  =    3;
+			    SiS_Pr->PanelVCLKIdx300 = VCLK28;
+			    SiS_Pr->PanelVCLKIdx315 = VCLK28;
+			    break;
+     case Panel_640x480:    SiS_Pr->PanelXRes =  640; SiS_Pr->PanelYRes =  480;
+     			    			      SiS_Pr->PanelVRE  =    3;
+			    SiS_Pr->PanelVCLKIdx300 = VCLK28;
+			    SiS_Pr->PanelVCLKIdx315 = VCLK28;
+			    break;
+     case Panel_800x600:    SiS_Pr->PanelXRes =  800; SiS_Pr->PanelYRes =  600;
+     			    SiS_Pr->PanelHT   = 1056; SiS_Pr->PanelVT   =  628;
+			    SiS_Pr->PanelHRS  =   40; SiS_Pr->PanelHRE  =  128;
+			    SiS_Pr->PanelVRS  =    1; SiS_Pr->PanelVRE  =    4;
+			    SiS_Pr->PanelVCLKIdx300 = VCLK40;
+			    SiS_Pr->PanelVCLKIdx315 = VCLK40;
+			    break;
+     case Panel_1024x600:   SiS_Pr->PanelXRes = 1024; SiS_Pr->PanelYRes =  600;
+     			    SiS_Pr->PanelHT   = 1344; SiS_Pr->PanelVT   =  800;
+			    SiS_Pr->PanelHRS  =   24; SiS_Pr->PanelHRE  =  136;
+			    SiS_Pr->PanelVRS  =    2 /* 88 */ ; SiS_Pr->PanelVRE  =    6;
+     			    SiS_Pr->PanelVCLKIdx300 = VCLK65_300;
+			    SiS_Pr->PanelVCLKIdx315 = VCLK65_315;
+     			    break;
+     case Panel_1024x768:   SiS_Pr->PanelXRes = 1024; SiS_Pr->PanelYRes =  768;
+     			    SiS_Pr->PanelHT   = 1344; SiS_Pr->PanelVT   =  806;
+			    SiS_Pr->PanelHRS  =   24; SiS_Pr->PanelHRE  =  136;
+			    SiS_Pr->PanelVRS  =    3; SiS_Pr->PanelVRE  =    6;
+			    if(HwInfo->jChipType < SIS_315H) {
+			       SiS_Pr->PanelHRS = 23;
+			       			      SiS_Pr->PanelVRE  =    5;
+			    }
+			    SiS_Pr->PanelVCLKIdx300 = VCLK65_300;
+			    SiS_Pr->PanelVCLKIdx315 = VCLK65_315;
+			    SiS_GetLCDInfoBIOS(SiS_Pr, HwInfo);
+			    break;
+     case Panel_1152x768:   SiS_Pr->PanelXRes = 1152; SiS_Pr->PanelYRes =  768;
+     			    SiS_Pr->PanelHT   = 1344; SiS_Pr->PanelVT   =  806;
+			    SiS_Pr->PanelHRS  =   24;
+			    SiS_Pr->PanelVRS  =    3; SiS_Pr->PanelVRE  =    6;
+			    if(HwInfo->jChipType < SIS_315H) {
+			       SiS_Pr->PanelHRS = 23;
+			       			      SiS_Pr->PanelVRE  =    5;
+			    }
+     			    SiS_Pr->PanelVCLKIdx300 = VCLK65_300;
+			    SiS_Pr->PanelVCLKIdx315 = VCLK65_315;
+     			    break;
+     case Panel_1152x864:   SiS_Pr->PanelXRes = 1152; SiS_Pr->PanelYRes =  864;
+     			    break;
+     case Panel_1280x720:   SiS_Pr->PanelXRes = 1280; SiS_Pr->PanelYRes =  720;
+     			    SiS_Pr->PanelHT   = 1650; SiS_Pr->PanelVT   =  750;
+			    SiS_Pr->PanelHRS  =  110; SiS_Pr->PanelHRE  =   40;
+			    SiS_Pr->PanelVRS  =    5; SiS_Pr->PanelVRE  =    5;
+			    SiS_Pr->PanelVCLKIdx315 = VCLK_1280x720;
+			    /* Data above for TMDS (projector); get from BIOS for LVDS */
+			    SiS_GetLCDInfoBIOS(SiS_Pr, HwInfo);
+			    break;
+     case Panel_1280x768:   SiS_Pr->PanelXRes = 1280; SiS_Pr->PanelYRes =  768;
+     			    SiS_Pr->PanelHT   = 1688; SiS_Pr->PanelVT   =  802;
+			    SiS_Pr->PanelHRS  =   48; SiS_Pr->PanelHRS  =  112;
+			    SiS_Pr->PanelVRS  =    3; SiS_Pr->PanelVRE  =    6;
+			    SiS_Pr->PanelVCLKIdx300 = VCLK81_300;
+			    SiS_Pr->PanelVCLKIdx315 = VCLK81_315;
+			    break;
+     case Panel_1280x768_2: SiS_Pr->PanelXRes = 1280; SiS_Pr->PanelYRes =  768;
+     			    SiS_Pr->PanelHT   = 1408; SiS_Pr->PanelVT   =  806;
+			    SiS_Pr->PanelHRS  =   16; SiS_Pr->PanelHRE  =   64;
+			    SiS_Pr->PanelVRS  =    3; SiS_Pr->PanelVRE  =    6;
+			    SiS_Pr->PanelVCLKIdx315 = VCLK_1280x768_2;
+			    SiS_GetLCDInfoBIOS(SiS_Pr, HwInfo);
+			    break;
+     case Panel_1280x768_3: SiS_Pr->PanelXRes = 1280; SiS_Pr->PanelYRes =  768;
+     			    SiS_Pr->PanelHT   = 1664; SiS_Pr->PanelVT   =  798;
+			    SiS_Pr->PanelHRS   =  64; SiS_Pr->PanelHRE  =  128;
+			    SiS_Pr->PanelVRS   =   3; SiS_Pr->PanelVRE  =    7;
+			    SiS_Pr->PanelVCLKIdx315 = VCLK_1280x768_3;
+			    SiS_GetLCDInfoBIOS(SiS_Pr, HwInfo);
+			    break;
+     case Panel_1280x800:   SiS_Pr->PanelXRes = 1280; SiS_Pr->PanelYRes =  800;
+     			    SiS_Pr->PanelHT   = 1656; SiS_Pr->PanelVT   =  841;  /* 1408, 816 */
+			    SiS_Pr->PanelHRS   =  32; SiS_Pr->PanelHRE  =  312;  /*   16,  64 */
+			    SiS_Pr->PanelVRS   =  16; SiS_Pr->PanelVRE  =    8;  /*    4,   3 */
+			    SiS_Pr->PanelVCLKIdx315 = VCLK83_315;
+			    SiS_GetLCDInfoBIOS(SiS_Pr, HwInfo);
+			    break;
+     case Panel_1280x960:   SiS_Pr->PanelXRes = 1280; SiS_Pr->PanelYRes =  960;
+     			    SiS_Pr->PanelHT   = 1800; SiS_Pr->PanelVT   = 1000;
+			    SiS_Pr->PanelVCLKIdx300 = VCLK108_3_300;
+			    SiS_Pr->PanelVCLKIdx315 = VCLK108_3_315;
+		 	    if(resinfo == SIS_RI_1280x1024) {
+			       SiS_Pr->PanelVCLKIdx300 = VCLK100_300;
+			       SiS_Pr->PanelVCLKIdx315 = VCLK100_315;
+			    }
+			    break;
+     case Panel_1280x1024:  SiS_Pr->PanelXRes = 1280; SiS_Pr->PanelYRes = 1024;
+     			    SiS_Pr->PanelHT   = 1688; SiS_Pr->PanelVT   = 1066;
+			    SiS_Pr->PanelHRS  =   48; SiS_Pr->PanelHRE  =  112;
+			    SiS_Pr->PanelVRS  =    1; SiS_Pr->PanelVRE  =    3;
+			    SiS_Pr->PanelVCLKIdx300 = VCLK108_3_300;
+			    SiS_Pr->PanelVCLKIdx315 = VCLK108_2_315;
+			    SiS_GetLCDInfoBIOS(SiS_Pr, HwInfo);
+			    break;
+     case Panel_1400x1050:  SiS_Pr->PanelXRes = 1400; SiS_Pr->PanelYRes = 1050;
+     			    SiS_Pr->PanelHT   = 1688; SiS_Pr->PanelVT   = 1066;
+			    SiS_Pr->PanelHRS  =   48; SiS_Pr->PanelHRE  =  112; /* HRE OK for LVDS, not for LCDA */
+			    SiS_Pr->PanelVRS  =    1; SiS_Pr->PanelVRE  =    3;
+			    SiS_Pr->PanelVCLKIdx315 = VCLK108_2_315;
+			    SiS_GetLCDInfoBIOS(SiS_Pr, HwInfo);
+			    break;
+     case Panel_1600x1200:  SiS_Pr->PanelXRes = 1600; SiS_Pr->PanelYRes = 1200;
+     			    SiS_Pr->PanelHT   = 2160; SiS_Pr->PanelVT   = 1250;
+			    SiS_Pr->PanelHRS  =   64; SiS_Pr->PanelHRE  =  192;
+			    SiS_Pr->PanelVRS  =    1; SiS_Pr->PanelVRE  =    3;
+			    SiS_Pr->PanelVCLKIdx315 = VCLK162_315;
+			    SiS_GetLCDInfoBIOS(SiS_Pr, HwInfo);
+			    break;
+     case Panel_1680x1050:  SiS_Pr->PanelXRes = 1680; SiS_Pr->PanelYRes = 1050;
+     			    SiS_Pr->PanelHT   = 1900; SiS_Pr->PanelVT   = 1066;
+			    SiS_Pr->PanelHRS  =   26; SiS_Pr->PanelHRE  =   76;
+			    SiS_Pr->PanelVRS  =    3; SiS_Pr->PanelVRE  =    6;
+			    SiS_Pr->PanelVCLKIdx315 = VCLK121_315;
+			    SiS_GetLCDInfoBIOS(SiS_Pr, HwInfo);
+			    break;
+     case Panel_Custom:     SiS_Pr->PanelXRes = SiS_Pr->CP_MaxX;
+    			    SiS_Pr->PanelYRes = SiS_Pr->CP_MaxY;
+			    SiS_Pr->PanelHT   = SiS_Pr->CHTotal;
+			    SiS_Pr->PanelVT   = SiS_Pr->CVTotal;
+			    if(SiS_Pr->CP_PreferredIndex != -1) {
+			       SiS_Pr->PanelXRes = SiS_Pr->CP_HDisplay[SiS_Pr->CP_PreferredIndex];
+    			       SiS_Pr->PanelYRes = SiS_Pr->CP_VDisplay[SiS_Pr->CP_PreferredIndex];
+			       SiS_Pr->PanelHT   = SiS_Pr->CP_HTotal[SiS_Pr->CP_PreferredIndex];
+			       SiS_Pr->PanelVT   = SiS_Pr->CP_VTotal[SiS_Pr->CP_PreferredIndex];
+			       SiS_Pr->PanelHRS  = SiS_Pr->CP_HSyncStart[SiS_Pr->CP_PreferredIndex];
+			       SiS_Pr->PanelHRE  = SiS_Pr->CP_HSyncEnd[SiS_Pr->CP_PreferredIndex];
+			       SiS_Pr->PanelVRS  = SiS_Pr->CP_VSyncStart[SiS_Pr->CP_PreferredIndex];
+			       SiS_Pr->PanelVRE  = SiS_Pr->CP_VSyncEnd[SiS_Pr->CP_PreferredIndex];
+			       SiS_Pr->PanelHRS -= SiS_Pr->PanelXRes;
+			       SiS_Pr->PanelHRE -= SiS_Pr->PanelHRS;
+			       SiS_Pr->PanelVRS -= SiS_Pr->PanelYRes;
+			       SiS_Pr->PanelVRE -= SiS_Pr->PanelVRS;
+			    }
+			    break;
+     case Panel_Barco1366:  SiS_Pr->PanelXRes = 1360; SiS_Pr->PanelYRes = 1024;
+     			    SiS_Pr->PanelHT   = 1688; SiS_Pr->PanelVT   = 1066;
+     			    break;
+     case Panel_848x480:    SiS_Pr->PanelXRes =  848; SiS_Pr->PanelYRes =  480;
+     			    SiS_Pr->PanelHT   = 1088; SiS_Pr->PanelVT   =  525;
+     			    break;
+     default:		    SiS_Pr->PanelXRes = 1024; SiS_Pr->PanelYRes =  768;
+     			    SiS_Pr->PanelHT   = 1344; SiS_Pr->PanelVT   =  806;
+			    break;
   }
 
   temp = SiS_GetReg(SiS_Pr->SiS_P3d4,0x37);
-  if(HwInfo->jChipType < SIS_661) {
-     temp &= ~0xe;
-  } else {
+  SiS_Pr->SiS_LCDInfo = temp & ~0x000e;
+
+  if(!(SiS_Pr->UsePanelScaler))        SiS_Pr->SiS_LCDInfo &= ~DontExpandLCD;
+  else if(SiS_Pr->UsePanelScaler == 1) SiS_Pr->SiS_LCDInfo |= DontExpandLCD;
+
 #ifdef SIS315H
-     if(!(temp & 0x10)) {
-        if(temp & 0x08) temp |= LCDPass11;
+  if(HwInfo->jChipType >= SIS_661) {
+     if(SiS_Pr->SiS_LCDInfo & DontExpandLCD) {
+        if(temp & 0x08) SiS_Pr->SiS_LCDInfo |= LCDPass11;
      }
-     temp &= ~0xe;
      if(SiS_Pr->SiS_VBType & (VB_SIS302LV | VB_SIS302ELV)) {
-        myptr = GetLCDStructPtr661(SiS_Pr, HwInfo);
-        if(myptr) {
-           if(myptr[2] & 0x01) temp |= LCDDualLink;
-        }
+        if(SiS_Pr->SiS_ROMNew) {
+	   if(temp & 0x02) SiS_Pr->SiS_LCDInfo |= LCDDualLink;
+	} else if((myptr = GetLCDStructPtr661(SiS_Pr, HwInfo))) {
+           if(myptr[2] & 0x01) SiS_Pr->SiS_LCDInfo |= LCDDualLink;
+	}
+     }
+  } else if(HwInfo->jChipType >= SIS_315H) {
+     if(SiS_Pr->SiS_LCDInfo & DontExpandLCD) {
+        if(SiS_GetReg(SiS_Pr->SiS_P3d4,0x39) & 0x01) SiS_Pr->SiS_LCDInfo |= LCDPass11;
      }
+     if((SiS_Pr->SiS_ROMNew) && (!(SiS_Pr->PanelSelfDetected))) {
+        SiS_Pr->SiS_LCDInfo &= ~(LCDRGB18Bit);
+	temp = SiS_GetReg(SiS_Pr->SiS_P3d4,0x35);
+        if(temp & 0x01) SiS_Pr->SiS_LCDInfo |= LCDRGB18Bit;
+	if(SiS_Pr->SiS_VBType & (VB_SIS302LV | VB_SIS302ELV)) {
+	   if(temp & 0x02) SiS_Pr->SiS_LCDInfo |= LCDDualLink;
+	}
+     }
+  }
 #endif
+
+  if(SiS_Pr->SiS_IF_DEF_LVDS == 1) {
+     /* Always center screen on LVDS (if scaling is disabled) */
+     SiS_Pr->SiS_LCDInfo &= ~LCDPass11;
+  } else if(SiS_Pr->SiS_VBType & VB_SISVB) {
+     if(SiS_Pr->SiS_VBType & VB_SIS301LV302LV) {
+        /* Always center screen on SiS LVDS (if scaling is disabled) */
+        SiS_Pr->SiS_LCDInfo &= ~LCDPass11;
+     } else {
+        /* By default, pass 1:1 on SiS TMDS (if scaling is disabled) */
+        SiS_Pr->SiS_LCDInfo |= LCDPass11;
+        if(SiS_Pr->CenterScreen == 1) SiS_Pr->SiS_LCDInfo &= ~LCDPass11;
+     }
   }
-  SiS_Pr->SiS_LCDInfo = temp;
 
   if(SiS_Pr->SiS_IF_DEF_LVDS == 1) {
      if(SiS_Pr->SiS_CustomT == CUT_PANEL848) {
-        SiS_Pr->SiS_LCDInfo = 0x80 | 0x40 | 0x20;   /* neg h/v sync, RGB24 */
+        SiS_Pr->SiS_LCDInfo = 0x80 | 0x40 | 0x20;   /* neg h/v sync, RGB24(D0 = 0) */
      }
   }
 
-  if(!(SiS_Pr->UsePanelScaler))        SiS_Pr->SiS_LCDInfo &= ~DontExpandLCD;
-  else if(SiS_Pr->UsePanelScaler == 1) SiS_Pr->SiS_LCDInfo |= DontExpandLCD;
-
   if(SiS_Pr->SiS_VBType & VB_SISVB) {
      if(SiS_Pr->SiS_VBInfo & (SetCRT2ToLCD | SetCRT2ToLCDA)) {
-        if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_PanelCustom) {
-	   /* For non-standard LCD resolution, we let the panel scale */
-           SiS_Pr->SiS_LCDInfo |= DontExpandLCD;
-        } else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1280x1024) {
-	   if(ModeNo == 0x7c || ModeNo == 0x7d || ModeNo == 0x7e) {
-	      /* We do not scale to 1280x960 (B/C bridges only) */
-              SiS_Pr->SiS_LCDInfo |= DontExpandLCD;
-	   }
-	   if(((HwInfo->jChipType >= SIS_315H) && (ModeNo == 0x23 || ModeNo == 0x24 || ModeNo == 0x25)) ||
-	      ((HwInfo->jChipType < SIS_315H)  && (ModeNo == 0x55 || ModeNo == 0x5a || ModeNo == 0x5b))) {
-	      /* We do not scale to 1280x768 (B/C bridges only) */
-              SiS_Pr->SiS_LCDInfo |= DontExpandLCD;
-	   }
-	   if(SiS_Pr->SiS_VBType & VB_SIS301LV302LV) {
-	      /* No non-scaling data available for LV bridges */
-	      SiS_Pr->SiS_LCDInfo &= ~DontExpandLCD;
-	   }
-        } else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1280x768) {
-           /* No idea about the timing and zoom factors */
-           SiS_Pr->SiS_LCDInfo |= DontExpandLCD;
-        } else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1400x1050) {
-	   if(ModeNo == 0x3a || ModeNo == 0x4d || ModeNo == 0x65) {
-	      /* We do not scale to 1280x1024 (all bridges) */
-	      SiS_Pr->SiS_LCDInfo |= DontExpandLCD;
-	   }
-	} else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1600x1200) {
-	   if(SiS_Pr->SiS_VBType & VB_SIS301B302B) {
-	      /* No idea about the timing and zoom factors (C bridge only) */
-	      SiS_Pr->SiS_LCDInfo |= DontExpandLCD;
-	   }
-	}
-	if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCD) {
-	   if(SiS_Pr->SiS_CustomT == CUT_CLEVO1024) {
-              if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1024x768) {
-	         SiS_Pr->SiS_LCDInfo &= ~DontExpandLCD;
-	      }
-	   }
+        if(modeflag & NoSupportLCDScale) {
+	   /* No scaling for this mode on any panel */
+	   SiS_Pr->SiS_LCDInfo |= DontExpandLCD;
+	}
+        switch(SiS_Pr->SiS_LCDResInfo) {
+        case Panel_Custom:
+		/* For non-standard LCD resolution, we let the panel scale */
+           	SiS_Pr->SiS_LCDInfo |= DontExpandLCD;
+		break;
+	case Panel_1280x720:
+	      	if(SiS_Pr->PanelHT == 1650) {
+		   SiS_Pr->SiS_LCDInfo |= DontExpandLCD;
+		}
+	case Panel_1280x768:	/* TMDS only */
+		/* No idea about the timing and zoom factors */
+           	SiS_Pr->SiS_LCDInfo |= DontExpandLCD;
+		break;
+	case Panel_1280x960:
+	 	SiS_Pr->SiS_LCDInfo &= ~DontExpandLCD;
+		break;
+	case Panel_1280x1024:
+	        if(SiS_Pr->SiS_VBType & VB_SISTMDS) {
+		   if(ModeNo == 0x7c || ModeNo == 0x7d || ModeNo == 0x7e ||
+		      ModeNo == 0x79 || ModeNo == 0x75 || ModeNo == 0x78 ||
+		      ModeNo == 0x14 || ModeNo == 0x15 || ModeNo == 0x16) {
+	      	      /* We do not scale to 1280x720/800/960 (B/C bridges only) */
+                      SiS_Pr->SiS_LCDInfo |= DontExpandLCD;
+	           }
+	           if(((HwInfo->jChipType >= SIS_315H) &&
+		       (ModeNo == 0x23 || ModeNo == 0x24 || ModeNo == 0x25)) ||
+	              ((HwInfo->jChipType < SIS_315H)  &&
+		       (ModeNo == 0x55 || ModeNo == 0x5a || ModeNo == 0x5b))) {
+	              /* We do not scale to 1280x768 (B/C bridges only) */
+                      SiS_Pr->SiS_LCDInfo |= DontExpandLCD;
+	           }
+		}
+		break;
+	case Panel_1400x1050:
+	 	if(SiS_Pr->SiS_VBType & VB_SISTMDS) {
+	  	   if(ModeNo == 0x7c || ModeNo == 0x7d || ModeNo == 0x7e ||
+		      ModeNo == 0x79 || ModeNo == 0x75 || ModeNo == 0x78 ||
+		      ModeNo == 0x14 || ModeNo == 0x15 || ModeNo == 0x16 ||
+		      ModeNo == 0x23 || ModeNo == 0x24 || ModeNo == 0x25) {
+	      	      /* Do not scale to 1280x720/768/800/960 (B/C bridges only) */
+                      SiS_Pr->SiS_LCDInfo |= DontExpandLCD;
+	           }
+		}
+		if(SiS_Pr->SiS_VBType & VB_SIS301LV302LV) {
+		   if(ModeNo == 0x79 || ModeNo == 0x75 || ModeNo == 0x78) {
+		      if(SiS_Pr->UsePanelScaler == -1) {
+		         /* Do not scale to 1280x720 by default (LVDS bridges) */
+	      	         SiS_Pr->SiS_LCDInfo |= DontExpandLCD;
+		      }
+		   }
+		}
+		if(ModeNo == 0x3a || ModeNo == 0x4d || ModeNo == 0x65) {
+	      	   /* Do not scale to 1280x1024 (all bridges) */
+	      	   SiS_Pr->SiS_LCDInfo |= DontExpandLCD;
+	   	}
+		break;
+	case Panel_1600x1200:
+		if(SiS_Pr->SiS_VBType & VB_SISTMDS) {
+	      	   /* No idea about the timing and zoom factors (C bridge only) */
+	      	   SiS_Pr->SiS_LCDInfo |= DontExpandLCD;
+	   	}
+		break;
 	}
      }
   }
 
-  if(HwInfo->jChipType >= SIS_315H) {
-#ifdef SIS315H
-     if(HwInfo->jChipType < SIS_661) {
-        if(SiS_GetReg(SiS_Pr->SiS_P3d4,0x39) & 0x01) {
-           SiS_Pr->SiS_LCDInfo &= (~DontExpandLCD);
-	   SiS_Pr->SiS_LCDInfo |= LCDPass11;
-	}
-     }
-#endif
-  } else {
 #ifdef SIS300
+  if(HwInfo->jChipType < SIS_315H) {
      if(SiS_Pr->SiS_IF_DEF_LVDS == 1) {
-        if((ROMAddr) && SiS_Pr->SiS_UseROM) {
+        if(SiS_Pr->SiS_UseROM) {
 	   if((ROMAddr[0x233] == 0x12) && (ROMAddr[0x234] == 0x34)) {
               if(!(ROMAddr[0x235] & 0x02)) {
 	         SiS_Pr->SiS_LCDInfo &= (~DontExpandLCD);
@@ -1685,34 +1889,63 @@
            SiS_Pr->SiS_LCDInfo &= (~DontExpandLCD);
 	}
      }
+  }
 #endif
+
+  /* Special cases */
+  if(SiS_Pr->SiS_IF_DEF_TRUMPION) {
+     SiS_Pr->SiS_LCDInfo |= (DontExpandLCD | LCDPass11);
+  }
+
+  if(SiS_Pr->SiS_LCDResInfo == Panel_640x480) {
+     SiS_Pr->SiS_LCDInfo |= LCDPass11;
+  }
+
+  if(SiS_Pr->UseCustomMode) {
+     SiS_Pr->SiS_LCDInfo |= (DontExpandLCD | LCDPass11);
+  }
+
+  /* (In)validate LCDPass11 flag */
+  if(!(SiS_Pr->SiS_LCDInfo & DontExpandLCD)) {
+     SiS_Pr->SiS_LCDInfo &= ~LCDPass11;
   }
 
-  /* Trumpion: Assume non-expanding */
-  if(SiS_Pr->SiS_IF_DEF_TRUMPION != 0) {
-     SiS_Pr->SiS_LCDInfo &= (~DontExpandLCD);
+  /* Special cases */
+  if( (SiS_Pr->SiS_IF_DEF_FSTN)              ||
+      (SiS_Pr->SiS_IF_DEF_DSTN)              ||
+      (SiS_Pr->SiS_CustomT == CUT_BARCO1366) ||
+      (SiS_Pr->SiS_CustomT == CUT_BARCO1024) ||
+      (SiS_Pr->SiS_CustomT == CUT_PANEL848) ) {
+     SiS_Pr->PanelHRS = 999;
+     SiS_Pr->PanelHRE = 999;
   }
 
-  if(SiS_Pr->SiS_LCDInfo & DontExpandLCD) {
-     SiS_Pr->SiS_LCDInfo &= (~LCDPass11);
+  if( (SiS_Pr->SiS_CustomT == CUT_BARCO1366) ||
+      (SiS_Pr->SiS_CustomT == CUT_BARCO1024) ||
+      (SiS_Pr->SiS_CustomT == CUT_PANEL848) ) {
+     SiS_Pr->PanelVRS = 999;
+     SiS_Pr->PanelVRE = 999;
   }
 
 #ifdef SIS315H
   if((HwInfo->jChipType >= SIS_315H) && (HwInfo->jChipType < SIS_661)) {
-     if(SiS_Pr->SiS_VBType & (VB_SIS302LV | VB_SIS302ELV)) {
-	/* Enable 302LV/302ELV dual link mode.
-	 * For 661, this is done above.
-	 */
-        if((SiS_Pr->SiS_CustomT == CUT_CLEVO1024) &&
-	   (SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1024x768)) {
-	   /* (Sets this in SenseLCD; new paneltypes) */
-	   SiS_Pr->SiS_LCDInfo |= LCDDualLink;
-	}
-        if((SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1280x1024) ||
-	   (SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1400x1050) ||
-           (SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1600x1200)) {
-	   SiS_Pr->SiS_LCDInfo |= LCDDualLink;
-	}
+     if(!(SiS_Pr->SiS_ROMNew)) {
+        if(SiS_Pr->SiS_VBType & (VB_SIS302LV | VB_SIS302ELV)) {
+	   /* Enable 302LV/302ELV dual link mode.
+	    * For 661, this is done above.
+	    */
+           if((SiS_Pr->SiS_CustomT == CUT_CLEVO1024) &&
+	      (SiS_Pr->SiS_LCDResInfo == Panel_1024x768)) {
+	      /* (Sets this in SenseLCD; new paneltypes) */
+	      SiS_Pr->SiS_LCDInfo |= LCDDualLink;
+	   }
+           if((SiS_Pr->SiS_LCDResInfo == Panel_1280x1024) ||
+	      (SiS_Pr->SiS_LCDResInfo == Panel_1400x1050) ||
+              (SiS_Pr->SiS_LCDResInfo == Panel_1600x1200) ||
+	      (SiS_Pr->SiS_LCDResInfo == Panel_1680x1050)) {
+	      SiS_Pr->SiS_LCDInfo |= LCDDualLink;
+	   }
+        }
      }
   }
 #endif
@@ -1720,37 +1953,37 @@
   if(!((HwInfo->jChipType < SIS_315H) && (SiS_Pr->SiS_SetFlag & SetDOSMode))) {
 
      if(SiS_Pr->SiS_IF_DEF_LVDS == 1) {
-        if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1024x600) {
-	   if(ModeNo > 0x13) {
-	      if(!(SiS_Pr->SiS_LCDInfo & DontExpandLCD)) {
-                 if((resinfo == SIS_RI_800x600) || (resinfo == SIS_RI_400x300)) {
-                    SiS_Pr->SiS_SetFlag |= EnableLVDSDDA;
+	if(SiS_Pr->SiS_IF_DEF_TRUMPION == 0) {
+	   if(ModeNo == 0x12) {
+	      if(SiS_Pr->SiS_LCDInfo & LCDPass11) {
+	         SiS_Pr->SiS_SetFlag |= EnableLVDSDDA;
+	      }
+	   } else if(ModeNo > 0x13) {
+	      if(SiS_Pr->SiS_LCDResInfo == Panel_1024x600) {
+	         if(!(SiS_Pr->SiS_LCDInfo & DontExpandLCD)) {
+	            if((resinfo == SIS_RI_800x600) || (resinfo == SIS_RI_400x300)) {
+                       SiS_Pr->SiS_SetFlag |= EnableLVDSDDA;
+		    }
 		 }
-              }
-           }
-        }
-	if(ModeNo == 0x12) {
-	   if(SiS_Pr->SiS_LCDInfo & LCDPass11) {
-	      SiS_Pr->SiS_SetFlag |= EnableLVDSDDA;
+	      }
 	   }
 	}
      }
 
      if(modeflag & HalfDCLK) {
-        if(SiS_Pr->SiS_IF_DEF_TRUMPION == 0) {
-           if(!(SiS_Pr->SiS_LCDInfo & DontExpandLCD)) {
-	      if(!(((SiS_Pr->SiS_IF_DEF_LVDS == 1) || (HwInfo->jChipType < SIS_315H)) &&
-	                                      (SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel640x480))) {
-                 if(ModeNo > 0x13) {
-                    if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1024x768) {
-                       if(resinfo == SIS_RI_512x384) SiS_Pr->SiS_SetFlag |= EnableLVDSDDA;
-                    } else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel800x600) {
-                       if(resinfo == SIS_RI_400x300) SiS_Pr->SiS_SetFlag |= EnableLVDSDDA;
-                    }
-                 }
-	      } else SiS_Pr->SiS_SetFlag |= EnableLVDSDDA;
-           } else SiS_Pr->SiS_SetFlag |= EnableLVDSDDA;
-        } else SiS_Pr->SiS_SetFlag |= EnableLVDSDDA;
+        if(SiS_Pr->SiS_IF_DEF_TRUMPION == 1) {
+	   SiS_Pr->SiS_SetFlag |= EnableLVDSDDA;
+        } else if(SiS_Pr->SiS_LCDInfo & DontExpandLCD) {
+	   SiS_Pr->SiS_SetFlag |= EnableLVDSDDA;
+	} else if(SiS_Pr->SiS_LCDResInfo == Panel_640x480) {
+	   SiS_Pr->SiS_SetFlag |= EnableLVDSDDA;
+	} else if(ModeNo > 0x13) {
+           if(SiS_Pr->SiS_LCDResInfo == Panel_1024x768) {
+              if(resinfo == SIS_RI_512x384) SiS_Pr->SiS_SetFlag |= EnableLVDSDDA;
+           } else if(SiS_Pr->SiS_LCDResInfo == Panel_800x600) {
+              if(resinfo == SIS_RI_400x300) SiS_Pr->SiS_SetFlag |= EnableLVDSDDA;
+           }
+	}
      }
 
   }
@@ -1763,14 +1996,6 @@
      SiS_Pr->SiS_SetFlag |= LCDVESATiming;
   }
 
-  SiS_Pr->SiS_LCDInfo661 = 0;
-  if(SiS_Pr->SiS_SetFlag & LCDVESATiming) SiS_Pr->SiS_LCDInfo661 |= 0x0001;
-  if(SiS_Pr->SiS_SetFlag & EnableLVDSDDA) SiS_Pr->SiS_LCDInfo661 |= 0x0002;
-  if(SiS_Pr->SiS_LCDInfo & LCDPass11)     SiS_Pr->SiS_LCDInfo661 |= 0x0008;
-  if(SiS_Pr->SiS_LCDInfo & DontExpandLCD) SiS_Pr->SiS_LCDInfo661 |= 0x0010;
-  SiS_Pr->SiS_LCDInfo661 |= (SiS_Pr->SiS_LCDInfo & 0xe0);
-  if(SiS_Pr->SiS_LCDInfo & LCDDualLink)   SiS_Pr->SiS_LCDInfo661 |= 0x0100;
-
 #ifdef LINUX_KERNEL
 #ifdef TWDEBUG
   printk(KERN_DEBUG "sisfb: (LCDInfo=0x%04x LCDResInfo=0x%02x LCDTypeInfo=0x%02x)\n",
@@ -1792,54 +2017,21 @@
 SiS_GetVCLK2Ptr(SiS_Private *SiS_Pr, USHORT ModeNo, USHORT ModeIdIndex,
                 USHORT RefreshRateTableIndex, PSIS_HW_INFO HwInfo)
 {
-  USHORT tempbx;
-  const USHORT LCDXlat0VCLK[4]    = {VCLK40,       VCLK40,       VCLK40,       VCLK40};
-  const USHORT LVDSXlat1VCLK[4]   = {VCLK40,       VCLK40,       VCLK40,       VCLK40};
-  const USHORT LVDSXlat4VCLK[4]   = {VCLK28,       VCLK28,       VCLK28,       VCLK28};
-#ifdef SIS300
-  const USHORT LCDXlat1VCLK300[4] = {VCLK65_300,   VCLK65_300,   VCLK65_300,   VCLK65_300};
-  const USHORT LCDXlat2VCLK300[4] = {VCLK108_2_300,VCLK108_2_300,VCLK108_2_300,VCLK108_2_300};
-  const USHORT LVDSXlat2VCLK300[4]= {VCLK65_300,   VCLK65_300,   VCLK65_300,   VCLK65_300};
-  const USHORT LVDSXlat3VCLK300[4]= {VCLK65_300,   VCLK65_300,   VCLK65_300,   VCLK65_300};
-#endif
-#ifdef SIS315H
-  const USHORT LCDXlat1VCLK310[4] = {VCLK65_315,   VCLK65_315,   VCLK65_315,   VCLK65_315};
-  const USHORT LCDXlat2VCLK310[4] = {VCLK108_2_315,VCLK108_2_315,VCLK108_2_315,VCLK108_2_315};
-  const USHORT LVDSXlat2VCLK310[4]= {VCLK65_315,   VCLK65_315,   VCLK65_315,   VCLK65_315};
-  const USHORT LVDSXlat3VCLK310[4]= {VCLK108_2_315,VCLK108_2_315,VCLK108_2_315,VCLK108_2_315};
-#endif
-  USHORT CRT2Index,VCLKIndex=0;
-  USHORT modeflag,resinfo;
-  const UCHAR  *CHTVVCLKPtr = NULL;
-  const USHORT *LCDXlatVCLK1 = NULL;
-  const USHORT *LCDXlatVCLK2 = NULL;
-  const USHORT *LVDSXlatVCLK2 = NULL;
-  const USHORT *LVDSXlatVCLK3 = NULL;
-
-  if(HwInfo->jChipType >= SIS_315H) {
-#ifdef SIS315H
-     LCDXlatVCLK1 = LCDXlat1VCLK310;
-     LCDXlatVCLK2 = LCDXlat2VCLK310;
-     LVDSXlatVCLK2 = LVDSXlat2VCLK310;
-     LVDSXlatVCLK3 = LVDSXlat3VCLK310;
-#endif
-  } else {
-#ifdef SIS300
-     LCDXlatVCLK1 = LCDXlat1VCLK300;
-     LCDXlatVCLK2 = LCDXlat2VCLK300;
-     LVDSXlatVCLK2 = LVDSXlat2VCLK300;
-     LVDSXlatVCLK3 = LVDSXlat3VCLK300;
-#endif
-  }
+  USHORT CRT2Index,VCLKIndex=0,VCLKIndexGEN=0;
+  USHORT modeflag,resinfo,tempbx;
+  const UCHAR *CHTVVCLKPtr = NULL;
 
   if(ModeNo <= 0x13) {
      modeflag = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_ModeFlag;
      resinfo = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_ResInfo;
      CRT2Index = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_CRT2CRTC;
+     VCLKIndexGEN = (SiS_GetRegByte((SiS_Pr->SiS_P3ca+0x02)) >> 2) & 0x03;
   } else {
      modeflag = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag;
      resinfo = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_RESINFO;
      CRT2Index = SiS_Pr->SiS_RefIndex[RefreshRateTableIndex].Ext_CRT2CRTC;
+     VCLKIndexGEN = SiS_Pr->SiS_RefIndex[RefreshRateTableIndex].Ext_CRTVCLK;
+     if(HwInfo->jChipType < SIS_315H) VCLKIndexGEN &= 0x3f;
   }
 
   if(SiS_Pr->SiS_VBType & VB_SISVB) {    /* 30x/B/LV */
@@ -1847,50 +2039,34 @@
      if(SiS_Pr->SiS_SetFlag & ProgrammingCRT2) {
 
         CRT2Index >>= 6;
-        if(SiS_Pr->SiS_VBInfo & (SetCRT2ToLCD | SetCRT2ToLCDA)) {      /*  LCD */
+        if(SiS_Pr->SiS_VBInfo & (SetCRT2ToLCD | SetCRT2ToLCDA)) {      	/*  LCD */
 
            if(HwInfo->jChipType < SIS_315H) {
-	      if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel800x600) {
-	         VCLKIndex = LCDXlat0VCLK[CRT2Index];
-	      } else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1024x768) {
-	    	 VCLKIndex = LCDXlatVCLK1[CRT2Index];
-	      } else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1024x600) {
-	    	 VCLKIndex = LCDXlatVCLK1[CRT2Index];
-	      } else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1152x768) {
-	    	 VCLKIndex = LCDXlatVCLK1[CRT2Index];
-	      } else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1280x768) {
-	         VCLKIndex = VCLK81_300;	/* guessed */
-	      } else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1280x960) {
-		 VCLKIndex = VCLK108_3_300;
-		 if(resinfo == SIS_RI_1280x1024) VCLKIndex = VCLK100_300;
-	      } else {
-	    	 VCLKIndex = LCDXlatVCLK2[CRT2Index];
-	      }
+	      VCLKIndex = SiS_Pr->PanelVCLKIdx300;
 	   } else {
-	      if( (SiS_Pr->SiS_VBType & VB_SIS301LV302LV) ||
-	          (!(SiS_Pr->SiS_LCDInfo & DontExpandLCD)) ) {
-      	         if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1280x1024) {
-		    VCLKIndex = VCLK108_2_315;
-		 } else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1280x768) {
-		    VCLKIndex = VCLK81_315;  	/* guessed */
-		 } else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1400x1050) {
-		    VCLKIndex = VCLK108_2_315;
-		 } else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1600x1200) {
-		    VCLKIndex = VCLK162_315;
-		 } else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1280x960) {
-		    VCLKIndex = VCLK108_3_315;
-		    if(resinfo == SIS_RI_1280x1024) VCLKIndex = VCLK100_315;
-		 } else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1024x768) {
-		    VCLKIndex = LCDXlatVCLK1[CRT2Index];
-	         } else {
-		    VCLKIndex = LCDXlatVCLK2[CRT2Index];
-      	         }
-	      } else {
-                 VCLKIndex = (UCHAR)SiS_GetRegByte((USHORT)(SiS_Pr->SiS_P3ca+0x02));  /*  Port 3cch */
-         	 VCLKIndex = ((VCLKIndex >> 2) & 0x03);
-        	 if(ModeNo > 0x13) {
-          	    VCLKIndex = SiS_Pr->SiS_RefIndex[RefreshRateTableIndex].Ext_CRTVCLK;
-        	 }
+	      VCLKIndex = SiS_Pr->PanelVCLKIdx315;
+	      if((SiS_Pr->SiS_LCDInfo & DontExpandLCD) && (SiS_Pr->SiS_LCDInfo & LCDPass11)) {
+	         VCLKIndex = VCLKIndexGEN;
+		 switch(resinfo) {
+		 /* Only those whose IndexGEN doesn't match VBVCLK array: */
+		 case SIS_RI_1280x720: VCLKIndex = VCLK_1280x720;
+		 		       if(SiS_Pr->SiS_LCDResInfo == Panel_1280x720) {
+		                          if(SiS_Pr->PanelHT == 1344) {
+					     VCLKIndex = VCLK_1280x720_2;
+					  }
+				       }
+		 		       break;
+		 case SIS_RI_720x480:  VCLKIndex = VCLK_720x480;  break;
+		 case SIS_RI_720x576:  VCLKIndex = VCLK_720x576;  break;
+		 case SIS_RI_768x576:  VCLKIndex = VCLK_768x576;  break;
+		 case SIS_RI_848x480:  VCLKIndex = VCLK_848x480;  break;
+		 case SIS_RI_856x480:  VCLKIndex = VCLK_856x480;  break;
+		 case SIS_RI_800x480:  VCLKIndex = VCLK_800x480;  break;
+		 case SIS_RI_1024x576: VCLKIndex = VCLK_1024x576; break;
+		 case SIS_RI_1152x864: VCLKIndex = VCLK_1152x864; break;
+		 case SIS_RI_1360x768: VCLKIndex = VCLK_1360x768; break;
+		 }
+
 		 if(ModeNo <= 0x13) {
 		    if(HwInfo->jChipType <= SIS_315PRO) {
 		       if(SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_CRT2CRTC == 1) VCLKIndex = 0x42;
@@ -1906,34 +2082,28 @@
 	      }
 	   }
 
-        } else if(SiS_Pr->SiS_VBInfo & SetCRT2ToTV) {                 /*  TV */
+        } else if(SiS_Pr->SiS_VBInfo & SetCRT2ToTV) {                 	/*  TV */
 
 	   if(SiS_Pr->SiS_VBInfo & SetCRT2ToHiVision) {
-              if(SiS_Pr->SiS_TVMode & TVRPLLDIV2XO) VCLKIndex = HiTVVCLKDIV2;
-     	      else                                  VCLKIndex = HiTVVCLK;
+              if(SiS_Pr->SiS_TVMode & TVRPLLDIV2XO) 		VCLKIndex = HiTVVCLKDIV2;
+     	      else                                  		VCLKIndex = HiTVVCLK;
               if(SiS_Pr->SiS_TVMode & TVSetTVSimuMode) {
-            	 if(modeflag & Charx8Dot) 	    VCLKIndex = HiTVSimuVCLK;
-            	 else 			  	    VCLKIndex = HiTVTextVCLK;
+            	 if(modeflag & Charx8Dot) 	    		VCLKIndex = HiTVSimuVCLK;
+            	 else 			  	    		VCLKIndex = HiTVTextVCLK;
               }
-           } else if(SiS_Pr->SiS_TVMode & TVSetYPbPr750p) VCLKIndex = YPbPr750pVCLK - TVCLKBASE_315;
-	   else if(SiS_Pr->SiS_TVMode & TVSetYPbPr525p)   VCLKIndex = TVVCLKDIV2;
-	   else if(SiS_Pr->SiS_TVMode & TVRPLLDIV2XO)     VCLKIndex = TVVCLKDIV2;
-           else         		            	  VCLKIndex = TVVCLK;
+           } else if(SiS_Pr->SiS_TVMode & TVSetYPbPr750p) 	VCLKIndex = YPbPr750pVCLK;
+	   else if(SiS_Pr->SiS_TVMode & TVSetYPbPr525p)   	VCLKIndex = TVVCLKDIV2;
+	   else if(SiS_Pr->SiS_TVMode & TVRPLLDIV2XO)     	VCLKIndex = TVVCLKDIV2;
+           else         		            	  	VCLKIndex = TVVCLK;
 
-	   if(HwInfo->jChipType < SIS_315H) {
-              VCLKIndex += TVCLKBASE_300;
-  	   } else {
-	      VCLKIndex += TVCLKBASE_315;
-	   }
+	   if(HwInfo->jChipType < SIS_315H) VCLKIndex += TVCLKBASE_300;
+  	   else 	                    VCLKIndex += TVCLKBASE_315;
 
-        } else {         					/* VGA2 */
+        } else {         						/* VGA2 */
 
-           VCLKIndex = (UCHAR)SiS_GetRegByte((USHORT)(SiS_Pr->SiS_P3ca+0x02));
-           VCLKIndex = ((VCLKIndex >> 2) & 0x03);
-           if(ModeNo > 0x13) {
-              VCLKIndex = SiS_Pr->SiS_RefIndex[RefreshRateTableIndex].Ext_CRTVCLK;
-	      if(HwInfo->jChipType < SIS_315H) {
-          	 VCLKIndex &= 0x3f;
+	   VCLKIndex = VCLKIndexGEN;
+	   if(HwInfo->jChipType < SIS_315H) {
+              if(ModeNo > 0x13) {
 		 if( (HwInfo->jChipType == SIS_630) &&
 		     (HwInfo->jChipRevision >= 0x30)) {
 		    if(VCLKIndex == 0x14) VCLKIndex = 0x34;
@@ -1946,12 +2116,9 @@
 
      } else {   /* If not programming CRT2 */
 
-        VCLKIndex = (UCHAR)SiS_GetRegByte((USHORT)(SiS_Pr->SiS_P3ca+0x02));
-        VCLKIndex = ((VCLKIndex >> 2) & 0x03);
-        if(ModeNo > 0x13) {
-           VCLKIndex = SiS_Pr->SiS_RefIndex[RefreshRateTableIndex].Ext_CRTVCLK;
-	   if(HwInfo->jChipType < SIS_315H) {
-              VCLKIndex &= 0x3f;
+        VCLKIndex = VCLKIndexGEN;
+	if(HwInfo->jChipType < SIS_315H) {
+           if(ModeNo > 0x13) {
 	      if( (HwInfo->jChipType != SIS_630) &&
 		  (HwInfo->jChipType != SIS_300) ) {
 		 if(VCLKIndex == 0x1b) VCLKIndex = 0x35;
@@ -1964,7 +2131,7 @@
 
      VCLKIndex = CRT2Index;
 
-     if(SiS_Pr->SiS_SetFlag & ProgrammingCRT2) {  /* programming CRT2 */
+     if(SiS_Pr->SiS_SetFlag & ProgrammingCRT2) {
 
         if( (SiS_Pr->SiS_IF_DEF_CH70xx != 0) && (SiS_Pr->SiS_VBInfo & SetCRT2ToTV) ) {
 
@@ -2000,32 +2167,16 @@
 
         } else if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCD) {
 
-	   VCLKIndex >>= 6;
-     	   if((SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel800x600) ||
-	      (SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel320x480))
-     	      VCLKIndex = LVDSXlat1VCLK[VCLKIndex];
-	   else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel640x480   ||
-	           SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel640x480_2 ||
-		   SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel640x480_3)
-	      VCLKIndex = LVDSXlat4VCLK[VCLKIndex];
-     	   else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1024x768)
-     	      VCLKIndex = LVDSXlatVCLK2[VCLKIndex];
-	   else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1024x600)
-              VCLKIndex = LVDSXlatVCLK2[VCLKIndex];
-	   else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1152x768)
-              VCLKIndex = LVDSXlatVCLK2[VCLKIndex];
-	   else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1280x768)
-	      VCLKIndex = VCLK68_315;
-	   else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1600x1200)
-	      VCLKIndex = VCLK162_315;
-     	   else
-	      VCLKIndex = LVDSXlatVCLK3[VCLKIndex];
-
-	   if(SiS_Pr->SiS_CustomT == CUT_BARCO1366) {
-	      /* Special Timing: Barco iQ Pro R series */
-	      VCLKIndex = 0x44;
+	   if(HwInfo->jChipType < SIS_315H) {
+	      VCLKIndex = SiS_Pr->PanelVCLKIdx300;
+	   } else {
+	      VCLKIndex = SiS_Pr->PanelVCLKIdx315;
 	   }
 
+	   /* Special Timing: Barco iQ Pro R series */
+	   if(SiS_Pr->SiS_CustomT == CUT_BARCO1366) VCLKIndex = 0x44;
+
+	   /* Special Timing: 848x480 parallel lvds */
 	   if(SiS_Pr->SiS_CustomT == CUT_PANEL848) {
 	      if(HwInfo->jChipType < SIS_315H) {
 		 VCLKIndex = VCLK34_300;
@@ -2038,28 +2189,22 @@
 
         } else {
 
-	   VCLKIndex = (UCHAR)SiS_GetRegByte((USHORT)(SiS_Pr->SiS_P3ca+0x02));
-           VCLKIndex = ((VCLKIndex >> 2) & 0x03);
-           if(ModeNo > 0x13) {
-              VCLKIndex = SiS_Pr->SiS_RefIndex[RefreshRateTableIndex].Ext_CRTVCLK;
-	      if(HwInfo->jChipType < SIS_315H) {
-    	 	 VCLKIndex &= 0x3F;
+	   VCLKIndex = VCLKIndexGEN;
+	   if(HwInfo->jChipType < SIS_315H) {
+              if(ModeNo > 0x13) {
+		 if( (HwInfo->jChipType == SIS_630) &&
+                     (HwInfo->jChipRevision >= 0x30) ) {
+		    if(VCLKIndex == 0x14) VCLKIndex = 0x2e;
+	         }
               }
-	      if( (HwInfo->jChipType == SIS_630) &&
-                  (HwInfo->jChipRevision >= 0x30) ) {
-		 if(VCLKIndex == 0x14) VCLKIndex = 0x2e;
-	      }
 	   }
         }
 
      } else {  /* if not programming CRT2 */
 
-        VCLKIndex = (UCHAR)SiS_GetRegByte((USHORT)(SiS_Pr->SiS_P3ca+0x02));
-        VCLKIndex = ((VCLKIndex >> 2) & 0x03);
-        if(ModeNo > 0x13) {
-           VCLKIndex = SiS_Pr->SiS_RefIndex[RefreshRateTableIndex].Ext_CRTVCLK;
-           if(HwInfo->jChipType < SIS_315H) {
-	      VCLKIndex &= 0x3F;
+        VCLKIndex = VCLKIndexGEN;
+	if(HwInfo->jChipType < SIS_315H) {
+           if(ModeNo > 0x13) {
 	      if( (HwInfo->jChipType != SIS_630) &&
 	          (HwInfo->jChipType != SIS_300) ) {
 		 if(VCLKIndex == 0x1b) VCLKIndex = 0x35;
@@ -2094,21 +2239,20 @@
 {
   USHORT i,j,modeflag;
   USHORT tempcl,tempah=0;
-#ifdef SIS300
-  USHORT temp;
+#if defined(SIS300) || defined(SIS315H)
+  USHORT tempbl;
 #endif
 #ifdef SIS315H
-  USHORT tempbl, tempah2, tempbl2;
+  UCHAR  *ROMAddr = HwInfo->pjVirtualRomBase;
+  USHORT tempah2, tempbl2;
 #endif
 
   if(ModeNo <= 0x13) {
      modeflag = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_ModeFlag;
+  } else if(SiS_Pr->UseCustomMode) {
+     modeflag = SiS_Pr->CModeFlag;
   } else {
-     if(SiS_Pr->UseCustomMode) {
-        modeflag = SiS_Pr->CModeFlag;
-     } else {
-    	modeflag = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag;
-     }
+     modeflag = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag;
   }
 
   /* BIOS does not do this (neither 301 nor LVDS) */
@@ -2123,6 +2267,9 @@
   } else {
 
      for(i=0,j=4; i<3; i++,j++) SiS_SetReg(SiS_Pr->SiS_Part1Port,j,0);
+     if(HwInfo->jChipType >= SIS_315H) {
+        SiS_SetRegAND(SiS_Pr->SiS_Part1Port,0x02,0x7F);
+     }
 
      tempcl = SiS_Pr->SiS_ModeType;
 
@@ -2132,14 +2279,14 @@
 
         /* For 301BDH: (with LCD via LVDS) */
         if(SiS_Pr->SiS_VBType & VB_NoLCD) {
-	   temp = SiS_GetReg(SiS_Pr->SiS_P3c4,0x32);
-	   temp &= 0xef;
-	   temp |= 0x02;
+	   tempbl = SiS_GetReg(SiS_Pr->SiS_P3c4,0x32);
+	   tempbl &= 0xef;
+	   tempbl |= 0x02;
 	   if((SiS_Pr->SiS_VBInfo & SetCRT2ToTV) || (SiS_Pr->SiS_VBInfo & SetCRT2ToRAMDAC)) {
-	      temp |= 0x10;
-	      temp &= 0xfd;
+	      tempbl |= 0x10;
+	      tempbl &= 0xfd;
 	   }
-	   SiS_SetReg(SiS_Pr->SiS_P3c4,0x32,temp);
+	   SiS_SetReg(SiS_Pr->SiS_P3c4,0x32,tempbl);
         }
 
         if(ModeNo > 0x13) {
@@ -2226,8 +2373,8 @@
         }
 
         if((HwInfo->jChipType < SIS_315H) && (SiS_Pr->SiS_VBType & VB_SIS301)) {
-	   if((SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1280x1024) ||
-	      (SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1280x960)) {
+	   if((SiS_Pr->SiS_LCDResInfo == Panel_1280x1024) ||
+	      (SiS_Pr->SiS_LCDResInfo == Panel_1280x960)) {
 	      tempah |= 0x80;
 	   }
         } else {
@@ -2254,9 +2401,9 @@
        	   }
         }
 
-	if((SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1280x1024) ||
-	   (SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1280x960)  ||
-	   ((SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_PanelCustom) &&
+	if((SiS_Pr->SiS_LCDResInfo == Panel_1280x1024) ||
+	   (SiS_Pr->SiS_LCDResInfo == Panel_1280x960)  ||
+	   ((SiS_Pr->SiS_LCDResInfo == Panel_Custom) &&
 	    (SiS_Pr->CP_MaxX >= 1280) && (SiS_Pr->CP_MaxY >= 960))) {
 	   tempah |= 0x80;
         }
@@ -2344,10 +2491,11 @@
 	 * in a 650 box (Jake). What is the criteria?
 	 */
 
-	if((IS_SIS740) || (HwInfo->jChipType >= SIS_661)) {
+	if((IS_SIS740) || (HwInfo->jChipType >= SIS_661) || (SiS_Pr->SiS_ROMNew)) {
 	   tempah = 0x30;
 	   tempbl = 0xc0;
-	   if(SiS_Pr->SiS_VBInfo & DisableCRT2Display) {
+	   if((SiS_Pr->SiS_VBInfo & DisableCRT2Display) ||
+	      ((SiS_Pr->SiS_ROMNew) && (!(ROMAddr[0x5b] & 0x04)))) {
 	      tempah = 0x00;
 	      tempbl = 0x00;
 	   }
@@ -2378,23 +2526,23 @@
 
 	if(IS_SIS740) {
 	   tempah = 0x80;
-	   if(SiS_Pr->SiS_VBInfo & DisableCRT2Display) {
-	      tempah = 0x00;
-	   }
+	   if(SiS_Pr->SiS_VBInfo & DisableCRT2Display) tempah = 0x00;
 	   SiS_SetRegANDOR(SiS_Pr->SiS_Part4Port,0x23,0x7f,tempah);
 	} else {
 	   tempah = 0x00;
            tempbl = 0x7f;
            if(!(SiS_Pr->SiS_VBInfo & SetCRT2ToLCDA)) {
               tempbl = 0xff;
-	      if(!(SiS_IsDualEdge(SiS_Pr, HwInfo))) {
-	         tempah = 0x80;
-	      }
+	      if(!(SiS_IsDualEdge(SiS_Pr, HwInfo))) tempah = 0x80;
            }
            SiS_SetRegANDOR(SiS_Pr->SiS_Part4Port,0x23,tempbl,tempah);
 	}
 
-	/* 661: Sets p4 27 and 34 here, done in SetGroup4 here */
+#if 0
+	if(SiS_Pr->SiS_VBType & VB_SIS301C) {
+	   SiS_SetRegOR(SiS_Pr->SiS_Part4Port,0x3a,0xc0);
+	}
+#endif
 
 #endif /* SIS315H */
 
@@ -2423,9 +2571,7 @@
 	   tempbl = 0xfb;
            if(!(SiS_Pr->SiS_VBInfo & SetCRT2ToLCDA)) {
               tempah = 0x00;
-	      if(SiS_IsDualEdge(SiS_Pr, HwInfo)) {
-	         tempbl = 0xff;
-	      }
+	      if(SiS_IsDualEdge(SiS_Pr, HwInfo)) tempbl = 0xff;
            }
 	   SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x13,tempbl,tempah);
 
@@ -2456,14 +2602,8 @@
 USHORT
 SiS_GetResInfo(SiS_Private *SiS_Pr,USHORT ModeNo,USHORT ModeIdIndex)
 {
-  USHORT resindex;
-
-  if(ModeNo <= 0x13)
-     resindex = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_ResInfo;
-  else
-     resindex = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_RESINFO;
-
-  return(resindex);
+  if(ModeNo <= 0x13) return((USHORT)SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_ResInfo);
+  else               return((USHORT)SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_RESINFO);
 }
 
 static void
@@ -2473,8 +2613,12 @@
   USHORT xres,yres,modeflag=0,resindex;
 
   if(SiS_Pr->UseCustomMode) {
-     SiS_Pr->SiS_VGAHDE = SiS_Pr->SiS_HDE = SiS_Pr->CHDisplay;
-     SiS_Pr->SiS_VGAVDE = SiS_Pr->SiS_VDE = SiS_Pr->CVDisplay;
+     xres = SiS_Pr->CHDisplay;
+     if(SiS_Pr->CModeFlag & HalfDCLK) xres *= 2;
+     SiS_Pr->SiS_VGAHDE = SiS_Pr->SiS_HDE = xres;
+     yres = SiS_Pr->CVDisplay;
+     if(SiS_Pr->CModeFlag & DoubleScanMode) yres *= 2;
+     SiS_Pr->SiS_VGAVDE = SiS_Pr->SiS_VDE = yres;
      return;
   }
 
@@ -2489,7 +2633,7 @@
      modeflag = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag;
   }
 
-  if((!SiS_Pr->SiS_IF_DEF_DSTN) && (!SiS_Pr->SiS_IF_DEF_FSTN)) {
+  if(!SiS_Pr->SiS_IF_DEF_DSTN && !SiS_Pr->SiS_IF_DEF_FSTN) {
 
      if((HwInfo->jChipType >= SIS_315H) && (SiS_Pr->SiS_IF_DEF_LVDS == 1)) {
         if((ModeNo != 0x03) && (SiS_Pr->SiS_SetFlag & SetDOSMode)) {
@@ -2500,72 +2644,66 @@
         }
      }
 
-     if(ModeNo > 0x13) {
-  	if(modeflag & HalfDCLK)       xres *= 2;
-  	if(modeflag & DoubleScanMode) yres *= 2;
-     }
+     if(modeflag & HalfDCLK)       xres *= 2;
+     if(modeflag & DoubleScanMode) yres *= 2;
 
   }
 
-  if(SiS_Pr->SiS_VBType & VB_SISVB) {
-        if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCDA) {
+  if((SiS_Pr->SiS_VBType & VB_SISVB) && (!(SiS_Pr->SiS_VBType & VB_NoLCD))) {
+
+#if 0
+        if(SiS_Pr->SiS_VBInfo & (SetCRT2ToLCDA | SetCRT2ToLCD | SetCRT2ToHiVision)) {
            if(xres == 720) xres = 640;
-	} else {
-	   if(SiS_Pr->SiS_VBType & VB_NoLCD) {           /* 301BDH */
-	        if(SiS_Pr->SiS_VBInfo & (SetCRT2ToLCD | SetCRT2ToHiVision)) {
-                   if(xres == 720) xres = 640;
-		}
-		if(SiS_Pr->SiS_SetFlag & SetDOSMode) {
-	           yres = 400;
-	           if(HwInfo->jChipType >= SIS_315H) {
-	              if(SiS_GetReg(SiS_Pr->SiS_P3c4,0x17) & 0x80) yres = 480;
-	           } else {
-	              if(SiS_GetReg(SiS_Pr->SiS_P3c4,0x13) & 0x80) yres = 480;
-	           }
-	        }
-	   } else {
-	      if(SiS_Pr->SiS_VBInfo & (SetCRT2ToLCD | SetCRT2ToHiVision)) {
-	         if(xres == 720) xres = 640;
-	      }
-	      if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCD) {
-		 if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1600x1200) {
-		    if(!(SiS_Pr->SiS_SetFlag & LCDVESATiming)) {
-        	       if(yres == 1024) yres = 1056;
-      		    }
-		 } else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1280x1024) {
-		    if(!(SiS_Pr->SiS_LCDInfo & DontExpandLCD)) {
-		       /* BIOS bug - does this regardless of scaling */
-      		       if(yres == 400) yres = 405;
-		    }
-      		    if(yres == 350) yres = 360;
-      		    if(SiS_Pr->SiS_SetFlag & LCDVESATiming) {
-        	       if(yres == 360) yres = 375;
-      		    }
-   	         } else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1024x768) {
-      		    if(!(SiS_Pr->SiS_SetFlag & LCDVESATiming)) {
-        	       if(!(SiS_Pr->SiS_LCDInfo & DontExpandLCD)) {
-          	          if(yres == 350) yres = 357;
-          	          if(yres == 400) yres = 420;
-            	          if(yres == 480) yres = 525;
-        	       }
-      		    }
-    	         }
+	}
+#endif
+
+	if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCD) {
+	   switch(SiS_Pr->SiS_LCDResInfo) {
+	   case Panel_1024x768:
+	      if(!(SiS_Pr->SiS_SetFlag & LCDVESATiming)) {
+                 if(!(SiS_Pr->SiS_LCDInfo & DontExpandLCD)) {
+          	    if(yres == 350) yres = 357;
+          	    if(yres == 400) yres = 420;
+            	    if(yres == 480) yres = 525;
+        	 }
+      	      }
+	      break;
+	   case Panel_1280x1024:
+	      if(!(SiS_Pr->SiS_LCDInfo & DontExpandLCD)) {
+		 /* BIOS bug - does this regardless of scaling */
+      		 if(yres == 400) yres = 405;
 	      }
+      	      if(yres == 350) yres = 360;
+      	      if(SiS_Pr->SiS_SetFlag & LCDVESATiming) {
+                 if(yres == 360) yres = 375;
+      	      }
+	      break;
+	   case Panel_1600x1200:
+	      if(!(SiS_Pr->SiS_SetFlag & LCDVESATiming)) {
+        	 if(yres == 1024) yres = 1056;
+      	      }
+	      break;
 	   }
 	}
+
   } else {
-    	if(xres == 720) xres = 640;
-	if(SiS_Pr->SiS_SetFlag & SetDOSMode) {
-	   yres = 400;
-	   if(HwInfo->jChipType >= SIS_315H) {
-	      if(SiS_GetReg(SiS_Pr->SiS_P3c4,0x17) & 0x80) yres = 480;
-	   } else {
-	      if(SiS_GetReg(SiS_Pr->SiS_P3c4,0x13) & 0x80) yres = 480;
-	   }
-	   if(SiS_Pr->SiS_IF_DEF_DSTN || SiS_Pr->SiS_IF_DEF_FSTN) {
-	      yres = 480;
-	   }
+
+     if(SiS_Pr->SiS_VBType & VB_SISVB) {
+        if(SiS_Pr->SiS_VBInfo & (SetCRT2ToLCD | SetCRT2ToHiVision)) {
+           if(xres == 720) xres = 640;
 	}
+     } else if(xres == 720) xres = 640;
+
+     if(SiS_Pr->SiS_SetFlag & SetDOSMode) {
+	yres = 400;
+        if(HwInfo->jChipType >= SIS_315H) {
+           if(SiS_GetReg(SiS_Pr->SiS_P3c4,0x17) & 0x80) yres = 480;
+        } else {
+           if(SiS_GetReg(SiS_Pr->SiS_P3c4,0x13) & 0x80) yres = 480;
+        }
+        if(SiS_Pr->SiS_IF_DEF_DSTN || SiS_Pr->SiS_IF_DEF_FSTN)  yres = 480;
+     }
+
   }
   SiS_Pr->SiS_VGAHDE = SiS_Pr->SiS_HDE = xres;
   SiS_Pr->SiS_VGAVDE = SiS_Pr->SiS_VDE = yres;
@@ -2580,103 +2718,84 @@
 		   USHORT RefreshRateTableIndex, USHORT *ResIndex,
 		   USHORT *DisplayType)
  {
-  USHORT tempbx,modeflag=0;
-  USHORT Flag,CRT2CRTC;
+  USHORT modeflag=0;
 
   if(SiS_Pr->SiS_IF_DEF_LVDS == 1) {
      if(!(SiS_Pr->SiS_VBInfo & SetCRT2ToLCDA)) {
         if(!(SiS_Pr->SiS_VBInfo & SetInSlaveMode)) return FALSE;
      }
   } else if(SiS_Pr->SiS_VBType & VB_SISVB) {
-     if(!(SiS_Pr->SiS_VBInfo & SetInSlaveMode)) return FALSE;
+     if(!(SiS_Pr->SiS_VBInfo & SetInSlaveMode))    return FALSE;
   } else
      return FALSE;
 
   if(ModeNo <= 0x13) {
      modeflag = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_ModeFlag;
-     CRT2CRTC = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_CRT2CRTC;
+     (*ResIndex) = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_CRT2CRTC;
   } else {
      modeflag = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag;
-     CRT2CRTC = SiS_Pr->SiS_RefIndex[RefreshRateTableIndex].Ext_CRT2CRTC;
+     (*ResIndex) = SiS_Pr->SiS_RefIndex[RefreshRateTableIndex].Ext_CRT2CRTC;
   }
 
-  Flag = 1;
-  tempbx = 0;
-  if(SiS_Pr->SiS_IF_DEF_CH70xx != 0) {
-     if(!(SiS_Pr->SiS_VBInfo & SetCRT2ToLCD)) {
-        Flag = 0;
-        tempbx = 18;
-        if(SiS_Pr->SiS_TVMode & TVSetCHOverScan) tempbx++;
-        if(SiS_Pr->SiS_TVMode & TVSetPAL) {
-      	   tempbx += 2;
-	   if(SiS_Pr->SiS_ModeType > ModeVGA) {
-	      if(SiS_Pr->SiS_CHSOverScan) tempbx = 99;
-	   }
-	   if(SiS_Pr->SiS_TVMode & TVSetPALM) {
-	      tempbx = 18;  /* PALM uses NTSC data */
-	      if(SiS_Pr->SiS_TVMode & TVSetCHOverScan) tempbx++;
-	   } else if(SiS_Pr->SiS_TVMode & TVSetPALN) {
-	      tempbx = 20;  /* PALN uses PAL data  */
-	      if(SiS_Pr->SiS_TVMode & TVSetCHOverScan) tempbx++;
-	   }
-        }
+  (*ResIndex) &= 0x3F;
+
+  if((SiS_Pr->SiS_IF_DEF_CH70xx) && (SiS_Pr->SiS_VBInfo & SetCRT2ToTV)) {
+     (*DisplayType) = 18;
+     if(SiS_Pr->SiS_TVMode & TVSetCHOverScan) (*DisplayType)++;
+     if(SiS_Pr->SiS_TVMode & TVSetPAL) {
+      	(*DisplayType) += 2;
+	if(SiS_Pr->SiS_ModeType > ModeVGA) {
+	   if(SiS_Pr->SiS_CHSOverScan) (*DisplayType) = 99;
+	}
+	if(SiS_Pr->SiS_TVMode & TVSetPALM) {
+	   (*DisplayType) = 18;  /* PALM uses NTSC data */
+	   if(SiS_Pr->SiS_TVMode & TVSetCHOverScan) (*DisplayType)++;
+	} else if(SiS_Pr->SiS_TVMode & TVSetPALN) {
+	   (*DisplayType) = 20;  /* PALN uses PAL data  */
+	   if(SiS_Pr->SiS_TVMode & TVSetCHOverScan) (*DisplayType)++;
+	}
      }
-  }
-  if(Flag) {
-     tempbx = SiS_Pr->SiS_LCDResInfo;
-     tempbx -= SiS_Pr->SiS_PanelMinLVDS;
-     if(SiS_Pr->SiS_LCDResInfo <= SiS_Pr->SiS_Panel1280x1024) {
-        if(SiS_Pr->SiS_LCDInfo & DontExpandLCD) tempbx += 6;
-        if(modeflag & HalfDCLK) tempbx += 3;
-     } else {
-        if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1400x1050) {
-           tempbx = 14;
-	   if(SiS_Pr->SiS_LCDInfo & DontExpandLCD) tempbx += 2;
-	   if(modeflag & HalfDCLK) tempbx++;
-        } else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1024x600) {
-           tempbx = 23;
-	   if(SiS_Pr->SiS_LCDInfo & DontExpandLCD) tempbx += 2;
-	   if(modeflag & HalfDCLK) tempbx++;
-        } else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1152x768) {
-           tempbx = 27;
-	   if(SiS_Pr->SiS_LCDInfo & DontExpandLCD) tempbx += 2;
-	   if(modeflag & HalfDCLK) tempbx++;
-        } else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1600x1200) {
-           tempbx = 36;
-	   if(SiS_Pr->SiS_LCDInfo & DontExpandLCD) tempbx += 2;
-	   if(modeflag & HalfDCLK) tempbx++;
-        } else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1280x768) {
-           tempbx = 40;
-	   if(SiS_Pr->SiS_LCDInfo & DontExpandLCD) tempbx += 2;
-	   if(modeflag & HalfDCLK) tempbx++;
-        } else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel640x480_3) {
-           tempbx = 54;
-	   if(modeflag & HalfDCLK) tempbx++;
-	} else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel640x480_2) {
-           tempbx = 52;
-	   if(modeflag & HalfDCLK) tempbx++;
-	} else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel640x480) {
-           tempbx = 50;
-	   if(modeflag & HalfDCLK) tempbx++;
-        }
+  } else {
+     switch(SiS_Pr->SiS_LCDResInfo) {
+     case Panel_640x480:   (*DisplayType) = 50; break;
+     case Panel_640x480_2: (*DisplayType) = 52; break;
+     case Panel_640x480_3: (*DisplayType) = 54; break;
+     case Panel_800x600:   (*DisplayType) =  0; break;
+     case Panel_1024x600:  (*DisplayType) = 23; break;
+     case Panel_1024x768:  (*DisplayType) =  4; break;
+     case Panel_1152x768:  (*DisplayType) = 27; break;
+     case Panel_1280x768:  (*DisplayType) = 40; break;
+     case Panel_1280x1024: (*DisplayType) =  8; break;
+     case Panel_1400x1050: (*DisplayType) = 14; break;
+     case Panel_1600x1200: (*DisplayType) = 36; break;
+     default: return FALSE;
+     }
+
+     if(modeflag & HalfDCLK) (*DisplayType)++;
 
+     switch(SiS_Pr->SiS_LCDResInfo) {
+     case Panel_640x480:
+     case Panel_640x480_2:
+     case Panel_640x480_3:
+        break;
+     default:
+        if(SiS_Pr->SiS_LCDInfo & DontExpandLCD) (*DisplayType) += 2;
      }
+
      if(SiS_Pr->SiS_LCDInfo & LCDPass11) {
-        tempbx = 12;
-	if(modeflag & HalfDCLK) tempbx++;
+        (*DisplayType) = 12;
+	if(modeflag & HalfDCLK) (*DisplayType)++;
      }
   }
 
 #if 0
   if(SiS_Pr->SiS_IF_DEF_FSTN) {
      if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel320x480){
-        tempbx = 22;
+        (*DisplayType) = 22;
      }
   }
 #endif
 
-  *ResIndex = CRT2CRTC & 0x3F;
-  *DisplayType = tempbx;
   return TRUE;
 }
 
@@ -2685,8 +2804,7 @@
 	       USHORT RefreshRateTableIndex,USHORT *CRT2Index,USHORT *ResIndex,
 	       PSIS_HW_INFO HwInfo)
 {
-  USHORT tempbx=0,tempal=0;
-  USHORT Flag,resinfo=0;
+  USHORT tempbx=0,tempal=0,resinfo=0;
 
   if(ModeNo <= 0x13) {
      tempal = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_CRT2CRTC;
@@ -2699,55 +2817,35 @@
 
      if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCD) {                            /* LCD */
 
-	if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1280x960) {
-	   tempbx = 15;
-  	} else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1400x1050) {
-	   tempbx = 20;
-	   if(SiS_Pr->SiS_LCDInfo & DontExpandLCD)         tempbx = 21;
-	   else if(!(SiS_Pr->SiS_SetFlag & LCDVESATiming)) tempbx = 22;
- 	} else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1600x1200) {
-	   tempbx = 23;
-	   if(SiS_Pr->SiS_LCDInfo & DontExpandLCD)         tempbx = 24;
-	   else if(!(SiS_Pr->SiS_SetFlag & LCDVESATiming)) tempbx = 25;
-#if 0
-	} else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1280x768) {
-	   tempbx = 26;
-	   if(SiS_Pr->SiS_LCDInfo & DontExpandLCD)         tempbx = 27;
-	   else if(!(SiS_Pr->SiS_SetFlag & LCDVESATiming)) tempbx = 28;
-#endif
- 	} else if(SiS_Pr->SiS_LCDInfo & DontExpandLCD) {
-	   if(SiS_Pr->SiS_VBType & VB_SIS301LV302LV) {
-	      if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1024x768)       tempbx = 13;
-	      else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1280x1024) tempbx = 14;
-	      else {
-	         tempbx = 29;
-		 if(ModeNo >= 0x13) {
-	            /* see below */
-	            if(resinfo == SIS_RI_1280x960) tempal = 10;
-	         }
-              }
-	   } else {
-	      tempbx = 29;
-	      if(ModeNo >= 0x13) {
-	         /* 1280x768 and 1280x960 have same CRT2CRTC,
-	          * so we change it here if 1280x960 is chosen
-	          */
-	         if(resinfo == SIS_RI_1280x960) tempal = 10;
+        tempbx = SiS_Pr->SiS_LCDResInfo;
+	if(!(SiS_Pr->SiS_SetFlag & LCDVESATiming)) tempbx += 32;
+
+	if(SiS_Pr->SiS_LCDResInfo == Panel_1680x1050) {
+	   if     (resinfo == SIS_RI_1280x800)  tempal =  9;
+	   else if(resinfo == SIS_RI_1400x1050) tempal = 11;
+	}
+
+  	if(SiS_Pr->SiS_LCDInfo & DontExpandLCD) {  /* Pass 1:1 only (center-screen handled outside) */
+	   tempbx = 100;
+	   if(ModeNo >= 0x13) {
+	      tempal = SiS_Pr->SiS_RefIndex[RefreshRateTableIndex].Ext_CRT2CRTC_NS;
+	      if((SiS_Pr->SiS_RefIndex[RefreshRateTableIndex].XRes == 1280) &&
+	         (SiS_Pr->SiS_RefIndex[RefreshRateTableIndex].YRes ==  768)) {
+	         /* Special for Fujitsu 7911 (VL-17WDX8), others custom */
+	         if(SiS_Pr->SiS_LCDResInfo == Panel_1280x768)        tempal = 0x08;
+		 else if(SiS_Pr->SiS_LCDResInfo == Panel_1280x768_2) tempal = 0x0f;
+		 else if(SiS_Pr->SiS_LCDResInfo == Panel_1280x768_3) tempal = 0x10;
 	      }
-   	   }
-	} else {
-      	   tempbx = SiS_Pr->SiS_LCDResInfo - SiS_Pr->SiS_Panel1024x768;
-      	   if(!(SiS_Pr->SiS_SetFlag & LCDVESATiming)) {
-              tempbx += 10;
-       	   }
+	   }
 	}
 
 #ifdef SIS315H
 	if(SiS_Pr->SiS_CustomT == CUT_COMPAQ1280) {
-	   if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1280x1024) {
-	      tempbx = 50;
-	      if(SiS_Pr->SiS_LCDInfo & DontExpandLCD)         tempbx = 51;
-	      else if(!(SiS_Pr->SiS_SetFlag & LCDVESATiming)) tempbx = 52;
+	   if(SiS_Pr->SiS_LCDResInfo == Panel_1280x1024) {
+	      if(!(SiS_Pr->SiS_LCDInfo & DontExpandLCD)) {
+	         tempbx = 200;
+	         if(!(SiS_Pr->SiS_SetFlag & LCDVESATiming)) tempbx++;
+	      }
 	   }
 	}
 #endif
@@ -2783,12 +2881,20 @@
 	      (resinfo == SIS_RI_720x576) ||
 	      (resinfo == SIS_RI_768x576)) {
 	      tempal = 6;
+	      if(SiS_Pr->SiS_TVMode & (TVSetPAL | TVSetPALN)) {
+	         if(resinfo == SIS_RI_720x480) tempal = 9;
+	      }
 	   }
 	   if(SiS_Pr->SiS_VBInfo & SetCRT2ToYPbPr525750) {
               if(SiS_Pr->SiS_TVMode & TVSetYPbPr525p) {
-	         if(resinfo == SIS_RI_1024x768) {
+	         if(resinfo == SIS_RI_1024x768) tempal = 8;
+	      }
+	      if(SiS_Pr->SiS_TVMode & TVSetYPbPr750p) {
+		 if((resinfo == SIS_RI_720x576) ||
+	            (resinfo == SIS_RI_768x576)) {
 	            tempal = 8;
 	         }
+		 if(resinfo == SIS_RI_1280x720) tempal = 9;
 	      }
 	   }
 	}
@@ -2799,70 +2905,54 @@
 
   } else {   /* LVDS, 301B-DH (if running on LCD) */
 
-     Flag = 1;
      tempbx = 0;
-     if(SiS_Pr->SiS_IF_DEF_CH70xx != 0) {
-        if(!(SiS_Pr->SiS_VBInfo & SetCRT2ToLCD)) {
-           Flag = 0;
-           tempbx = 10;
-	   if(SiS_Pr->SiS_TVMode & TVSetCHOverScan) tempbx += 1;
-           if(SiS_Pr->SiS_TVMode & TVSetPAL) {
-	      tempbx += 2;
-	      if(SiS_Pr->SiS_ModeType > ModeVGA) {
-		 if(SiS_Pr->SiS_CHSOverScan) tempbx = 99;
-	      }
-	      if(SiS_Pr->SiS_TVMode & TVSetPALM) {
-		 tempbx = 90;
-		 if(SiS_Pr->SiS_TVMode & TVSetCHOverScan) tempbx += 1;
-	      } else if(SiS_Pr->SiS_TVMode & TVSetPALN) {
-		 tempbx = 92;
-		 if(SiS_Pr->SiS_TVMode & TVSetCHOverScan) tempbx += 1;
-	      }
-           }
-        }
-     }
-
-     if(Flag) {
-
-	if(SiS_Pr->SiS_LCDResInfo <= SiS_Pr->SiS_Panel1280x1024) {
-	   tempbx = SiS_Pr->SiS_LCDResInfo - SiS_Pr->SiS_PanelMinLVDS;
-   	   if(SiS_Pr->SiS_LCDInfo & DontExpandLCD)  tempbx += 3;
-
-	   if(SiS_Pr->SiS_CustomT == CUT_BARCO1024) {
-	      tempbx = 82;
-	      if(SiS_Pr->SiS_LCDInfo & DontExpandLCD)  tempbx++;
+     if((SiS_Pr->SiS_IF_DEF_CH70xx) && (SiS_Pr->SiS_VBInfo & SetCRT2ToTV)) {
+        tempbx = 10;
+	if(SiS_Pr->SiS_TVMode & TVSetCHOverScan) tempbx += 1;
+        if(SiS_Pr->SiS_TVMode & TVSetPAL) {
+	   tempbx += 2;
+	   if(SiS_Pr->SiS_ModeType > ModeVGA) {
+	      if(SiS_Pr->SiS_CHSOverScan) tempbx = 99;
 	   }
-	} else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1280x768) {
-	   tempbx = 18;
-	   if(SiS_Pr->SiS_LCDInfo & DontExpandLCD)  tempbx++;
-	} else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel640x480) {
-	   tempbx = 6;
-	} else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel640x480_2) {
-	   tempbx = 30;
-	} else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel640x480_3) {
-	   tempbx = 30;
-	} else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1024x600) {
-	   tempbx = 15;
-  	   if(SiS_Pr->SiS_LCDInfo & DontExpandLCD)  tempbx += 2;
-	} else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1152x768) {
-	   tempbx = 16;
-	   if(SiS_Pr->SiS_LCDInfo & DontExpandLCD)  tempbx += 2;
-	} else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1400x1050) {
-	   tempbx = 8;
-	   if(SiS_Pr->SiS_LCDInfo & DontExpandLCD)  tempbx++;
-	} else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1600x1200) {
-	   tempbx = 21;
-	   if(SiS_Pr->SiS_LCDInfo & DontExpandLCD)  tempbx++;
-	} else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_PanelBarco1366) {
-	   tempbx = 80;
-   	   if(SiS_Pr->SiS_LCDInfo & DontExpandLCD)  tempbx++;
+	   if(SiS_Pr->SiS_TVMode & TVSetPALM) {
+	      tempbx = 90;
+	      if(SiS_Pr->SiS_TVMode & TVSetCHOverScan) tempbx += 1;
+	   } else if(SiS_Pr->SiS_TVMode & TVSetPALN) {
+	      tempbx = 92;
+	      if(SiS_Pr->SiS_TVMode & TVSetCHOverScan) tempbx += 1;
+	   }
+        }
+     } else {
+        switch(SiS_Pr->SiS_LCDResInfo) {
+	case Panel_640x480:   tempbx = 6;  break;
+	case Panel_640x480_2: tempbx = 30; break;
+	case Panel_640x480_3: tempbx = 30; break;
+	case Panel_800x600:   tempbx = 0;  break;
+	case Panel_1024x600:  tempbx = 15; break;
+	case Panel_1024x768:  tempbx = 2;  break;
+	case Panel_1152x768:  tempbx = 17; break;
+	case Panel_1280x768:  tempbx = 18; break;
+	case Panel_1280x1024: tempbx = 4;  break;
+	case Panel_1400x1050: tempbx = 8;  break;
+	case Panel_1600x1200: tempbx = 21; break;
+	case Panel_Barco1366: tempbx = 80; break;
+	}
+
+	switch(SiS_Pr->SiS_LCDResInfo) {
+	case Panel_640x480:
+	case Panel_640x480_2:
+	case Panel_640x480_3:
+	   break;
+	default:
+	   if(SiS_Pr->SiS_LCDInfo & DontExpandLCD) tempbx++;
 	}
 
-	if(SiS_Pr->SiS_LCDInfo & LCDPass11) {
-	   tempbx = 7;
-        }
+	if(SiS_Pr->SiS_LCDInfo & LCDPass11) tempbx = 7;
 
-	if(SiS_Pr->SiS_CustomT == CUT_PANEL848) {
+	if(SiS_Pr->SiS_CustomT == CUT_BARCO1024) {
+	   tempbx = 82;
+	   if(SiS_Pr->SiS_LCDInfo & DontExpandLCD)  tempbx++;
+	} else if(SiS_Pr->SiS_CustomT == CUT_PANEL848) {
 	   tempbx = 84;
 	   if(SiS_Pr->SiS_LCDInfo & DontExpandLCD)  tempbx++;
 	}
@@ -2870,45 +2960,17 @@
      }
 
      if(SiS_Pr->SiS_SetFlag & SetDOSMode) {
-        if(SiS_Pr->SiS_LCDResInfo != SiS_Pr->SiS_Panel640x480) tempal = 7;
+        if(SiS_Pr->SiS_LCDResInfo != Panel_640x480) tempal = 7;
   	if(HwInfo->jChipType < SIS_315H) {
 	   if(SiS_GetReg(SiS_Pr->SiS_P3c4,0x13) & 0x80) tempal++;
 	}
      }
 
-     *CRT2Index = tempbx;
-     *ResIndex = tempal & 0x1F;
+     (*CRT2Index) = tempbx;
+     (*ResIndex) = tempal & 0x1F;
   }
 }
 
-#ifdef SIS315H
-static void
-SiS_GetCRT2PtrA(SiS_Private *SiS_Pr,USHORT ModeNo,USHORT ModeIdIndex,
-		USHORT RefreshRateTableIndex,USHORT *CRT2Index,
-		USHORT *ResIndex)
-{
-  USHORT tempbx,tempal;
-
-  tempbx = SiS_Pr->SiS_LCDResInfo;
-
-  if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1600x1200)      tempbx = 4;
-  else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1400x1050) tempbx = 3;
-  else tempbx -= SiS_Pr->SiS_Panel1024x768;
-
-  if(SiS_Pr->SiS_LCDInfo & DontExpandLCD)  tempbx += 5;
-
-  if(ModeNo <= 0x13)
-     tempal = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_CRT2CRTC;
-  else
-     tempal = SiS_Pr->SiS_RefIndex[RefreshRateTableIndex].Ext_CRT2CRTC;
-
-  /* No customs required yet (Clevo, Compaq, etc) */
-
-  *CRT2Index = tempbx;
-  *ResIndex = tempal & 0x1F;
-}
-#endif
-
 static void
 SiS_GetRAMDAC2DATA(SiS_Private *SiS_Pr,USHORT ModeNo,USHORT ModeIdIndex,
                    USHORT RefreshRateTableIndex,PSIS_HW_INFO HwInfo)
@@ -2969,8 +3031,7 @@
 
 static void
 SiS_GetCRT2DataLVDS(SiS_Private *SiS_Pr,USHORT ModeNo,USHORT ModeIdIndex,
-                    USHORT RefreshRateTableIndex,
-		    PSIS_HW_INFO HwInfo)
+                    USHORT RefreshRateTableIndex, PSIS_HW_INFO HwInfo)
 {
    USHORT CRT2Index, ResIndex;
    const SiS_LVDSDataStruct *LVDSData = NULL;
@@ -2988,23 +3049,55 @@
       SiS_Pr->SiS_RY4COE = 0;
    }
 
-   if((SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) && (SiS_Pr->SiS_VBInfo & SetCRT2ToLCDA)) {
+   if((SiS_Pr->SiS_VBType & VB_SISVB) && (SiS_Pr->SiS_VBInfo & SetCRT2ToLCDA)) {
 
 #ifdef SIS315H
-      SiS_GetCRT2PtrA(SiS_Pr,ModeNo,ModeIdIndex,RefreshRateTableIndex,
-                      &CRT2Index,&ResIndex);
-
-      switch (CRT2Index) {
-      	case  0:  LVDSData = SiS_Pr->SiS_LCDA1024x768Data_1;    break;
-      	case  1:  LVDSData = SiS_Pr->SiS_LCDA1280x1024Data_1;   break;
-	case  3:  LVDSData = SiS_Pr->SiS_LCDA1400x1050Data_1;   break;
-	case  4:  LVDSData = SiS_Pr->SiS_LCDA1600x1200Data_1;   break;
-      	case  5:  LVDSData = SiS_Pr->SiS_LCDA1024x768Data_2;    break;
-      	case  6:  LVDSData = SiS_Pr->SiS_LCDA1280x1024Data_2;   break;
-	case  8:  LVDSData = SiS_Pr->SiS_LCDA1400x1050Data_2;   break;
-	case  9:  LVDSData = SiS_Pr->SiS_LCDA1600x1200Data_2;   break;
-	default:  LVDSData = SiS_Pr->SiS_LCDA1024x768Data_1;    break;
+      if(SiS_Pr->SiS_LCDInfo & DontExpandLCD) {
+         if(SiS_Pr->SiS_LCDInfo & LCDPass11) {
+	    if(SiS_Pr->UseCustomMode) {
+	       SiS_Pr->SiS_VGAHT = SiS_Pr->SiS_HT = SiS_Pr->CHTotal;
+	       SiS_Pr->SiS_VGAVT = SiS_Pr->SiS_VT = SiS_Pr->CVTotal;
+	    } else {
+	       if(ModeNo < 0x13) {
+	          ResIndex = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_CRT2CRTC;
+	       } else {
+	          ResIndex = SiS_Pr->SiS_RefIndex[RefreshRateTableIndex].Ext_CRT2CRTC_NS;
+		  /* Special for our 3 types, others custom (works with default) */
+		  if((SiS_Pr->SiS_RefIndex[RefreshRateTableIndex].XRes == 1280) &&
+	             (SiS_Pr->SiS_RefIndex[RefreshRateTableIndex].YRes ==  768)) {
+	             if(SiS_Pr->SiS_LCDResInfo == Panel_1280x768)        ResIndex = 0x08;
+		     else if(SiS_Pr->SiS_LCDResInfo == Panel_1280x768_2) ResIndex = 0x0f;
+		     else if(SiS_Pr->SiS_LCDResInfo == Panel_1280x768_3) ResIndex = 0x10;
+	          }
+		  /* Special for 1280x720 TMDS <> LVDS */
+		  if((SiS_Pr->SiS_RefIndex[RefreshRateTableIndex].XRes == 1280) &&
+	             (SiS_Pr->SiS_RefIndex[RefreshRateTableIndex].YRes ==  720)) {
+		     if(SiS_Pr->SiS_LCDResInfo == Panel_1280x720) {
+		        if(SiS_Pr->PanelHT == 1344) ResIndex = 0x12;
+		     }
+	          }
+	       }
+	       SiS_Pr->SiS_VGAHT = SiS_Pr->SiS_NoScaleData[ResIndex].VGAHT;
+               SiS_Pr->SiS_VGAVT = SiS_Pr->SiS_NoScaleData[ResIndex].VGAVT;
+               SiS_Pr->SiS_HT    = SiS_Pr->SiS_NoScaleData[ResIndex].LCDHT;
+               SiS_Pr->SiS_VT    = SiS_Pr->SiS_NoScaleData[ResIndex].LCDVT;
+	    }
+	 } else {
+     	    SiS_Pr->SiS_VGAHT = SiS_Pr->SiS_HT = SiS_Pr->PanelHT;
+            SiS_Pr->SiS_VGAVT = SiS_Pr->SiS_VT = SiS_Pr->PanelVT;
+	 }
+      } else {
+	 /* This handles custom modes and custom panels */
+	 SiS_Pr->SiS_HDE = SiS_Pr->PanelXRes;
+         SiS_Pr->SiS_VDE = SiS_Pr->PanelYRes;
+         SiS_Pr->SiS_HT  = SiS_Pr->PanelHT;
+         SiS_Pr->SiS_VT  = SiS_Pr->PanelVT;
+	 SiS_Pr->SiS_VGAHT = SiS_Pr->PanelHT - (SiS_Pr->PanelXRes - SiS_Pr->SiS_VGAHDE);
+	 SiS_Pr->SiS_VGAVT = SiS_Pr->PanelVT - (SiS_Pr->PanelYRes - SiS_Pr->SiS_VGAVDE);
       }
+
+      SiS_CalcLCDACRT1Timing(SiS_Pr,ModeNo,ModeIdIndex);
+
 #endif
 
    } else {
@@ -3015,7 +3108,7 @@
       }
 
       SiS_GetCRT2Ptr(SiS_Pr, ModeNo, ModeIdIndex, RefreshRateTableIndex,
-                     &CRT2Index, &ResIndex, HwInfo);
+                     		&CRT2Index, &ResIndex, HwInfo);
 
       /* 301BDH needs LVDS Data */
       if((SiS_Pr->SiS_VBType & VB_NoLCD) && (SiS_Pr->SiS_VBInfo & SetCRT2ToLCD)) {
@@ -3023,72 +3116,59 @@
       }
 
       switch (CRT2Index) {
-      	case  0:  LVDSData = SiS_Pr->SiS_LVDS800x600Data_1;    break;
-      	case  1:  LVDSData = SiS_Pr->SiS_LVDS1024x768Data_1;   break;
-      	case  2:  LVDSData = SiS_Pr->SiS_LVDS1280x1024Data_1;  break;
-      	case  3:  LVDSData = SiS_Pr->SiS_LVDS800x600Data_2;    break;
-      	case  4:  LVDSData = SiS_Pr->SiS_LVDS1024x768Data_2;   break;
-      	case  5:  LVDSData = SiS_Pr->SiS_LVDS1280x1024Data_2;  break;
-	case  6:  LVDSData = SiS_Pr->SiS_LVDS640x480Data_1;    break;
-        case  7:  LVDSData = SiS_Pr->SiS_LVDSXXXxXXXData_1;    break;
-	case  8:  LVDSData = SiS_Pr->SiS_LVDS1400x1050Data_1;  break;
-	case  9:  LVDSData = SiS_Pr->SiS_LVDS1400x1050Data_2;  break;
-      	case 10:  LVDSData = SiS_Pr->SiS_CHTVUNTSCData;        break;
-      	case 11:  LVDSData = SiS_Pr->SiS_CHTVONTSCData;        break;
-      	case 12:  LVDSData = SiS_Pr->SiS_CHTVUPALData;         break;
-      	case 13:  LVDSData = SiS_Pr->SiS_CHTVOPALData;         break;
-      	case 14:  LVDSData = SiS_Pr->SiS_LVDS320x480Data_1;    break;
-	case 15:  LVDSData = SiS_Pr->SiS_LVDS1024x600Data_1;   break;
-	case 16:  LVDSData = SiS_Pr->SiS_LVDS1152x768Data_1;   break;
-	case 17:  LVDSData = SiS_Pr->SiS_LVDS1024x600Data_2;   break;
-	case 18:  LVDSData = SiS_Pr->SiS_LVDS1152x768Data_2;   break;
-	case 19:  LVDSData = SiS_Pr->SiS_LVDS1280x768Data_1;   break;
-	case 20:  LVDSData = SiS_Pr->SiS_LVDS1280x768Data_2;   break;
-	case 21:  LVDSData = SiS_Pr->SiS_LVDS1600x1200Data_1;  break;
-	case 22:  LVDSData = SiS_Pr->SiS_LVDS1600x1200Data_2;  break;
-	case 30:  LVDSData = SiS_Pr->SiS_LVDS640x480Data_2;    break;
-	case 80:  LVDSData = SiS_Pr->SiS_LVDSBARCO1366Data_1;  break;
-	case 81:  LVDSData = SiS_Pr->SiS_LVDSBARCO1366Data_2;  break;
-	case 82:  LVDSData = SiS_Pr->SiS_LVDSBARCO1024Data_1;  break;
-	case 83:  LVDSData = SiS_Pr->SiS_LVDSBARCO1024Data_2;  break;
-	case 84:  LVDSData = SiS_Pr->SiS_LVDS848x480Data_1;    break;
-	case 85:  LVDSData = SiS_Pr->SiS_LVDS848x480Data_2;    break;
-	case 90:  LVDSData = SiS_Pr->SiS_CHTVUPALMData;        break;
-      	case 91:  LVDSData = SiS_Pr->SiS_CHTVOPALMData;        break;
-      	case 92:  LVDSData = SiS_Pr->SiS_CHTVUPALNData;        break;
-      	case 93:  LVDSData = SiS_Pr->SiS_CHTVOPALNData;        break;
-	case 99:  LVDSData = SiS_Pr->SiS_CHTVSOPALData;	       break;  /* Super Overscan */
-	default:  LVDSData = SiS_Pr->SiS_LVDS1024x768Data_1;   break;
-      }
-   }
-
-   SiS_Pr->SiS_VGAHT = (LVDSData+ResIndex)->VGAHT;
-   SiS_Pr->SiS_VGAVT = (LVDSData+ResIndex)->VGAVT;
-   SiS_Pr->SiS_HT    = (LVDSData+ResIndex)->LCDHT;
-   SiS_Pr->SiS_VT    = (LVDSData+ResIndex)->LCDVT;
+      	 case  0: LVDSData = SiS_Pr->SiS_LVDS800x600Data_1;    break;
+	 case  1: LVDSData = SiS_Pr->SiS_LVDS800x600Data_2;    break;
+      	 case  2: LVDSData = SiS_Pr->SiS_LVDS1024x768Data_1;   break;
+	 case  3: LVDSData = SiS_Pr->SiS_LVDS1024x768Data_2;   break;
+      	 case  4: LVDSData = SiS_Pr->SiS_LVDS1280x1024Data_1;  break;
+      	 case  5: LVDSData = SiS_Pr->SiS_LVDS1280x1024Data_2;  break;
+	 case  6: LVDSData = SiS_Pr->SiS_LVDS640x480Data_1;    break;
+         case  7: LVDSData = SiS_Pr->SiS_LVDSXXXxXXXData_1;    break;
+	 case  8: LVDSData = SiS_Pr->SiS_LVDS1400x1050Data_1;  break;
+	 case  9: LVDSData = SiS_Pr->SiS_LVDS1400x1050Data_2;  break;
+      	 case 10: LVDSData = SiS_Pr->SiS_CHTVUNTSCData;        break;
+      	 case 11: LVDSData = SiS_Pr->SiS_CHTVONTSCData;        break;
+      	 case 12: LVDSData = SiS_Pr->SiS_CHTVUPALData;         break;
+      	 case 13: LVDSData = SiS_Pr->SiS_CHTVOPALData;         break;
+      	 case 14: LVDSData = SiS_Pr->SiS_LVDS320x480Data_1;    break;
+	 case 15: LVDSData = SiS_Pr->SiS_LVDS1024x600Data_1;   break;
+	 case 16: LVDSData = SiS_Pr->SiS_LVDS1024x600Data_2;   break;
+	 case 17: LVDSData = SiS_Pr->SiS_LVDS1152x768Data_1;   break;
+	 case 18: LVDSData = SiS_Pr->SiS_LVDS1152x768Data_2;   break;
+	 case 19: LVDSData = SiS_Pr->SiS_LVDS1280x768Data_1;   break;
+	 case 20: LVDSData = SiS_Pr->SiS_LVDS1280x768Data_2;   break;
+	 case 21: LVDSData = SiS_Pr->SiS_LVDS1600x1200Data_1;  break;
+	 case 22: LVDSData = SiS_Pr->SiS_LVDS1600x1200Data_2;  break;
+	 case 30: LVDSData = SiS_Pr->SiS_LVDS640x480Data_2;    break;
+	 case 80: LVDSData = SiS_Pr->SiS_LVDSBARCO1366Data_1;  break;
+	 case 81: LVDSData = SiS_Pr->SiS_LVDSBARCO1366Data_2;  break;
+	 case 82: LVDSData = SiS_Pr->SiS_LVDSBARCO1024Data_1;  break;
+	 case 83: LVDSData = SiS_Pr->SiS_LVDSBARCO1024Data_2;  break;
+	 case 84: LVDSData = SiS_Pr->SiS_LVDS848x480Data_1;    break;
+	 case 85: LVDSData = SiS_Pr->SiS_LVDS848x480Data_2;    break;
+	 case 90: LVDSData = SiS_Pr->SiS_CHTVUPALMData;        break;
+      	 case 91: LVDSData = SiS_Pr->SiS_CHTVOPALMData;        break;
+      	 case 92: LVDSData = SiS_Pr->SiS_CHTVUPALNData;        break;
+      	 case 93: LVDSData = SiS_Pr->SiS_CHTVOPALNData;        break;
+	 case 99: LVDSData = SiS_Pr->SiS_CHTVSOPALData;	       break;  /* Super Overscan */
+	 default: LVDSData = SiS_Pr->SiS_LVDS1024x768Data_1;   break;
+      }
+
+      SiS_Pr->SiS_VGAHT = (LVDSData+ResIndex)->VGAHT;
+      SiS_Pr->SiS_VGAVT = (LVDSData+ResIndex)->VGAVT;
+      SiS_Pr->SiS_HT    = (LVDSData+ResIndex)->LCDHT;
+      SiS_Pr->SiS_VT    = (LVDSData+ResIndex)->LCDVT;
 
-   if(SiS_Pr->SiS_VBType & VB_SISVB) {
-
-      if(!(SiS_Pr->SiS_LCDInfo & DontExpandLCD)) {
-         SiS_Pr->SiS_HDE = SiS_Pr->PanelXRes;
-         SiS_Pr->SiS_VDE = SiS_Pr->PanelYRes;
-      }
-
-   } else {
-
-      if(SiS_Pr->SiS_IF_DEF_TRUMPION == 0) {
+      if(!(SiS_Pr->SiS_VBType & VB_SISVB)) {
          if((SiS_Pr->SiS_VBInfo & SetCRT2ToLCD) && (!(SiS_Pr->SiS_LCDInfo & LCDPass11))) {
-            if(SiS_Pr->SiS_LCDResInfo != SiS_Pr->SiS_Panel640x480) {
-               if((!(SiS_Pr->SiS_LCDInfo & DontExpandLCD)) || (SiS_Pr->SiS_SetFlag & SetDOSMode)) {
-	          SiS_Pr->SiS_HDE = SiS_Pr->PanelXRes;
-                  SiS_Pr->SiS_VDE = SiS_Pr->PanelYRes;
-
-	 	  if(SiS_Pr->SiS_CustomT == CUT_BARCO1366) {
-		     if(ResIndex < 0x08) {
-		        SiS_Pr->SiS_HDE = 1280;
-                        SiS_Pr->SiS_VDE = 1024;
-		     }
-		  }
+            if((!(SiS_Pr->SiS_LCDInfo & DontExpandLCD)) || (SiS_Pr->SiS_SetFlag & SetDOSMode)) {
+	       SiS_Pr->SiS_HDE = SiS_Pr->PanelXRes;
+               SiS_Pr->SiS_VDE = SiS_Pr->PanelYRes;
+	       if(SiS_Pr->SiS_CustomT == CUT_BARCO1366) {
+		  if(ResIndex < 0x08) {
+		     SiS_Pr->SiS_HDE = 1280;
+                     SiS_Pr->SiS_VDE = 1024;
+                  }
                }
             }
          }
@@ -3101,23 +3181,38 @@
                    USHORT RefreshRateTableIndex,
 		   PSIS_HW_INFO HwInfo)
 {
-  USHORT tempax,tempbx,modeflag;
-  USHORT resinfo;
-  USHORT CRT2Index,ResIndex;
+  UCHAR  *ROMAddr = NULL;
+  USHORT tempax,tempbx,modeflag,romptr=0;
+  USHORT resinfo,CRT2Index,ResIndex;
   const SiS_LCDDataStruct *LCDPtr = NULL;
   const SiS_TVDataStruct  *TVPtr  = NULL;
+#ifdef SIS315H
+  SHORT  resinfo661;
+#endif
 
   if(ModeNo <= 0x13) {
      modeflag = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_ModeFlag;
      resinfo = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_ResInfo;
+  } else if(SiS_Pr->UseCustomMode) {
+     modeflag = SiS_Pr->CModeFlag;
+     resinfo = 0;
   } else {
-     if(SiS_Pr->UseCustomMode) {
-        modeflag = SiS_Pr->CModeFlag;
-	resinfo = 0;
-     } else {
-    	modeflag = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag;
-    	resinfo = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_RESINFO;
+     modeflag = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag;
+     resinfo = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_RESINFO;
+#ifdef SIS315H
+     resinfo661 = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].ROMMODEIDX661;
+     if( (SiS_Pr->SiS_VBInfo & SetCRT2ToLCD)   &&
+         (SiS_Pr->SiS_SetFlag & LCDVESATiming) &&
+         (resinfo661 >= 0)                     &&
+	 (SiS_Pr->SiS_NeedRomModeData) ) {
+        if((ROMAddr = GetLCDStructPtr661(SiS_Pr, HwInfo))) {
+	   if((romptr = (SISGETROMW(21)))) {
+              romptr += (resinfo661 * 10);
+	      ROMAddr = HwInfo->pjVirtualRomBase;
+	   }
+	}
      }
+#endif
   }
   
   SiS_Pr->SiS_NewFlickerMode = 0;
@@ -3145,6 +3240,7 @@
      } else {
 
         SiS_GetRAMDAC2DATA(SiS_Pr, ModeNo, ModeIdIndex, RefreshRateTableIndex, HwInfo);
+
      }
 
   } else if(SiS_Pr->SiS_VBInfo & SetCRT2ToTV) {
@@ -3153,20 +3249,20 @@
                     &CRT2Index,&ResIndex,HwInfo);
 
      switch(CRT2Index) {
-       case  2:  TVPtr = SiS_Pr->SiS_ExtHiTVData;   break;
-       case  3:  TVPtr = SiS_Pr->SiS_ExtPALData;    break;
-       case  4:  TVPtr = SiS_Pr->SiS_ExtNTSCData;   break;
-       case  5:  TVPtr = SiS_Pr->SiS_Ext525iData;   break;
-       case  6:  TVPtr = SiS_Pr->SiS_Ext525pData;   break;
-       case  7:  TVPtr = SiS_Pr->SiS_Ext750pData;   break;
-       case  8:  TVPtr = SiS_Pr->SiS_StPALData;     break;
-       case  9:  TVPtr = SiS_Pr->SiS_StNTSCData;    break;
-       case 10:  TVPtr = SiS_Pr->SiS_St525iData;    break;
-       case 11:  TVPtr = SiS_Pr->SiS_St525pData;    break;
-       case 12:  TVPtr = SiS_Pr->SiS_St750pData;    break;
-       case 13:  TVPtr = SiS_Pr->SiS_St1HiTVData;   break;
-       case 14:  TVPtr = SiS_Pr->SiS_St2HiTVData;   break;
-       default:  TVPtr = SiS_Pr->SiS_StPALData;     break;
+        case  2: TVPtr = SiS_Pr->SiS_ExtHiTVData;   break;
+        case  3: TVPtr = SiS_Pr->SiS_ExtPALData;    break;
+        case  4: TVPtr = SiS_Pr->SiS_ExtNTSCData;   break;
+        case  5: TVPtr = SiS_Pr->SiS_Ext525iData;   break;
+        case  6: TVPtr = SiS_Pr->SiS_Ext525pData;   break;
+        case  7: TVPtr = SiS_Pr->SiS_Ext750pData;   break;
+        case  8: TVPtr = SiS_Pr->SiS_StPALData;     break;
+        case  9: TVPtr = SiS_Pr->SiS_StNTSCData;    break;
+        case 10: TVPtr = SiS_Pr->SiS_St525iData;    break;
+        case 11: TVPtr = SiS_Pr->SiS_St525pData;    break;
+        case 12: TVPtr = SiS_Pr->SiS_St750pData;    break;
+        case 13: TVPtr = SiS_Pr->SiS_St1HiTVData;   break;
+        case 14: TVPtr = SiS_Pr->SiS_St2HiTVData;   break;
+        default: TVPtr = SiS_Pr->SiS_StPALData;     break;
      }
 
      SiS_Pr->SiS_RVBHCMAX  = (TVPtr+ResIndex)->RVBHCMAX;
@@ -3247,10 +3343,11 @@
 
   } else if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCD) {
 
+     SiS_Pr->SiS_RVBHCMAX  = 1;
+     SiS_Pr->SiS_RVBHCFACT = 1;
+
      if(SiS_Pr->UseCustomMode) {
 
-        SiS_Pr->SiS_RVBHCMAX  = 1;
-        SiS_Pr->SiS_RVBHCFACT = 1;
         SiS_Pr->SiS_VGAHT     = SiS_Pr->CHTotal;
         SiS_Pr->SiS_VGAVT     = SiS_Pr->CVTotal;
         SiS_Pr->SiS_HT        = SiS_Pr->CHTotal;
@@ -3260,58 +3357,85 @@
 
      } else {
 
-        SiS_GetCRT2Ptr(SiS_Pr,ModeNo,ModeIdIndex,RefreshRateTableIndex,
-                      &CRT2Index,&ResIndex,HwInfo);
+        BOOLEAN gotit = FALSE;
+
+        if((SiS_Pr->SiS_LCDInfo & DontExpandLCD) && (!(SiS_Pr->SiS_LCDInfo & LCDPass11))) {
+
+           SiS_Pr->SiS_VGAHT     = SiS_Pr->PanelHT;
+           SiS_Pr->SiS_VGAVT     = SiS_Pr->PanelVT;
+           SiS_Pr->SiS_HT        = SiS_Pr->PanelHT;
+           SiS_Pr->SiS_VT        = SiS_Pr->PanelVT;
+	   gotit = TRUE;
+
+	} else if( (!(SiS_Pr->SiS_LCDInfo & DontExpandLCD)) && (romptr) && (ROMAddr) ) {
+
+#ifdef SIS315H
+	   SiS_Pr->SiS_RVBHCMAX  = ROMAddr[romptr];
+           SiS_Pr->SiS_RVBHCFACT = ROMAddr[romptr+1];
+           SiS_Pr->SiS_VGAHT     = ROMAddr[romptr+2] | ((ROMAddr[romptr+3] & 0x0f) << 8);
+           SiS_Pr->SiS_VGAVT     = ROMAddr[romptr+4] | ((ROMAddr[romptr+3] & 0xf0) << 4);
+           SiS_Pr->SiS_HT        = ROMAddr[romptr+5] | ((ROMAddr[romptr+6] & 0x0f) << 8);
+           SiS_Pr->SiS_VT        = ROMAddr[romptr+7] | ((ROMAddr[romptr+6] & 0xf0) << 4);
+	   if(SiS_Pr->SiS_VGAHT) gotit = TRUE;
+#endif
+
+	}
 
-        switch(CRT2Index) {
-         case  0: LCDPtr = SiS_Pr->SiS_ExtLCD1024x768Data;        break; /* VESA Timing */
-         case  1: LCDPtr = SiS_Pr->SiS_ExtLCD1280x1024Data;       break; /* VESA Timing */
-         case  5: LCDPtr = SiS_Pr->SiS_StLCD1024x768Data;         break; /* Obviously unused */
-         case  6: LCDPtr = SiS_Pr->SiS_StLCD1280x1024Data;        break; /* Obviously unused */
-         case 10: LCDPtr = SiS_Pr->SiS_St2LCD1024x768Data;        break; /* Non-VESA Timing */
-         case 11: LCDPtr = SiS_Pr->SiS_St2LCD1280x1024Data;       break; /* Non-VESA Timing */
-         case 13: LCDPtr = SiS_Pr->SiS_NoScaleData1024x768;       break; /* Non-expanding */
-         case 14: LCDPtr = SiS_Pr->SiS_NoScaleData1280x1024;      break; /* Non-expanding */
-         case 15: LCDPtr = SiS_Pr->SiS_LCD1280x960Data;           break; /* 1280x960 */
-         case 20: LCDPtr = SiS_Pr->SiS_ExtLCD1400x1050Data;       break; /* VESA Timing */
-         case 21: LCDPtr = SiS_Pr->SiS_NoScaleData1400x1050;      break; /* Non-expanding (let panel scale) */
-         case 22: LCDPtr = SiS_Pr->SiS_StLCD1400x1050Data;        break; /* Non-VESA Timing (let panel scale) */
-         case 23: LCDPtr = SiS_Pr->SiS_ExtLCD1600x1200Data;       break; /* VESA Timing */
-         case 24: LCDPtr = SiS_Pr->SiS_NoScaleData1600x1200;      break; /* Non-expanding */
-         case 25: LCDPtr = SiS_Pr->SiS_StLCD1600x1200Data;        break; /* Non-VESA Timing */
-         case 26: LCDPtr = SiS_Pr->SiS_ExtLCD1280x768Data;        break; /* VESA Timing */
-         case 27: LCDPtr = SiS_Pr->SiS_NoScaleData1280x768;       break; /* Non-expanding */
-         case 28: LCDPtr = SiS_Pr->SiS_StLCD1280x768Data;         break; /* Non-VESA Timing */
-         case 29: LCDPtr = SiS_Pr->SiS_NoScaleData;	          break; /* Generic no-scale data */
-#ifdef SIS315H
-	 case 50: LCDPtr = (SiS_LCDDataStruct *)SiS310_ExtCompaq1280x1024Data;	break;
-	 case 51: LCDPtr = SiS_Pr->SiS_NoScaleData1280x1024;			break;
-	 case 52: LCDPtr = SiS_Pr->SiS_St2LCD1280x1024Data;	  		break;
-#endif
-         default: LCDPtr = SiS_Pr->SiS_ExtLCD1024x768Data;	  break;
-        }
-
-        SiS_Pr->SiS_RVBHCMAX  = (LCDPtr+ResIndex)->RVBHCMAX;
-        SiS_Pr->SiS_RVBHCFACT = (LCDPtr+ResIndex)->RVBHCFACT;
-        SiS_Pr->SiS_VGAHT     = (LCDPtr+ResIndex)->VGAHT;
-        SiS_Pr->SiS_VGAVT     = (LCDPtr+ResIndex)->VGAVT;
-        SiS_Pr->SiS_HT        = (LCDPtr+ResIndex)->LCDHT;
-        SiS_Pr->SiS_VT        = (LCDPtr+ResIndex)->LCDVT;
+	if(!gotit) {
+
+           SiS_GetCRT2Ptr(SiS_Pr,ModeNo,ModeIdIndex,RefreshRateTableIndex,
+                          &CRT2Index,&ResIndex,HwInfo);
+
+           switch(CRT2Index) {
+	      case Panel_1024x768      : LCDPtr = SiS_Pr->SiS_ExtLCD1024x768Data;   break;
+	      case Panel_1024x768  + 32: LCDPtr = SiS_Pr->SiS_St2LCD1024x768Data;   break;
+	      case Panel_1280x720      :
+	      case Panel_1280x720  + 32: LCDPtr = SiS_Pr->SiS_LCD1280x720Data;      break;
+	      case Panel_1280x768_2    : LCDPtr = SiS_Pr->SiS_ExtLCD1280x768_2Data; break;
+              case Panel_1280x768_2+ 32: LCDPtr = SiS_Pr->SiS_StLCD1280x768_2Data;  break;
+	      case Panel_1280x768_3    :
+	      case Panel_1280x768_3+ 32: LCDPtr = SiS_Pr->SiS_LCD1280x768_3Data;    break;
+	      case Panel_1280x800      :
+	      case Panel_1280x800  + 32: LCDPtr = SiS_Pr->SiS_LCD1280x800Data;      break;
+	      case Panel_1280x960      :
+	      case Panel_1280x960  + 32: LCDPtr = SiS_Pr->SiS_LCD1280x960Data;      break;
+              case Panel_1280x1024     : LCDPtr = SiS_Pr->SiS_ExtLCD1280x1024Data;  break;
+              case Panel_1280x1024 + 32: LCDPtr = SiS_Pr->SiS_St2LCD1280x1024Data;  break;
+              case Panel_1400x1050     : LCDPtr = SiS_Pr->SiS_ExtLCD1400x1050Data;  break;
+              case Panel_1400x1050 + 32: LCDPtr = SiS_Pr->SiS_StLCD1400x1050Data;   break;
+              case Panel_1600x1200     : LCDPtr = SiS_Pr->SiS_ExtLCD1600x1200Data;  break;
+              case Panel_1600x1200 + 32: LCDPtr = SiS_Pr->SiS_StLCD1600x1200Data;   break;
+	      case Panel_1680x1050     :
+	      case Panel_1680x1050 + 32: LCDPtr = SiS_Pr->SiS_LCD1680x1050Data;     break;
+	      case 100		       : LCDPtr = SiS_Pr->SiS_NoScaleData;	    break;
+#ifdef SIS315H
+	      case 200                 : LCDPtr = SiS310_ExtCompaq1280x1024Data;    break;
+	      case 201                 : LCDPtr = SiS_Pr->SiS_St2LCD1280x1024Data;  break;
+#endif
+              default                  : LCDPtr = SiS_Pr->SiS_ExtLCD1024x768Data;   break;
+           }
 
 #ifdef TWDEBUG
-        xf86DrvMsg(0, X_INFO,
-    	    "GetCRT2Data: Index %d ResIndex %d\n", CRT2Index, ResIndex);
+           xf86DrvMsg(0, X_INFO, "GetCRT2Data: Index %d ResIndex %d\n", CRT2Index, ResIndex);
 #endif
 
-	if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1024x768) {
-           tempax = 1024;
+           SiS_Pr->SiS_RVBHCMAX  = (LCDPtr+ResIndex)->RVBHCMAX;
+           SiS_Pr->SiS_RVBHCFACT = (LCDPtr+ResIndex)->RVBHCFACT;
+           SiS_Pr->SiS_VGAHT     = (LCDPtr+ResIndex)->VGAHT;
+           SiS_Pr->SiS_VGAVT     = (LCDPtr+ResIndex)->VGAVT;
+           SiS_Pr->SiS_HT        = (LCDPtr+ResIndex)->LCDHT;
+           SiS_Pr->SiS_VT        = (LCDPtr+ResIndex)->LCDVT;
+
+        }
+
+	tempax = SiS_Pr->PanelXRes;
+        tempbx = SiS_Pr->PanelYRes;
+
+	if(SiS_Pr->SiS_LCDResInfo == Panel_1024x768) {
            if(SiS_Pr->SiS_SetFlag & LCDVESATiming) {
               if(HwInfo->jChipType < SIS_315H) {
                  if     (SiS_Pr->SiS_VGAVDE == 350) tempbx = 560;
                  else if(SiS_Pr->SiS_VGAVDE == 400) tempbx = 640;
-                 else                               tempbx = 768;
-              } else {
-                 tempbx = 768;
               }
            } else {
               if     (SiS_Pr->SiS_VGAVDE == 357) tempbx = 527;
@@ -3320,43 +3444,27 @@
               else if(SiS_Pr->SiS_VGAVDE == 600) tempbx = 775;
               else if(SiS_Pr->SiS_VGAVDE == 350) tempbx = 560;
               else if(SiS_Pr->SiS_VGAVDE == 400) tempbx = 640;
-              else                               tempbx = 768;
            }
-	} else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1280x1024) {
-           tempax = 1280;
-           if     (SiS_Pr->SiS_VGAVDE == 360) tempbx = 768;
-           else if(SiS_Pr->SiS_VGAVDE == 375) tempbx = 800;
-           else if(SiS_Pr->SiS_VGAVDE == 405) tempbx = 864;
-           else                               tempbx = 1024;
-        } else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1280x960) {
-           tempax = 1280;
+	} else if(SiS_Pr->SiS_LCDResInfo == Panel_1280x960) {
            if     (SiS_Pr->SiS_VGAVDE == 350)  tempbx = 700;
            else if(SiS_Pr->SiS_VGAVDE == 400)  tempbx = 800;
            else if(SiS_Pr->SiS_VGAVDE == 1024) tempbx = 960;
-           else                                tempbx = 960;
-	} else if((SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1400x1050) &&
-	          (HwInfo->jChipType >= SIS_661)) {
-	   tempax = 1400;
-	   tempbx = 1050;
-	   if(SiS_Pr->SiS_VGAVDE == 1024) {
-	      tempax = 1280;
-	      tempbx = 1024;
-	   }
-        } else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1600x1200) {
-           tempax = 1600;
-	   tempbx = 1200;
-	   if((HwInfo->jChipType < SIS_661) || (!(SiS_Pr->SiS_SetFlag & LCDVESATiming))) {
+	} else if(SiS_Pr->SiS_LCDResInfo == Panel_1280x1024) {
+           if     (SiS_Pr->SiS_VGAVDE == 360) tempbx = 768;
+           else if(SiS_Pr->SiS_VGAVDE == 375) tempbx = 800;
+           else if(SiS_Pr->SiS_VGAVDE == 405) tempbx = 864;
+        } else if(SiS_Pr->SiS_LCDResInfo == Panel_1600x1200) {
+	   if(!(SiS_Pr->SiS_SetFlag & LCDVESATiming)) {
               if     (SiS_Pr->SiS_VGAVDE == 350)  tempbx = 875;
               else if(SiS_Pr->SiS_VGAVDE == 400)  tempbx = 1000;
            }
-        } else {
-	   tempax = SiS_Pr->PanelXRes;
-           tempbx = SiS_Pr->PanelYRes;
-	}
+        }
+
         if(SiS_Pr->SiS_LCDInfo & DontExpandLCD) {
            tempax = SiS_Pr->SiS_VGAHDE;
            tempbx = SiS_Pr->SiS_VGAVDE;
         }
+
         SiS_Pr->SiS_HDE = tempax;
         SiS_Pr->SiS_VDE = tempbx;
      }
@@ -3370,31 +3478,15 @@
 
   if(SiS_Pr->SiS_VBType & VB_SISVB) {
 
-     if(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) {
-
-        if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCDA) {
-
-           SiS_GetCRT2DataLVDS(SiS_Pr, ModeNo, ModeIdIndex, RefreshRateTableIndex, HwInfo);
-
-        } else {
-
-	   if((SiS_Pr->SiS_VBType & VB_NoLCD) && (SiS_Pr->SiS_VBInfo & SetCRT2ToLCD)) {
-
-	      /* Need LVDS Data for LCD on 301B-DH */
-	      SiS_GetCRT2DataLVDS(SiS_Pr, ModeNo, ModeIdIndex, RefreshRateTableIndex, HwInfo);
-
-	   } else {
-
-	      SiS_GetCRT2Data301(SiS_Pr, ModeNo, ModeIdIndex, RefreshRateTableIndex, HwInfo);
-
-           }
-
-        }
-
+     if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCDA) {
+        SiS_GetCRT2DataLVDS(SiS_Pr, ModeNo, ModeIdIndex, RefreshRateTableIndex, HwInfo);
      } else {
-
-     	SiS_GetCRT2Data301(SiS_Pr, ModeNo, ModeIdIndex, RefreshRateTableIndex, HwInfo);
-
+	if((SiS_Pr->SiS_VBType & VB_NoLCD) && (SiS_Pr->SiS_VBInfo & SetCRT2ToLCD)) {
+	   /* Need LVDS Data for LCD on 301B-DH */
+	   SiS_GetCRT2DataLVDS(SiS_Pr, ModeNo, ModeIdIndex, RefreshRateTableIndex, HwInfo);
+	} else {
+	   SiS_GetCRT2Data301(SiS_Pr, ModeNo, ModeIdIndex, RefreshRateTableIndex, HwInfo);
+        }
      }
 
   } else {
@@ -3405,7 +3497,7 @@
 }
 
 /*********************************************/
-/*            GET LVDS DES DATA              */
+/*         GET LVDS DES (SKEW) DATA          */
 /*********************************************/
 
 static void
@@ -3413,106 +3505,55 @@
                   USHORT RefreshRateTableIndex, USHORT *PanelIndex,
 		  USHORT *ResIndex, PSIS_HW_INFO HwInfo)
 {
-  USHORT tempbx,tempal,modeflag;
+  USHORT modeflag;
 
   if(ModeNo <= 0x13) {
      modeflag = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_ModeFlag;
-     tempal = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_CRT2CRTC;
+     (*ResIndex) = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_CRT2CRTC;
   } else {
      modeflag = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag;
-     tempal = SiS_Pr->SiS_RefIndex[RefreshRateTableIndex].Ext_CRT2CRTC;
+     (*ResIndex) = SiS_Pr->SiS_RefIndex[RefreshRateTableIndex].Ext_CRT2CRTC;
   }
 
-  tempbx = 0;
+  (*ResIndex) &= 0x1F;
+  (*PanelIndex) = 0;
+
   if(SiS_Pr->SiS_IF_DEF_CH70xx != 0) {
      if(SiS_Pr->SiS_VBInfo & SetCRT2ToTV) {
-        tempbx = 50;
-        if((SiS_Pr->SiS_TVMode & TVSetPAL) && (!(SiS_Pr->SiS_TVMode & TVSetPALM))) tempbx += 2;
-        if(SiS_Pr->SiS_TVMode & TVSetCHOverScan) tempbx += 1;
+        (*PanelIndex) = 50;
+        if((SiS_Pr->SiS_TVMode & TVSetPAL) && (!(SiS_Pr->SiS_TVMode & TVSetPALM))) (*PanelIndex) += 2;
+        if(SiS_Pr->SiS_TVMode & TVSetCHOverScan) (*PanelIndex) += 1;
         /* Nothing special needed for SOverscan    */
-        /*     PALM uses NTSC data, PALN uses PAL data */
+        /* PALM uses NTSC data, PALN uses PAL data */
      }
   }
 
   if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCD) {
-     tempbx = SiS_Pr->SiS_LCDTypeInfo;
+     *PanelIndex = SiS_Pr->SiS_LCDTypeInfo;
      if(HwInfo->jChipType >= SIS_661) {
         /* As long as we don's use the BIOS tables, we
 	 * need to convert the TypeInfo as for 315 series
 	 */
-        tempbx = SiS_Pr->SiS_LCDResInfo - 1;
+        (*PanelIndex) = SiS_Pr->SiS_LCDResInfo - 1;
      }
-     if(SiS_Pr->SiS_LCDInfo & DontExpandLCD) tempbx += 16;
-     if(SiS_Pr->SiS_LCDInfo & LCDPass11) {
-        tempbx = 32;
-        if(modeflag & HalfDCLK) tempbx++;
+     if(SiS_Pr->SiS_LCDInfo & DontExpandLCD) {
+        (*PanelIndex) += 16;
+        if(SiS_Pr->SiS_LCDInfo & LCDPass11) {
+           (*PanelIndex) = 32;
+           if(modeflag & HalfDCLK) (*PanelIndex)++;
+	}
      }
   }
 
   if(SiS_Pr->SiS_SetFlag & SetDOSMode) {
-     if(SiS_Pr->SiS_LCDResInfo != SiS_Pr->SiS_Panel640x480)  {
-        tempal = 0x07;
+     if(SiS_Pr->SiS_LCDResInfo != Panel_640x480) {
+        (*ResIndex) = 7;
         if(HwInfo->jChipType < SIS_315H) {
-           if(SiS_GetReg(SiS_Pr->SiS_P3c4,0x13) & 0x80) tempal++;
+           if(SiS_GetReg(SiS_Pr->SiS_P3c4,0x13) & 0x80) (*ResIndex)++;
         }
      }
   }
-
-  *PanelIndex = tempbx;
-  *ResIndex = tempal & 0x1F;
-}
-
-#ifdef SIS315H
-static void
-SiS_GetLVDSDesPtrA(SiS_Private *SiS_Pr, USHORT ModeNo, USHORT ModeIdIndex,
-                   USHORT RefreshRateTableIndex, USHORT *PanelIndex, USHORT *ResIndex,
-		   PSIS_HW_INFO HwInfo)
-{
-  USHORT tempbx=0,tempal;
-
-  if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1400x1050)      tempbx = 2;
-  else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1600x1200) tempbx = 3;
-  else tempbx = SiS_Pr->SiS_LCDResInfo - 2;
-
-  if(SiS_Pr->SiS_LCDInfo & DontExpandLCD)  tempbx += 4;
-
-  if(SiS_Pr->SiS_CustomT == CUT_CLEVO1024) {
-     if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1024x768) {
-        if(SiS_IsDualLink(SiS_Pr, HwInfo)) {
-	   tempbx = 80;
-	   if(SiS_Pr->SiS_LCDInfo & DontExpandLCD) tempbx++;
-	}
-     }
-  }
-  if((SiS_Pr->SiS_CustomT == CUT_UNIWILL1024) ||
-     (SiS_Pr->SiS_CustomT == CUT_UNIWILL10242)) {
-     if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1024x768) {
-	tempbx = 82;
-	if(SiS_Pr->SiS_LCDInfo & DontExpandLCD) tempbx++;
-     }
-  }
-  if(SiS_Pr->SiS_CustomT == CUT_COMPAQ1280) {
-     if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1280x1024) {
-	tempbx = 84;
-	if(SiS_Pr->SiS_LCDInfo & DontExpandLCD) tempbx++;
-     }
-  }
-  if(SiS_Pr->SiS_CustomT == CUT_ASUSA2H_2) {
-     if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1024x768) {
-	tempbx = 86;
-	if(SiS_Pr->SiS_LCDInfo & DontExpandLCD) tempbx++;
-     }
-  }
-
-  if(ModeNo <= 0x13)
-     tempal = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_CRT2CRTC;
-  else
-     tempal = SiS_Pr->SiS_RefIndex[RefreshRateTableIndex].Ext_CRT2CRTC;
-
-  *PanelIndex = tempbx;
-  *ResIndex = tempal & 0x1F;
 }
-#endif
 
 static void
 SiS_GetLVDSDesData(SiS_Private *SiS_Pr, USHORT ModeNo,USHORT ModeIdIndex,
@@ -3522,39 +3563,45 @@
   USHORT PanelIndex,ResIndex;
   const  SiS_LVDSDesStruct *PanelDesPtr = NULL;
 
-  if((SiS_Pr->UseCustomMode) ||
-     (SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_PanelCustom) ||
-     (SiS_Pr->SiS_CustomT == CUT_PANEL848)) {
-     SiS_Pr->SiS_LCDHDES = 0;
-     SiS_Pr->SiS_LCDVDES = 0;
+  SiS_Pr->SiS_LCDHDES = 0;
+  SiS_Pr->SiS_LCDVDES = 0;
+
+  if( (SiS_Pr->UseCustomMode) 		         ||
+      (SiS_Pr->SiS_LCDResInfo == Panel_Custom)   ||
+      (SiS_Pr->SiS_CustomT == CUT_PANEL848)      ||
+      ((SiS_Pr->SiS_VBType & VB_SISVB) &&
+       (SiS_Pr->SiS_LCDInfo & DontExpandLCD) &&
+       (SiS_Pr->SiS_LCDInfo & LCDPass11)) ) {
      return;
   }
 
   if((SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) && (SiS_Pr->SiS_VBInfo & SetCRT2ToLCDA)) {
 
 #ifdef SIS315H
-     SiS_GetLVDSDesPtrA(SiS_Pr, ModeNo, ModeIdIndex, RefreshRateTableIndex,
-                        &PanelIndex, &ResIndex, HwInfo);
-
-     switch (PanelIndex)
-     {
-     	case  0: PanelDesPtr = SiS_Pr->LVDS1024x768Des_1;   break;  /* --- expanding --- */
-     	case  1: PanelDesPtr = SiS_Pr->LVDS1280x1024Des_1;  break;
-	case  2: PanelDesPtr = SiS_Pr->LVDS1400x1050Des_1;  break;
-	case  3: PanelDesPtr = SiS_Pr->LVDS1600x1200Des_1;  break;
-     	case  4: PanelDesPtr = SiS_Pr->LVDS1024x768Des_2;   break;  /* --- non expanding --- */
-     	case  5: PanelDesPtr = SiS_Pr->LVDS1280x1024Des_2;  break;
-	case  6: PanelDesPtr = SiS_Pr->LVDS1400x1050Des_2;  break;
-	case  7: PanelDesPtr = SiS_Pr->LVDS1600x1200Des_2;  break;
-	case 80: PanelDesPtr = (SiS_LVDSDesStruct *)Clevo1024x768Des_1;   break;  /*  custom  */
-	case 81: PanelDesPtr = (SiS_LVDSDesStruct *)Clevo1024x768Des_2;   break;
-	case 82: PanelDesPtr = (SiS_LVDSDesStruct *)Uniwill1024x768Des_1; break;
-	case 83: PanelDesPtr = (SiS_LVDSDesStruct *)Uniwill1024x768Des_2; break;
-	case 84: PanelDesPtr = (SiS_LVDSDesStruct *)Compaq1280x1024Des_1; break;
-	case 85: PanelDesPtr = (SiS_LVDSDesStruct *)Compaq1280x1024Des_2; break;
-	case 86: PanelDesPtr = (SiS_LVDSDesStruct *)Asus1024x768Des_1;    break;  /*  custom  */
-	case 87: PanelDesPtr = (SiS_LVDSDesStruct *)Asus1024x768Des_2;    break;
-	default: PanelDesPtr = SiS_Pr->LVDS1024x768Des_1;   break;
+     if(SiS_Pr->SiS_LCDInfo & DontExpandLCD) {
+        /* non-pass 1:1 only, see above */
+        if(SiS_Pr->SiS_VGAHDE != SiS_Pr->PanelXRes) {
+           SiS_Pr->SiS_LCDHDES = SiS_Pr->SiS_HT - ((SiS_Pr->PanelXRes - SiS_Pr->SiS_VGAHDE) / 2);
+	}
+	if(SiS_Pr->SiS_VGAVDE != SiS_Pr->PanelYRes) {
+	   SiS_Pr->SiS_LCDVDES = SiS_Pr->SiS_VT - ((SiS_Pr->PanelYRes - SiS_Pr->SiS_VGAVDE) / 2);
+	}
+     }
+     if(SiS_Pr->SiS_VGAVDE == SiS_Pr->PanelYRes) {
+        switch(SiS_Pr->SiS_CustomT) {
+        case CUT_UNIWILL1024:
+        case CUT_UNIWILL10242:
+        case CUT_CLEVO1400:
+	   if(SiS_Pr->SiS_LCDResInfo == Panel_1024x768) {
+	      SiS_Pr->SiS_LCDVDES = SiS_Pr->PanelVT - 1;
+	   }
+	   break;
+	}
+	if(SiS_Pr->SiS_LCDResInfo == Panel_1280x1024) {
+	   if(SiS_Pr->SiS_CustomT != CUT_COMPAQ1280) {
+	      SiS_Pr->SiS_LCDVDES = SiS_Pr->PanelVT - 1;
+	   }
+	}
      }
 #endif
 
@@ -3563,87 +3610,68 @@
      SiS_GetLVDSDesPtr(SiS_Pr, ModeNo, ModeIdIndex, RefreshRateTableIndex,
                        &PanelIndex, &ResIndex, HwInfo);
 
-     switch (PanelIndex)
-     {
-     	case  0: PanelDesPtr = SiS_Pr->SiS_PanelType00_1;   break;   /* ---  */
-     	case  1: PanelDesPtr = SiS_Pr->SiS_PanelType01_1;   break;
-     	case  2: PanelDesPtr = SiS_Pr->SiS_PanelType02_1;   break;
-     	case  3: PanelDesPtr = SiS_Pr->SiS_PanelType03_1;   break;
-     	case  4: PanelDesPtr = SiS_Pr->SiS_PanelType04_1;   break;
-     	case  5: PanelDesPtr = SiS_Pr->SiS_PanelType05_1;   break;
-     	case  6: PanelDesPtr = SiS_Pr->SiS_PanelType06_1;   break;
-     	case  7: PanelDesPtr = SiS_Pr->SiS_PanelType07_1;   break;
-     	case  8: PanelDesPtr = SiS_Pr->SiS_PanelType08_1;   break;
-     	case  9: PanelDesPtr = SiS_Pr->SiS_PanelType09_1;   break;
-     	case 10: PanelDesPtr = SiS_Pr->SiS_PanelType0a_1;   break;
-     	case 11: PanelDesPtr = SiS_Pr->SiS_PanelType0b_1;   break;
-     	case 12: PanelDesPtr = SiS_Pr->SiS_PanelType0c_1;   break;
-     	case 13: PanelDesPtr = SiS_Pr->SiS_PanelType0d_1;   break;
-     	case 14: PanelDesPtr = SiS_Pr->SiS_PanelType0e_1;   break;
-     	case 15: PanelDesPtr = SiS_Pr->SiS_PanelType0f_1;   break;
-     	case 16: PanelDesPtr = SiS_Pr->SiS_PanelType00_2;   break;    /* --- */
-     	case 17: PanelDesPtr = SiS_Pr->SiS_PanelType01_2;   break;
-     	case 18: PanelDesPtr = SiS_Pr->SiS_PanelType02_2;   break;
-     	case 19: PanelDesPtr = SiS_Pr->SiS_PanelType03_2;   break;
-     	case 20: PanelDesPtr = SiS_Pr->SiS_PanelType04_2;   break;
-     	case 21: PanelDesPtr = SiS_Pr->SiS_PanelType05_2;   break;
-     	case 22: PanelDesPtr = SiS_Pr->SiS_PanelType06_2;   break;
-     	case 23: PanelDesPtr = SiS_Pr->SiS_PanelType07_2;   break;
-     	case 24: PanelDesPtr = SiS_Pr->SiS_PanelType08_2;   break;
-     	case 25: PanelDesPtr = SiS_Pr->SiS_PanelType09_2;   break;
-     	case 26: PanelDesPtr = SiS_Pr->SiS_PanelType0a_2;   break;
-     	case 27: PanelDesPtr = SiS_Pr->SiS_PanelType0b_2;   break;
-     	case 28: PanelDesPtr = SiS_Pr->SiS_PanelType0c_2;   break;
-     	case 29: PanelDesPtr = SiS_Pr->SiS_PanelType0d_2;   break;
-     	case 30: PanelDesPtr = SiS_Pr->SiS_PanelType0e_2;   break;
-     	case 31: PanelDesPtr = SiS_Pr->SiS_PanelType0f_2;   break;
-	case 32: PanelDesPtr = SiS_Pr->SiS_PanelTypeNS_1;   break;    /* pass 1:1 */
-	case 33: PanelDesPtr = SiS_Pr->SiS_PanelTypeNS_2;   break;
-     	case 50: PanelDesPtr = SiS_Pr->SiS_CHTVUNTSCDesData;   break; /* TV */
-     	case 51: PanelDesPtr = SiS_Pr->SiS_CHTVONTSCDesData;   break;
-     	case 52: PanelDesPtr = SiS_Pr->SiS_CHTVUPALDesData;    break;
-     	case 53: PanelDesPtr = SiS_Pr->SiS_CHTVOPALDesData;    break;
-	default:
-		 if(HwInfo->jChipType < SIS_315H)
-		    PanelDesPtr = SiS_Pr->SiS_PanelType0e_1;
-		 else
-		    PanelDesPtr = SiS_Pr->SiS_PanelType01_1;
-		 break;
-     }
-  }
-  SiS_Pr->SiS_LCDHDES = (PanelDesPtr+ResIndex)->LCDHDES;
-  SiS_Pr->SiS_LCDVDES = (PanelDesPtr+ResIndex)->LCDVDES;
-
-  if(SiS_Pr->SiS_LCDInfo & DontExpandLCD){
-     if((SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) && (SiS_Pr->SiS_VBInfo & SetCRT2ToLCDA)) {
-        if(ModeNo <= 0x13) {
-           modeflag = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_ModeFlag;
-	   if(!(modeflag & HalfDCLK)) {
-	      SiS_Pr->SiS_LCDHDES = 632;
-	   }
-        }
-     } else {
-        if(!(SiS_Pr->SiS_SetFlag & SetDOSMode)) {
-           if(SiS_Pr->SiS_LCDResInfo != SiS_Pr->SiS_Panel1280x1024) {
-              if(SiS_Pr->SiS_LCDResInfo >= SiS_Pr->SiS_Panel1024x768) {
-                 if(ModeNo <= 0x13) {
-	            modeflag = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_ModeFlag;
-	            if(HwInfo->jChipType < SIS_315H) {
-	               if(!(modeflag & HalfDCLK)) SiS_Pr->SiS_LCDHDES = 320;
-	            } else {
-	               if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1024x768)
-	                  SiS_Pr->SiS_LCDHDES = 480;
-                       if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1400x1050)
-	                  SiS_Pr->SiS_LCDHDES = 804;
-		       if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1600x1200)
-	                  SiS_Pr->SiS_LCDHDES = 704;
-                       if(!(modeflag & HalfDCLK)) {
-                          SiS_Pr->SiS_LCDHDES = 320;
-	                  if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1400x1050)
-	                     SiS_Pr->SiS_LCDHDES = 632;
-		          else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1600x1200)
-	                     SiS_Pr->SiS_LCDHDES = 542;
-                       }
+     switch(PanelIndex) {
+     	case  0: PanelDesPtr = SiS_Pr->SiS_PanelType00_1;    break;   /* ---  */
+     	case  1: PanelDesPtr = SiS_Pr->SiS_PanelType01_1;    break;
+     	case  2: PanelDesPtr = SiS_Pr->SiS_PanelType02_1;    break;
+     	case  3: PanelDesPtr = SiS_Pr->SiS_PanelType03_1;    break;
+     	case  4: PanelDesPtr = SiS_Pr->SiS_PanelType04_1;    break;
+     	case  5: PanelDesPtr = SiS_Pr->SiS_PanelType05_1;    break;
+     	case  6: PanelDesPtr = SiS_Pr->SiS_PanelType06_1;    break;
+     	case  7: PanelDesPtr = SiS_Pr->SiS_PanelType07_1;    break;
+     	case  8: PanelDesPtr = SiS_Pr->SiS_PanelType08_1;    break;
+     	case  9: PanelDesPtr = SiS_Pr->SiS_PanelType09_1;    break;
+     	case 10: PanelDesPtr = SiS_Pr->SiS_PanelType0a_1;    break;
+     	case 11: PanelDesPtr = SiS_Pr->SiS_PanelType0b_1;    break;
+     	case 12: PanelDesPtr = SiS_Pr->SiS_PanelType0c_1;    break;
+     	case 13: PanelDesPtr = SiS_Pr->SiS_PanelType0d_1;    break;
+     	case 14: PanelDesPtr = SiS_Pr->SiS_PanelType0e_1;    break;
+     	case 15: PanelDesPtr = SiS_Pr->SiS_PanelType0f_1;    break;
+     	case 16: PanelDesPtr = SiS_Pr->SiS_PanelType00_2;    break;    /* --- */
+     	case 17: PanelDesPtr = SiS_Pr->SiS_PanelType01_2;    break;
+     	case 18: PanelDesPtr = SiS_Pr->SiS_PanelType02_2;    break;
+     	case 19: PanelDesPtr = SiS_Pr->SiS_PanelType03_2;    break;
+     	case 20: PanelDesPtr = SiS_Pr->SiS_PanelType04_2;    break;
+     	case 21: PanelDesPtr = SiS_Pr->SiS_PanelType05_2;    break;
+     	case 22: PanelDesPtr = SiS_Pr->SiS_PanelType06_2;    break;
+     	case 23: PanelDesPtr = SiS_Pr->SiS_PanelType07_2;    break;
+     	case 24: PanelDesPtr = SiS_Pr->SiS_PanelType08_2;    break;
+     	case 25: PanelDesPtr = SiS_Pr->SiS_PanelType09_2;    break;
+     	case 26: PanelDesPtr = SiS_Pr->SiS_PanelType0a_2;    break;
+     	case 27: PanelDesPtr = SiS_Pr->SiS_PanelType0b_2;    break;
+     	case 28: PanelDesPtr = SiS_Pr->SiS_PanelType0c_2;    break;
+     	case 29: PanelDesPtr = SiS_Pr->SiS_PanelType0d_2;    break;
+     	case 30: PanelDesPtr = SiS_Pr->SiS_PanelType0e_2;    break;
+     	case 31: PanelDesPtr = SiS_Pr->SiS_PanelType0f_2;    break;
+	case 32: PanelDesPtr = SiS_Pr->SiS_PanelTypeNS_1;    break;    /* pass 1:1 */
+	case 33: PanelDesPtr = SiS_Pr->SiS_PanelTypeNS_2;    break;
+     	case 50: PanelDesPtr = SiS_Pr->SiS_CHTVUNTSCDesData; break;    /* TV */
+     	case 51: PanelDesPtr = SiS_Pr->SiS_CHTVONTSCDesData; break;
+     	case 52: PanelDesPtr = SiS_Pr->SiS_CHTVUPALDesData;  break;
+     	case 53: PanelDesPtr = SiS_Pr->SiS_CHTVOPALDesData;  break;
+	default: return;
+     }
+
+     SiS_Pr->SiS_LCDHDES = (PanelDesPtr+ResIndex)->LCDHDES;
+     SiS_Pr->SiS_LCDVDES = (PanelDesPtr+ResIndex)->LCDVDES;
+
+     if((ModeNo <= 0x13) && (SiS_Pr->SiS_LCDInfo & DontExpandLCD)) {
+        modeflag = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_ModeFlag;
+        if((SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) && (SiS_Pr->SiS_VBInfo & SetCRT2ToLCDA)) {
+	   if(!(modeflag & HalfDCLK)) SiS_Pr->SiS_LCDHDES = 632;
+        } else if(!(SiS_Pr->SiS_SetFlag & SetDOSMode)) {
+           if(SiS_Pr->SiS_LCDResInfo != Panel_1280x1024) {
+              if(SiS_Pr->SiS_LCDResInfo >= Panel_1024x768) {
+	         if(HwInfo->jChipType < SIS_315H) {
+	            if(!(modeflag & HalfDCLK)) SiS_Pr->SiS_LCDHDES = 320;
+	         } else {
+	            if(SiS_Pr->SiS_LCDResInfo == Panel_1024x768)  SiS_Pr->SiS_LCDHDES = 480;
+                    if(SiS_Pr->SiS_LCDResInfo == Panel_1400x1050) SiS_Pr->SiS_LCDHDES = 804;
+		    if(SiS_Pr->SiS_LCDResInfo == Panel_1600x1200) SiS_Pr->SiS_LCDHDES = 704;
+                    if(!(modeflag & HalfDCLK)) {
+                       SiS_Pr->SiS_LCDHDES = 320;
+	               if(SiS_Pr->SiS_LCDResInfo == Panel_1400x1050) SiS_Pr->SiS_LCDHDES = 632;
+		       if(SiS_Pr->SiS_LCDResInfo == Panel_1600x1200) SiS_Pr->SiS_LCDHDES = 542;
                     }
                  }
               }
@@ -3654,18 +3682,6 @@
 }
 
 /*********************************************/
-/*          SET CRT2 AUTO-THRESHOLD          */
-/*********************************************/
-
-#ifdef SIS315H
-static void
-SiS_CRT2AutoThreshold(SiS_Private *SiS_Pr)
-{
-  SiS_SetRegOR(SiS_Pr->SiS_Part1Port,0x01,0x40);
-}
-#endif
-
-/*********************************************/
 /*           DISABLE VIDEO BRIDGE            */
 /*********************************************/
 
@@ -3683,55 +3699,40 @@
 
   if(SiS_Pr->SiS_VBType & VB_SISVB) {
 
-      if(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) {   /* ===== For 30xB/LV ===== */
+     if(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) {   /* ===== For 30xB/LV ===== */
 
         if(HwInfo->jChipType < SIS_315H) {
 
 #ifdef SIS300	   /* 300 series */
 
-           if(HwInfo->jChipType == SIS_300) {  /* For 300+301LV (A907) */
-
-	      if(!(SiS_CR36BIOSWord23b(SiS_Pr,HwInfo))) {
-	         if(SiS_Pr->SiS_VBType & VB_SIS301LV302LV) {
-	            SiS_SetRegAND(SiS_Pr->SiS_Part4Port,0x26,0xFE);
-		    SiS_PanelDelay(SiS_Pr, HwInfo, 3);
-		 }
+	   if(!(SiS_CR36BIOSWord23b(SiS_Pr,HwInfo))) {
+	      if(SiS_Pr->SiS_VBType & VB_SIS301LV302LV) {
+	         SiS_SetRegAND(SiS_Pr->SiS_Part4Port,0x26,0xFE);
+	      } else {
+		 SiS_SetRegSR11ANDOR(SiS_Pr,HwInfo,0xF7,0x08);
 	      }
+	      SiS_PanelDelay(SiS_Pr, HwInfo, 3);
+	   }
+	   if(SiS_Is301B(SiS_Pr)) {
 	      SiS_SetRegAND(SiS_Pr->SiS_Part4Port,0x1f,0x3f);
 	      SiS_ShortDelay(SiS_Pr,1);
-	      SiS_SetRegAND(SiS_Pr->SiS_Part2Port,0x00,0xDF);
-	      SiS_DisplayOff(SiS_Pr);
-	      SiS_SetRegAND(SiS_Pr->SiS_P3c4,0x32,0xDF);
-	      SiS_SetRegAND(SiS_Pr->SiS_P3c4,0x1E,0xDF);
-	      if(SiS_Pr->SiS_VBType & VB_SIS301LV302LV) {
-	         if( (!(SiS_CRT2IsLCD(SiS_Pr, HwInfo))) ||
-	             (!(SiS_CR36BIOSWord23d(SiS_Pr, HwInfo))) ) {
-	            SiS_PanelDelay(SiS_Pr, HwInfo, 2);
-                    SiS_SetRegAND(SiS_Pr->SiS_Part4Port,0x26,0xFD);
-		 }
-	      }
-
-	   } else {
-
-	      if(!(SiS_CR36BIOSWord23b(SiS_Pr,HwInfo))) {
-	         SiS_SetRegSR11ANDOR(SiS_Pr,HwInfo,0xF7,0x08);
-	         SiS_PanelDelay(SiS_Pr, HwInfo, 3);
-	      }
-	      if(SiS_Is301B(SiS_Pr)) {
-	         SiS_SetRegAND(SiS_Pr->SiS_Part4Port,0x1f,0x3f);
-	         SiS_ShortDelay(SiS_Pr,1);
-	      }
-	      SiS_SetRegAND(SiS_Pr->SiS_Part2Port,0x00,0xDF);
-	      SiS_DisplayOff(SiS_Pr);
-	      SiS_SetRegAND(SiS_Pr->SiS_P3c4,0x32,0xDF);
-	      SiS_SetRegAND(SiS_Pr->SiS_P3c4,0x1E,0xDF);
-	      SiS_UnLockCRT2(SiS_Pr,HwInfo);
+           }
+	   SiS_SetRegAND(SiS_Pr->SiS_Part2Port,0x00,0xDF);
+	   SiS_DisplayOff(SiS_Pr);
+	   SiS_SetRegAND(SiS_Pr->SiS_P3c4,0x32,0xDF);
+	   SiS_SetRegAND(SiS_Pr->SiS_P3c4,0x1E,0xDF);
+	   SiS_UnLockCRT2(SiS_Pr,HwInfo);
+	   if(!(SiS_Pr->SiS_VBType & VB_SIS301LV302LV)) {
 	      SiS_SetRegOR(SiS_Pr->SiS_Part1Port,0x01,0x80);
 	      SiS_SetRegOR(SiS_Pr->SiS_Part1Port,0x02,0x40);
-	      if( (!(SiS_CRT2IsLCD(SiS_Pr, HwInfo))) ||
-	          (!(SiS_CR36BIOSWord23d(SiS_Pr, HwInfo))) ) {
-	         SiS_PanelDelay(SiS_Pr, HwInfo, 2);
-                 SiS_SetRegSR11ANDOR(SiS_Pr,HwInfo,0xFB,0x04);
+	   }
+	   if( (!(SiS_CRT2IsLCD(SiS_Pr, HwInfo))) ||
+	       (!(SiS_CR36BIOSWord23d(SiS_Pr, HwInfo))) ) {
+	      SiS_PanelDelay(SiS_Pr, HwInfo, 2);
+	      if(SiS_Pr->SiS_VBType & VB_SIS301LV302LV) {
+                 SiS_SetRegAND(SiS_Pr->SiS_Part4Port,0x26,0xFD);
+	      } else {
+		 SiS_SetRegSR11ANDOR(SiS_Pr,HwInfo,0xFB,0x04);
 	      }
 	   }
 
@@ -3741,149 +3742,99 @@
 
 #ifdef SIS315H	   /* 315 series */
 
-           if(IS_SIS550650740660) {		/* 550, 650, 740, 660 */
+	   BOOLEAN custom1 = ((SiS_Pr->SiS_CustomT == CUT_COMPAQ1280) ||
+	                      (SiS_Pr->SiS_CustomT == CUT_CLEVO1400)) ? TRUE : FALSE;
+
+	   modenum = SiS_GetReg(SiS_Pr->SiS_P3d4,0x34) & 0x7f;
 
-	      modenum = SiS_GetReg(SiS_Pr->SiS_P3d4,0x34) & 0x7f;
+           if(SiS_Pr->SiS_VBType & VB_SIS301LV302LV) {
 
-              if(SiS_Pr->SiS_VBType & VB_SIS301LV302LV) {			/* LV */
 #ifdef SET_EMI
-	         if(SiS_Pr->SiS_VBType & (VB_SIS302LV | VB_SIS302ELV)) {
-		    if(SiS_Pr->SiS_CustomT != CUT_CLEVO1400) {
-	               SiS_SetRegAND(SiS_Pr->SiS_Part4Port,0x30,0x0c);
-		    }
+	      if(SiS_Pr->SiS_VBType & (VB_SIS302LV | VB_SIS302ELV)) {
+		 if(SiS_Pr->SiS_CustomT != CUT_CLEVO1400) {
+	            SiS_SetRegAND(SiS_Pr->SiS_Part4Port,0x30,0x0c);
 		 }
+	      }
 #endif
-		 if( (modenum <= 0x13) ||
-		     (!(SiS_IsDualEdge(SiS_Pr,HwInfo))) ||
-		     (SiS_IsVAMode(SiS_Pr,HwInfo)) ) {
-	     	    SiS_SetRegAND(SiS_Pr->SiS_Part4Port,0x26,0xFE);
-		    if((SiS_Pr->SiS_CustomT == CUT_COMPAQ1280) ||
-		       (SiS_Pr->SiS_CustomT == CUT_CLEVO1400)) {
-		       SiS_PanelDelay(SiS_Pr, HwInfo, 3);
-		    }
-	         }
+	      if( (modenum <= 0x13)                  ||
+		  (SiS_IsVAMode(SiS_Pr,HwInfo))      ||
+		  (!(SiS_IsDualEdge(SiS_Pr,HwInfo))) ) {
+	     	 SiS_SetRegAND(SiS_Pr->SiS_Part4Port,0x26,0xFE);
+		 if(custom1) SiS_PanelDelay(SiS_Pr, HwInfo, 3);
+	      }
 
-		 if((SiS_Pr->SiS_CustomT != CUT_COMPAQ1280) &&
-		    (SiS_Pr->SiS_CustomT != CUT_CLEVO1400)) {
-		    SiS_DDC2Delay(SiS_Pr,0xff00);
-		    SiS_DDC2Delay(SiS_Pr,0xe000);
+	      if(!custom1) {
+		 SiS_DDC2Delay(SiS_Pr,0xff00);
+		 SiS_DDC2Delay(SiS_Pr,0xe000);
+	         SiS_SetRegByte(SiS_Pr->SiS_P3c6,0x00);
+                 pushax = SiS_GetReg(SiS_Pr->SiS_P3c4,0x06);
+		 if(IS_SIS740) {
+		    SiS_SetRegAND(SiS_Pr->SiS_P3c4,0x06,0xE3);
+		 }
+	         SiS_PanelDelay(SiS_Pr, HwInfo, 3);
+	      }
 
-	            SiS_SetRegByte(SiS_Pr->SiS_P3c6,0x00);
+           }
 
-                    pushax = SiS_GetReg(SiS_Pr->SiS_P3c4,0x06);
+	   if(!(SiS_IsNotM650orLater(SiS_Pr, HwInfo))) {
+	      tempah = 0xef;
+	      if(SiS_IsVAMode(SiS_Pr,HwInfo)) tempah = 0xf7;
+	      SiS_SetRegAND(SiS_Pr->SiS_Part1Port,0x4c,tempah);
+	   }
 
-		    if(IS_SIS740) {
-		       SiS_SetRegAND(SiS_Pr->SiS_P3c4,0x06,0xE3);
-		    }
+	   if(SiS_Pr->SiS_VBType & VB_SIS301LV302LV) {
+	      SiS_SetRegAND(SiS_Pr->SiS_Part4Port,0x1F,~0x10);
+	   }
 
-	            SiS_PanelDelay(SiS_Pr, HwInfo, 3);
+	   tempah = 0x3f;
+	   if(SiS_IsDualEdge(SiS_Pr,HwInfo)) {
+	      tempah = 0x7f;
+	      if(!(SiS_IsVAMode(SiS_Pr,HwInfo))) tempah = 0xbf;
+	   }
+	   SiS_SetRegAND(SiS_Pr->SiS_Part4Port,0x1F,tempah);
 
-		    if(!(SiS_IsNotM650orLater(SiS_Pr, HwInfo))) {
-	               tempah = 0xef;
-	               if(SiS_IsVAMode(SiS_Pr,HwInfo)) {
-	                  tempah = 0xf7;
-                       }
-	               SiS_SetRegAND(SiS_Pr->SiS_Part1Port,0x4c,tempah);
-	            }
-		 }
+           if((SiS_IsVAMode(SiS_Pr,HwInfo)) ||
+	      ((SiS_Pr->SiS_VBType & VB_SIS301LV302LV) && (modenum <= 0x13))) {
 
-              } else if(SiS_Pr->SiS_VBType & VB_NoLCD) {			/* B-DH */
+	      SiS_DisplayOff(SiS_Pr);
+	      if(SiS_Pr->SiS_VBType & VB_SIS301LV302LV) {
+		 SiS_PanelDelay(SiS_Pr, HwInfo, 2);
+	      }
+	      SiS_SetRegAND(SiS_Pr->SiS_P3c4,0x32,0xDF);
+	      SiS_SetRegAND(SiS_Pr->SiS_Part1Port,0x1E,0xDF);
 
-	         if(!(SiS_IsNotM650orLater(SiS_Pr,HwInfo))) {
-	            SiS_SetRegAND(SiS_Pr->SiS_Part1Port,0x4c,0xef);
-	         }
+	   }
 
-	      }
+	   if((!(SiS_IsVAMode(SiS_Pr,HwInfo))) ||
+	      ((SiS_Pr->SiS_VBType & VB_SIS301LV302LV) && (modenum <= 0x13))) {
 
-	      if((SiS_Pr->SiS_CustomT == CUT_COMPAQ1280) ||
-	         (SiS_Pr->SiS_CustomT == CUT_CLEVO1400)) {
-	         SiS_SetRegAND(SiS_Pr->SiS_Part4Port,0x1F,0xef);
+	      if(!(SiS_IsDualEdge(SiS_Pr,HwInfo))) {
+		 SiS_SetRegAND(SiS_Pr->SiS_Part2Port,0x00,0xdf);
+		 SiS_DisplayOff(SiS_Pr);
 	      }
+	      SiS_SetRegOR(SiS_Pr->SiS_Part1Port,0x00,0x80);
 
-              if((SiS_Pr->SiS_VBType & VB_SIS301B302B) ||
-	         (SiS_Pr->SiS_CustomT == CUT_COMPAQ1280) ||
-		 (SiS_Pr->SiS_CustomT == CUT_CLEVO1400)) {
-	         tempah = 0x3f;
-	         if(SiS_IsDualEdge(SiS_Pr,HwInfo)) {
-	            tempah = 0x7f;
-	            if(!(SiS_IsVAMode(SiS_Pr,HwInfo))) {
-		       tempah = 0xbf;
-                    }
-	         }
-	         SiS_SetRegAND(SiS_Pr->SiS_Part4Port,0x1F,tempah);
+	      if(SiS_Pr->SiS_VBType & VB_SIS301LV302LV) {
+		 SiS_PanelDelay(SiS_Pr, HwInfo, 2);
 	      }
 
-              if((SiS_IsVAMode(SiS_Pr,HwInfo)) ||
-	         ((SiS_Pr->SiS_VBType & VB_SIS301LV302LV) && (modenum <= 0x13))) {
-
-	         if((SiS_Pr->SiS_VBType & VB_SIS301B302B) ||
-		    (SiS_Pr->SiS_CustomT == CUT_COMPAQ1280) ||
-		    (SiS_Pr->SiS_CustomT == CUT_CLEVO1400)) {
-		    SiS_SetRegAND(SiS_Pr->SiS_Part1Port,0x1E,0xDF);
-		    SiS_DisplayOff(SiS_Pr);
-		    SiS_SetRegAND(SiS_Pr->SiS_P3c4,0x32,0xDF);
-		 } else {
-	            SiS_DisplayOff(SiS_Pr);
-	            SiS_PanelDelay(SiS_Pr, HwInfo, 2);
-	            SiS_SetRegAND(SiS_Pr->SiS_P3c4,0x32,0xDF);
-	            SiS_SetRegAND(SiS_Pr->SiS_Part1Port,0x1E,0xDF);
-		    if((SiS_Pr->SiS_VBType & VB_SIS301LV302LV) && (modenum <= 0x13)) {
-		       SiS_DisplayOff(SiS_Pr);
-	               SiS_SetRegOR(SiS_Pr->SiS_Part1Port,0x00,0x80);
-	               SiS_PanelDelay(SiS_Pr, HwInfo, 2);
-	               SiS_SetRegAND(SiS_Pr->SiS_P3c4,0x32,0xDF);
-	               temp = SiS_GetReg(SiS_Pr->SiS_Part1Port,0x00);
-                       SiS_SetRegOR(SiS_Pr->SiS_Part1Port,0x00,0x10);
-	               SiS_SetRegAND(SiS_Pr->SiS_P3c4,0x1E,0xDF);
-	               SiS_SetReg(SiS_Pr->SiS_Part1Port,0x00,temp);
-		    }
-		 }
-
-	      } else {
-
-	         if((SiS_Pr->SiS_VBType & VB_SIS301B302B) ||
-		    (SiS_Pr->SiS_CustomT == CUT_COMPAQ1280) ||
-		    (SiS_Pr->SiS_CustomT == CUT_CLEVO1400)) {
-		    if(!(SiS_IsDualEdge(SiS_Pr,HwInfo))) {
-		       SiS_SetRegAND(SiS_Pr->SiS_Part2Port,0x00,0xdf);
-		       SiS_DisplayOff(SiS_Pr);
-		    }
-		    SiS_SetRegOR(SiS_Pr->SiS_Part1Port,0x00,0x80);
-		 } else {
-                    SiS_DisplayOff(SiS_Pr);
-	            SiS_SetRegOR(SiS_Pr->SiS_Part1Port,0x00,0x80);
-	            SiS_PanelDelay(SiS_Pr, HwInfo, 2);
-		 }
-
-		 SiS_SetRegAND(SiS_Pr->SiS_P3c4,0x32,0xDF);
-	         temp = SiS_GetReg(SiS_Pr->SiS_Part1Port,0x00);
-                 SiS_SetRegOR(SiS_Pr->SiS_Part1Port,0x00,0x10);
-	         SiS_SetRegAND(SiS_Pr->SiS_P3c4,0x1E,0xDF);
-	         SiS_SetReg(SiS_Pr->SiS_Part1Port,0x00,temp);
-
-	      }
+	      SiS_SetRegAND(SiS_Pr->SiS_P3c4,0x32,0xDF);
+	      temp = SiS_GetReg(SiS_Pr->SiS_Part1Port,0x00);
+              SiS_SetRegOR(SiS_Pr->SiS_Part1Port,0x00,0x10);
+	      SiS_SetRegAND(SiS_Pr->SiS_P3c4,0x1E,0xDF);
+	      SiS_SetReg(SiS_Pr->SiS_Part1Port,0x00,temp);
 
-	      if((SiS_Pr->SiS_VBType & VB_SIS301LV302LV) &&
-	         (SiS_Pr->SiS_CustomT != CUT_COMPAQ1280) &&
-		 (SiS_Pr->SiS_CustomT != CUT_CLEVO1400)) {
+	   }
 
-		 SiS_SetRegAND(SiS_Pr->SiS_Part4Port,0x1f,~0x10);
+	   if(SiS_IsNotM650orLater(SiS_Pr,HwInfo)) {
+	      SiS_SetRegAND(SiS_Pr->SiS_Part1Port,0x2e,0x7f);
+	   }
 
-	         tempah = 0x3f;
-	         if(SiS_IsDualEdge(SiS_Pr,HwInfo)) {
-	            tempah = 0x7f;
-	            if(!(SiS_IsVAMode(SiS_Pr,HwInfo))) {
-		       tempah = 0xbf;
-                    }
-	         }
-	         SiS_SetRegAND(SiS_Pr->SiS_Part4Port,0x1F,tempah);
+	   if(SiS_Pr->SiS_VBType & VB_SIS301LV302LV) {
 
-		 if(SiS_IsNotM650orLater(SiS_Pr,HwInfo)) {
-	            SiS_SetRegAND(SiS_Pr->SiS_Part1Port,0x2e,0x7f);
-		 }
+	      if(!custom1) {
 
 	         if(!(SiS_IsVAMode(SiS_Pr,HwInfo))) {
-	            SiS_SetRegAND(SiS_Pr->SiS_Part2Port,0x00,0xdf);
 	            if(!(SiS_CRT2IsLCD(SiS_Pr,HwInfo))) {
 	               if(!(SiS_IsDualEdge(SiS_Pr,HwInfo))) {
 		          SiS_SetRegAND(SiS_Pr->SiS_Part4Port,0x26,0xFD);
@@ -3894,95 +3845,39 @@
 	         SiS_SetReg(SiS_Pr->SiS_P3c4,0x06,pushax);
 
 		 if(SiS_Pr->SiS_VBType & (VB_SIS302LV | VB_SIS302ELV)) {
-	            if( (SiS_IsVAMode(SiS_Pr, HwInfo)) ||
-	                (SiS_CRT2IsLCD(SiS_Pr, HwInfo)) ) {
+	            if(SiS_IsVAorLCD(SiS_Pr, HwInfo)) {
 		       SiS_PanelDelayLoop(SiS_Pr, HwInfo, 3, 20);
 		    }
 	         }
 
-  	      } else if(SiS_Pr->SiS_VBType & VB_NoLCD) {
-
-	         /* NIL */
+	      } else {
 
-	      } else if((SiS_Pr->SiS_VBType & VB_SIS301B302B) ||
-	                (SiS_Pr->SiS_CustomT == CUT_COMPAQ1280) ||
-			(SiS_Pr->SiS_CustomT == CUT_CLEVO1400)) {
-
-		 if(!(SiS_IsNotM650orLater(SiS_Pr,HwInfo))) {
-	            tempah = 0xef;
-	            if(SiS_IsDualEdge(SiS_Pr,HwInfo)) {
-		       if(modenum > 0x13) {
-	                  tempah = 0xf7;
-		       }
-                    }
-	            SiS_SetRegAND(SiS_Pr->SiS_Part1Port,0x4c,tempah);
-		 }
-		 if((SiS_Pr->SiS_CustomT == CUT_COMPAQ1280) ||
-		    (SiS_Pr->SiS_CustomT == CUT_CLEVO1400)) {
-		    if((SiS_IsVAMode(SiS_Pr,HwInfo)) ||
-		       (!(SiS_IsDualEdge(SiS_Pr,HwInfo)))) {
-		       if((!(SiS_WeHaveBacklightCtrl(SiS_Pr, HwInfo))) ||
-		          (!(SiS_CRT2IsLCD(SiS_Pr, HwInfo)))) {
-			  SiS_PanelDelay(SiS_Pr, HwInfo, 2);
-	     	          SiS_SetRegAND(SiS_Pr->SiS_Part4Port,0x26,0xFD);
-			  SiS_PanelDelay(SiS_Pr, HwInfo, 4);
-	               }
+		 if((SiS_IsVAMode(SiS_Pr,HwInfo)) ||
+		    (!(SiS_IsDualEdge(SiS_Pr,HwInfo)))) {
+		    if((!(SiS_WeHaveBacklightCtrl(SiS_Pr, HwInfo))) ||
+		       (!(SiS_CRT2IsLCD(SiS_Pr, HwInfo)))) {
+		       SiS_PanelDelay(SiS_Pr, HwInfo, 2);
+	     	       SiS_SetRegAND(SiS_Pr->SiS_Part4Port,0x26,0xFD);
+		       SiS_PanelDelay(SiS_Pr, HwInfo, 4);
 		    }
 		 }
 
 	      }
-
-	  } else {			/* 315, 330 - all bridge types */
-
-	     if(SiS_Is301B(SiS_Pr)) {
-	        tempah = 0x3f;
-	        if(SiS_IsDualEdge(SiS_Pr,HwInfo)) {
-	           tempah = 0x7f;
-	           if(!(SiS_IsVAMode(SiS_Pr,HwInfo))) {
-		      tempah = 0xbf;
-                   }
-	        }
-	        SiS_SetRegAND(SiS_Pr->SiS_Part4Port,0x1F,tempah);
-	        if(SiS_IsVAMode(SiS_Pr,HwInfo)) {
-	           SiS_DisplayOff(SiS_Pr);
-		   SiS_SetRegAND(SiS_Pr->SiS_P3c4,0x32,0xDF);
-	        }
-	     }
-	     if( (!(SiS_Is301B(SiS_Pr))) ||
-	         (!(SiS_IsVAMode(SiS_Pr,HwInfo))) ) {
-
- 	 	if( (!(SiS_Is301B(SiS_Pr))) ||
-		    (!(SiS_IsDualEdge(SiS_Pr,HwInfo))) ) {
-
-	           SiS_SetRegAND(SiS_Pr->SiS_Part2Port,0x00,0xDF);
-	           SiS_DisplayOff(SiS_Pr);
-
-		}
-
-                SiS_SetRegOR(SiS_Pr->SiS_Part1Port,0x00,0x80);
-
-                SiS_SetRegAND(SiS_Pr->SiS_P3c4,0x32,0xDF);
-
-	        temp = SiS_GetReg(SiS_Pr->SiS_Part1Port,0x00);
-                SiS_SetRegOR(SiS_Pr->SiS_Part1Port,0x00,0x10);
-	        SiS_SetRegAND(SiS_Pr->SiS_P3c4,0x1E,0xDF);
-	        SiS_SetReg(SiS_Pr->SiS_Part1Port,0x00,temp);
-
-	     }
-
-	  }    /* 315/330 */
+           }
 
 #endif /* SIS315H */
 
 	}
 
-      } else {     /* ============ For 301 ================ */
+     } else {     /* ============ For 301 ================ */
 
         if(HwInfo->jChipType < SIS_315H) {
+#ifdef SIS300
            if(!(SiS_CR36BIOSWord23b(SiS_Pr,HwInfo))) {
 	      SiS_SetRegSR11ANDOR(SiS_Pr,HwInfo,0xF7,0x08);
 	      SiS_PanelDelay(SiS_Pr, HwInfo, 3);
 	   }
+#endif
 	}
 
         SiS_SetRegAND(SiS_Pr->SiS_Part2Port,0x00,0xDF);           /* disable VB */
@@ -4000,12 +3895,14 @@
 	    SiS_SetRegOR(SiS_Pr->SiS_P3c4,0x1E,0x20);
 	    SiS_SetReg(SiS_Pr->SiS_Part1Port,0x00,temp);
 	} else {
+#ifdef SIS300
             SiS_SetRegAND(SiS_Pr->SiS_P3c4,0x1E,0xDF);            /* disable CRT2 */
 	    if( (!(SiS_CRT2IsLCD(SiS_Pr, HwInfo))) ||
 	        (!(SiS_CR36BIOSWord23d(SiS_Pr,HwInfo))) ) {
 		SiS_PanelDelay(SiS_Pr, HwInfo, 2);
 		SiS_SetRegSR11ANDOR(SiS_Pr,HwInfo,0xFB,0x04);
 	    }
+#endif
 	}
 
       }
@@ -4064,6 +3961,10 @@
 
 #ifdef SIS315H	/* 315 series */
 
+        if(!(SiS_IsNotM650orLater(SiS_Pr,HwInfo))) {
+          SiS_SetRegAND(SiS_Pr->SiS_Part1Port,0x4c,~0x18);
+        }
+
 	if(SiS_Pr->SiS_IF_DEF_CH70xx != 0) {
 
 	   if(HwInfo->jChipType == SIS_740) {
@@ -4194,7 +4095,6 @@
   BOOLEAN delaylong = FALSE;
 #endif
 
-
   if(SiS_Pr->SiS_VBType & VB_SISVB) {
 
     if(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) {   /* ====== For 301B et al  ====== */
@@ -4203,28 +4103,55 @@
 
 #ifdef SIS300     /* 300 series */
 
-         if(HwInfo->jChipType == SIS_300) {
-
-	    if(SiS_CRT2IsLCD(SiS_Pr, HwInfo)) {
-	       if(SiS_Pr->SiS_VBType & VB_SIS301LV302LV) {
-	          SiS_SetRegOR(SiS_Pr->SiS_Part4Port,0x26,0x02);
-	          if(!(SiS_CR36BIOSWord23d(SiS_Pr, HwInfo))) {
-	             SiS_PanelDelay(SiS_Pr, HwInfo, 0);
-	          }
+	 if(SiS_CRT2IsLCD(SiS_Pr, HwInfo)) {
+	    if(SiS_Pr->SiS_VBType & VB_SIS301LV302LV) {
+	       SiS_SetRegOR(SiS_Pr->SiS_Part4Port,0x26,0x02);
+	    } else if(SiS_Pr->SiS_VBType & VB_NoLCD) {
+	       SiS_SetRegSR11ANDOR(SiS_Pr,HwInfo,0xFB,0x00);
+	    }
+	    if(SiS_Pr->SiS_VBType & (VB_SIS301LV302LV | VB_NoLCD)) {
+	       if(!(SiS_CR36BIOSWord23d(SiS_Pr, HwInfo))) {
+	          SiS_PanelDelay(SiS_Pr, HwInfo, 0);
 	       }
 	    }
+	 }
+
+	 if((SiS_Pr->SiS_VBType & VB_NoLCD) &&
+	    (SiS_CRT2IsLCD(SiS_Pr, HwInfo))) {
+
+	    SiS_SetRegOR(SiS_Pr->SiS_P3c4,0x1E,0x20);   		/* Enable CRT2 */
+            SiS_DisplayOn(SiS_Pr);
+	    SiS_UnLockCRT2(SiS_Pr,HwInfo);
+	    SiS_SetRegAND(SiS_Pr->SiS_Part1Port,0x02,0xBF);
+	    if(SiS_BridgeInSlavemode(SiS_Pr)) {
+      	       SiS_SetRegAND(SiS_Pr->SiS_Part1Port,0x01,0x1F);
+      	    } else {
+      	       SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x01,0x1F,0x40);
+            }
+	    if(!(SiS_GetReg(SiS_Pr->SiS_P3c4,0x13) & 0x40)) {
+	       if(!(SiS_GetReg(SiS_Pr->SiS_P3c4,0x16) & 0x10)) {
+		  if(!(SiS_CR36BIOSWord23b(SiS_Pr,HwInfo))) {
+		     SiS_PanelDelay(SiS_Pr, HwInfo, 1);
+                  }
+		  SiS_WaitVBRetrace(SiS_Pr,HwInfo);
+                  SiS_SetRegSR11ANDOR(SiS_Pr,HwInfo,0xF7,0x00);
+               }
+	    }
+
+	 } else {
+
 	    temp = SiS_GetReg(SiS_Pr->SiS_P3c4,0x32) & 0xDF;             /* lock mode */
-            if(SiS_BridgeInSlave(SiS_Pr)) {
+            if(SiS_BridgeInSlavemode(SiS_Pr)) {
                tempah = SiS_GetReg(SiS_Pr->SiS_P3d4,0x30);
-               if(!(tempah & SetCRT2ToRAMDAC))  temp |= 0x20;
+               if(!(tempah & SetCRT2ToRAMDAC)) temp |= 0x20;
             }
             SiS_SetReg(SiS_Pr->SiS_P3c4,0x32,temp);
 	    SiS_SetRegOR(SiS_Pr->SiS_P3c4,0x1E,0x20);
 	    SiS_SetRegANDOR(SiS_Pr->SiS_Part2Port,0x00,0x1F,0x20);        /* enable VB processor */
 	    SiS_SetRegOR(SiS_Pr->SiS_Part4Port,0x1F,0xC0);
 	    SiS_DisplayOn(SiS_Pr);
-	    if(SiS_CRT2IsLCD(SiS_Pr, HwInfo)) {
-	       if(SiS_Pr->SiS_VBType & VB_SIS301LV302LV) {
+	    if(SiS_Pr->SiS_VBType & VB_SIS301LV302LV) {
+	       if(SiS_CRT2IsLCD(SiS_Pr, HwInfo)) {
 	          if(!(SiS_GetReg(SiS_Pr->SiS_P3c4,0x16) & 0x10)) {
 		     if(!(SiS_CR36BIOSWord23b(SiS_Pr,HwInfo))) {
 		        SiS_PanelDelay(SiS_Pr, HwInfo, 1);
@@ -4234,440 +4161,279 @@
 	       }
 	    }
 
-	 } else {
+	 }
 
-	    if((SiS_Pr->SiS_VBType & VB_NoLCD) &&
-	       (SiS_CRT2IsLCD(SiS_Pr, HwInfo))) {
-	       /* This is only for LCD output on 301B-DH via LVDS */
-	       SiS_SetRegSR11ANDOR(SiS_Pr,HwInfo,0xFB,0x00);
-	       if(!(SiS_CR36BIOSWord23d(SiS_Pr,HwInfo))) {
-	          SiS_PanelDelay(SiS_Pr, HwInfo, 0);
-	       }
-	       SiS_SetRegOR(SiS_Pr->SiS_P3c4,0x1E,0x20);   /* Enable CRT2 */
-               SiS_DisplayOn(SiS_Pr);
-	       SiS_UnLockCRT2(SiS_Pr,HwInfo);
-	       SiS_SetRegAND(SiS_Pr->SiS_Part1Port,0x02,0xBF);
-	       if(SiS_BridgeInSlave(SiS_Pr)) {
-      		  SiS_SetRegAND(SiS_Pr->SiS_Part1Port,0x01,0x1F);
-      	       } else {
-      		  SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x01,0x1F,0x40);
-               }
-	       if(!(SiS_GetReg(SiS_Pr->SiS_P3c4,0x13) & 0x40)) {
-	           if(!(SiS_GetReg(SiS_Pr->SiS_P3c4,0x16) & 0x10)) {
-		       if(!(SiS_CR36BIOSWord23b(SiS_Pr,HwInfo))) {
-		           SiS_PanelDelay(SiS_Pr, HwInfo, 1);
-                       }
-		       SiS_WaitVBRetrace(SiS_Pr,HwInfo);
-                       SiS_SetRegSR11ANDOR(SiS_Pr,HwInfo,0xF7,0x00);
-                   }
-	       }
-            } else {
-	       temp = SiS_GetReg(SiS_Pr->SiS_P3c4,0x32) & 0xDF;             /* lock mode */
-               if(SiS_BridgeInSlave(SiS_Pr)) {
-                  tempah = SiS_GetReg(SiS_Pr->SiS_P3d4,0x30);
-                  if(!(tempah & SetCRT2ToRAMDAC))  temp |= 0x20;
-               }
-               SiS_SetReg(SiS_Pr->SiS_P3c4,0x32,temp);
-	       SiS_SetRegOR(SiS_Pr->SiS_P3c4,0x1E,0x20);
-	       SiS_SetRegANDOR(SiS_Pr->SiS_Part2Port,0x00,0x1F,0x20);        /* enable VB processor */
-	       SiS_SetRegOR(SiS_Pr->SiS_Part4Port,0x1F,0xC0);
-	       SiS_DisplayOn(SiS_Pr);
-	    }
 
-         }
 #endif /* SIS300 */
 
       } else {
 
 #ifdef SIS315H    /* 315 series */
 
-	 if(IS_SIS550650740660) {		/* 550, 650, 740, 660 */
+#ifdef SET_EMI
+	 UCHAR   r30=0, r31=0, r32=0, r33=0, cr36=0;
+	 /* USHORT  emidelay=0; */
+#endif
+
+	 if(SiS_Pr->SiS_VBType & VB_SIS301LV302LV) {
+	    SiS_SetRegAND(SiS_Pr->SiS_Part4Port,0x1f,0xef);
+#ifdef SET_EMI
+	    if(SiS_Pr->SiS_VBType & (VB_SIS302LV | VB_SIS302ELV)) {
+	       SiS_SetRegAND(SiS_Pr->SiS_Part4Port,0x30,0x0c);
+	    }
+#endif
+	 }
+
+         if(!(SiS_IsNotM650orLater(SiS_Pr, HwInfo))) {
+	    tempah = 0x10;
+	    if(SiS_LCDAEnabled(SiS_Pr, HwInfo)) {
+	       if(SiS_TVEnabled(SiS_Pr, HwInfo)) tempah = 0x18;
+	       else 			         tempah = 0x08;
+	    }
+	    SiS_SetReg(SiS_Pr->SiS_Part1Port,0x4c,tempah);
+	 }
 
-	    UCHAR r30=0, r31=0, r32=0, r33=0, cr36=0;
+	 if(SiS_Pr->SiS_VBType & VB_SIS301LV302LV) {
 
-	    if(SiS_Pr->SiS_VBType & VB_SIS301LV302LV) {
+	    SiS_SetRegByte(SiS_Pr->SiS_P3c6,0x00);
+	    SiS_DisplayOff(SiS_Pr);
+	    pushax = SiS_GetReg(SiS_Pr->SiS_P3c4,0x06);
+	    if(IS_SIS740) {
+	       SiS_SetRegAND(SiS_Pr->SiS_P3c4,0x06,0xE3);
+	    }
 
-	       if((SiS_Pr->SiS_CustomT != CUT_COMPAQ1280) &&
-	          (SiS_Pr->SiS_CustomT != CUT_CLEVO1400)) {
-	          SiS_SetRegAND(SiS_Pr->SiS_Part4Port,0x1f,0xef);
-#ifdef SET_EMI
+	    if(SiS_IsVAorLCD(SiS_Pr, HwInfo)) {
+               if(!(SiS_GetReg(SiS_Pr->SiS_Part4Port,0x26) & 0x02)) {
+		  SiS_PanelDelayLoop(SiS_Pr, HwInfo, 3, 2);
+		  SiS_SetRegOR(SiS_Pr->SiS_Part4Port,0x26,0x02);
+		  SiS_PanelDelayLoop(SiS_Pr, HwInfo, 3, 2);
 		  if(SiS_Pr->SiS_VBType & (VB_SIS302LV | VB_SIS302ELV)) {
-	             SiS_SetRegAND(SiS_Pr->SiS_Part4Port,0x30,0x0c);
+		     SiS_GenericDelay(SiS_Pr, 0x4500);
 		  }
-#endif
 	       }
+	    }
 
-               if(!(SiS_IsNotM650orLater(SiS_Pr,HwInfo))) {
-	          tempah = 0x10;
-		  if(SiS_LCDAEnabled(SiS_Pr, HwInfo)) {
-		     if(SiS_TVEnabled(SiS_Pr, HwInfo)) tempah = 0x18;
-		     else 			       tempah = 0x08;
-		  }
-		  SiS_SetReg(SiS_Pr->SiS_Part1Port,0x4c,tempah);
-	       }
+	    if(!(SiS_GetReg(SiS_Pr->SiS_P3d4,0x31) & 0x40)) {
+               SiS_PanelDelayLoop(SiS_Pr, HwInfo, 3, 10);
+	       delaylong = TRUE;
+	    }
 
-	       if((SiS_Pr->SiS_CustomT != CUT_COMPAQ1280) &&
-	          (SiS_Pr->SiS_CustomT != CUT_CLEVO1400)) {
-	          SiS_SetRegByte(SiS_Pr->SiS_P3c6,0x00);
-	          SiS_DisplayOff(SiS_Pr);
-	          pushax = SiS_GetReg(SiS_Pr->SiS_P3c4,0x06);
-	          if(IS_SIS740) {
-	             SiS_SetRegAND(SiS_Pr->SiS_P3c4,0x06,0xE3);
-	          }
-	       }
-
-	       if( (SiS_IsVAMode(SiS_Pr,HwInfo)) ||
-	           (SiS_CRT2IsLCD(SiS_Pr, HwInfo)) ) {
-                  if(!(SiS_GetReg(SiS_Pr->SiS_Part4Port,0x26) & 0x02)) {
-		     if((SiS_Pr->SiS_CustomT != CUT_COMPAQ1280) &&
-		        (SiS_Pr->SiS_CustomT != CUT_CLEVO1400)) {
-		        SiS_PanelDelayLoop(SiS_Pr, HwInfo, 3, 2);
-			SiS_SetRegOR(SiS_Pr->SiS_Part4Port,0x26,0x02);
-			if(SiS_Pr->SiS_VBType & (VB_SIS302LV | VB_SIS302ELV)) {
-			   SiS_GenericDelay(SiS_Pr, 0x4500);
-			}
-	                SiS_PanelDelayLoop(SiS_Pr, HwInfo, 3, 2);
-		     } else {
-		        SiS_SetRegOR(SiS_Pr->SiS_Part4Port,0x26,0x02);
-			SiS_PanelDelay(SiS_Pr, HwInfo, 0);
-		     }
-	          }
-	       }
-
-               if((SiS_Pr->SiS_CustomT != CUT_COMPAQ1280) &&
-	          (SiS_Pr->SiS_CustomT != CUT_CLEVO1400)) {
-	          if(!(SiS_GetReg(SiS_Pr->SiS_P3d4,0x31) & 0x40)) {
-                     SiS_PanelDelayLoop(SiS_Pr, HwInfo, 3, 10);
-		     delaylong = TRUE;
-		  }
-	       }
+	 }
 
-	    } else if(SiS_Pr->SiS_VBType & VB_NoLCD) {
+	 if(!(SiS_IsVAMode(SiS_Pr,HwInfo))) {
 
-	       if(!(SiS_IsNotM650orLater(SiS_Pr,HwInfo))) {
-	          SiS_SetRegOR(SiS_Pr->SiS_Part1Port,0x4c,0x10);
+            temp = SiS_GetReg(SiS_Pr->SiS_P3c4,0x32) & 0xDF;
+	    if(SiS_BridgeInSlavemode(SiS_Pr)) {
+               tempah = SiS_GetReg(SiS_Pr->SiS_P3d4,0x30);
+               if(!(tempah & SetCRT2ToRAMDAC)) {
+		  if(!(SiS_LCDAEnabled(SiS_Pr, HwInfo))) temp |= 0x20;
 	       }
+            }
+            SiS_SetReg(SiS_Pr->SiS_P3c4,0x32,temp);
 
-  	    } else if(SiS_Pr->SiS_VBType & VB_SIS301B302B) {
+	    SiS_SetRegOR(SiS_Pr->SiS_P3c4,0x1E,0x20);                   /* enable CRT2 */
 
-	       if(!(SiS_IsNotM650orLater(SiS_Pr,HwInfo))) {
-	          tempah = 0x10;
-		  if(SiS_LCDAEnabled(SiS_Pr, HwInfo)) {
-		     if(SiS_TVEnabled(SiS_Pr, HwInfo)) tempah = 0x18;
-		     else 			       tempah = 0x08;
-		  }
-		  SiS_SetReg(SiS_Pr->SiS_Part1Port,0x4c,tempah);
-	       }
+	    SiS_SetRegAND(SiS_Pr->SiS_Part1Port,0x2e,0x7f);
+	    SiS_SetRegOR(SiS_Pr->SiS_Part1Port,0x2e,0x80);
 
+	    if(SiS_Pr->SiS_VBType & VB_SIS301LV302LV) {
+	       SiS_PanelDelay(SiS_Pr, HwInfo, 2);
 	    }
 
-	    if(!(SiS_IsVAMode(SiS_Pr,HwInfo))) {
-               temp = SiS_GetReg(SiS_Pr->SiS_P3c4,0x32) & 0xDF;
-	       if(SiS_BridgeInSlave(SiS_Pr)) {
-                  tempah = SiS_GetReg(SiS_Pr->SiS_P3d4,0x30);
-                  if(!(tempah & SetCRT2ToRAMDAC)) {
-		     if(!(SiS_LCDAEnabled(SiS_Pr, HwInfo))) temp |= 0x20;
-		  }
-               }
-               SiS_SetReg(SiS_Pr->SiS_P3c4,0x32,temp);
+	 } else {
 
-	       SiS_SetRegOR(SiS_Pr->SiS_P3c4,0x1E,0x20);                   /* enable CRT2 */
+	    SiS_SetRegOR(SiS_Pr->SiS_Part1Port,0x1e,0x20);
 
-	       if((SiS_Pr->SiS_VBType & VB_SIS301B302B) ||
-	          (SiS_Pr->SiS_CustomT == CUT_COMPAQ1280) ||
-		  (SiS_Pr->SiS_CustomT == CUT_CLEVO1400)) {
-	          SiS_SetRegAND(SiS_Pr->SiS_Part1Port,0x2e,0x7f);
-		  temp = SiS_GetReg(SiS_Pr->SiS_Part1Port,0x2e);
-		  if(!(temp & 0x80)) {
-		     SiS_SetRegOR(SiS_Pr->SiS_Part1Port,0x2e,0x80);
-		  }
-	       } else {
-	          SiS_PanelDelay(SiS_Pr, HwInfo, 2);
-	       }
-	    } else {
-	       SiS_SetRegOR(SiS_Pr->SiS_Part1Port,0x1e,0x20);
-	    }
+	 }
 
-	    SiS_SetRegANDOR(SiS_Pr->SiS_Part2Port,0x00,0x1f,0x20);
+	 SiS_SetRegANDOR(SiS_Pr->SiS_Part2Port,0x00,0x1f,0x20);
+	 SiS_SetRegOR(SiS_Pr->SiS_Part1Port,0x2e,0x80);
 
-	    if((SiS_Pr->SiS_VBType & VB_SIS301B302B) ||
-	       (SiS_Pr->SiS_CustomT == CUT_COMPAQ1280) ||
-	       (SiS_Pr->SiS_CustomT == CUT_CLEVO1400)) {
-	       temp = SiS_GetReg(SiS_Pr->SiS_Part1Port,0x2e);
-	       if(!(temp & 0x80)) {
-		  SiS_SetRegOR(SiS_Pr->SiS_Part1Port,0x2e,0x80);
-	       }
-	    }
+	 tempah = 0xc0;
+	 if(SiS_IsDualEdge(SiS_Pr, HwInfo)) {
+	    tempah = 0x80;
+	    if(!(SiS_IsVAMode(SiS_Pr, HwInfo))) tempah = 0x40;
+	 }
+         SiS_SetRegOR(SiS_Pr->SiS_Part4Port,0x1F,tempah);
 
-	    tempah = 0xc0;
-	    if(SiS_IsDualEdge(SiS_Pr, HwInfo)) {
-	       tempah = 0x80;
-	       if(!(SiS_IsVAMode(SiS_Pr, HwInfo))) {
-	          tempah = 0x40;
-               }
-	    }
-            SiS_SetRegOR(SiS_Pr->SiS_Part4Port,0x1F,tempah);
+	 if(SiS_Pr->SiS_VBType & VB_SIS301LV302LV) {
 
-	    if((SiS_Pr->SiS_VBType & VB_SIS301B302B) ||
-	       (((SiS_Pr->SiS_CustomT == CUT_COMPAQ1280) ||
-	         (SiS_Pr->SiS_CustomT == CUT_CLEVO1400))     &&
-	        (!(SiS_WeHaveBacklightCtrl(SiS_Pr,HwInfo))))) {
-               SiS_SetRegAND(SiS_Pr->SiS_Part1Port,0x00,0x7f);
-	    }
+	    SiS_PanelDelay(SiS_Pr, HwInfo, 2);
 
-	    if(SiS_Pr->SiS_VBType & VB_SIS301LV302LV) {
+	    SiS_SetRegOR(SiS_Pr->SiS_Part4Port,0x1f,0x10);
+	    SiS_SetRegOR(SiS_Pr->SiS_Part1Port,0x2e,0x80);
 
-	       if((SiS_Pr->SiS_CustomT != CUT_COMPAQ1280) &&
-	          (SiS_Pr->SiS_CustomT != CUT_CLEVO1400)) {
-	          SiS_PanelDelay(SiS_Pr, HwInfo, 2);
-	       }
-#ifdef COMPAQ_HACK
-	       if(SiS_Pr->SiS_CustomT == CUT_COMPAQ1280) {
-	          SiS_PanelDelay(SiS_Pr, HwInfo, 2);
+	    if(SiS_Pr->SiS_CustomT != CUT_CLEVO1400) {
+#ifdef SET_EMI
+	       if(SiS_Pr->SiS_VBType & (VB_SIS302LV | VB_SIS302ELV)) {
+	          SiS_SetRegAND(SiS_Pr->SiS_Part4Port,0x30,0x0c);
 	       }
 #endif
+	       SiS_SetRegOR(SiS_Pr->SiS_Part4Port,0x27,0x0c);
 
-	       SiS_SetRegOR(SiS_Pr->SiS_Part4Port,0x1f,0x10);
-
-	       if(SiS_Pr->SiS_CustomT != CUT_CLEVO1400) {
+	       if(SiS_Pr->SiS_VBType & (VB_SIS302LV | VB_SIS302ELV)) {
 #ifdef SET_EMI
-	          if(SiS_Pr->SiS_VBType & (VB_SIS302LV | VB_SIS302ELV)) {
-	             SiS_SetRegAND(SiS_Pr->SiS_Part4Port,0x30,0x0c);
-		  }
-#endif
-	          SiS_SetRegOR(SiS_Pr->SiS_Part4Port,0x27,0x0c);
-#ifdef SET_EMI
-	          if(SiS_Pr->SiS_VBType & (VB_SIS302LV | VB_SIS302ELV)) {
-
-		     cr36 = SiS_GetReg(SiS_Pr->SiS_P3d4,0x36);
+		  cr36 = SiS_GetReg(SiS_Pr->SiS_P3d4,0x36);
 
-		     /*                                              (P4_30|0x40)  */
-		     /* Compal 1400x1050: 0x05, 0x60, 0x00                YES  (1.10.7w;  CR36=69)      */
-		     /* Compal 1400x1050: 0x0d, 0x70, 0x40                YES  (1.10.7x;  CR36=69)      */
-		     /* Acer   1280x1024: 0x12, 0xd0, 0x6b                NO   (1.10.9k;  CR36=73)      */
-		     /* Compaq 1280x1024: 0x0d, 0x70, 0x6b                YES  (1.12.04b; CR36=03)      */
-		     /* Clevo   1024x768: 0x05, 0x60, 0x33                NO   (1.10.8e;  CR36=12, DL!) */
-		     /* Clevo   1024x768: 0x0d, 0x70, 0x40 (if type == 3) YES  (1.10.8y;  CR36=?2)      */
-		     /* Clevo   1024x768: 0x05, 0x60, 0x33 (if type != 3) YES  (1.10.8y;  CR36=?2)      */
-		     /* Asus    1024x768: ?                                ?   (1.10.8o;  CR36=?2)      */
-		     /* Asus    1024x768: 0x08, 0x10, 0x3c (problematic)  YES  (1.10.8q;  CR36=22)      */
-
-		     if(SiS_Pr->HaveEMI) {
-		        r30 = SiS_Pr->EMI_30;
-			r31 = SiS_Pr->EMI_31;
-			r32 = SiS_Pr->EMI_32;
-			r33 = SiS_Pr->EMI_33;
-		     } else {
-		        r30 = 0;
+		  if(SiS_Pr->SiS_ROMNew) {
+		     UCHAR  *ROMAddr = HwInfo->pjVirtualRomBase;
+		     USHORT romptr   = GetLCDStructPtr661_2(SiS_Pr, HwInfo);
+		     if(romptr) {
+		        SiS_SetRegOR(SiS_Pr->SiS_Part4Port,0x30,0x20);
+			SiS_Pr->EMI_30 = 0;
+			SiS_Pr->EMI_31 = ROMAddr[romptr + 14];
+			SiS_Pr->EMI_32 = ROMAddr[romptr + 15];
+			SiS_Pr->EMI_33 = ROMAddr[romptr + 16];
+			if(ROMAddr[romptr + 1] & 0x10) SiS_Pr->EMI_30 = 0x40;
+			/* emidelay = SISGETROMW((romptr + 0x22)); */
+			SiS_Pr->HaveEMI = SiS_Pr->HaveEMILCD = SiS_Pr->OverruleEMI = TRUE;
 		     }
+		  }
 
-		     /* EMI_30 is read at driver start; however, the BIOS sets this
-		      * (if it is used) only if the LCD is in use. In case we caught
-		      * the machine while on TV output, this bit is not set and we
-		      * don't know if it should be set - hence our detection is wrong.
-		      * Work-around this here:
-		      */
-
-		     if((!SiS_Pr->HaveEMI) || (!SiS_Pr->HaveEMILCD)) {
-		        if((cr36 & 0x0f) == 0x02) {			/* 1024x768 */
-		           r30 |= 0x40;
-			   if(SiS_Pr->SiS_CustomT == CUT_CLEVO1024) {
-			      r30 &= ~0x40;
-			   }
-		        } else if((cr36 & 0x0f) == 0x03) {		/* 1280x1024 */
-		           r30 |= 0x40;
-			   if(SiS_Pr->SiS_CustomT != CUT_COMPAQ1280) {
-			      r30 &= ~0x40;
-			   }
-		        } else if((cr36 & 0x0f) == 0x09) {		/* 1400x1050 */
-		           r30 |= 0x40;
-		        } else if((cr36 & 0x0f) == 0x0b) {		/* 1600x1200 - unknown */
-		           r30 |= 0x40;
-		        }
-                     }
+		  /*                                              (P4_30|0x40)  */
+		  /* Compal 1400x1050: 0x05, 0x60, 0x00                YES  (1.10.7w;  CR36=69)      */
+		  /* Compal 1400x1050: 0x0d, 0x70, 0x40                YES  (1.10.7x;  CR36=69)      */
+		  /* Acer   1280x1024: 0x12, 0xd0, 0x6b                NO   (1.10.9k;  CR36=73)      */
+		  /* Compaq 1280x1024: 0x0d, 0x70, 0x6b                YES  (1.12.04b; CR36=03)      */
+		  /* Clevo   1024x768: 0x05, 0x60, 0x33                NO   (1.10.8e;  CR36=12, DL!) */
+		  /* Clevo   1024x768: 0x0d, 0x70, 0x40 (if type == 3) YES  (1.10.8y;  CR36=?2)      */
+		  /* Clevo   1024x768: 0x05, 0x60, 0x33 (if type != 3) YES  (1.10.8y;  CR36=?2)      */
+		  /* Asus    1024x768: ?                                ?   (1.10.8o;  CR36=?2)      */
+		  /* Asus    1024x768: 0x08, 0x10, 0x3c (problematic)  YES  (1.10.8q;  CR36=22)      */
+
+		  if(SiS_Pr->HaveEMI) {
+		     r30 = SiS_Pr->EMI_30; r31 = SiS_Pr->EMI_31;
+		     r32 = SiS_Pr->EMI_32; r33 = SiS_Pr->EMI_33;
+		  } else {
+		     r30 = 0;
+		  }
 
-		     if(!SiS_Pr->HaveEMI) {
-		        if((cr36 & 0x0f) == 0x02) {
+		  /* EMI_30 is read at driver start; however, the BIOS sets this
+		   * (if it is used) only if the LCD is in use. In case we caught
+		   * the machine while on TV output, this bit is not set and we
+		   * don't know if it should be set - hence our detection is wrong.
+		   * Work-around this here:
+		   */
+
+		  if((!SiS_Pr->HaveEMI) || (!SiS_Pr->HaveEMILCD)) {
+		     switch((cr36 & 0x0f)) {
+		     case 2:
+			r30 |= 0x40;
+			if(SiS_Pr->SiS_CustomT == CUT_CLEVO1024) r30 &= ~0x40;
+			if(!SiS_Pr->HaveEMI) {
+			   r31 = 0x05; r32 = 0x60; r33 = 0x33;
 			   if((cr36 & 0xf0) == 0x30) {
 			      r31 = 0x0d; r32 = 0x70; r33 = 0x40;
-			   } else {
-			      r31 = 0x05; r32 = 0x60; r33 = 0x33;
 			   }
-		        } else if((cr36 & 0x0f) == 0x03) {
+			}
+			break;
+		     case 3:  /* 1280x1024 */
+			if(SiS_Pr->SiS_CustomT == CUT_COMPAQ1280) r30 |= 0x40;
+			if(!SiS_Pr->HaveEMI) {
+			   r31 = 0x12; r32 = 0xd0; r33 = 0x6b;
 			   if(SiS_Pr->SiS_CustomT == CUT_COMPAQ1280) {
 			      r31 = 0x0d; r32 = 0x70; r33 = 0x6b;
-			   } else {
-			      r31 = 0x12; r32 = 0xd0; r33 = 0x6b;
 			   }
-			} else if((cr36 & 0x0f) == 0x09) {
+			}
+			break;
+		     case 9:  /* 1400x1050 */
+			r30 |= 0x40;
+			if(!SiS_Pr->HaveEMI) {
+			   r31 = 0x05; r32 = 0x60; r33 = 0x00;
 			   if(SiS_Pr->SiS_CustomT == CUT_COMPAL1400_2) {
 			      r31 = 0x0d; r32 = 0x70; r33 = 0x40;  /* BIOS values */
-			   } else {
-			      r31 = 0x05; r32 = 0x60; r33 = 0x00;
 			   }
-			} else {
+			}
+			break;
+		     case 11: /* 1600x1200 - unknown */
+			r30 |= 0x40;
+			if(!SiS_Pr->HaveEMI) {
 			   r31 = 0x05; r32 = 0x60; r33 = 0x00;
 			}
 		     }
+                  }
 
-		     /* BIOS values don't work so well sometimes */
-		     if(!SiS_Pr->OverruleEMI) {
+		  /* BIOS values don't work so well sometimes */
+		  if(!SiS_Pr->OverruleEMI) {
 #ifdef COMPAL_HACK
-		        if(SiS_Pr->SiS_CustomT == CUT_COMPAL1400_2) {
-		           if((cr36 & 0x0f) == 0x09) {
-			      r30 = 0x60; r31 = 0x05; r32 = 0x60; r33 = 0x00;
-			   }
- 		        }
+		     if(SiS_Pr->SiS_CustomT == CUT_COMPAL1400_2) {
+		        if((cr36 & 0x0f) == 0x09) {
+			   r30 = 0x60; r31 = 0x05; r32 = 0x60; r33 = 0x00;
+			}
+ 		     }
 #endif
 #ifdef COMPAQ_HACK
-		        if(SiS_Pr->SiS_CustomT == CUT_COMPAQ1280) {
-		           if((cr36 & 0x0f) == 0x03) {
-			      r30 = 0x20; r31 = 0x12; r32 = 0xd0; r33 = 0x6b;     /* rev 1 */
-			   }
+		     if(SiS_Pr->SiS_CustomT == CUT_COMPAQ1280) {
+		        if((cr36 & 0x0f) == 0x03) {
+			   r30 = 0x20; r31 = 0x12; r32 = 0xd0; r33 = 0x6b;
 			}
+		     }
 #endif
 #ifdef ASUS_HACK
-		        if(SiS_Pr->SiS_CustomT == CUT_ASUSA2H_2) {
-		           if((cr36 & 0x0f) == 0x02) {
-			      /* r30 = 0x60; r31 = 0x05; r32 = 0x60; r33 = 0x33;  */   /* rev 2 */
-			      /* r30 = 0x20; r31 = 0x05; r32 = 0x60; r33 = 0x33;  */   /* rev 3 */
-			      /* r30 = 0x60; r31 = 0x0d; r32 = 0x70; r33 = 0x40;  */   /* rev 4 */
-			      /* r30 = 0x20; r31 = 0x0d; r32 = 0x70; r33 = 0x40;  */   /* rev 5 */
-			   }
+		     if(SiS_Pr->SiS_CustomT == CUT_ASUSA2H_2) {
+		        if((cr36 & 0x0f) == 0x02) {
+			   /* r30 = 0x60; r31 = 0x05; r32 = 0x60; r33 = 0x33;  */   /* rev 2 */
+			   /* r30 = 0x20; r31 = 0x05; r32 = 0x60; r33 = 0x33;  */   /* rev 3 */
+			   /* r30 = 0x60; r31 = 0x0d; r32 = 0x70; r33 = 0x40;  */   /* rev 4 */
+			   /* r30 = 0x20; r31 = 0x0d; r32 = 0x70; r33 = 0x40;  */   /* rev 5 */
 			}
-#endif
- 		     }
-		     if(!(SiS_Pr->OverruleEMI && (!r30) && (!r31) && (!r32) && (!r33))) {
-		        SiS_SetRegOR(SiS_Pr->SiS_Part4Port,0x30,0x20);
 		     }
-		     SiS_SetReg(SiS_Pr->SiS_Part4Port,0x31,r31);
-		     SiS_SetReg(SiS_Pr->SiS_Part4Port,0x32,r32);
-		     SiS_SetReg(SiS_Pr->SiS_Part4Port,0x33,r33);
-		     if(!(SiS_Pr->OverruleEMI && (!r30) && (!r31) && (!r32) && (!r33))) {
-		        SiS_SetReg(SiS_Pr->SiS_Part4Port,0x34,0x10);
-		     } else {
-		        SiS_SetReg(SiS_Pr->SiS_Part4Port,0x34,0x00);
-		     }
-		     if( (SiS_IsVAMode(SiS_Pr,HwInfo)) ||
-	                 (SiS_CRT2IsLCD(SiS_Pr, HwInfo)) ) {
-	                if(r30 & 0x40) {
-		           SiS_PanelDelayLoop(SiS_Pr, HwInfo, 3, 5);
-			   if(delaylong) {
-			      SiS_PanelDelayLoop(SiS_Pr, HwInfo, 3, 5);
-			      delaylong = FALSE;
-			   }
-			   SiS_WaitVBRetrace(SiS_Pr,HwInfo);
-			   if(SiS_Pr->SiS_CustomT == CUT_ASUSA2H_2) {
-			      SiS_GenericDelay(SiS_Pr, 0x500);
-			   }
-	                   SiS_SetRegOR(SiS_Pr->SiS_Part4Port,0x30,0x40);
-	                }
-		     }
-		  }
 #endif
-	       }
-
-	       if(SiS_Pr->SiS_CustomT == CUT_COMPAQ1280) {
-
-	          if( (SiS_IsVAMode(SiS_Pr,HwInfo)) ||
-	              (SiS_CRT2IsLCD(SiS_Pr, HwInfo)) ) {
-		     SiS_DisplayOn(SiS_Pr);
-		     SiS_PanelDelay(SiS_Pr, HwInfo, 1);
-		     SiS_WaitVBRetrace(SiS_Pr, HwInfo);
-		     SiS_PanelDelay(SiS_Pr, HwInfo, 3);
-		     if(!(SiS_WeHaveBacklightCtrl(SiS_Pr,HwInfo))) {
-		        SiS_SetRegOR(SiS_Pr->SiS_Part4Port,0x26,0x01);
-	  	     }
-		  }
-
-	       } else if(SiS_Pr->SiS_CustomT == CUT_CLEVO1400) {
+ 		  }
 
-	          if(!(SiS_WeHaveBacklightCtrl(SiS_Pr,HwInfo))) {
-	             if( (SiS_IsVAMode(SiS_Pr, HwInfo)) ||
-	                 (SiS_CRT2IsLCD(SiS_Pr, HwInfo)) ) {
-		        SiS_DisplayOn(SiS_Pr);
-		        SiS_PanelDelay(SiS_Pr, HwInfo, 1);
-		        SiS_WaitVBRetrace(SiS_Pr,HwInfo);
-		        SiS_SetRegOR(SiS_Pr->SiS_Part4Port,0x26,0x01);
-		     }
+		  if(!(SiS_Pr->OverruleEMI && (!r30) && (!r31) && (!r32) && (!r33))) {
+		     SiS_SetRegOR(SiS_Pr->SiS_Part4Port,0x30,0x20);
 		  }
+		  SiS_SetReg(SiS_Pr->SiS_Part4Port,0x31,r31);
+		  SiS_SetReg(SiS_Pr->SiS_Part4Port,0x32,r32);
+		  SiS_SetReg(SiS_Pr->SiS_Part4Port,0x33,r33);
+#endif	/* SET_EMI */
 
-	       } else {
+		  SiS_SetReg(SiS_Pr->SiS_Part4Port,0x34,0x10);
 
-	          SiS_SetRegOR(SiS_Pr->SiS_Part1Port,0x2e,0x80);
-	          if(!(SiS_WeHaveBacklightCtrl(SiS_Pr,HwInfo))) {
-	             if( (SiS_IsVAMode(SiS_Pr,HwInfo)) ||
-	                 ((SiS_CRT2IsLCD(SiS_Pr, HwInfo))) ) {
-		        SiS_PanelDelayLoop(SiS_Pr, HwInfo, 3, 10);
-		        if(delaylong) {
-			   SiS_PanelDelayLoop(SiS_Pr, HwInfo, 3, 10);
-		        }
-                        SiS_WaitVBRetrace(SiS_Pr,HwInfo);
-			if(SiS_Pr->SiS_VBType & (VB_SIS302LV | VB_SIS302ELV)) {
+#ifdef SET_EMI
+		  if( (SiS_LCDAEnabled(SiS_Pr, HwInfo)) ||
+	              (SiS_CRT2IsLCD(SiS_Pr, HwInfo)) ) {
+	             if(r30 & 0x40) {
+		        SiS_PanelDelayLoop(SiS_Pr, HwInfo, 3, 5);
+			if(delaylong) {
+			   SiS_PanelDelayLoop(SiS_Pr, HwInfo, 3, 5);
+			   delaylong = FALSE;
+			}
+			SiS_WaitVBRetrace(SiS_Pr,HwInfo);
+			if(SiS_Pr->SiS_CustomT == CUT_ASUSA2H_2) {
 			   SiS_GenericDelay(SiS_Pr, 0x500);
 			}
-		        SiS_SetRegOR(SiS_Pr->SiS_Part4Port,0x26,0x01);
+	                SiS_SetRegOR(SiS_Pr->SiS_Part4Port,0x30,0x40);
 	             }
-	          }
-
-	          SiS_SetReg(SiS_Pr->SiS_P3c4,0x06,pushax);
-	          SiS_DisplayOn(SiS_Pr);
-	          SiS_SetRegByte(SiS_Pr->SiS_P3c6,0xff);
-
-	          if(!(SiS_WeHaveBacklightCtrl(SiS_Pr,HwInfo))) {
-	             SiS_SetRegAND(SiS_Pr->SiS_Part1Port,0x00,0x7f);
-	          }
-
+		  }
+#endif
 	       }
-
 	    }
 
-	 } else {			/* 315, 330 */
-
-	    if(!(SiS_IsVAMode(SiS_Pr,HwInfo))) {
-	       temp = SiS_GetReg(SiS_Pr->SiS_P3c4,0x32) & 0xDF;
-	       if(SiS_BridgeInSlave(SiS_Pr)) {
-                  tempah = SiS_GetReg(SiS_Pr->SiS_P3d4,0x30);
-                  if(!(tempah & SetCRT2ToRAMDAC))  temp |= 0x20;
-               }
-               SiS_SetReg(SiS_Pr->SiS_P3c4,0x32,temp);
-
-	       SiS_SetRegOR(SiS_Pr->SiS_P3c4,0x1E,0x20);                   /* enable CRT2 */
-
-	       temp = SiS_GetReg(SiS_Pr->SiS_Part1Port,0x2E);
-               if(!(temp & 0x80))
-                  SiS_SetRegOR(SiS_Pr->SiS_Part1Port,0x2E,0x80);
-            }
-
-	    SiS_SetRegANDOR(SiS_Pr->SiS_Part2Port,0x00,0x1f,0x20);
-
-	    if(SiS_Is301B(SiS_Pr)) {
-
-	       temp=SiS_GetReg(SiS_Pr->SiS_Part1Port,0x2E);
-               if(!(temp & 0x80))
-                  SiS_SetRegOR(SiS_Pr->SiS_Part1Port,0x2E,0x80);
-
-	       tempah = 0xc0;
-	       if(SiS_IsDualEdge(SiS_Pr,HwInfo)) {
-	          tempah = 0x80;
-	          if(!(SiS_IsVAMode(SiS_Pr,HwInfo))) {
-	             tempah = 0x40;
-                  }
+	    if(!(SiS_WeHaveBacklightCtrl(SiS_Pr,HwInfo))) {
+	       if(SiS_IsVAorLCD(SiS_Pr, HwInfo)) {
+		  SiS_PanelDelayLoop(SiS_Pr, HwInfo, 3, 10);
+		  if(delaylong) {
+		     SiS_PanelDelayLoop(SiS_Pr, HwInfo, 3, 10);
+		  }
+                  SiS_WaitVBRetrace(SiS_Pr,HwInfo);
+		  if(SiS_Pr->SiS_VBType & (VB_SIS302LV | VB_SIS302ELV)) {
+	 	     SiS_GenericDelay(SiS_Pr, 0x500);
+		  }
+		  SiS_SetRegOR(SiS_Pr->SiS_Part4Port,0x26,0x01);
 	       }
-               SiS_SetRegOR(SiS_Pr->SiS_Part4Port,0x1F,tempah);
-
-	       SiS_SetRegAND(SiS_Pr->SiS_Part1Port,0x00,0x7f);
-
-	    } else {
+	    }
 
-	       SiS_VBLongWait(SiS_Pr);
-               SiS_DisplayOn(SiS_Pr);
-	       SiS_SetRegAND(SiS_Pr->SiS_Part1Port,0x00,0x7F);
-               SiS_VBLongWait(SiS_Pr);
+	    SiS_SetReg(SiS_Pr->SiS_P3c4,0x06,pushax);
+	    SiS_DisplayOn(SiS_Pr);
+	    SiS_SetRegByte(SiS_Pr->SiS_P3c6,0xff);
 
-	    }
+	 }
 
-	 }   /* 315, 330 */
+	 if(!(SiS_WeHaveBacklightCtrl(SiS_Pr,HwInfo))) {
+	    SiS_SetRegAND(SiS_Pr->SiS_Part1Port,0x00,0x7f);
+	 }
 
 #endif /* SIS315H */
 
@@ -4683,9 +4449,9 @@
        }
 
        temp = SiS_GetReg(SiS_Pr->SiS_P3c4,0x32) & 0xDF;          /* lock mode */
-       if(SiS_BridgeInSlave(SiS_Pr)) {
+       if(SiS_BridgeInSlavemode(SiS_Pr)) {
           tempah = SiS_GetReg(SiS_Pr->SiS_P3d4,0x30);
-          if(!(tempah & SetCRT2ToRAMDAC))  temp |= 0x20;
+          if(!(tempah & SetCRT2ToRAMDAC)) temp |= 0x20;
        }
        SiS_SetReg(SiS_Pr->SiS_P3c4,0x32,temp);
 
@@ -4734,11 +4500,11 @@
 	  }
        }
 
-       SiS_EnableCRT2(SiS_Pr);
+       SiS_SetRegOR(SiS_Pr->SiS_P3c4,0x1E,0x20);
        SiS_DisplayOn(SiS_Pr);
        SiS_UnLockCRT2(SiS_Pr,HwInfo);
        SiS_SetRegAND(SiS_Pr->SiS_Part1Port,0x02,0xBF);
-       if(SiS_BridgeInSlave(SiS_Pr)) {
+       if(SiS_BridgeInSlavemode(SiS_Pr)) {
       	  SiS_SetRegAND(SiS_Pr->SiS_Part1Port,0x01,0x1F);
        } else {
       	  SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x01,0x1F,0x40);
@@ -4770,6 +4536,10 @@
 
 #ifdef SIS315H    /* 315 series */
 
+       if(!(SiS_IsNotM650orLater(SiS_Pr,HwInfo))) {
+          SiS_SetRegOR(SiS_Pr->SiS_Part1Port,0x4c,0x18);
+       }
+
        if(SiS_Pr->SiS_IF_DEF_CH70xx == 0) {
 	  if(SiS_CRT2IsLCD(SiS_Pr, HwInfo)) {
 	     SiS_SetRegSR11ANDOR(SiS_Pr,HwInfo,0xFB,0x00);
@@ -4777,7 +4547,7 @@
           }
        }
 
-       SiS_EnableCRT2(SiS_Pr);
+       SiS_SetRegOR(SiS_Pr->SiS_P3c4,0x1E,0x20);
        SiS_UnLockCRT2(SiS_Pr,HwInfo);
 
        SiS_SetRegAND(SiS_Pr->SiS_Part1Port,0x2e,0xf7);
@@ -4868,33 +4638,31 @@
 /*         SET PART 1 REGISTER GROUP         */
 /*********************************************/
 
-/********** Set CRT2 OFFSET / PITCH **********/
+/* Set CRT2 OFFSET / PITCH */
 static void
-SiS_SetCRT2Offset(SiS_Private *SiS_Pr,USHORT ModeNo,
-                  USHORT ModeIdIndex ,USHORT RefreshRateTableIndex,
-	          PSIS_HW_INFO HwInfo)
+SiS_SetCRT2Offset(SiS_Private *SiS_Pr, USHORT ModeNo, USHORT ModeIdIndex,
+	          USHORT RRTI, PSIS_HW_INFO HwInfo)
 {
   USHORT offset;
   UCHAR temp;
 
   if(SiS_Pr->SiS_VBInfo & SetInSlaveMode) return;
 
-  offset = SiS_GetOffset(SiS_Pr, ModeNo, ModeIdIndex, RefreshRateTableIndex,
-                         HwInfo);
+  offset = SiS_GetOffset(SiS_Pr,ModeNo,ModeIdIndex,RRTI,HwInfo);
 
-  if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel640x480_2 ||
-     SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel640x480_3) offset >>= 1;
+  if((SiS_Pr->SiS_LCDResInfo == Panel_640x480_2) ||
+     (SiS_Pr->SiS_LCDResInfo == Panel_640x480_3)) {
+     offset >>= 1;
+  }
 
-  temp = (UCHAR)(offset & 0xFF);
-  SiS_SetReg(SiS_Pr->SiS_Part1Port,0x07,temp);
-  temp = (UCHAR)(offset >> 8);
-  SiS_SetReg(SiS_Pr->SiS_Part1Port,0x09,temp);
+  SiS_SetReg(SiS_Pr->SiS_Part1Port,0x07,(offset & 0xFF));
+  SiS_SetReg(SiS_Pr->SiS_Part1Port,0x09,(offset >> 8));
   temp = (UCHAR)(((offset >> 3) & 0xFF) + 1);
   if(offset % 8) temp++;
   SiS_SetReg(SiS_Pr->SiS_Part1Port,0x03,temp);
 }
 
-/************* Set CRT2 Sync *************/
+/* Set CRT2 sync and PanelLink mode */
 static void
 SiS_SetCRT2Sync(SiS_Private *SiS_Pr, USHORT ModeNo, USHORT RefreshRateTableIndex,
                 PSIS_HW_INFO HwInfo)
@@ -4916,23 +4684,27 @@
      } else if((SiS_Pr->SiS_VBInfo & SetCRT2ToLCD) && (SiS_Pr->SiS_LCDInfo & LCDSync)) {
         tempah = SiS_Pr->SiS_LCDInfo;
      } else tempah = infoflag >> 8;
-
      tempah &= 0xC0;
-
      tempah |= 0x20;
      if(!(SiS_Pr->SiS_LCDInfo & LCDRGB18Bit)) tempah |= 0x10;
-
      if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCD) {
         if((SiS_Pr->SiS_CustomT == CUT_BARCO1366) ||
            (SiS_Pr->SiS_CustomT == CUT_BARCO1024)) {
-	   tempah |= 0xc0;
+	   tempah |= 0xf0;
+        }
+	if( (SiS_Pr->SiS_IF_DEF_FSTN) ||
+            (SiS_Pr->SiS_IF_DEF_DSTN) ||
+            (SiS_Pr->SiS_IF_DEF_TRUMPION) ||
+            (SiS_Pr->SiS_CustomT == CUT_PANEL848) ) {
+           tempah |= 0x30;
         }
      }
-
      if(SiS_Pr->SiS_VBInfo & SetCRT2ToTV) {
         if(HwInfo->jChipType >= SIS_315H) {
            tempah >>= 3;
+	   tempah &= 0x18;
            SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x13,0xE7,tempah);
+	   /* Don't care about 12/18/24 bit mode - TV is via VGA, not PL */
         } else {
            SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x19,0x0F,0xe0);
         }
@@ -4949,19 +4721,21 @@
         if(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) {			/* 630 - 301B(-DH) */
 
 	   tempah = infoflag >> 8;
+	   tempbl = 0;
            if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCD) {
 	      if(SiS_Pr->SiS_LCDInfo & LCDSync) {
 	         tempah = SiS_Pr->SiS_LCDInfo;
+		 tempbl = (tempah >> 6) & 0x03;
               }
            }
            tempah &= 0xC0;
-
            tempah |= 0x20;
            if(!(SiS_Pr->SiS_LCDInfo & LCDRGB18Bit)) tempah |= 0x10;
-
- 	   tempah &= 0x3f;
-  	   tempah |= tempbl;
+  	   tempah |= 0xc0;
            SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x19,0x0F,tempah);
+	   if((SiS_Pr->SiS_VBInfo & SetCRT2ToLCD) && (!(SiS_Pr->SiS_VBType & VB_NoLCD))) {
+	      SiS_SetRegANDOR(SiS_Pr->SiS_Part2Port,0x1a,0xf0,tempbl);
+	   }
 
         } else {							/* 630 - 301 */
 
@@ -4979,43 +4753,72 @@
 
 #ifdef SIS315H  /* ------- 315 series ------ */
 
-        if(SiS_Pr->SiS_VBType & VB_SIS301LV302LV) {	  		/* 315 - 30xLV */
+        if(SiS_Pr->SiS_VBType & VB_SIS301LV302LV) {	  		/* 315 - LVDS */
 
-	   if(((SiS_Pr->SiS_CustomT == CUT_COMPAQ1280) &&
-	       (SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1280x1024)) ||
-	      ((SiS_Pr->SiS_CustomT == CUT_CLEVO1400)  &&
-	       (SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1400x1050))) {
+	   tempbl = 0;
+	   if((SiS_Pr->SiS_CustomT == CUT_COMPAQ1280) &&
+	      (SiS_Pr->SiS_LCDResInfo == Panel_1280x1024)) {
 	      tempah = infoflag >> 8;
+	      if(SiS_Pr->SiS_LCDInfo & LCDSync) {
+	        tempbl = ((SiS_Pr->SiS_LCDInfo & 0xc0) >> 6);
+	      }
+	   } else if((SiS_Pr->SiS_CustomT == CUT_CLEVO1400)  &&
+	             (SiS_Pr->SiS_LCDResInfo == Panel_1400x1050)) {
+       	      tempah = infoflag >> 8;
+	      tempbl = 0x03;
 	   } else {
               tempah = SiS_GetReg(SiS_Pr->SiS_P3d4,0x37);
+	      tempbl = (tempah >> 6) & 0x03;
+	      tempbl |= 0x08;
+	      if(!(SiS_Pr->SiS_LCDInfo & LCDRGB18Bit)) tempbl |= 0x04;
 	   }
 	   tempah &= 0xC0;
-
            tempah |= 0x20;
            if(!(SiS_Pr->SiS_LCDInfo & LCDRGB18Bit)) tempah |= 0x10;
+	   if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCDA)   tempah |= 0xc0;
            SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x19,0x0F,tempah);
+	   if(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) {
+	      if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCD) {
+	         SiS_SetRegANDOR(SiS_Pr->SiS_Part2Port,0x1a,0xf0,tempbl);
+	      }
+	   }
 
-        } else {							/* 315 - 301, 301B */
+        } else {							/* 315 - TMDS */
 
-           tempah = infoflag >> 8;
+           tempah = tempbl = infoflag >> 8;
 	   if(!SiS_Pr->UseCustomMode) {
-	      if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCD) {
+	      tempbl = 0;
+	      if((SiS_Pr->SiS_VBType & VB_SIS301C) && (SiS_Pr->SiS_VBInfo & SetCRT2ToRAMDAC)) {
+	         if(ModeNo <= 0x13) {
+	            tempah = SiS_GetRegByte((SiS_Pr->SiS_P3ca+0x02));
+  	         }
+	      }
+	      if(SiS_Pr->SiS_VBInfo & (SetCRT2ToLCD | SetCRT2ToLCDA)) {
 	         if(SiS_Pr->SiS_LCDInfo & LCDSync) {
 	            tempah = SiS_Pr->SiS_LCDInfo;
+		    tempbl = (tempah >> 6) & 0x03;
 	         }
 	      }
 	   }
 	   tempah &= 0xC0;
-
            tempah |= 0x20;
            if(!(SiS_Pr->SiS_LCDInfo & LCDRGB18Bit)) tempah |= 0x10;
-
-	   if(SiS_Pr->SiS_VBType & VB_NoLCD) {			/* TEST, imitate BIOS bug */
-	      if(SiS_Pr->SiS_VBInfo & SetCRT2ToTV) {
-	         tempah |= 0xc0;
+	   if(SiS_Pr->SiS_VBType & VB_NoLCD) {
+	      /* Imitate BIOS bug */
+	      if(SiS_Pr->SiS_VBInfo & SetCRT2ToTV)  tempah |= 0xc0;
+	   }
+	   if((SiS_Pr->SiS_VBType & VB_SIS301C) && (SiS_Pr->SiS_VBInfo & SetCRT2ToRAMDAC)) {
+	      tempah >>= 3;
+	      tempah &= 0x18;
+	      SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x13,0xe7,tempah);
+	   } else {
+              SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x19,0x0F,tempah);
+	      if(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) {
+	         if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCD) {
+	            SiS_SetRegANDOR(SiS_Pr->SiS_Part2Port,0x1a,0xf0,tempbl);
+		 }
 	      }
 	   }
-           SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x19,0x0F,tempah);
 
         }
 #endif  /* SIS315H */
@@ -5023,7 +4826,7 @@
    }
 }
 
-/******** Set CRT2 FIFO on 300/630/730 *******/
+/* Set CRT2 FIFO on 300/630/730 */
 #ifdef SIS300
 static void
 SiS_SetCRT2FIFO_300(SiS_Private *SiS_Pr,USHORT ModeNo,
@@ -5078,7 +4881,7 @@
 
   if(!SiS_Pr->CRT1UsesCustomMode) {
 
-     CRT1ModeNo = SiS_Pr->SiS_CRT1Mode;                                 	/* get CRT1 ModeNo */
+     CRT1ModeNo = SiS_Pr->SiS_CRT1Mode;                                 /* get CRT1 ModeNo */
      SiS_SearchModeID(SiS_Pr, &CRT1ModeNo, &modeidindex);
      SiS_Pr->SiS_SetFlag &= (~ProgrammingCRT2);
      SiS_Pr->SiS_SelectCRT2Rate = 0;
@@ -5087,7 +4890,7 @@
      if(CRT1ModeNo >= 0x13) {
         index = SiS_Pr->SiS_RefIndex[refreshratetableindex].Ext_CRTVCLK;
         index &= 0x3F;
-        VCLK = SiS_Pr->SiS_VCLKData[index].CLOCK;				/* Get VCLK */
+        VCLK = SiS_Pr->SiS_VCLKData[index].CLOCK;			/* Get VCLK */
 
 	colorth = SiS_GetColorDepth(SiS_Pr,CRT1ModeNo,modeidindex); 	/* Get colordepth */
         colorth >>= 1;
@@ -5097,9 +4900,9 @@
   } else {
 
      CRT1ModeNo = 0xfe;
-     VCLK = SiS_Pr->CSRClock_CRT1;						/* Get VCLK */
+     VCLK = SiS_Pr->CSRClock_CRT1;					/* Get VCLK */
      data2 = (SiS_Pr->CModeFlag_CRT1 & ModeInfoFlag) - 2;
-     switch(data2) {								/* Get color depth */
+     switch(data2) {							/* Get color depth */
         case 0 : colorth = 1; break;
         case 1 : colorth = 1; break;
         case 2 : colorth = 2; break;
@@ -5246,10 +5049,10 @@
 
        index = SiS_GetVCLK2Ptr(SiS_Pr,CRT2ModeNo,modeidindex,
                                refreshratetableindex,HwInfo);
-       VCLK = SiS_Pr->SiS_VCLKData[index].CLOCK;                         	/* Get VCLK  */
+       VCLK = SiS_Pr->SiS_VCLKData[index].CLOCK;                /* Get VCLK  */
 
        if((SiS_Pr->SiS_CustomT == CUT_BARCO1366) || (SiS_Pr->SiS_CustomT == CUT_BARCO1024)) {
-          if((ROMAddr) && SiS_Pr->SiS_UseROM) {
+          if(SiS_Pr->SiS_UseROM) {
 	     if(ROMAddr[0x220] & 0x01) {
                 VCLK = ROMAddr[0x229] | (ROMAddr[0x22a] << 8);
 	     }
@@ -5259,11 +5062,11 @@
     } else {
 
        CRT2ModeNo = 0xfe;
-       VCLK = SiS_Pr->CSRClock;							/* Get VCLK */
+       VCLK = SiS_Pr->CSRClock;					/* Get VCLK */
 
     }
 
-    colorth = SiS_GetColorDepth(SiS_Pr,CRT2ModeNo,modeidindex);   	/* Get colordepth */
+    colorth = SiS_GetColorDepth(SiS_Pr,CRT2ModeNo,modeidindex); /* Get colordepth */
     colorth >>= 1;
     if(!colorth) colorth++;
 
@@ -5282,8 +5085,8 @@
     if(HwInfo->jChipType == SIS_300) {
        if(data <= 0x0f) temp = (temp & (~0x1F)) | 0x13;
        else             temp = (temp & (~0x1F)) | 0x16;
-       if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1280x1024) {
-       		temp = (temp & (~0x1F)) | 0x13;
+       if(SiS_Pr->SiS_LCDResInfo == Panel_1280x1024) {
+       	  temp = (temp & (~0x1F)) | 0x13;
        }
     } else {
        if( ( (HwInfo->jChipType == SIS_630) ||
@@ -5313,359 +5116,114 @@
 }
 #endif
 
-/**** Set CRT2 FIFO on 315/330 series ****/
+/* Set CRT2 FIFO on 315/330 series */
 #ifdef SIS315H
 static void
-SiS_SetCRT2FIFO_310(SiS_Private *SiS_Pr)
+SiS_SetCRT2FIFO_310(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo)
 {
   SiS_SetReg(SiS_Pr->SiS_Part1Port,0x01,0x3B);
-  SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x02,~0x3F,0x04);
+  if( (HwInfo->jChipType == SIS_760)      &&
+      (SiS_Pr->SiS_SysFlags & SF_760LFB)  &&
+      (SiS_Pr->SiS_ModeType == Mode32Bpp) &&
+      (SiS_Pr->SiS_VGAHDE >= 1280)	  &&
+      (SiS_Pr->SiS_VGAVDE >= 1024) ) {
+     SiS_SetReg(SiS_Pr->SiS_Part1Port,0x2f,0x03);
+     SiS_SetReg(SiS_Pr->SiS_Part1Port,0x01,0x3b);
+     SiS_SetReg(SiS_Pr->SiS_Part1Port,0x4d,0xc0);
+     SiS_SetReg(SiS_Pr->SiS_Part1Port,0x2f,0x01);
+     SiS_SetReg(SiS_Pr->SiS_Part1Port,0x4d,0xc0);
+     SiS_SetReg(SiS_Pr->SiS_Part1Port,0x02,0x6e);
+  } else {
+     SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x02,~0x3f,0x04);
+  }
+
 }
 #endif
 
-/*************** Set LCD-A ***************/
-#ifdef SIS315H
-static void
-SiS_SetGroup1_LCDA(SiS_Private *SiS_Pr, USHORT ModeNo, USHORT ModeIdIndex,
-                   PSIS_HW_INFO HwInfo, USHORT RefreshRateTableIndex)
+static USHORT
+SiS_GetVGAHT2(SiS_Private *SiS_Pr)
 {
-  USHORT modeflag,resinfo;
-  USHORT push2,tempax,tempbx,tempcx,temp;
-  ULONG tempeax=0,tempebx,tempecx,tempvcfact;
+  ULONG tempax,tempbx;
 
-  /* This is not supported with LCDA */
-  if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_PanelCustom) return;
-  if(SiS_Pr->UseCustomMode) return;
+  tempbx = (SiS_Pr->SiS_VGAVT - SiS_Pr->SiS_VGAVDE) * SiS_Pr->SiS_RVBHCMAX;
+  tempax = (SiS_Pr->SiS_VT - SiS_Pr->SiS_VDE) * SiS_Pr->SiS_RVBHCFACT;
+  tempax = (tempax * SiS_Pr->SiS_HT) / tempbx;
+  return((USHORT)tempax);
+}
 
-  if(IS_SIS330) {
-     SiS_SetRegOR(SiS_Pr->SiS_Part1Port,0x2D,0x10);			/* Xabre 1.01.03 */
-  } else if(IS_SIS740) {
-     if(SiS_Pr->SiS_IF_DEF_LVDS == 1) {					/* 740/LVDS */
-        SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x13,0xfb,0x04);      	/* 740/LVDS */
-	SiS_SetRegOR(SiS_Pr->SiS_Part1Port,0x2D,0x03);
-     } else if(SiS_Pr->SiS_VBType & VB_SISVB) {
-        SiS_SetRegOR(SiS_Pr->SiS_Part1Port,0x2D,0x10);			/* 740/301LV, 301BDH */
-     }
-  } else {
-     if(SiS_Pr->SiS_IF_DEF_LVDS == 1) {					/* 650/LVDS */
-        SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x13,0xfb,0x04);      	/* 650/LVDS */
-	SiS_SetRegOR(SiS_Pr->SiS_Part1Port,0x2D,0x00);			/* 650/LVDS 1.10.07 */
-     } else if(SiS_Pr->SiS_VBType & VB_SISVB) {
-        SiS_SetRegAND(SiS_Pr->SiS_Part1Port,0x2D,0x0f);			/* 650/30xLv 1.10.6s */
-     }
-  }
+/* Set Part 1 / SiS bridge slave mode */
+static void
+SiS_SetGroup1_301(SiS_Private *SiS_Pr, USHORT ModeNo,USHORT ModeIdIndex,
+                  PSIS_HW_INFO HwInfo,USHORT RefreshRateTableIndex)
+{
+  USHORT  push1,push2;
+  USHORT  tempax,tempbx,tempcx,temp;
+  USHORT  resinfo,modeflag,xres=0;
+  unsigned char p1_7, p1_8;
 
   if(ModeNo <= 0x13) {
      modeflag = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_ModeFlag;
      resinfo = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_ResInfo;
+  } else if(SiS_Pr->UseCustomMode) {
+     modeflag = SiS_Pr->CModeFlag;
+     resinfo = 0;
+     xres = SiS_Pr->CHDisplay;
   } else {
      modeflag = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag;
      resinfo = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_RESINFO;
+     xres = SiS_Pr->SiS_RefIndex[RefreshRateTableIndex].XRes;
   }
 
-  tempax = SiS_Pr->SiS_LCDHDES;
-
-  temp = (tempax & 0x0007);                        		/* BPLHDESKEW[2:0]   */
-  SiS_SetReg(SiS_Pr->SiS_Part1Port,0x1A,temp);                         /* Part1_1Ah  */
-  temp = (tempax >> 3) & 0x00FF;                               	/* BPLHDESKEW[10:3]  */
-  SiS_SetReg(SiS_Pr->SiS_Part1Port,0x16,temp);                         /* Part1_16h  */
-
-  tempbx = SiS_Pr->SiS_HDE;
-  if(SiS_Pr->SiS_LCDInfo & DontExpandLCD) {
-     tempbx = SiS_Pr->PanelXRes;
-  }
-
-  tempax += tempbx;	                                    	/* HDE + HSKEW = lcdhdee  */
-  if(tempax >= SiS_Pr->SiS_HT) tempax -= SiS_Pr->SiS_HT;
-
-  temp = tempax;
-  if(SiS_Pr->SiS_VBType & VB_SISVB) {
-     if(temp & 0x07) temp += 8;
-  }
-  temp >>= 3;                                        		/* BPLHDEE  */
-  SiS_SetReg(SiS_Pr->SiS_Part1Port,0x17,temp);                        	/* Part1_17h  */
-
-  tempcx = (SiS_Pr->SiS_HT - tempbx) >> 2;     	            	/* (HT-HDE) / 4  */
-
-  /* 650/30xLV 1.10.6s, 740/LVDS */
-  if( ((SiS_Pr->SiS_VBType & VB_SISVB) && (SiS_Pr->SiS_VBInfo & SetCRT2ToLCDA)) ||
-      ((SiS_Pr->SiS_IF_DEF_LVDS == 1) && (SiS_Pr->SiS_VBInfo & SetCRT2ToLCD)) ) {
-     if(SiS_Pr->SiS_LCDResInfo != SiS_Pr->SiS_Panel640x480) {
-        if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel800x600)        tempcx = 0x28;
- 	else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1024x768)  tempcx = 0x18;
-	else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1400x1050) tempcx = 0x30;
-	else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1600x1200) tempcx = 0x40;
-	else                                                          tempcx = 0x30;
-     }
-  }
-
-  tempcx += tempax;  	                                  	/* lcdhrs  */
-  if(tempcx >= SiS_Pr->SiS_HT) tempcx -= SiS_Pr->SiS_HT;
-
-  temp = (tempcx >> 3) & 0x00FF;				/* BPLHRS */
-  SiS_SetReg(SiS_Pr->SiS_Part1Port,0x14,temp);                 		/* Part1_14h  */
+  /* The following is only done if bridge is in slave mode: */
 
-  temp += 10;
-  if(SiS_Pr->SiS_IF_DEF_LVDS == 1) {
-     if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCD) {
-        if(SiS_Pr->SiS_LCDResInfo != SiS_Pr->SiS_Panel640x480) {
-	   temp += 6;
-	   if(SiS_Pr->SiS_LCDResInfo != SiS_Pr->SiS_Panel800x600) {
-	      temp++;
-	      if(SiS_Pr->SiS_LCDResInfo != SiS_Pr->SiS_Panel1024x768) {
-	         temp += 7;
-		 if(SiS_Pr->SiS_LCDResInfo != SiS_Pr->SiS_Panel1600x1200) {
-		    temp -= 10;
-		 }
-	      }
-	   }
-	}
+  if((HwInfo->jChipType >= SIS_661) && (ModeNo > 0x13)) {
+     if(xres >= 1600) {
+        SiS_SetRegOR(SiS_Pr->SiS_P3c4,0x31,0x04);
      }
   }
-  temp &= 0x1F;
-  temp |= ((tempcx & 0x07) << 5);
-  SiS_SetReg(SiS_Pr->SiS_Part1Port,0x15,temp);                         /* Part1_15h  */
 
-  if(SiS_Pr->SiS_IF_DEF_TRUMPION == 0) {
-     tempax = SiS_Pr->PanelYRes;
-  } else {
-     tempax = SiS_Pr->SiS_VGAVDE;
-  }
+  SiS_SetReg(SiS_Pr->SiS_Part1Port,0x03,0xff);                  /* set MAX HT */
 
-  tempbx = SiS_Pr->SiS_LCDVDES + tempax;
-  if(tempbx >= SiS_Pr->SiS_VT) tempbx -= SiS_Pr->SiS_VT;
-  push2 = tempbx;
+  if(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV)  modeflag |= Charx8Dot;
 
-  tempcx = (SiS_Pr->SiS_VGAVT - SiS_Pr->SiS_VGAVDE) >> 2;
+  if(modeflag & Charx8Dot) tempcx = 0x08;
+  else                     tempcx = 0x09;
 
-  if( ((SiS_Pr->SiS_VBType & VB_SISVB) && (SiS_Pr->SiS_VBInfo & SetCRT2ToLCDA)) ||
-      ((SiS_Pr->SiS_IF_DEF_LVDS == 1) && (SiS_Pr->SiS_VBInfo & SetCRT2ToLCD)) ) {
-     if(SiS_Pr->SiS_LCDResInfo != SiS_Pr->SiS_Panel640x480) {
-        if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel800x600)         tempcx = 1;
-   	else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1024x768)   tempcx = 3;
-	else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1280x768)   tempcx = 3;
-	else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1280x1024)  tempcx = 1;
-	else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1400x1050)  tempcx = 1;
-	else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1600x1200)  tempcx = 1;
-	else                                                           tempcx = 0x0057;
-     }
-  }
+  tempax = SiS_Pr->SiS_VGAHDE;                                 	/* 0x04 Horizontal Display End */
+  if(modeflag & HalfDCLK) tempax >>= 1;
+  tempax = ((tempax / tempcx) - 1) & 0xff;
+  tempbx = tempax;
 
-  tempbx += tempcx;
-  if(SiS_Pr->SiS_VBType & VB_SISVB) {
-     tempbx++;                                                	/* BPLVRS  */
-  }
-  if(tempbx >= SiS_Pr->SiS_VT) tempbx -= SiS_Pr->SiS_VT;
-  temp = tempbx & 0x00FF;
-  SiS_SetReg(SiS_Pr->SiS_Part1Port,0x18,temp);                             /* Part1_18h  */
+  temp = tempax;
+  SiS_SetReg(SiS_Pr->SiS_Part1Port,0x04,temp);
 
-  tempcx >>= 3;
-  if(SiS_Pr->SiS_IF_DEF_LVDS == 1) {
-     if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCD) {
-        if(SiS_Pr->SiS_LCDResInfo != SiS_Pr->SiS_Panel640x480) {
-	   if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel800x600)         tempcx = 3;
-   	   else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1024x768)   tempcx = 5;
-	   else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1280x768)   tempcx = 5;
-	   else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1280x1024)  tempcx = 5;
-	   else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1400x1050)  tempcx = 2;
-	   else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1600x1200)  tempcx = 2;
-	}
+  if(SiS_Pr->SiS_VBInfo & SetCRT2ToTV) {
+     if(!(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV)) {
+        temp += 2;
      }
   }
-  tempcx += tempbx;
-  tempcx++;                                                	/* BPLVRE  */
-  temp = tempcx & 0x000F;
-  if(SiS_Pr->SiS_VBType & VB_SISVB) {
-     temp |= 0xC0;
-     SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x19,0xF0,temp); 		/* Part1_19h  */
-  } else {
-     SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x19,0xF0,temp);
+  if(SiS_Pr->SiS_VBInfo & SetCRT2ToHiVision) {
+     if(resinfo == SIS_RI_800x600) temp -= 2;
   }
+  SiS_SetReg(SiS_Pr->SiS_Part1Port,0x05,temp);                 /* 0x05 Horizontal Display Start */
 
-  temp = ((tempbx >> 8) & 0x07) << 3;
-  if(SiS_Pr->SiS_VGAVDE != SiS_Pr->SiS_VDE) temp |= 0x40;
-  if(SiS_Pr->SiS_SetFlag & EnableLVDSDDA)   temp |= 0x40;
-  if(SiS_Pr->SiS_VBType & VB_SISVB) {
-     /* Don't check Part1Port,0x00 -> is not being set if LCDA! */
-     /* We check SR06 instead here: */
-     if(SiS_Pr->SiS_LCDInfo & LCDRGB18Bit) {
-        if(SiS_GetReg(SiS_Pr->SiS_P3c4,0x06) & 0x10) temp |= 0x80;
-     }
-  } else {
-     if(SiS_Pr->SiS_LCDInfo & LCDRGB18Bit) {
-        if(SiS_GetReg(SiS_Pr->SiS_Part1Port,0x00) & 0x01) temp |= 0x80;
-     }
-  }
-  SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x1A,0x07,temp);            /* Part1_1Ah */
+  SiS_SetReg(SiS_Pr->SiS_Part1Port,0x06,0x03);                 /* 0x06 Horizontal Blank end     */
 
-  tempbx = push2;                                      		/* BPLVDEE */
+  tempax = 0xFFFF;
+  if(!(SiS_Pr->SiS_VBInfo & SetCRT2ToTV)) tempax = SiS_GetVGAHT2(SiS_Pr);
+  if(tempax >= SiS_Pr->SiS_VGAHT) tempax = SiS_Pr->SiS_VGAHT;
+  if(modeflag & HalfDCLK)         tempax >>= 1;
+  tempax = (tempax / tempcx) - 5;
+  tempcx = tempax;
 
-  tempcx = SiS_Pr->SiS_LCDVDES;                        		/* NPLVDES */
-  if(!(SiS_Pr->SiS_VBInfo & SetInSlaveMode)) {
-     if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel800x600) {
-        if(resinfo == SIS_RI_800x600) tempcx++;
-     }
-  }
-  if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel640x480) {
-     tempbx = tempcx = SiS_Pr->SiS_VGAVDE;
-     tempbx--;
-  }
-
-  temp = ((tempbx >> 8) & 0x07) << 3;
-  temp = temp | ((tempcx >> 8) & 0x07);
-  SiS_SetReg(SiS_Pr->SiS_Part1Port,0x1D,temp);                          /* Part1_1Dh */
-  temp = tempbx & 0x00FF;
-  SiS_SetReg(SiS_Pr->SiS_Part1Port,0x1C,temp);                          /* Part1_1Ch  */
-  temp = tempcx & 0x00FF;
-  SiS_SetReg(SiS_Pr->SiS_Part1Port,0x1B,temp);                          /* Part1_1Bh  */
-
-  tempeax = SiS_Pr->SiS_VGAVDE << 18;
-  tempebx = SiS_Pr->SiS_VDE;
-  temp = (USHORT)(tempeax % tempebx);
-  tempeax = tempeax / tempebx;
-  if(temp) tempeax++;
-  tempvcfact = tempeax;
-
-  temp = (USHORT)(tempeax & 0x00FF);
-  SiS_SetReg(SiS_Pr->SiS_Part1Port,0x37,temp);
-
-  temp = (USHORT)((tempeax & 0x00FF00) >> 8);
-  SiS_SetReg(SiS_Pr->SiS_Part1Port,0x36,temp);
-
-  temp = (USHORT)((tempeax & 0x00030000) >> 16);
-  if(SiS_Pr->SiS_VDE == SiS_Pr->SiS_VGAVDE) temp |= 0x04;
-  SiS_SetReg(SiS_Pr->SiS_Part1Port,0x35,temp);
-
-  if(SiS_Pr->SiS_VBType & (VB_SIS301C | VB_SIS302ELV)) {
-     temp = (USHORT)(tempeax & 0x00FF);
-     SiS_SetReg(SiS_Pr->SiS_Part4Port,0x3c,temp);
-     temp = (USHORT)((tempeax & 0x00FF00) >> 8);
-     SiS_SetReg(SiS_Pr->SiS_Part4Port,0x3b,temp);
-     temp = (USHORT)(((tempeax & 0x00030000) >> 16) << 6);
-     SiS_SetRegANDOR(SiS_Pr->SiS_Part4Port,0x3a,0x3f,temp);
-     temp = 0;
-     if(SiS_Pr->SiS_VDE != SiS_Pr->SiS_VGAVDE) temp |= 0x08;
-     SiS_SetRegANDOR(SiS_Pr->SiS_Part4Port,0x30,0xf3,temp);
-  }
-
-  tempeax = SiS_Pr->SiS_VGAHDE << 16;
-  tempebx = SiS_Pr->SiS_HDE;
-  temp = tempeax % tempebx;
-  tempeax /= tempebx;
-  if(temp) tempeax++;
-  if(tempebx == SiS_Pr->SiS_VGAHDE) tempeax = 0xFFFF;
-  tempecx = tempeax;
-  tempeax = ((SiS_Pr->SiS_VGAHDE << 16) / tempecx) - 1;
-  tempecx = (tempecx << 16) | (tempeax & 0xFFFF);
-  temp = (USHORT)(tempecx & 0x00FF);
-  SiS_SetReg(SiS_Pr->SiS_Part1Port,0x1F,temp);                          /* Part1_1Fh  */
-
-  tempeax = (SiS_Pr->SiS_VGAVDE << 18) / tempvcfact;
-  tempbx = (USHORT)(tempeax & 0x0FFFF);
-
-  if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1024x768) tempbx--;
-
-  if(SiS_Pr->SiS_SetFlag & EnableLVDSDDA)  tempbx = 1;
-
-  temp = ((tempbx >> 8) & 0x07) << 3;
-  temp = temp | ((tempecx >> 8) & 0x07);
-  SiS_SetReg(SiS_Pr->SiS_Part1Port,0x20,temp);                         /* Part1_20h */
-
-  temp = tempbx & 0x00FF;
-  SiS_SetReg(SiS_Pr->SiS_Part1Port,0x21,temp);                         /* Part1_21h */
-
-  tempecx >>= 16;   	                                  	/* BPLHCFACT  */
-  if(modeflag & HalfDCLK) tempecx >>= 1;
-  temp = (USHORT)((tempecx & 0x0000FF00) >> 8);
-  SiS_SetReg(SiS_Pr->SiS_Part1Port,0x22,temp);                         /* Part1_22h */
-
-  temp = (USHORT)(tempecx & 0x000000FF);
-  SiS_SetReg(SiS_Pr->SiS_Part1Port,0x23,temp);
-
-  if((SiS_Pr->SiS_IF_DEF_LVDS == 1) || (SiS_Pr->SiS_VBInfo & VB_SIS301LV302LV)) {
-     SiS_SetReg(SiS_Pr->SiS_Part1Port,0x1e,0x20);
-  }
-}
-#endif  /* SIS 315 */
-
-static USHORT
-SiS_GetVGAHT2(SiS_Private *SiS_Pr)
-{
-  ULONG tempax,tempbx;
-
-  tempbx = ((SiS_Pr->SiS_VGAVT - SiS_Pr->SiS_VGAVDE) * SiS_Pr->SiS_RVBHCMAX) & 0xFFFF;
-  tempax = (SiS_Pr->SiS_VT - SiS_Pr->SiS_VDE) * SiS_Pr->SiS_RVBHCFACT;
-  tempax = (tempax * SiS_Pr->SiS_HT) / tempbx;
-  return((USHORT) tempax);
-}
-
-/******* Set Part 1 / SiS bridge *********/
-static void
-SiS_SetGroup1_301(SiS_Private *SiS_Pr, USHORT ModeNo,USHORT ModeIdIndex,
-                  PSIS_HW_INFO HwInfo,USHORT RefreshRateTableIndex)
-{
-  USHORT  push1,push2;
-  USHORT  tempax,tempbx,tempcx,temp;
-  USHORT  resinfo,modeflag;
-  unsigned char p1_7, p1_8;
-
-  if(ModeNo <= 0x13) {
-     modeflag = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_ModeFlag;
-     resinfo = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_ResInfo;
-  } else {
-     if(SiS_Pr->UseCustomMode) {
-        modeflag = SiS_Pr->CModeFlag;
-	resinfo = 0;
-     } else {
-    	modeflag = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag;
-    	resinfo = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_RESINFO;
-     }
-  }
-
-  /* The following is only done if bridge is in slave mode: */
-
-  SiS_SetReg(SiS_Pr->SiS_Part1Port,0x03,0xff);                  /* set MAX HT */
-
-  if(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV)  modeflag |= Charx8Dot;
-
-  if(modeflag & Charx8Dot) tempcx = 0x08;
-  else                     tempcx = 0x09;
-
-  tempax = SiS_Pr->SiS_VGAHDE;                                 	/* 0x04 Horizontal Display End */
-  if(modeflag & HalfDCLK) tempax >>= 1;
-  tempax = ((tempax / tempcx) - 1) & 0xff;
-  tempbx = tempax;
-
-  temp = tempax;
-  SiS_SetReg(SiS_Pr->SiS_Part1Port,0x04,temp);
-
-  if(SiS_Pr->SiS_VBInfo & SetCRT2ToTV) {
-     if(!(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV)) {
-        temp += 2;
-     }
-  }
-  if(SiS_Pr->SiS_VBInfo & SetCRT2ToHiVision) {
-     if(resinfo == SIS_RI_800x600) temp -= 2;
-  }
-  SiS_SetReg(SiS_Pr->SiS_Part1Port,0x05,temp);                 /* 0x05 Horizontal Display Start */
-
-  SiS_SetReg(SiS_Pr->SiS_Part1Port,0x06,0x03);                 /* 0x06 Horizontal Blank end     */
-
-  tempax = 0xFFFF;
-  if(!(SiS_Pr->SiS_VBInfo & SetCRT2ToTV)) tempax = SiS_GetVGAHT2(SiS_Pr);
-  if(tempax >= SiS_Pr->SiS_VGAHT) tempax = SiS_Pr->SiS_VGAHT;
-  if(modeflag & HalfDCLK)         tempax >>= 1;
-  tempax = (tempax / tempcx) - 5;
-  tempcx = tempax;
-
-  if(SiS_Pr->SiS_VBInfo & SetCRT2ToHiVision) {
-     temp = tempcx - 1;
-     if(!(modeflag & HalfDCLK)) {
-        temp -= 6;
-        if(SiS_Pr->SiS_TVMode & TVSetTVSimuMode) {
-           temp -= 2;
-           if(ModeNo > 0x13) temp -= 10;
-        }
+  if(SiS_Pr->SiS_VBInfo & SetCRT2ToHiVision) {
+     temp = tempcx - 1;
+     if(!(modeflag & HalfDCLK)) {
+        temp -= 6;
+        if(SiS_Pr->SiS_TVMode & TVSetTVSimuMode) {
+           temp -= 2;
+           if(ModeNo > 0x13) temp -= 10;
+        }
      }
   } else {
      tempcx = (tempcx + tempbx) >> 1;
@@ -5684,21 +5242,20 @@
      } else {
         if(!(modeflag & HalfDCLK)) {
            temp -= 4;
-           if((SiS_Pr->SiS_LCDResInfo != SiS_Pr->SiS_Panel1280x960) &&
-	      (SiS_Pr->SiS_LCDResInfo != SiS_Pr->SiS_Panel1600x1200)) {
+           if((SiS_Pr->SiS_LCDResInfo != Panel_1280x960) &&
+	      (SiS_Pr->SiS_LCDResInfo != Panel_1600x1200)) {
               if(SiS_Pr->SiS_VGAHDE >= 800) {
                  temp -= 7;
 	         if(HwInfo->jChipType < SIS_315H) {
-	            /* 650/301LV(x) does not do this, 630/301B, 300/301LV do */
                     if(SiS_Pr->SiS_ModeType == ModeEGA) {
                        if(SiS_Pr->SiS_VGAVDE == 1024) {
                           temp += 15;
-                          if(SiS_Pr->SiS_LCDResInfo != SiS_Pr->SiS_Panel1280x1024)
+                          if(SiS_Pr->SiS_LCDResInfo != Panel_1280x1024)
 		  	     temp += 7;
                        }
                     }
 	         }
-		 if(SiS_Pr->SiS_LCDResInfo != SiS_Pr->SiS_Panel1400x1050) {
+		 if(SiS_Pr->SiS_LCDResInfo != Panel_1400x1050) {
                     if(SiS_Pr->SiS_VGAHDE >= 1280) {
                        if(SiS_Pr->SiS_LCDInfo & DontExpandLCD) temp += 28;
 		    }
@@ -5762,6 +5319,10 @@
 	      p1_7 = 0xab;
 	   }
 	}
+     } else {
+        if(SiS_Pr->SiS_TVMode & TVSetYPbPr525p) {
+	   if(modeflag & HalfDCLK) p1_7 = 0x30;
+	}
      }
   }
 
@@ -5784,7 +5345,7 @@
   else if(tempbx == 525) tempbx = 480;
   push2 = tempbx;
   if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCD) {
-     if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1024x768) {
+     if(SiS_Pr->SiS_LCDResInfo == Panel_1024x768) {
       	if(!(SiS_Pr->SiS_SetFlag & LCDVESATiming)) {
            if     (tempbx == 350) tempbx += 5;
            else if(tempbx == 480) tempbx += 5;
@@ -5830,7 +5391,7 @@
 	tempbx += (tempax << 1);
      }
   } else if(HwInfo->jChipType >= SIS_315H) {
-     if(SiS_Pr->SiS_LCDResInfo != SiS_Pr->SiS_Panel1400x1050) {
+     if(SiS_Pr->SiS_LCDResInfo != Panel_1400x1050) {
 	tempbx += (tempax << 1);
      }
   }
@@ -5907,521 +5468,465 @@
      }
   }
   SiS_SetReg(SiS_Pr->SiS_Part1Port,0x1A,temp);                	/* 0x1A SR0E */
+
+  temp = SiS_GetRegByte((SiS_Pr->SiS_P3ca+0x02));
+  SiS_SetReg(SiS_Pr->SiS_Part1Port,0x1b,temp);
 }
 
-/*********** Set Part 1 / LVDS ***********/
+/* Setup panel link
+ * This is used for LVDS, LCDA and Chrontel TV output
+ * 300/LVDS+TV, 300/301B-DH, 315/LVDS+TV, 315/LCDA
+ */
 static void
 SiS_SetGroup1_LVDS(SiS_Private *SiS_Pr, USHORT ModeNo, USHORT ModeIdIndex,
- 		   PSIS_HW_INFO HwInfo, USHORT RefreshRateTableIndex)
+                   PSIS_HW_INFO HwInfo, USHORT RefreshRateTableIndex)
 {
-  USHORT modeflag, resinfo;
-  USHORT push1, push2, tempax, tempbx, tempcx, temp;
+  USHORT modeflag,resinfo;
+  USHORT push2,tempax,tempbx,tempcx,temp;
+  ULONG tempeax=0,tempebx,tempecx,tempvcfact=0;
+  BOOLEAN islvds = FALSE, issis  = FALSE, chkdclkfirst = FALSE;
+#ifdef SIS300
+  USHORT crt2crtc;
+#endif
 #ifdef SIS315H
   USHORT pushcx;
 #endif
-  ULONG  tempeax=0, tempebx, tempecx, tempvcfact=0;
-
-  /* This is not supported on LVDS */
-  if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_PanelCustom) return;
-  if(SiS_Pr->UseCustomMode) return;
 
   if(ModeNo <= 0x13) {
      modeflag = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_ModeFlag;
      resinfo = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_ResInfo;
+#ifdef SIS300
+     crt2crtc = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_CRT2CRTC;
+#endif
+  } else if(SiS_Pr->UseCustomMode) {
+     modeflag = SiS_Pr->CModeFlag;
+     resinfo = 0;
+#ifdef SIS300
+     crt2crtc = 0;
+#endif
   } else {
      modeflag = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag;
      resinfo = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_RESINFO;
+#ifdef SIS300
+     crt2crtc = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_CRT2CRTC;
+#endif
   }
 
-  /* Set up Panel Link */
-
-  /* 1. Horizontal setup */
-
-  tempax = SiS_Pr->SiS_LCDHDES;
-
-  if((!SiS_Pr->SiS_IF_DEF_FSTN) && (!SiS_Pr->SiS_IF_DEF_DSTN)) {
-     if( (SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel640x480) &&
-         (!(SiS_Pr->SiS_VBInfo & SetInSlaveMode)) ) {
-  	   tempax -= 8;
-     }
+  /* is lvds if really LVDS, or SiS 301B-DH with external LVDS transmitter */
+  if((SiS_Pr->SiS_IF_DEF_LVDS == 1) ||
+     ((SiS_Pr->SiS_VBType & VB_SISVB) && (SiS_Pr->SiS_VBType & VB_NoLCD))) {
+     islvds = TRUE;
   }
 
-  tempcx = SiS_Pr->SiS_HT;    				  /* Horiz. Total */
-
-  tempbx = SiS_Pr->SiS_HDE;                               /* Horiz. Display End */
+  /* is really sis if sis bridge, but not 301B-DH */
+  if((SiS_Pr->SiS_VBType & VB_SISVB) && (!(SiS_Pr->SiS_VBType & VB_NoLCD))) {
+     issis = TRUE;
+  }
 
-  if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel640x480_2 ||
-     SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel640x480_3) {
-     tempbx >>= 1;
+  if((HwInfo->jChipType >= SIS_315H) && (islvds) && (!(SiS_Pr->SiS_VBInfo & SetCRT2ToLCDA))) {
+     if((!SiS_Pr->SiS_IF_DEF_FSTN) && (!SiS_Pr->SiS_IF_DEF_DSTN)) {
+        chkdclkfirst = TRUE;
+     }
   }
 
-  if(!(SiS_Pr->SiS_LCDInfo & LCDPass11)) {
-     if(SiS_Pr->SiS_LCDInfo & DontExpandLCD) {
-        if(SiS_Pr->SiS_IF_DEF_FSTN || SiS_Pr->SiS_IF_DEF_DSTN) {
-	   tempbx = SiS_Pr->PanelXRes;
-	} else if(SiS_Pr->SiS_LCDResInfo != SiS_Pr->SiS_Panel640x480) {
-	   tempbx = SiS_Pr->PanelXRes;
-	   if(SiS_Pr->SiS_CustomT == CUT_BARCO1024) {
-	      tempbx = 800;
-	      if(SiS_Pr->SiS_LCDResInfo != SiS_Pr->SiS_Panel800x600) {
-	         tempbx = 1024;
+#ifdef SIS315H
+  if((HwInfo->jChipType >= SIS_315H) && (SiS_Pr->SiS_VBInfo & SetCRT2ToLCDA)) {
+     if(IS_SIS330) {
+        SiS_SetRegOR(SiS_Pr->SiS_Part1Port,0x2D,0x10);
+     } else if(IS_SIS740) {
+        if(islvds) {
+           SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x13,0xfb,0x04);
+	   SiS_SetRegOR(SiS_Pr->SiS_Part1Port,0x2D,0x03);
+        } else if(SiS_Pr->SiS_VBType & VB_SISVB) {
+           SiS_SetRegOR(SiS_Pr->SiS_Part1Port,0x2D,0x10);
+        }
+     } else {
+        if(islvds) {
+           SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x13,0xfb,0x04);
+	   SiS_SetRegOR(SiS_Pr->SiS_Part1Port,0x2D,0x00);
+        } else if(SiS_Pr->SiS_VBType & VB_SISVB) {
+           SiS_SetRegAND(SiS_Pr->SiS_Part1Port,0x2D,0x0f);
+	   if(SiS_Pr->SiS_VBType & VB_SIS301C) {
+	      if((SiS_Pr->SiS_LCDResInfo == Panel_1024x768) ||
+	         (SiS_Pr->SiS_LCDResInfo == Panel_1280x1024)) {
+	         SiS_SetRegOR(SiS_Pr->SiS_Part1Port,0x2D,0x20);
 	      }
 	   }
         }
      }
   }
-  tempcx = (tempcx - tempbx) >> 2;		 /* HT-HDE / 4 */
-
-  push1 = tempax;
-
-  tempax += tempbx;
-
-  if(tempax >= SiS_Pr->SiS_HT) tempax -= SiS_Pr->SiS_HT;
+#endif
 
-  push2 = tempax;
+  /* Horizontal */
 
-  if((!SiS_Pr->SiS_IF_DEF_FSTN) &&
-     (!SiS_Pr->SiS_IF_DEF_DSTN) &&
-     (SiS_Pr->SiS_CustomT != CUT_BARCO1366) &&
-     (SiS_Pr->SiS_CustomT != CUT_BARCO1024) &&
-     (SiS_Pr->SiS_CustomT != CUT_PANEL848)) {
-     if(!(SiS_Pr->SiS_LCDInfo & LCDPass11)) {
-        if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCD) {
-           if(SiS_Pr->SiS_LCDResInfo != SiS_Pr->SiS_Panel640x480) {
-     	      if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel800x600)        tempcx = 0x0028;
-	      else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1024x600)  tempcx = 0x0018;
-     	      else if( (SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1024x768) ||
-	            (SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1152x768) ) {
-	  	   if(HwInfo->jChipType < SIS_315H) {
-		      if(SiS_Pr->SiS_VBType & VB_SISVB) {
-		         tempcx = 0x0017;  /* A901; sometimes 0x0018; */
-		      } else {
-		         tempcx = 0x0017;
-#ifdef TWNEWPANEL
-			 tempcx = 0x0018;
-#endif
-		      }
-		   } else {
-		      tempcx = 0x0018;
-		   }
-	      }
-	      else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1280x768)  tempcx = 0x0028;
-	      else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1280x1024) tempcx = 0x0030;
-	      else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1400x1050) tempcx = 0x0030;
-	      else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1600x1200) tempcx = 0x0040;
+  tempax = SiS_Pr->SiS_LCDHDES;
+  if(islvds) {
+     if(SiS_Pr->SiS_VBInfo & (SetCRT2ToLCD | SetCRT2ToLCDA)) {
+        if((!SiS_Pr->SiS_IF_DEF_FSTN) && (!SiS_Pr->SiS_IF_DEF_DSTN)) {
+           if((SiS_Pr->SiS_LCDResInfo == Panel_640x480) &&
+              (!(SiS_Pr->SiS_VBInfo & SetInSlaveMode))) {
+  	      tempax -= 8;
 	   }
-        }
+	}
      }
   }
 
-  tempcx += tempax;                              /* lcdhrs  */
-  if(tempcx >= SiS_Pr->SiS_HT) tempcx -= SiS_Pr->SiS_HT;
-
-  tempax = tempcx >> 3;                          /* BPLHRS */
-  temp = tempax & 0x00FF;
-  SiS_SetReg(SiS_Pr->SiS_Part1Port,0x14,temp);		 /* Part1_14h; Panel Link Horizontal Retrace Start  */
+  temp = (tempax & 0x0007);
+  SiS_SetReg(SiS_Pr->SiS_Part1Port,0x1A,temp);			/* BPLHDESKEW[2:0]   */
+  temp = (tempax >> 3) & 0x00FF;
+  SiS_SetReg(SiS_Pr->SiS_Part1Port,0x16,temp);			/* BPLHDESKEW[10:3]  */
 
-  if(SiS_Pr->SiS_LCDInfo & LCDPass11) {
-     temp = (tempax & 0x00FF) + 2;
-  } else {
-     temp = (tempax & 0x00FF) + 10;
-     if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCD) {
-        if((!SiS_Pr->SiS_IF_DEF_DSTN) &&
-	   (!SiS_Pr->SiS_IF_DEF_FSTN) &&
-	   (SiS_Pr->SiS_CustomT != CUT_BARCO1366) &&
-	   (SiS_Pr->SiS_CustomT != CUT_BARCO1024) &&
-	   (SiS_Pr->SiS_CustomT != CUT_PANEL848)) {
-           if(SiS_Pr->SiS_LCDResInfo != SiS_Pr->SiS_Panel640x480) {
-	      temp += 6;
-              if(SiS_Pr->SiS_LCDResInfo != SiS_Pr->SiS_Panel800x600) {
-	         temp++;
-	         if(HwInfo->jChipType >= SIS_315H) {
-	            if(SiS_Pr->SiS_LCDResInfo != SiS_Pr->SiS_Panel1024x768) {
-	               temp += 7;
-		       if(SiS_Pr->SiS_LCDResInfo != SiS_Pr->SiS_Panel1600x1200) {
-		          temp -= 0x14;
-			  if(SiS_Pr->SiS_LCDResInfo != SiS_Pr->SiS_Panel1280x768) {
-			     temp -= 10;
-			  }
-		       }
-	            }
-	         }
-	      }
-           }
-        }
+  tempbx = SiS_Pr->SiS_HDE;
+  if(SiS_Pr->SiS_VBInfo & (SetCRT2ToLCD | SetCRT2ToLCDA)) {
+     if((SiS_Pr->SiS_LCDResInfo == Panel_640x480_2) ||
+        (SiS_Pr->SiS_LCDResInfo == Panel_640x480_3)) {
+        tempbx >>= 1;
+     }
+     if(!(SiS_Pr->SiS_LCDInfo & LCDPass11)) {
+        tempbx = SiS_Pr->PanelXRes;
      }
   }
 
-  temp &= 0x1F;
-  temp |= ((tempcx & 0x0007) << 5);
-#if 0
-  if(SiS_Pr->SiS_IF_DEF_FSTN) temp = 0x20;       /* WRONG? BIOS loads cl, not ah */
-#endif
-  SiS_SetReg(SiS_Pr->SiS_Part1Port,0x15,temp);    	 /* Part1_15h; Panel Link Horizontal Retrace End/Skew */
-
-  tempbx = push2;
-  tempcx = push1;                                /* lcdhdes  */
+  tempax += tempbx;
+  if(tempax >= SiS_Pr->SiS_HT) tempax -= SiS_Pr->SiS_HT;
 
-  temp = (tempcx & 0x0007);                      /* BPLHDESKEW  */
-  SiS_SetReg(SiS_Pr->SiS_Part1Port,0x1A,temp);   	 /* Part1_1Ah; Panel Link Vertical Retrace Start (2:0) */
+  temp = tempax;
+  if(temp & 0x07) temp += 8;
+  temp >>= 3;
+  SiS_SetReg(SiS_Pr->SiS_Part1Port,0x17,temp);			/* BPLHDEE  */
 
-  tempcx >>= 3;                                  /* BPLHDES */
-  temp = (tempcx & 0x00FF);
-#if 0 /* Not 550 FSTN */
-  if(HwInfo->jChipType >= SIS_315H) {
-     if(ModeNo == 0x5b) temp--; */
-  }
-#endif
-  SiS_SetReg(SiS_Pr->SiS_Part1Port,0x16,temp);    	 /* Part1_16h; Panel Link Horizontal Display Enable Start  */
+  tempcx = (SiS_Pr->SiS_HT - tempbx) >> 2;
 
-  if((HwInfo->jChipType < SIS_315H) ||
-     (SiS_Pr->SiS_IF_DEF_FSTN) ||
-     (SiS_Pr->SiS_IF_DEF_DSTN)) {
-     if(tempbx & 0x07) tempbx += 8;
-  }
-  tempbx >>= 3;                                  /* BPLHDEE  */
-  temp = tempbx & 0x00FF;
-#if 0 /* Not 550 FSTN */
-  if(HwInfo->jChipType >= SIS_315H) {
-     if(ModeNo == 0x5b) temp--;
+  if(SiS_Pr->SiS_VBInfo & (SetCRT2ToLCD | SetCRT2ToLCDA)) {
+     if(!(SiS_Pr->SiS_LCDInfo & LCDPass11)) {
+        if(SiS_Pr->PanelHRS != 999) tempcx = SiS_Pr->PanelHRS;
+     }
   }
-#endif
-  SiS_SetReg(SiS_Pr->SiS_Part1Port,0x17,temp);   	 /* Part1_17h; Panel Link Horizontal Display Enable End  */
 
-  /* 2. Vertical setup */
+  tempcx += tempax;
+  if(tempcx >= SiS_Pr->SiS_HT) tempcx -= SiS_Pr->SiS_HT;
 
-  if(HwInfo->jChipType < SIS_315H) {
-     tempcx = SiS_Pr->SiS_VGAVT;
-     tempbx = SiS_Pr->SiS_VGAVDE;
-     if((SiS_Pr->SiS_CustomT != CUT_BARCO1366) && (SiS_Pr->SiS_CustomT != CUT_BARCO1024)) {
-        if(SiS_Pr->SiS_LCDInfo & DontExpandLCD) {
-           if(SiS_Pr->SiS_LCDResInfo != SiS_Pr->SiS_Panel640x480) {
-	      tempbx = SiS_Pr->PanelYRes;
+  temp = (tempcx >> 3) & 0x00FF;
+  if(SiS_Pr->SiS_VBInfo & (SetCRT2ToLCD | SetCRT2ToLCDA)) {
+     if(SiS_Pr->SiS_IF_DEF_TRUMPION) {
+        if(SiS_Pr->SiS_LCDResInfo == Panel_1024x768) {
+           switch(ModeNo) {
+           case 0x04:
+           case 0x05:
+           case 0x0d: temp = 0x56; break;
+           case 0x10: temp = 0x60; break;
+           case 0x13: temp = 0x5f; break;
+           case 0x40:
+           case 0x41:
+           case 0x4f:
+           case 0x43:
+           case 0x44:
+           case 0x62:
+           case 0x56:
+           case 0x53:
+           case 0x5d:
+           case 0x5e: temp = 0x54; break;
            }
-	}
+        }
      }
-     tempcx -= tempbx;
+  }
+  SiS_SetReg(SiS_Pr->SiS_Part1Port,0x14,temp);			/* BPLHRS */
 
+  if(SiS_Pr->SiS_VBInfo & (SetCRT2ToLCD | SetCRT2ToLCDA)) {
+     temp += 2;
+     if(!(SiS_Pr->SiS_LCDInfo & LCDPass11)) {
+        temp += 8;
+        if(SiS_Pr->PanelHRE != 999) {
+           temp = tempcx + SiS_Pr->PanelHRE;
+	   if(temp >= SiS_Pr->SiS_HT) temp -= SiS_Pr->SiS_HT;
+	   temp >>= 3;
+        }
+     }
   } else {
-
-     tempcx = SiS_Pr->SiS_VGAVT - SiS_Pr->SiS_VGAVDE;           /* VGAVT-VGAVDE  */
-
+     temp += 10;
   }
 
-  tempbx = SiS_Pr->SiS_LCDVDES;	   		 	 	/* VGAVDES  */
-  push1 = tempbx;
+  temp &= 0x1F;
+  temp |= ((tempcx & 0x07) << 5);
+#if 0
+  if(SiS_Pr->SiS_IF_DEF_FSTN) temp = 0x20;       		/* WRONG? BIOS loads cl, not ah */
+#endif
+  SiS_SetReg(SiS_Pr->SiS_Part1Port,0x15,temp);			/* BPLHRE */
+
+  /* Vertical */
 
   tempax = SiS_Pr->SiS_VGAVDE;
-
-  if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCD) {
-     if((SiS_Pr->SiS_CustomT == CUT_BARCO1366) || (SiS_Pr->SiS_CustomT == CUT_BARCO1024)) {
-        if(SiS_Pr->SiS_LCDResInfo != SiS_Pr->SiS_Panel640x480) {
-           tempax = 600;
-	   if(SiS_Pr->SiS_LCDResInfo != SiS_Pr->SiS_Panel800x600) {
-	      tempax = 768;
-	   }
-	}
-     } else if( (SiS_Pr->SiS_IF_DEF_TRUMPION == 0)   &&
-                (!(SiS_Pr->SiS_LCDInfo & LCDPass11)) &&
-                ((SiS_Pr->SiS_LCDResInfo != SiS_Pr->SiS_Panel640x480) ||
-	         (SiS_Pr->SiS_IF_DEF_FSTN) ||
-	         (SiS_Pr->SiS_IF_DEF_DSTN)) ) {
+  if(SiS_Pr->SiS_VBInfo & (SetCRT2ToLCD | SetCRT2ToLCDA)) {
+     if(!(SiS_Pr->SiS_LCDInfo & LCDPass11)) {
 	tempax = SiS_Pr->PanelYRes;
      }
   }
 
-  tempbx += tempax;
+  tempbx = SiS_Pr->SiS_LCDVDES + tempax;
   if(tempbx >= SiS_Pr->SiS_VT) tempbx -= SiS_Pr->SiS_VT;
 
   push2 = tempbx;
 
-  tempcx >>= 1;
-
-  if((SiS_Pr->SiS_VBInfo & SetCRT2ToLCD) &&
-     (SiS_Pr->SiS_LCDResInfo != SiS_Pr->SiS_Panel640x480) &&
-     (SiS_Pr->SiS_CustomT != CUT_BARCO1366) &&
-     (SiS_Pr->SiS_CustomT != CUT_BARCO1024) &&
-     (SiS_Pr->SiS_CustomT != CUT_PANEL848)) {
-     if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel640x480_2 ||
-        SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel640x480_3) {
-	tempcx = 0x0017;
-     } else if(!(SiS_Pr->SiS_LCDInfo & LCDPass11)) {
-        if(SiS_Pr->SiS_IF_DEF_FSTN || SiS_Pr->SiS_IF_DEF_DSTN) {
-	   if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel800x600)         tempcx = 0x0003;
-  	   else if((SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1024x768) ||
-	           (SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1280x768)) tempcx = 0x0003;
-           else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1280x1024)  tempcx = 0x0001;
-           else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1400x1050)  tempcx = 0x0001;
-	   else 							  tempcx = 0x0057;
-        } else  {
-     	   if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel800x600)         tempcx = 0x0001;
-	   else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1024x600)   tempcx = 0x0001;
-     	   else if((SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1024x768) ||
-	           (SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1152x768)) {
-		   if(HwInfo->jChipType < SIS_315H) {
-		      if(SiS_Pr->SiS_VBType & VB_SISVB) {
-		         tempcx = 0x0002;   /* A901; sometimes 0x0003; */
-		      } else {
-			 tempcx = 0x0002;
-#ifdef TWNEWPANEL
-			 tempcx = 0x0003;
-#endif
-		      }
-		   } else tempcx = 0x0003;
-           }
-     	   else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1280x768)  tempcx = 0x0003;
-     	   else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1280x1024) tempcx = 0x0001;
-     	   else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1400x1050) tempcx = 0x0001;
-	   else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1600x1200) tempcx = 0x0001;
-     	   else 							 tempcx = 0x0057;
+  tempcx = SiS_Pr->SiS_VGAVT - SiS_Pr->SiS_VGAVDE;
+  if(HwInfo->jChipType < SIS_315H) {
+     if(SiS_Pr->SiS_VBInfo & (SetCRT2ToLCD | SetCRT2ToLCDA)) {
+        if(!(SiS_Pr->SiS_LCDInfo & LCDPass11)) {
+	   tempcx = SiS_Pr->SiS_VGAVT - SiS_Pr->PanelYRes;
 	}
      }
   }
+  if(islvds) tempcx >>= 1;
+  else       tempcx >>= 2;
 
-  tempbx += tempcx;			 	/* BPLVRS  */
-
-  if((HwInfo->jChipType < SIS_315H) ||
-     (SiS_Pr->SiS_IF_DEF_FSTN) ||
-     (SiS_Pr->SiS_IF_DEF_DSTN)) {
-     tempbx++;
+  if( (SiS_Pr->SiS_VBInfo & (SetCRT2ToLCD | SetCRT2ToLCDA)) &&
+      (!(SiS_Pr->SiS_LCDInfo & LCDPass11)) 		    &&
+      (SiS_Pr->PanelVRS != 999) ) {
+     tempcx = SiS_Pr->PanelVRS;
+     tempbx += tempcx;
+     if(issis) tempbx++;
+  } else {
+     tempbx += tempcx;
+     if(HwInfo->jChipType < SIS_315H) tempbx++;
+     else if(issis)                   tempbx++;
   }
 
-  if(tempbx >= SiS_Pr->SiS_VT) tempbx -= SiS_Pr->SiS_VT;
+  if(tempbx >= SiS_Pr->SiS_VT) tempbx -= SiS_Pr->SiS_VT;	/* BPLVRS  */
 
   temp = tempbx & 0x00FF;
-  SiS_SetReg(SiS_Pr->SiS_Part1Port,0x18,temp);       	 /* Part1_18h; Panel Link Vertical Retrace Start  */
+  if(SiS_Pr->SiS_IF_DEF_TRUMPION) {
+     if(SiS_Pr->SiS_LCDResInfo == Panel_1024x768) {
+        if(ModeNo == 0x10) temp = 0xa9;
+     }
+  }
+  SiS_SetReg(SiS_Pr->SiS_Part1Port,0x18,temp);
 
   tempcx >>= 3;
+  tempcx++;
 
-  if((!(SiS_Pr->SiS_LCDInfo & LCDPass11)) &&
-     (SiS_Pr->SiS_CustomT != CUT_BARCO1366) &&
-     (SiS_Pr->SiS_CustomT != CUT_BARCO1024) &&
-     (SiS_Pr->SiS_CustomT != CUT_PANEL848)) {
-     if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCD) {
-        if( (HwInfo->jChipType < SIS_315H) &&
-            (SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel640x480) )     tempcx = 0x0001;
-	else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel640x480_2)  tempcx = 0x0002;
-	else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel640x480_3)  tempcx = 0x0002;
-        else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel800x600)    tempcx = 0x0003;
-        else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1024x600)   tempcx = 0x0005;
-        else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1152x768)   tempcx = 0x0005;
-	else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1280x768)   tempcx = 0x0011;
-        else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1280x1024)  tempcx = 0x0005;
-        else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1400x1050)  tempcx = 0x0002;
-        else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1600x1200)  tempcx = 0x0011;
-        else if(SiS_Pr->SiS_LCDResInfo != SiS_Pr->SiS_Panel640x480)  {
-     		if(HwInfo->jChipType < SIS_315H) {
-		   if(SiS_Pr->SiS_VBType & VB_SISVB) {
-		      tempcx = 0x0004;   /* A901; Other BIOS sets 0x0005; */
-		   } else {
-		      tempcx = 0x0004;
-#ifdef TWNEWPANEL
-		      tempcx = 0x0005;
-#endif
-		   }
-		} else {
-		   tempcx = 0x0005;
-		}
-        }
+  if(SiS_Pr->SiS_VBInfo & (SetCRT2ToLCD | SetCRT2ToLCDA)) {
+     if(!(SiS_Pr->SiS_LCDInfo & LCDPass11)) {
+        if(SiS_Pr->PanelVRE != 999) tempcx = SiS_Pr->PanelVRE;
      }
   }
 
-  tempcx = tempcx + tempbx + 1;                  /* BPLVRE  */
+  tempcx += tempbx;
   temp = tempcx & 0x000F;
-  if(SiS_Pr->SiS_IF_DEF_FSTN ||
-     SiS_Pr->SiS_IF_DEF_DSTN ||
-     (SiS_Pr->SiS_CustomT == CUT_BARCO1366) ||
-     (SiS_Pr->SiS_CustomT == CUT_BARCO1024) ||
-     (SiS_Pr->SiS_CustomT == CUT_PANEL848)) {
-     temp |= 0x30;
-  }
-  SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x19,0xf0,temp); /* Part1_19h; Panel Link Vertical Retrace End (3:0); Misc.  */
+  SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x19,0xF0,temp);	/* BPLVRE  */
 
-  temp = ((tempbx & 0x0700) >> 8) << 3;          /* BPLDESKEW =0 */
+  temp = ((tempbx >> 8) & 0x07) << 3;
   if(SiS_Pr->SiS_IF_DEF_FSTN || SiS_Pr->SiS_IF_DEF_DSTN) {
      if(SiS_Pr->SiS_HDE != 640) {
-        if(SiS_Pr->SiS_VGAVDE != SiS_Pr->SiS_VDE)   temp |= 0x40;
+        if(SiS_Pr->SiS_VGAVDE != SiS_Pr->SiS_VDE)  temp |= 0x40;
      }
-  } else if(SiS_Pr->SiS_VGAVDE != SiS_Pr->SiS_VDE)  temp |= 0x40;
-  if(SiS_Pr->SiS_SetFlag & EnableLVDSDDA)           temp |= 0x40;
-  if(SiS_Pr->SiS_LCDInfo & LCDRGB18Bit) {
-     if(HwInfo->jChipType >= SIS_315H) {
-        if(SiS_GetReg(SiS_Pr->SiS_Part1Port,0x00) & 0x01) {
-           temp |= 0x80;
+  } else if(SiS_Pr->SiS_VGAVDE != SiS_Pr->SiS_VDE) temp |= 0x40;
+  if(SiS_Pr->SiS_SetFlag & EnableLVDSDDA)          temp |= 0x40;
+  tempbx = 0x87;
+  if((HwInfo->jChipType >= SIS_315H) ||
+     (HwInfo->jChipRevision >= 0x30)) {
+     tempbx = 0x07;
+     if((SiS_Pr->SiS_IF_DEF_CH70xx == 1) && (SiS_Pr->SiS_VBInfo & SetCRT2ToTV)) {
+	if(SiS_GetReg(SiS_Pr->SiS_Part1Port,0x00) & 0x03)    temp |= 0x80;
+     }
+     /* Chrontel 701x operates in 24bit mode (8-8-8, 2x12bit mutliplexed) via VGA2 */
+     if(SiS_Pr->SiS_LCDInfo & LCDRGB18Bit) {
+	if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCDA) {
+	   if(SiS_GetReg(SiS_Pr->SiS_P3c4,0x06) & 0x10)      temp |= 0x80;
+	} else {
+	   if(SiS_GetReg(SiS_Pr->SiS_Part1Port,0x00) & 0x01) temp |= 0x80;
+	}
+     }
+  }
+  SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x1A,tempbx,temp);
+
+  tempbx = push2;                                      		/* BPLVDEE */
+
+  tempcx = SiS_Pr->SiS_LCDVDES;                        		/* BPLVDES */
+
+  if(SiS_Pr->SiS_VBInfo & (SetCRT2ToLCD | SetCRT2ToLCDA)) {
+     switch(SiS_Pr->SiS_LCDResInfo) {
+     case Panel_640x480:
+        tempbx = SiS_Pr->SiS_VGAVDE - 1;
+        tempcx = SiS_Pr->SiS_VGAVDE;
+	break;
+     case Panel_800x600:
+        if(!(SiS_Pr->SiS_VBInfo & SetInSlaveMode)) {
+           if(resinfo == SIS_RI_800x600) tempcx++;
         }
-     } else {
-	if( (HwInfo->jChipType == SIS_630) ||
-	    (HwInfo->jChipType == SIS_730) ) {
-	   if(HwInfo->jChipRevision >= 0x30) {
-	      temp |= 0x80;
+	break;
+     case Panel_1024x600:
+        if(!(SiS_Pr->SiS_VBInfo & SetInSlaveMode)) {
+           if(resinfo == SIS_RI_1024x600) tempcx++;
+           if(SiS_Pr->SiS_LCDInfo & DontExpandLCD) {
+	      if(resinfo == SIS_RI_800x600) tempcx++;
 	   }
-	}
+        }
+	break;
+     case Panel_1024x768:
+        if(HwInfo->jChipType < SIS_315H) {
+           if(!(SiS_Pr->SiS_VBInfo & SetInSlaveMode)) {
+              if(resinfo == SIS_RI_1024x768) tempcx++;
+	   }
+        }
+	break;
      }
   }
-  SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x1A,0x87,temp);  /* Part1_1Ah; Panel Link Control Signal (7:3); Vertical Retrace Start (2:0) */
 
-  if (HwInfo->jChipType < SIS_315H) {
+  temp = ((tempbx >> 8) & 0x07) << 3;
+  temp = temp | ((tempcx >> 8) & 0x07);
+  SiS_SetReg(SiS_Pr->SiS_Part1Port,0x1D,temp);
+  /* if(SiS_Pr->SiS_IF_DEF_FSTN) tempbx++;  */
+  SiS_SetReg(SiS_Pr->SiS_Part1Port,0x1C,tempbx);
+  SiS_SetReg(SiS_Pr->SiS_Part1Port,0x1B,tempcx);
 
-#ifdef SIS300      /* 300 series */
+  /* Vertical scaling */
 
-        tempeax = SiS_Pr->SiS_VGAVDE << 6;
-        temp = (USHORT)(tempeax % (ULONG)SiS_Pr->SiS_VDE);
-        tempeax = tempeax / (ULONG)SiS_Pr->SiS_VDE;
-        if(temp != 0) tempeax++;
-        tempebx = tempeax;                         /* BPLVCFACT  */
+  if(HwInfo->jChipType < SIS_315H) {
 
-  	if(SiS_Pr->SiS_SetFlag & EnableLVDSDDA) {
-	   tempebx = 0x003F;
-	}
+#ifdef SIS300      /* 300 series */
+     tempeax = SiS_Pr->SiS_VGAVDE << 6;
+     temp = (tempeax % (ULONG)SiS_Pr->SiS_VDE);
+     tempeax = tempeax / (ULONG)SiS_Pr->SiS_VDE;
+     if(temp) tempeax++;
 
-  	temp = (USHORT)(tempebx & 0x00FF);
-  	SiS_SetReg(SiS_Pr->SiS_Part1Port,0x1E,temp);      /* Part1_1Eh; Panel Link Vertical Scaling Factor */
+     if(SiS_Pr->SiS_SetFlag & EnableLVDSDDA) tempeax = 0x3F;
 
+     temp = (USHORT)(tempeax & 0x00FF);
+     SiS_SetReg(SiS_Pr->SiS_Part1Port,0x1E,temp);      	/* BPLVCFACT */
+     tempvcfact = temp;
 #endif /* SIS300 */
 
   } else {
 
 #ifdef SIS315H  /* 315 series */
+     tempeax = SiS_Pr->SiS_VGAVDE << 18;
+     tempebx = SiS_Pr->SiS_VDE;
+     temp = (tempeax % tempebx);
+     tempeax = tempeax / tempebx;
+     if(temp) tempeax++;
+     tempvcfact = tempeax;
 
-        if(HwInfo->jChipType == SIS_740) {
-           SiS_SetRegOR(SiS_Pr->SiS_Part1Port,0x1E,0x03);
-        } else {
-	   SiS_SetReg(SiS_Pr->SiS_Part1Port,0x1E,0x23);
-	}
-
-	tempeax = SiS_Pr->SiS_VGAVDE << 18;
-    	temp = (USHORT)(tempeax % (ULONG)SiS_Pr->SiS_VDE);
-    	tempeax = tempeax / SiS_Pr->SiS_VDE;
-    	if(temp != 0) tempeax++;
-    	tempebx = tempeax;                         /* BPLVCFACT  */
-        tempvcfact = tempeax;
-    	temp = (USHORT)(tempebx & 0x00FF);
-    	SiS_SetReg(SiS_Pr->SiS_Part1Port,0x37,temp);      /* Part1_37h; Panel Link Vertical Scaling Factor */
-    	temp = (USHORT)((tempebx & 0x00FF00) >> 8);
-    	SiS_SetReg(SiS_Pr->SiS_Part1Port,0x36,temp);      /* Part1_36h; Panel Link Vertical Scaling Factor */
-    	temp = (USHORT)((tempebx & 0x00030000) >> 16);
-	temp &= 0x03;
-    	if(SiS_Pr->SiS_VDE == SiS_Pr->SiS_VGAVDE) temp |= 0x04;
-    	SiS_SetReg(SiS_Pr->SiS_Part1Port,0x35,temp);      /* Part1_35h; Panel Link Vertical Scaling Factor */
-
-#endif /* SIS315H */
-
-  }
-
-  tempbx = push2;                                  /* BPLVDEE  */
-  tempcx = push1;
-
-  push1 = temp;
-
-  if(!(SiS_Pr->SiS_VBInfo & SetInSlaveMode)) {
-   	if(!SiS_Pr->SiS_IF_DEF_FSTN && !SiS_Pr->SiS_IF_DEF_DSTN) {
-		if(HwInfo->jChipType < SIS_315H) {
-			if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1024x600) {
-      				if(resinfo == SIS_RI_1024x600) tempcx++;
-				if(SiS_Pr->SiS_LCDInfo & DontExpandLCD) {
-					if(resinfo == SIS_RI_800x600) tempcx++;
-		    		}
-			} else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel800x600) {
-      				if(resinfo == SIS_RI_800x600)  tempcx++;
-				if(resinfo == SIS_RI_1024x768) tempcx++; /* Doesnt make sense anyway... */
-			} else  if(resinfo == SIS_RI_1024x768) tempcx++;
-		} else {
-			if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel800x600) {
-      				if(resinfo == SIS_RI_800x600)  tempcx++;
-			}
-		}
-	}
-  }
+     temp = (USHORT)(tempeax & 0x00FF);
+     SiS_SetReg(SiS_Pr->SiS_Part1Port,0x37,temp);
+     temp = (USHORT)((tempeax & 0x00FF00) >> 8);
+     SiS_SetReg(SiS_Pr->SiS_Part1Port,0x36,temp);
+     temp = (USHORT)((tempeax & 0x00030000) >> 16);
+     if(SiS_Pr->SiS_VDE == SiS_Pr->SiS_VGAVDE) temp |= 0x04;
+     SiS_SetReg(SiS_Pr->SiS_Part1Port,0x35,temp);
 
-  if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel640x480) {
-     if((!SiS_Pr->SiS_IF_DEF_FSTN) && (!SiS_Pr->SiS_IF_DEF_DSTN)) {
-        tempcx = SiS_Pr->SiS_VGAVDE;
-        tempbx = SiS_Pr->SiS_VGAVDE - 1;
+     if(SiS_Pr->SiS_VBType & (VB_SIS301C | VB_SIS302ELV)) {
+        temp = (USHORT)(tempeax & 0x00FF);
+        SiS_SetReg(SiS_Pr->SiS_Part4Port,0x3c,temp);
+        temp = (USHORT)((tempeax & 0x00FF00) >> 8);
+        SiS_SetReg(SiS_Pr->SiS_Part4Port,0x3b,temp);
+        temp = (USHORT)(((tempeax & 0x00030000) >> 16) << 6);
+        SiS_SetRegANDOR(SiS_Pr->SiS_Part4Port,0x3a,0x3f,temp);
+        temp = 0;
+        if(SiS_Pr->SiS_VDE != SiS_Pr->SiS_VGAVDE) temp |= 0x08;
+        SiS_SetRegANDOR(SiS_Pr->SiS_Part4Port,0x30,0xf3,temp);
      }
-  }
-
-  temp = ((tempbx & 0x0700) >> 8) << 3;
-  temp |= ((tempcx & 0x0700) >> 8);
-  SiS_SetReg(SiS_Pr->SiS_Part1Port,0x1D,temp);     	/* Part1_1Dh; Vertical Display Overflow; Control Signal */
-
-  temp = tempbx & 0x00FF;
-  /* if(SiS_Pr->SiS_IF_DEF_FSTN) temp++;  */
-  SiS_SetReg(SiS_Pr->SiS_Part1Port,0x1C,temp);      	/* Part1_1Ch; Panel Link Vertical Display Enable End  */
+#endif
 
-  temp = tempcx & 0x00FF;
-  SiS_SetReg(SiS_Pr->SiS_Part1Port,0x1B,temp);      	/* Part1_1Bh; Panel Link Vertical Display Enable Start  */
+  }
 
-  /* 3. Additional horizontal setup (scaling, etc) */
+  /* Horizontal scaling */
 
-  tempecx = SiS_Pr->SiS_VGAHDE;
-  if(HwInfo->jChipType >= SIS_315H) {
-     if((!SiS_Pr->SiS_IF_DEF_FSTN) && (!SiS_Pr->SiS_IF_DEF_DSTN)) {
-        if(modeflag & HalfDCLK) tempecx >>= 1;
-     }
+  tempeax = SiS_Pr->SiS_VGAHDE;		/* 1f = ( (VGAHDE * 65536) / ( (VGAHDE * 65536) / HDE ) ) - 1*/
+  if(chkdclkfirst) {
+     if(modeflag & HalfDCLK) tempeax >>= 1;
   }
-  tempebx = SiS_Pr->SiS_HDE;
-  if(tempecx == tempebx) tempeax = 0xFFFF;
-  else {
-     tempeax = tempecx;
-     tempeax <<= 16;
-     temp = (USHORT)(tempeax % tempebx);
-     tempeax = tempeax / tempebx;
+  tempebx = tempeax << 16;
+  if(SiS_Pr->SiS_HDE == tempeax) {
+     tempecx = 0xFFFF;
+  } else {
+     tempecx = tempebx / SiS_Pr->SiS_HDE;
      if(HwInfo->jChipType >= SIS_315H) {
-        if(temp) tempeax++;
+        if(tempebx % SiS_Pr->SiS_HDE) tempecx++;
      }
   }
-  tempecx = tempeax;
 
   if(HwInfo->jChipType >= SIS_315H) {
-     tempeax = SiS_Pr->SiS_VGAHDE;
-     if((!SiS_Pr->SiS_IF_DEF_FSTN) && (!SiS_Pr->SiS_IF_DEF_DSTN)) {
-        if(modeflag & HalfDCLK) tempeax >>= 1;
-     }
-     tempeax <<= 16;
-     tempeax = (tempeax / tempecx) - 1;
+     tempeax = (tempebx / tempecx) - 1;
   } else {
      tempeax = ((SiS_Pr->SiS_VGAHT << 16) / tempecx) - 1;
   }
-  tempecx <<= 16;
-  tempecx |= (tempeax & 0xFFFF);
+  tempecx = (tempecx << 16) | (tempeax & 0xFFFF);
   temp = (USHORT)(tempecx & 0x00FF);
-  SiS_SetReg(SiS_Pr->SiS_Part1Port,0x1F,temp);  	 /* Part1_1Fh; Panel Link DDA Operational Number in each horiz. line */
+  SiS_SetReg(SiS_Pr->SiS_Part1Port,0x1F,temp);
 
-  tempbx = SiS_Pr->SiS_VDE;
   if(HwInfo->jChipType >= SIS_315H) {
      tempeax = (SiS_Pr->SiS_VGAVDE << 18) / tempvcfact;
-     tempbx = (USHORT)(tempeax & 0x0FFFF);
+     tempbx = (USHORT)(tempeax & 0xFFFF);
   } else {
      tempeax = SiS_Pr->SiS_VGAVDE << 6;
-     tempbx = push1 & 0x3f;
+     tempbx = tempvcfact & 0x3f;
      if(tempbx == 0) tempbx = 64;
      tempeax /= tempbx;
-     tempbx = (USHORT)(tempeax & 0x0FFFF);
+     tempbx = (USHORT)(tempeax & 0xFFFF);
   }
-  if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1024x768) tempbx--;
+  if(SiS_Pr->SiS_LCDResInfo == Panel_1024x768) tempbx--;
   if(SiS_Pr->SiS_SetFlag & EnableLVDSDDA) {
      if((!SiS_Pr->SiS_IF_DEF_FSTN) && (!SiS_Pr->SiS_IF_DEF_DSTN)) tempbx = 1;
-     else if(SiS_Pr->SiS_LCDResInfo != SiS_Pr->SiS_Panel640x480)  tempbx = 1;
+     else if(SiS_Pr->SiS_LCDResInfo != Panel_640x480)             tempbx = 1;
   }
 
-  temp = ((tempbx & 0xFF00) >> 8) << 3;
-  temp |= (USHORT)((tempecx & 0x0700) >> 8);
-  SiS_SetReg(SiS_Pr->SiS_Part1Port,0x20,temp);  	/* Part1_20h; Overflow register */
-
-  temp = tempbx & 0x00FF;
-  SiS_SetReg(SiS_Pr->SiS_Part1Port,0x21,temp);  	/* Part1_21h; Panel Link Vertical Accumulator Register */
+  temp = ((tempbx >> 8) & 0x07) << 3;
+  temp = temp | ((tempecx >> 8) & 0x07);
+  SiS_SetReg(SiS_Pr->SiS_Part1Port,0x20,temp);
+  SiS_SetReg(SiS_Pr->SiS_Part1Port,0x21,tempbx);
 
-  tempecx >>= 16;                               /* BPLHCFACT  */
-  if((HwInfo->jChipType < SIS_315H) || (SiS_Pr->SiS_IF_DEF_FSTN) || (SiS_Pr->SiS_IF_DEF_DSTN)) {
+  tempecx >>= 16;   	                                  	/* BPLHCFACT  */
+  if(!chkdclkfirst) {
      if(modeflag & HalfDCLK) tempecx >>= 1;
   }
   temp = (USHORT)((tempecx & 0xFF00) >> 8);
-  SiS_SetReg(SiS_Pr->SiS_Part1Port,0x22,temp);     	/* Part1_22h; Panel Link Horizontal Scaling Factor High */
-
+  SiS_SetReg(SiS_Pr->SiS_Part1Port,0x22,temp);
   temp = (USHORT)(tempecx & 0x00FF);
-  SiS_SetReg(SiS_Pr->SiS_Part1Port,0x23,temp);         /* Part1_22h; Panel Link Horizontal Scaling Factor Low */
+  SiS_SetReg(SiS_Pr->SiS_Part1Port,0x23,temp);
+
+#ifdef SIS315H
+  if(HwInfo->jChipType >= SIS_315H) {
+     if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCDA) {
+        if((islvds) || (SiS_Pr->SiS_VBInfo & VB_SIS301LV302LV)) {
+           SiS_SetReg(SiS_Pr->SiS_Part1Port,0x1e,0x20);
+	}
+     } else {
+        if(islvds) {
+           if(HwInfo->jChipType == SIS_740) {
+              SiS_SetRegOR(SiS_Pr->SiS_Part1Port,0x1e,0x03);
+           } else {
+	      SiS_SetReg(SiS_Pr->SiS_Part1Port,0x1e,0x23);
+           }
+        }
+     }
+  }
+#endif
+
+#ifdef SIS300
+  if(SiS_Pr->SiS_IF_DEF_TRUMPION) {
+     int i;
+     UCHAR TrumpMode13[4]   = { 0x01, 0x10, 0x2c, 0x00 };
+     UCHAR TrumpMode10_1[4] = { 0x01, 0x10, 0x27, 0x00 };
+     UCHAR TrumpMode10_2[4] = { 0x01, 0x16, 0x10, 0x00 };
 
-  /* 630/301B and 630/LVDS do something for 640x480 panels here */
+     SiS_SetRegAND(SiS_Pr->SiS_Part1Port,0x02,0xbf);
+     for(i=0; i<5; i++) {
+        SiS_SetTrumpionBlock(SiS_Pr, &SiS300_TrumpionData[crt2crtc][0]);
+     }
+     if(SiS_Pr->SiS_LCDResInfo == Panel_1024x768) {
+        if(ModeNo == 0x13) {
+	   for(i=0; i<4; i++) {
+	      SiS_SetTrumpionBlock(SiS_Pr, &TrumpMode13[0]);
+	   }
+	} else if(ModeNo == 0x10) {
+	   for(i=0; i<4; i++) {
+	      SiS_SetTrumpionBlock(SiS_Pr, &TrumpMode10_1[0]);
+	      SiS_SetTrumpionBlock(SiS_Pr, &TrumpMode10_2[0]);
+	   }
+	}
+     }
+     SiS_SetRegOR(SiS_Pr->SiS_Part1Port,0x02,0x40);
+  }
+#endif
 
 #ifdef SIS315H
   if(SiS_Pr->SiS_IF_DEF_FSTN || SiS_Pr->SiS_IF_DEF_DSTN) {
@@ -6431,10 +5936,10 @@
      SiS_SetReg(SiS_Pr->SiS_Part1Port,0x28,0x87);
      SiS_SetReg(SiS_Pr->SiS_Part1Port,0x29,0x5A);
      SiS_SetReg(SiS_Pr->SiS_Part1Port,0x2A,0x4B);
-     SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x44,~0x007,0x03);
+     SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x44,~0x07,0x03);
      tempax = SiS_Pr->SiS_HDE;                       		/* Blps = lcdhdee(lcdhdes+HDE) + 64 */
-     if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel640x480_2 ||
-        SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel640x480_3) tempax >>= 1;
+     if(SiS_Pr->SiS_LCDResInfo == Panel_640x480_2 ||
+        SiS_Pr->SiS_LCDResInfo == Panel_640x480_3) tempax >>= 1;
      tempax += 64;
      temp = tempax & 0x00FF;
      SiS_SetReg(SiS_Pr->SiS_Part1Port,0x38,temp);
@@ -6448,8 +5953,8 @@
      SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x3C,~0x007,0x00);
 
      tempax = SiS_Pr->SiS_VDE;
-     if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel640x480_2 ||
-        SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel640x480_3) tempax >>= 1;
+     if(SiS_Pr->SiS_LCDResInfo == Panel_640x480_2 ||
+        SiS_Pr->SiS_LCDResInfo == Panel_640x480_3) tempax >>= 1;
      tempax >>= 1;
      temp = tempax & 0x00FF;
      SiS_SetReg(SiS_Pr->SiS_Part1Port,0x3B,temp);
@@ -6457,8 +5962,8 @@
      SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x3C,~0x038,temp);
 
      tempeax = SiS_Pr->SiS_HDE;
-     if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel640x480_2 ||
-        SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel640x480_3) tempeax >>= 1;
+     if(SiS_Pr->SiS_LCDResInfo == Panel_640x480_2 ||
+        SiS_Pr->SiS_LCDResInfo == Panel_640x480_3) tempeax >>= 1;
      tempeax <<= 2;                       			/* BDxFIFOSTOP = (HDE*4)/128 */
      tempebx = 128;
      temp = (USHORT)(tempeax % tempebx);
@@ -6472,8 +5977,8 @@
      SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x3C,~0x040,0x00);
 
      tempax = SiS_Pr->SiS_HDE;
-     if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel640x480_2 ||
-        SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel640x480_3) tempax >>= 1;
+     if(SiS_Pr->SiS_LCDResInfo == Panel_640x480_2 ||
+        SiS_Pr->SiS_LCDResInfo == Panel_640x480_3) tempax >>= 1;
      tempax >>= 4;                        			/* BDxWadroff = HDE*4/8/8 */
      pushcx = tempax;
      temp = tempax & 0x00FF;
@@ -6482,8 +5987,8 @@
      SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x44,~0x0F8,temp);
 
      tempax = SiS_Pr->SiS_VDE;                             	/* BDxWadrst1 = BDxWadrst0 + BDxWadroff * VDE */
-     if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel640x480_2 ||
-        SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel640x480_3) tempax >>= 1;
+     if(SiS_Pr->SiS_LCDResInfo == Panel_640x480_2 ||
+        SiS_Pr->SiS_LCDResInfo == Panel_640x480_3) tempax >>= 1;
      tempeax = (tempax * pushcx);
      tempebx = 0x00100000 + tempeax;
      temp = (USHORT)tempebx & 0x000000FF;
@@ -6525,496 +6030,380 @@
      }
   }
 #endif  /* SIS315H */
-
 }
 
-/************** Set Part 1 ***************/
+/* Set Part 1 */
 static void
 SiS_SetGroup1(SiS_Private *SiS_Pr, USHORT ModeNo, USHORT ModeIdIndex,
               PSIS_HW_INFO HwInfo, USHORT RefreshRateTableIndex)
 {
-  UCHAR  *ROMAddr  = HwInfo->pjVirtualRomBase;
-  USHORT  temp=0, tempax=0, tempbx=0, tempcx=0;
-  USHORT  pushbx=0, CRT1Index=0;
+#if defined(SIS300) || defined(SIS315H)
+  UCHAR   *ROMAddr = HwInfo->pjVirtualRomBase;
+#endif
+  USHORT  temp=0, tempax=0, tempbx=0, tempcx=0, bridgeadd=0;
+  USHORT  pushbx=0, CRT1Index=0, modeflag, resinfo=0;
 #ifdef SIS315H
   USHORT  tempbl=0;
 #endif
-  USHORT  modeflag, resinfo=0;
+
+  if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCDA) {
+     SiS_SetGroup1_LVDS(SiS_Pr, ModeNo, ModeIdIndex, HwInfo, RefreshRateTableIndex);
+     return;
+  }
 
   if(ModeNo <= 0x13) {
      modeflag = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_ModeFlag;
+  } else if(SiS_Pr->UseCustomMode) {
+     modeflag = SiS_Pr->CModeFlag;
   } else {
-     if(SiS_Pr->UseCustomMode) {
-	modeflag = SiS_Pr->CModeFlag;
-     } else {
-    	CRT1Index = SiS_Pr->SiS_RefIndex[RefreshRateTableIndex].Ext_CRT1CRTC;
-    	resinfo = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_RESINFO;
-	modeflag = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag;
-     }
+     CRT1Index = SiS_Pr->SiS_RefIndex[RefreshRateTableIndex].Ext_CRT1CRTC;
+     resinfo = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_RESINFO;
+     modeflag = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag;
   }
 
-  if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCDA) {
-
-#ifdef SIS315H
-     SiS_SetCRT2Sync(SiS_Pr, ModeNo, RefreshRateTableIndex, HwInfo);
-     SiS_SetGroup1_LCDA(SiS_Pr, ModeNo, ModeIdIndex, HwInfo, RefreshRateTableIndex);
-#endif
-
-  } else {
+  SiS_SetCRT2Offset(SiS_Pr, ModeNo, ModeIdIndex, RefreshRateTableIndex, HwInfo);
 
-     if( (HwInfo->jChipType >= SIS_315H) &&
+  if( ! ((HwInfo->jChipType >= SIS_315H) &&
          (SiS_Pr->SiS_IF_DEF_LVDS == 1) &&
-	 (SiS_Pr->SiS_VBInfo & SetInSlaveMode) ) {
-
-        SiS_SetCRT2Sync(SiS_Pr, ModeNo, RefreshRateTableIndex, HwInfo);
-
-     } else {
-
-        SiS_SetCRT2Offset(SiS_Pr, ModeNo, ModeIdIndex,
-      		          RefreshRateTableIndex, HwInfo);
+         (SiS_Pr->SiS_VBInfo & SetInSlaveMode)) ) {
 
-        if (HwInfo->jChipType < SIS_315H ) {
+     if(HwInfo->jChipType < SIS_315H ) {
 #ifdef SIS300
-    	      SiS_SetCRT2FIFO_300(SiS_Pr, ModeNo, HwInfo);
+  	SiS_SetCRT2FIFO_300(SiS_Pr, ModeNo, HwInfo);
 #endif
-        } else {
+     } else {
 #ifdef SIS315H
-              SiS_SetCRT2FIFO_310(SiS_Pr);
+        SiS_SetCRT2FIFO_310(SiS_Pr, HwInfo);
 #endif
-	}
-
-        SiS_SetCRT2Sync(SiS_Pr, ModeNo, RefreshRateTableIndex, HwInfo);
+     }
 
-	/* 1. Horizontal setup */
+     /* 1. Horizontal setup */
 
-        if(HwInfo->jChipType < SIS_315H ) {
+     if(HwInfo->jChipType < SIS_315H ) {
 
 #ifdef SIS300   /* ------------- 300 series --------------*/
 
-    		temp = (SiS_Pr->SiS_VGAHT - 1) & 0x0FF;   			/* BTVGA2HT 0x08,0x09 */
-    		SiS_SetReg(SiS_Pr->SiS_Part1Port,0x08,temp);                   /* CRT2 Horizontal Total */
+    	temp = (SiS_Pr->SiS_VGAHT - 1) & 0x0FF;   		  /* BTVGA2HT 0x08,0x09 */
+    	SiS_SetReg(SiS_Pr->SiS_Part1Port,0x08,temp);              /* CRT2 Horizontal Total */
 
-    		temp = (((SiS_Pr->SiS_VGAHT - 1) & 0xFF00) >> 8) << 4;
-    		SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x09,0x0f,temp);          /* CRT2 Horizontal Total Overflow [7:4] */
+    	temp = (((SiS_Pr->SiS_VGAHT - 1) & 0xFF00) >> 8) << 4;
+    	SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x09,0x0f,temp);    /* CRT2 Horizontal Total Overflow [7:4] */
 
-    		temp = (SiS_Pr->SiS_VGAHDE + 12) & 0x0FF;                       /* BTVGA2HDEE 0x0A,0x0C */
-    		SiS_SetReg(SiS_Pr->SiS_Part1Port,0x0A,temp);                   /* CRT2 Horizontal Display Enable End */
+    	temp = (SiS_Pr->SiS_VGAHDE + 12) & 0x0FF;                 /* BTVGA2HDEE 0x0A,0x0C */
+    	SiS_SetReg(SiS_Pr->SiS_Part1Port,0x0A,temp);              /* CRT2 Horizontal Display Enable End */
 
-    		pushbx = SiS_Pr->SiS_VGAHDE + 12;                               /* bx  BTVGA@HRS 0x0B,0x0C */
-    		tempcx = (SiS_Pr->SiS_VGAHT - SiS_Pr->SiS_VGAHDE) >> 2;
-    		tempbx = pushbx + tempcx;
-    		tempcx <<= 1;
-    		tempcx += tempbx;
-
-    		if(SiS_Pr->SiS_VBType & VB_SISVB) {
-
-		   if(SiS_Pr->UseCustomMode) {
-		      tempbx = SiS_Pr->CHSyncStart + 12;
-		      tempcx = SiS_Pr->CHSyncEnd + 12;
-		   }
+	pushbx = SiS_Pr->SiS_VGAHDE + 12;                         /* bx  BTVGA2HRS 0x0B,0x0C */
+    	tempcx = (SiS_Pr->SiS_VGAHT - SiS_Pr->SiS_VGAHDE) >> 2;
+    	tempbx = pushbx + tempcx;
+    	tempcx <<= 1;
+    	tempcx += tempbx;
 
-      		   if(SiS_Pr->SiS_VBInfo & SetCRT2ToRAMDAC) {
-		      unsigned char cr4, cr14, cr5, cr15;
-		      if(SiS_Pr->UseCustomMode) {
-		         cr4  = SiS_Pr->CCRT1CRTC[4];
-			 cr14 = SiS_Pr->CCRT1CRTC[14];
-			 cr5  = SiS_Pr->CCRT1CRTC[5];
-			 cr15 = SiS_Pr->CCRT1CRTC[15];
-		      } else {
-		         cr4  = SiS_Pr->SiS_CRT1Table[CRT1Index].CR[4];
-			 cr14 = SiS_Pr->SiS_CRT1Table[CRT1Index].CR[14];
-			 cr5  = SiS_Pr->SiS_CRT1Table[CRT1Index].CR[5];
-			 cr15 = SiS_Pr->SiS_CRT1Table[CRT1Index].CR[15];
-		      }
-        	      tempbx = ((cr4 | ((cr14 & 0xC0) << 2)) - 1) << 3;
-        	      tempcx = (((cr5 & 0x1F) | ((cr15 & 0x04) << (6-2))) - 1) << 3;
-      		   }
-
-    		   if((SiS_Pr->SiS_VBInfo & SetCRT2ToTV) && (resinfo == SIS_RI_1024x768)){
-        	      if(!(SiS_Pr->SiS_TVMode & TVSetPAL)){
-      			 tempbx = 1040;
-      			 tempcx = 1042;
-      		      }
-    		   }
-	        }
+	bridgeadd = 12;
 
-    		temp = tempbx & 0x00FF;
-    		SiS_SetReg(SiS_Pr->SiS_Part1Port,0x0B,temp);                   /* CRT2 Horizontal Retrace Start */
 #endif /* SIS300 */
 
- 	} else {
+     } else {
 
 #ifdef SIS315H  /* ------------------- 315/330 series --------------- */
 
-	        tempcx = SiS_Pr->SiS_VGAHT;				       /* BTVGA2HT 0x08,0x09 */
-		if(modeflag & HalfDCLK) {
-		    if(SiS_Pr->SiS_VBType & VB_SISVB) {
-		       tempcx >>= 1;
-		    } else {
-		       tempax = SiS_Pr->SiS_VGAHDE >> 1;
-		       tempcx = SiS_Pr->SiS_HT - SiS_Pr->SiS_HDE + tempax;
-		       if(SiS_Pr->SiS_LCDInfo & DontExpandLCD) {
-			  tempcx = SiS_Pr->SiS_HT - tempax;
-		       }
-		    }
-		}
-		tempcx--;
+	tempcx = SiS_Pr->SiS_VGAHT;				  /* BTVGA2HT 0x08,0x09 */
+	if(modeflag & HalfDCLK) {
+	   if(SiS_Pr->SiS_VBType & VB_SISVB) {
+	      tempcx >>= 1;
+	   } else {
+	      tempax = SiS_Pr->SiS_VGAHDE >> 1;
+	      tempcx = SiS_Pr->SiS_HT - SiS_Pr->SiS_HDE + tempax;
+	      if(SiS_Pr->SiS_LCDInfo & DontExpandLCD) {
+	         tempcx = SiS_Pr->SiS_HT - tempax;
+	      }
+	   }
+	}
+	tempcx--;
+	SiS_SetReg(SiS_Pr->SiS_Part1Port,0x08,tempcx);            /* CRT2 Horizontal Total */
+	temp = (tempcx >> 4) & 0xF0;
+	SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x09,0x0F,temp);    /* CRT2 Horizontal Total Overflow [7:4] */
 
-		temp = tempcx & 0xff;
-		SiS_SetReg(SiS_Pr->SiS_Part1Port,0x08,temp);                  /* CRT2 Horizontal Total */
+	tempcx = SiS_Pr->SiS_VGAHT;				  /* BTVGA2HDEE 0x0A,0x0C */
+	tempbx = SiS_Pr->SiS_VGAHDE;
+	tempcx -= tempbx;
+	tempcx >>= 2;
+	if(modeflag & HalfDCLK) {
+	   tempbx >>= 1;
+	   tempcx >>= 1;
+	}
+	tempbx += 16;
 
-		temp = ((tempcx & 0xff00) >> 8) << 4;
-		SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x09,0x0F,temp);         /* CRT2 Horizontal Total Overflow [7:4] */
+	SiS_SetReg(SiS_Pr->SiS_Part1Port,0x0A,tempbx);            /* CRT2 Horizontal Display Enable End */
 
-		tempcx = SiS_Pr->SiS_VGAHT;				       /* BTVGA2HDEE 0x0A,0x0C */
-		tempbx = SiS_Pr->SiS_VGAHDE;
-		tempcx -= tempbx;
-		tempcx >>= 2;
-		if(modeflag & HalfDCLK) {
-		   tempbx >>= 1;
-		   tempcx >>= 1;
-		}
-		tempbx += 16;
+	pushbx = tempbx;
+	tempcx >>= 1;
+	tempbx += tempcx;
+	tempcx += tempbx;
 
-		temp = tempbx & 0xff;
-		SiS_SetReg(SiS_Pr->SiS_Part1Port,0x0A,temp);                  /* CRT2 Horizontal Display Enable End */
+	bridgeadd = 16;
 
-		pushbx = tempbx;
-		tempcx >>= 1;
-		tempbx += tempcx;
-		tempcx += tempbx;
-
-		if(SiS_Pr->SiS_VBType & VB_SISVB) {
-
-		   if(HwInfo->jChipType >= SIS_661) {
-		      if((SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1600x1200) ||
-		         (SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1280x1024)) {
-			 if(resinfo == SIS_RI_1280x1024) {
-		            tempcx = 0x30;
-			 } else if(resinfo == SIS_RI_1600x1200) {
-			    tempcx = 0xff;
-			 }
-		      }
-		   }
+	if(SiS_Pr->SiS_VBType & VB_SISVB) {
+	   if(HwInfo->jChipType >= SIS_661) {
+	      if((SiS_Pr->SiS_LCDResInfo == Panel_1600x1200) ||
+		 (SiS_Pr->SiS_LCDResInfo == Panel_1280x1024)) {
+		 if(resinfo == SIS_RI_1280x1024) {
+		    tempcx = (tempcx & 0xff00) | 0x30;
+		 } else if(resinfo == SIS_RI_1600x1200) {
+		    tempcx = (tempcx & 0xff00) | 0xff;
+		 }
+	      }
+	   }
+        }
 
-		   if(SiS_Pr->UseCustomMode) {
-		      tempbx = SiS_Pr->CHSyncStart + 16;
-		      tempcx = SiS_Pr->CHSyncEnd + 16;
-		      tempax = SiS_Pr->SiS_VGAHT;
-		      if(modeflag & HalfDCLK) tempax >>= 1;
-		      tempax--;
-		      if(tempcx > tempax)  tempcx = tempax;
-		   }
+#endif  /* SIS315H */
 
-             	   if(SiS_Pr->SiS_VBInfo & SetCRT2ToRAMDAC) {
-		      unsigned char cr4, cr14, cr5, cr15;
-		      if(SiS_Pr->UseCustomMode) {
-		         cr4  = SiS_Pr->CCRT1CRTC[4];
-			 cr14 = SiS_Pr->CCRT1CRTC[14];
-			 cr5  = SiS_Pr->CCRT1CRTC[5];
-			 cr15 = SiS_Pr->CCRT1CRTC[15];
-		      } else {
-		         cr4  = SiS_Pr->SiS_CRT1Table[CRT1Index].CR[4];
-			 cr14 = SiS_Pr->SiS_CRT1Table[CRT1Index].CR[14];
-			 cr5  = SiS_Pr->SiS_CRT1Table[CRT1Index].CR[5];
-			 cr15 = SiS_Pr->SiS_CRT1Table[CRT1Index].CR[15];
-		      }
-                      tempbx = ((cr4 | ((cr14 & 0xC0) << 2)) - 3) << 3; 		/* (VGAHRS-3)*8 */
-                      tempcx = (((cr5 & 0x1f) | ((cr15 & 0x04) << (5-2))) - 3) << 3; 	/* (VGAHRE-3)*8 */
-		      tempcx &= 0x00FF;
-		      tempcx |= (tempbx & 0xFF00);
-                      tempbx += 16;
-                      tempcx += 16;
-		      tempax = SiS_Pr->SiS_VGAHT;
-		      if(modeflag & HalfDCLK) tempax >>= 1;
-		      tempax--;
-		      if(tempcx > tempax)  tempcx = tempax;
-             	   }
-
-		   if(SiS_Pr->SiS_TVMode & TVSetNTSC1024) {
-      		      tempbx = 1040;
-      		      tempcx = 1042;
-      	     	   }
+     }  /* 315/330 series */
 
-                }
+     if(SiS_Pr->SiS_VBType & VB_SISVB) {
 
-		temp = tempbx & 0xff;
-	 	SiS_SetReg(SiS_Pr->SiS_Part1Port,0x0B,temp);                 /* CRT2 Horizontal Retrace Start */
-#endif  /* SIS315H */
+        if(SiS_Pr->UseCustomMode) {
+	   tempbx = SiS_Pr->CHSyncStart + bridgeadd;
+	   tempcx = SiS_Pr->CHSyncEnd + bridgeadd;
+	   tempax = SiS_Pr->SiS_VGAHT;
+	   if(modeflag & HalfDCLK) tempax >>= 1;
+	   tempax--;
+	   if(tempcx > tempax) tempcx = tempax;
+	}
+
+	if(SiS_Pr->SiS_VBInfo & SetCRT2ToRAMDAC) {
+	   unsigned char cr4, cr14, cr5, cr15;
+	   if(SiS_Pr->UseCustomMode) {
+	      cr4  = SiS_Pr->CCRT1CRTC[4];
+	      cr14 = SiS_Pr->CCRT1CRTC[14];
+	      cr5  = SiS_Pr->CCRT1CRTC[5];
+	      cr15 = SiS_Pr->CCRT1CRTC[15];
+	   } else {
+	      cr4  = SiS_Pr->SiS_CRT1Table[CRT1Index].CR[4];
+	      cr14 = SiS_Pr->SiS_CRT1Table[CRT1Index].CR[14];
+	      cr5  = SiS_Pr->SiS_CRT1Table[CRT1Index].CR[5];
+	      cr15 = SiS_Pr->SiS_CRT1Table[CRT1Index].CR[15];
+	   }
+           tempbx = ((cr4 | ((cr14 & 0xC0) << 2)) - 3) << 3; 		    /* (VGAHRS-3)*8 */
+           tempcx = (((cr5 & 0x1f) | ((cr15 & 0x04) << (5-2))) - 3) << 3;   /* (VGAHRE-3)*8 */
+	   tempcx &= 0x00FF;
+	   tempcx |= (tempbx & 0xFF00);
+           tempbx += bridgeadd;
+           tempcx += bridgeadd;
+	   tempax = SiS_Pr->SiS_VGAHT;
+	   if(modeflag & HalfDCLK) tempax >>= 1;
+	   tempax--;
+	   if(tempcx > tempax) tempcx = tempax;
+        }
 
-     	}  /* 315/330 series */
+        if(SiS_Pr->SiS_TVMode & TVSetNTSC1024) {
+      	   tempbx = 1040;
+      	   tempcx = 1044;   /* HWCursor bug! */
+        }
 
-  	/* The following is done for all bridge/chip types/series */
+     }
 
-  	tempax = tempbx & 0xFF00;
-  	tempbx = pushbx;
-  	tempbx = (tempbx & 0x00FF) | ((tempbx & 0xFF00) << 4);
-  	tempax |= (tempbx & 0xFF00);
-  	temp = (tempax & 0xFF00) >> 8;
-  	SiS_SetReg(SiS_Pr->SiS_Part1Port,0x0C,temp);                        /* Overflow */
+     SiS_SetReg(SiS_Pr->SiS_Part1Port,0x0B,tempbx);            	  /* CRT2 Horizontal Retrace Start */
 
-  	temp = tempcx & 0x00FF;
-  	SiS_SetReg(SiS_Pr->SiS_Part1Port,0x0D,temp);                        /* CRT2 Horizontal Retrace End */
+     SiS_SetReg(SiS_Pr->SiS_Part1Port,0x0D,tempcx);               /* CRT2 Horizontal Retrace End */
 
-  	/* 2. Vertical setup */
+     temp = ((tempbx >> 8) & 0x0F) | ((pushbx >> 4) & 0xF0);
+     SiS_SetReg(SiS_Pr->SiS_Part1Port,0x0C,temp);		  /* Overflow */
 
-  	tempcx = SiS_Pr->SiS_VGAVT - 1;
-  	temp = tempcx & 0x00FF;
+     /* 2. Vertical setup */
 
-	if(HwInfo->jChipType < SIS_661) {
-           if(SiS_Pr->SiS_IF_DEF_LVDS == 1) {
-	      if(HwInfo->jChipType < SIS_315H) {
-	         if(SiS_Pr->SiS_IF_DEF_CH70xx != 0) {
-	            if(SiS_Pr->SiS_VBInfo & (SetCRT2ToSVIDEO | SetCRT2ToAVIDEO)) {
-	               temp--;
-	            }
-                 }
-	      } else {
- 	         temp--;
+     tempcx = SiS_Pr->SiS_VGAVT - 1;
+     temp = tempcx & 0x00FF;
+
+     if(HwInfo->jChipType < SIS_661) {
+        if(SiS_Pr->SiS_IF_DEF_LVDS == 1) {
+	   if(HwInfo->jChipType < SIS_315H) {
+	      if(SiS_Pr->SiS_IF_DEF_CH70xx != 0) {
+	         if(SiS_Pr->SiS_VBInfo & (SetCRT2ToSVIDEO | SetCRT2ToAVIDEO)) {
+	            temp--;
+	         }
               }
-           } else if(HwInfo->jChipType >= SIS_315H) {
-	      temp--;
-	   }
+	   } else {
+ 	      temp--;
+           }
+        } else if(HwInfo->jChipType >= SIS_315H) {
+	   temp--;
 	}
-  	SiS_SetReg(SiS_Pr->SiS_Part1Port,0x0E,temp);                        /* CRT2 Vertical Total */
+     }
+     SiS_SetReg(SiS_Pr->SiS_Part1Port,0x0E,temp);                 /* CRT2 Vertical Total */
 
-  	tempbx = SiS_Pr->SiS_VGAVDE - 1;
-  	temp = tempbx & 0x00FF;
-  	SiS_SetReg(SiS_Pr->SiS_Part1Port,0x0F,temp);                        /* CRT2 Vertical Display Enable End */
-
-  	temp = ((tempbx & 0xFF00) << 3) >> 8;
-  	temp |= ((tempcx & 0xFF00) >> 8);
-  	SiS_SetReg(SiS_Pr->SiS_Part1Port,0x12,temp);                        /* Overflow (and HWCursor Test Mode) */
-
-	if((HwInfo->jChipType >= SIS_315H) && (HwInfo->jChipType < SIS_661)) {
-           tempbx++;
-   	   tempax = tempbx;
-	   tempcx++;
-	   tempcx -= tempax;
-	   tempcx >>= 2;
-	   tempbx += tempcx;
-	   if(tempcx < 4) tempcx = 4;
-	   tempcx >>= 2;
-	   tempcx += tempbx;
-	   tempcx++;
-	} else {
-  	   tempbx = (SiS_Pr->SiS_VGAVT + SiS_Pr->SiS_VGAVDE) >> 1;                 /*  BTVGA2VRS     0x10,0x11   */
-  	   tempcx = ((SiS_Pr->SiS_VGAVT - SiS_Pr->SiS_VGAVDE) >> 4) + tempbx + 1;  /*  BTVGA2VRE     0x11        */
-	}
+     tempbx = SiS_Pr->SiS_VGAVDE - 1;
+     SiS_SetReg(SiS_Pr->SiS_Part1Port,0x0F,tempbx);               /* CRT2 Vertical Display Enable End */
 
-  	if(SiS_Pr->SiS_VBType & VB_SISVB) {
+     temp = ((tempbx >> 5) & 0x38) | ((tempcx >> 8) & 0x07);
+     SiS_SetReg(SiS_Pr->SiS_Part1Port,0x12,temp);                 /* Overflow */
+
+     if((HwInfo->jChipType >= SIS_315H) && (HwInfo->jChipType < SIS_661)) {
+        tempbx++;
+   	tempax = tempbx;
+	tempcx++;
+	tempcx -= tempax;
+	tempcx >>= 2;
+	tempbx += tempcx;
+	if(tempcx < 4) tempcx = 4;
+	tempcx >>= 2;
+	tempcx += tempbx;
+	tempcx++;
+     } else {
+  	tempbx = (SiS_Pr->SiS_VGAVT + SiS_Pr->SiS_VGAVDE) >> 1;                 /*  BTVGA2VRS     0x10,0x11   */
+  	tempcx = ((SiS_Pr->SiS_VGAVT - SiS_Pr->SiS_VGAVDE) >> 4) + tempbx + 1;  /*  BTVGA2VRE     0x11        */
+     }
 
+     if(SiS_Pr->SiS_VBType & VB_SISVB) {
+	if(SiS_Pr->UseCustomMode) {
+	   tempbx = SiS_Pr->CVSyncStart;
+	   tempcx = SiS_Pr->CVSyncEnd;
+	}
+        if(SiS_Pr->SiS_VBInfo & SetCRT2ToRAMDAC) {
+	   unsigned char cr8, cr7, cr13;
 	   if(SiS_Pr->UseCustomMode) {
-	      tempbx = SiS_Pr->CVSyncStart;
-	      tempcx = (tempcx & 0xFF00) | (SiS_Pr->CVSyncEnd & 0x00FF);
-	   }
+	      cr8    = SiS_Pr->CCRT1CRTC[8];
+	      cr7    = SiS_Pr->CCRT1CRTC[7];
+	      cr13   = SiS_Pr->CCRT1CRTC[13];
+	      tempcx = SiS_Pr->CCRT1CRTC[9];
+	   } else {
+	      cr8    = SiS_Pr->SiS_CRT1Table[CRT1Index].CR[8];
+	      cr7    = SiS_Pr->SiS_CRT1Table[CRT1Index].CR[7];
+	      cr13   = SiS_Pr->SiS_CRT1Table[CRT1Index].CR[13];
+	      tempcx = SiS_Pr->SiS_CRT1Table[CRT1Index].CR[9];
+	   }
+      	   tempbx = cr8;
+      	   if(cr7  & 0x04) tempbx |= 0x0100;
+      	   if(cr7  & 0x80) tempbx |= 0x0200;
+      	   if(cr13 & 0x08) tempbx |= 0x0400;
+       	}
+     }
+     SiS_SetReg(SiS_Pr->SiS_Part1Port,0x10,tempbx);               /* CRT2 Vertical Retrace Start */
 
-    	   if(SiS_Pr->SiS_VBInfo & SetCRT2ToRAMDAC) {
-	      unsigned char cr8, cr7, cr13, cr9;
-	      if(SiS_Pr->UseCustomMode) {
-	         cr8  = SiS_Pr->CCRT1CRTC[8];
-		 cr7  = SiS_Pr->CCRT1CRTC[7];
-		 cr13 = SiS_Pr->CCRT1CRTC[13];
-		 cr9  = SiS_Pr->CCRT1CRTC[9];
-	      } else {
-	         cr8  = SiS_Pr->SiS_CRT1Table[CRT1Index].CR[8];
-		 cr7  = SiS_Pr->SiS_CRT1Table[CRT1Index].CR[7];
-		 cr13 = SiS_Pr->SiS_CRT1Table[CRT1Index].CR[13];
-		 cr9  = SiS_Pr->SiS_CRT1Table[CRT1Index].CR[9];
-	      }
-      	      tempbx = cr8;
-      	      if(cr7 & 0x04)  tempbx |= 0x0100;
-      	      if(cr7 & 0x80)  tempbx |= 0x0200;
-      	      if(cr13 & 0x08) tempbx |= 0x0400;
-      	      tempcx = (tempcx & 0xFF00) | (cr9 & 0x00FF);
-    	   }
-  	}
-  	temp = tempbx & 0x00FF;
-  	SiS_SetReg(SiS_Pr->SiS_Part1Port,0x10,temp);           /* CRT2 Vertical Retrace Start */
-
-  	temp = ((tempbx & 0xFF00) >> 8) << 4;
-  	temp |= (tempcx & 0x000F);
-  	SiS_SetReg(SiS_Pr->SiS_Part1Port,0x11,temp);           /* CRT2 Vert. Retrace End; Overflow; "Enable CRTC Check" */
+     temp = ((tempbx >> 4) & 0x70) | (tempcx & 0x0F);
+     SiS_SetReg(SiS_Pr->SiS_Part1Port,0x11,temp);                 /* CRT2 Vert. Retrace End; Overflow */
 
-  	/* 3. Panel compensation delay */
+     /* 3. Panel delay compensation */
 
-  	if(HwInfo->jChipType < SIS_315H) {
+     if(HwInfo->jChipType < SIS_315H) {
 
 #ifdef SIS300  /* ---------- 300 series -------------- */
 
-	   if(SiS_Pr->SiS_VBType & VB_SISVB) {
-	        temp = 0x20;
+	if(SiS_Pr->SiS_VBType & VB_SISVB) {
+	   temp = 0x20;
+	   if(HwInfo->jChipType == SIS_300) {
+	      temp = 0x10;
+	      if(SiS_Pr->SiS_LCDResInfo == Panel_1024x768)  temp = 0x2c;
+	      if(SiS_Pr->SiS_LCDResInfo == Panel_1280x1024) temp = 0x20;
+	   }
+	   if(SiS_Pr->SiS_VBType & VB_SIS301) {
+	      if(SiS_Pr->SiS_LCDResInfo == Panel_1280x1024) temp = 0x20;
+	   }
+	   if(SiS_Pr->SiS_LCDResInfo == Panel_1280x960)     temp = 0x24;
+	   if(SiS_Pr->SiS_LCDResInfo == Panel_Custom)       temp = 0x2c;
+	   if(SiS_Pr->SiS_VBInfo & SetCRT2ToTV) 	    temp = 0x08;
+	   if(SiS_Pr->SiS_VBInfo & SetCRT2ToHiVision) {
+      	      if(SiS_Pr->SiS_VBInfo & SetInSlaveMode) 	    temp = 0x2c;
+      	      else 					    temp = 0x20;
+    	   }
+	   if(SiS_Pr->SiS_UseROM) {
+	      if(ROMAddr[0x220] & 0x80) {
+	         if(SiS_Pr->SiS_VBInfo & SetCRT2ToTVNoYPbPrHiVision)
+	   	    temp = ROMAddr[0x221];
+		 else if(SiS_Pr->SiS_VBInfo & SetCRT2ToHiVision)
+		    temp = ROMAddr[0x222];
+		 else if(SiS_Pr->SiS_LCDResInfo == Panel_1280x1024)
+		    temp = ROMAddr[0x223];
+		 else
+		    temp = ROMAddr[0x224];
+		 temp &= 0x3c;
+	      }
+	   }
+	   if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCD) {
+	      if(SiS_Pr->PDC != -1)  temp = SiS_Pr->PDC & 0x3c;
+	   }
 
-		if(HwInfo->jChipType == SIS_300) {
-		   temp = 0x10;
-		   if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1024x768)  temp = 0x2c;
-		   if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1280x1024) temp = 0x20;
-		}
-		if(SiS_Pr->SiS_VBType & VB_SIS301) {
-		   if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1280x1024) temp = 0x20;
-		}
-		if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1280x960)     temp = 0x24;
-		if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_PanelCustom)       temp = 0x2c;
-		if(SiS_Pr->SiS_VBInfo & SetCRT2ToTV) 		temp = 0x08;
-		if(SiS_Pr->SiS_VBInfo & SetCRT2ToHiVision) {
-      		   if(SiS_Pr->SiS_VBInfo & SetInSlaveMode) 	temp = 0x2c;
-      		   else 					temp = 0x20;
-    	        }
-		if((ROMAddr) && (SiS_Pr->SiS_UseROM)) {
-		    if(ROMAddr[0x220] & 0x80) {
-		        if(SiS_Pr->SiS_VBInfo & SetCRT2ToTVNoYPbPrHiVision)
-				temp = ROMAddr[0x221];
-			else if(SiS_Pr->SiS_VBInfo & SetCRT2ToHiVision)
-				temp = ROMAddr[0x222];
-		        else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1280x1024)
-				temp = ROMAddr[0x223];
-			else
-				temp = ROMAddr[0x224];
-			temp &= 0x3c;
-		    }
-		}
-		if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCD) {
-		   if(SiS_Pr->PDC) {
-			temp = SiS_Pr->PDC & 0x3c;
-		   }
-		}
-	   } else {
-	        temp = 0x20;
-		if(!(SiS_Pr->SiS_VBInfo & SetCRT2ToTV)) {
-		   if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel640x480) temp = 0x04;
-		}
-		if((ROMAddr) && SiS_Pr->SiS_UseROM) {
-		    if(ROMAddr[0x220] & 0x80) {
-		        temp = ROMAddr[0x220] & 0x3c;
-		    }
-		}
-		if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCD) {
-		   if(SiS_Pr->PDC) {
-		      temp = SiS_Pr->PDC & 0x3c;
-		   }
-		}
+	} else {
+	   temp = 0x20;
+	   if(!(SiS_Pr->SiS_VBInfo & SetCRT2ToTV)) {
+	      if(SiS_Pr->SiS_LCDResInfo == Panel_640x480) temp = 0x04;
+	   }
+	   if(SiS_Pr->SiS_UseROM) {
+	      if(ROMAddr[0x220] & 0x80) {
+	         temp = ROMAddr[0x220] & 0x3c;
+	      }
 	   }
+	   if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCD) {
+	      if(SiS_Pr->PDC != -1) temp = SiS_Pr->PDC & 0x3c;
+	   }
+        }
 
-    	   SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x13,~0x03C,temp);         /* Panel Link Delay Compensation; (Software Command Reset; Power Saving) */
+    	SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x13,~0x3C,temp);   /* Panel Link Delay Compensation; (Software Command Reset; Power Saving) */
 
 #endif  /* SIS300 */
 
-  	} else {
+     } else {
 
 #ifdef SIS315H   /* --------------- 315/330 series ---------------*/
 
-   	   if(HwInfo->jChipType < SIS_661) {
-
-	      if(SiS_Pr->SiS_VBType & VB_SISVB) {
+        if(HwInfo->jChipType < SIS_661) {
 
-                 temp = 0x10;
-                 if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1024x768)  temp = 0x2c;
-    	         if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1280x1024) temp = 0x20;
-    	         if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1280x960)  temp = 0x24;
-		 if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_PanelCustom)    temp = 0x2c;
-		 if(SiS_Pr->SiS_VBInfo & SetCRT2ToTV) {
-		    temp = 0x08;
-		    if(SiS_Pr->SiS_VBInfo & SetCRT2ToHiVision) {
-		       if(SiS_Pr->SiS_VBInfo & SetInSlaveMode)  temp = 0x2c;
-      		       else 					temp = 0x20;
-		    }
-		 }
-		 if((SiS_Pr->SiS_VBType & VB_SIS301B302B) && (!(SiS_Pr->SiS_VBType & VB_NoLCD))) {
-		    tempbl = 0x00;
-		    if((ROMAddr) && (SiS_Pr->SiS_UseROM)) {
-		       if(HwInfo->jChipType < SIS_330) {
-		          if(ROMAddr[0x13c] & 0x80) tempbl = 0xf0;
-		       } else {
-		          if(ROMAddr[0x1bc] & 0x80) tempbl = 0xf0;
-		       }
-		    }
-		 } else {  /* LV (550/301LV checks ROM byte, other LV BIOSes do not) */
-		    tempbl = 0xF0;
-		 }
-		 if(SiS_Pr->SiS_VBInfo & (SetCRT2ToLCD|SetCRT2ToLCDA)) {
-		    if(SiS_Pr->SiS_VBType & VB_SIS301LV302LV) {
-		       if(SiS_Pr->PDC) {
-		          temp = SiS_Pr->PDC;
-		          tempbl = 0;
-		       }
-		    }
-		 }
+	   if(SiS_Pr->SiS_IF_DEF_LVDS == 1) {
 
-	      } else {  /* LVDS */
+	      if(HwInfo->jChipType == SIS_740) temp = 0x03;
+	      else 		               temp = 0x00;
 
-	         if(HwInfo->jChipType == SIS_740) {
-		    temp = 0x03;
-	         } else {
-		    temp = 0x00;
-		 }
-	 	 if(SiS_Pr->SiS_VBInfo & SetCRT2ToTV) temp = 0x0a;
-		 tempbl = 0xF0;
-		 if(HwInfo->jChipType == SIS_650) {
-		    if(SiS_Pr->SiS_IF_DEF_CH70xx != 0) {
-		       if(!(SiS_Pr->SiS_VBInfo & SetCRT2ToTV)) tempbl = 0x0F;
-		    }
+	      if(SiS_Pr->SiS_VBInfo & SetCRT2ToTV) temp = 0x0a;
+	      tempbl = 0xF0;
+	      if(HwInfo->jChipType == SIS_650) {
+		 if(SiS_Pr->SiS_IF_DEF_CH70xx != 0) {
+		    if(!(SiS_Pr->SiS_VBInfo & SetCRT2ToTV)) tempbl = 0x0F;
 		 }
+	      }
 
-		 if(SiS_Pr->SiS_IF_DEF_DSTN || SiS_Pr->SiS_IF_DEF_FSTN) {
-		    temp = 0x08;
-		    tempbl = 0;
-		    if((ROMAddr) && (SiS_Pr->SiS_UseROM)) {
-		       if(ROMAddr[0x13c] & 0x80) tempbl = 0xf0;
-		    }
+	      if(SiS_Pr->SiS_IF_DEF_DSTN || SiS_Pr->SiS_IF_DEF_FSTN) {
+		 temp = 0x08;
+		 tempbl = 0;
+		 if((SiS_Pr->SiS_UseROM) && (!(SiS_Pr->SiS_ROMNew))) {
+		    if(ROMAddr[0x13c] & 0x80) tempbl = 0xf0;
 		 }
 	      }
 
 	      SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x2D,tempbl,temp);	    /* Panel Link Delay Compensation */
+	   }
 
-	   } /* < 661 */
+	} /* < 661 */
 
-    	   tempax = 0;
-    	   if (modeflag & DoubleScanMode) tempax |= 0x80;
-    	   if (modeflag & HalfDCLK)       tempax |= 0x40;
-    	   SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x2C,0x3f,tempax);
+    	tempax = 0;
+    	if(modeflag & DoubleScanMode) tempax |= 0x80;
+    	if(modeflag & HalfDCLK)       tempax |= 0x40;
+    	SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x2C,0x3f,tempax);
 
 #endif  /* SIS315H */
 
-  	}
-
-     }  /* Slavemode */
+     }
 
-     if(SiS_Pr->SiS_VBType & VB_SISVB) {
+  }  /* Slavemode */
 
+  if(SiS_Pr->SiS_VBType & VB_SISVB) {
+     if((SiS_Pr->SiS_VBType & VB_NoLCD) && (SiS_Pr->SiS_VBInfo & SetCRT2ToLCD)) {
         /* For 301BDH with LCD, we set up the Panel Link */
-        if( (SiS_Pr->SiS_VBType & VB_NoLCD) && (SiS_Pr->SiS_VBInfo & SetCRT2ToLCD) ) {
-
-	    SiS_SetGroup1_LVDS(SiS_Pr, ModeNo, ModeIdIndex,
-	                       HwInfo, RefreshRateTableIndex);
-
-        } else if(SiS_Pr->SiS_VBInfo & SetInSlaveMode) {
-
-    	    SiS_SetGroup1_301(SiS_Pr, ModeNo, ModeIdIndex,
-	                      HwInfo, RefreshRateTableIndex);
-        }
-
+	SiS_SetGroup1_LVDS(SiS_Pr, ModeNo, ModeIdIndex, HwInfo, RefreshRateTableIndex);
+     } else if(SiS_Pr->SiS_VBInfo & SetInSlaveMode) {
+    	SiS_SetGroup1_301(SiS_Pr, ModeNo, ModeIdIndex, HwInfo, RefreshRateTableIndex);
+     }
+  } else {
+     if(HwInfo->jChipType < SIS_315H) {
+	SiS_SetGroup1_LVDS(SiS_Pr, ModeNo, ModeIdIndex, HwInfo, RefreshRateTableIndex);
      } else {
-
-        if(HwInfo->jChipType < SIS_315H) {
-
-	   SiS_SetGroup1_LVDS(SiS_Pr, ModeNo, ModeIdIndex,
-	                        HwInfo, RefreshRateTableIndex);
+	if(SiS_Pr->SiS_IF_DEF_CH70xx != 0) {
+           if((!(SiS_Pr->SiS_VBInfo & SetCRT2ToTV)) || (SiS_Pr->SiS_VBInfo & SetInSlaveMode)) {
+    	      SiS_SetGroup1_LVDS(SiS_Pr, ModeNo,ModeIdIndex, HwInfo,RefreshRateTableIndex);
+           }
 	} else {
-
-	   if(SiS_Pr->SiS_IF_DEF_CH70xx != 0) {
-              if((!(SiS_Pr->SiS_VBInfo & SetCRT2ToTV)) || (SiS_Pr->SiS_VBInfo & SetInSlaveMode)) {
-    	          SiS_SetGroup1_LVDS(SiS_Pr, ModeNo,ModeIdIndex,
-	                              HwInfo,RefreshRateTableIndex);
-              }
-	   } else {
-	      SiS_SetGroup1_LVDS(SiS_Pr, ModeNo,ModeIdIndex,
-	                         HwInfo,RefreshRateTableIndex);
-	   }
-
+	   SiS_SetGroup1_LVDS(SiS_Pr, ModeNo,ModeIdIndex, HwInfo,RefreshRateTableIndex);
 	}
-
      }
-  } /* LCDA */
+  }
 }
 
 /*********************************************/
@@ -7025,9 +6414,8 @@
 static UCHAR *
 SiS_GetGroup2CLVXPtr(SiS_Private *SiS_Pr, int tabletype, PSIS_HW_INFO HwInfo)
 {
-   UCHAR  *ROMAddr = HwInfo->pjVirtualRomBase;
    const UCHAR  *tableptr = NULL;
-   USHORT a, b, p = 0;
+   USHORT       a, b, p = 0;
 
    a = SiS_Pr->SiS_VGAHDE;
    b = SiS_Pr->SiS_HDE;
@@ -7036,66 +6424,33 @@
       b = SiS_Pr->SiS_VDE;
    }
 
-   if((HwInfo->jChipType >= SIS_661) && (ROMAddr = (UCHAR *)HwInfo->pjVirtualRomBase) && SiS_Pr->SiS_UseROM) {
-
-      if(a < b) {
-         p = ROMAddr[0x278] | (ROMAddr[0x279] << 8);
-      } else if(a == b) {
-         p = ROMAddr[0x27a] | (ROMAddr[0x27b] << 8);
-      } else {
-         if(SiS_Pr->SiS_TVMode & TVSetPAL) {
-	    p = ROMAddr[0x27e] | (ROMAddr[0x27f] << 8);
-	 } else {
-	    p = ROMAddr[0x27c] | (ROMAddr[0x27d] << 8);
-	 }
-	 if(SiS_Pr->SiS_VBInfo & SetCRT2ToYPbPr525750) {
-	    if(SiS_Pr->SiS_TVMode & TVSetYPbPr525i) 	 p = ROMAddr[0x280] | (ROMAddr[0x281] << 8);
-	    else if(SiS_Pr->SiS_TVMode & TVSetYPbPr525p) p = ROMAddr[0x282] | (ROMAddr[0x283] << 8);
-	    else 				 	 p = ROMAddr[0x284] | (ROMAddr[0x285] << 8);
-	 } else if(SiS_Pr->SiS_VBInfo & SetCRT2ToHiVision) {
-	    p = ROMAddr[0x286] | (ROMAddr[0x287] << 8);
-	 }
-	 do {
-	    if((ROMAddr[p] | ROMAddr[p+1] << 8) == a) break;
-	    p += 0x42;
-	 } while((ROMAddr[p] | ROMAddr[p+1] << 8) != 0xffff);
-	 if((ROMAddr[p] | ROMAddr[p+1] << 8) == 0xffff) p -= 0x42;
-      }
-      p += 2;
-      return(&ROMAddr[p]);
-
+   if(a < b) {
+      tableptr = SiS_Part2CLVX_1;
+   } else if(a == b) {
+      tableptr = SiS_Part2CLVX_2;
    } else {
-
-      if(a < b) {
-         tableptr = SiS_Part2CLVX_1;
-      } else if(a == b) {
-         tableptr = SiS_Part2CLVX_2;
+      if(SiS_Pr->SiS_TVMode & TVSetPAL) {
+	 tableptr = SiS_Part2CLVX_4;
       } else {
-         if(SiS_Pr->SiS_TVMode & TVSetPAL) {
-	    tableptr = SiS_Part2CLVX_4;
-	 } else {
-	    tableptr = SiS_Part2CLVX_3;
-	 }
-	 if(SiS_Pr->SiS_VBInfo & SetCRT2ToYPbPr525750) {
-	    if(SiS_Pr->SiS_TVMode & TVSetYPbPr525i) 	 tableptr = SiS_Part2CLVX_3;
-	    else if(SiS_Pr->SiS_TVMode & TVSetYPbPr525p) tableptr = SiS_Part2CLVX_3;
-	    else 				         tableptr = SiS_Part2CLVX_5;
-
-	 } else if(SiS_Pr->SiS_VBInfo & SetCRT2ToHiVision) {
-	    tableptr = SiS_Part2CLVX_6;
-	 }
-	 do {
-	    if((tableptr[p] | tableptr[p+1] << 8) == a) break;
-	    p += 0x42;
-	 } while((tableptr[p] | tableptr[p+1] << 8) != 0xffff);
-	 if((tableptr[p] | tableptr[p+1] << 8) == 0xffff) p -= 0x42;
+	 tableptr = SiS_Part2CLVX_3;
       }
-      p += 2;
-      return((UCHAR *)&tableptr[p]);
+      if(SiS_Pr->SiS_VBInfo & SetCRT2ToYPbPr525750) {
+	 if(SiS_Pr->SiS_TVMode & TVSetYPbPr525i) 	tableptr = SiS_Part2CLVX_3;
+	 else if(SiS_Pr->SiS_TVMode & TVSetYPbPr525p) 	tableptr = SiS_Part2CLVX_3;
+	 else 				         	tableptr = SiS_Part2CLVX_5;
+      } else if(SiS_Pr->SiS_VBInfo & SetCRT2ToHiVision) {
+	 tableptr = SiS_Part2CLVX_6;
+      }
+      do {
+	 if((tableptr[p] | tableptr[p+1] << 8) == a) break;
+	 p += 0x42;
+      } while((tableptr[p] | tableptr[p+1] << 8) != 0xffff);
+      if((tableptr[p] | tableptr[p+1] << 8) == 0xffff) p -= 0x42;
    }
+   p += 2;
+   return((UCHAR *)&tableptr[p]);
 }
 
-
 static void
 SiS_SetGroup2_C_ELV(SiS_Private *SiS_Pr, USHORT ModeNo, USHORT ModeIdIndex,
 	      	    USHORT RefreshRateTableIndex, PSIS_HW_INFO HwInfo)
@@ -7121,49 +6476,97 @@
    SiS_SetRegANDOR(SiS_Pr->SiS_Part2Port,0x4e,0xeb,temp);
 }
 
-static void
+static BOOLEAN
 SiS_GetCRT2Part2Ptr(SiS_Private *SiS_Pr,USHORT ModeNo,USHORT ModeIdIndex,
 		    USHORT RefreshRateTableIndex,USHORT *CRT2Index,
 		    USHORT *ResIndex,PSIS_HW_INFO HwInfo)
 {
-  USHORT tempbx,tempal;
+
+  if(HwInfo->jChipType < SIS_315H) return FALSE;
 
   if(ModeNo <= 0x13)
-      	tempal = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_CRT2CRTC;
+     (*ResIndex) = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_CRT2CRTC;
   else
-      	tempal = SiS_Pr->SiS_RefIndex[RefreshRateTableIndex].Ext_CRT2CRTC;
+     (*ResIndex) = SiS_Pr->SiS_RefIndex[RefreshRateTableIndex].Ext_CRT2CRTC;
 
-  tempbx = SiS_Pr->SiS_LCDResInfo;
+  (*ResIndex) &= 0x3f;
+  (*CRT2Index) = 0;
 
-  if(SiS_Pr->SiS_LCDInfo & DontExpandLCD)      tempbx += 16;
-  else if(SiS_Pr->SiS_SetFlag & LCDVESATiming) tempbx += 32;
-
-  if(SiS_Pr->SiS_CustomT == CUT_COMPAQ1280) {
-     if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1280x1024) {
-        tempbx = 100;
-        if(SiS_Pr->SiS_LCDInfo & DontExpandLCD)      tempbx = 101;
-  	else if(SiS_Pr->SiS_SetFlag & LCDVESATiming) tempbx = 102;
-     }
-  } else if(SiS_Pr->SiS_CustomT == CUT_CLEVO1024) {
-     if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1024x768) {
-        if(SiS_IsDualLink(SiS_Pr, HwInfo)) {
-           tempbx = 103;
-           if(SiS_Pr->SiS_LCDInfo & DontExpandLCD)      tempbx = 104;
-  	   else if(SiS_Pr->SiS_SetFlag & LCDVESATiming) tempbx = 105;
-	}
-     }
-  } else if(SiS_Pr->SiS_CustomT == CUT_ASUSA2H_2) {
-     if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1024x768) {
-        if(SiS_Pr->SiS_SetFlag & LCDVESATiming) tempbx = 106;
+  if(SiS_Pr->SiS_LCDResInfo == Panel_1024x768) {
+     if(!(SiS_Pr->SiS_SetFlag & LCDVESATiming)) {
+        (*CRT2Index) = 200;
      }
   }
 
-  *CRT2Index = tempbx;
-  *ResIndex = tempal & 0x3F;
+  if(SiS_Pr->SiS_CustomT == CUT_ASUSA2H_2) {
+     if(SiS_Pr->SiS_LCDResInfo == Panel_1024x768) {
+        if(SiS_Pr->SiS_SetFlag & LCDVESATiming) (*CRT2Index) = 206;
+     }
+  }
+  return(((*CRT2Index) != 0));
 }
 #endif
 
 #ifdef SIS300
+static void
+SiS_Group2LCDSpecial(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo, USHORT ModeNo, USHORT crt2crtc)
+{
+   USHORT tempcx;
+   const UCHAR atable[] = {
+       0xc3,0x9e,0xc3,0x9e,0x02,0x02,0x02,
+       0xab,0x87,0xab,0x9e,0xe7,0x02,0x02
+   };
+
+   if(!SiS_Pr->UseCustomMode) {
+      if( ( ( (HwInfo->jChipType == SIS_630) ||
+              (HwInfo->jChipType == SIS_730) ) &&
+            (HwInfo->jChipRevision > 2) )  &&
+          (SiS_Pr->SiS_LCDResInfo == Panel_1024x768) &&
+          (!(SiS_Pr->SiS_SetFlag & LCDVESATiming))  &&
+          (!(SiS_Pr->SiS_LCDInfo & DontExpandLCD)) ) {
+         if(ModeNo == 0x13) {
+            SiS_SetReg(SiS_Pr->SiS_Part2Port,0x04,0xB9);
+            SiS_SetReg(SiS_Pr->SiS_Part2Port,0x05,0xCC);
+            SiS_SetReg(SiS_Pr->SiS_Part2Port,0x06,0xA6);
+         } else {
+            if((crt2crtc & 0x3F) == 4) {
+               SiS_SetReg(SiS_Pr->SiS_Part2Port,0x01,0x2B);
+               SiS_SetReg(SiS_Pr->SiS_Part2Port,0x02,0x13);
+               SiS_SetReg(SiS_Pr->SiS_Part2Port,0x04,0xE5);
+               SiS_SetReg(SiS_Pr->SiS_Part2Port,0x05,0x08);
+               SiS_SetReg(SiS_Pr->SiS_Part2Port,0x06,0xE2);
+            }
+         }
+      }
+
+      if(HwInfo->jChipType < SIS_315H) {
+         if(SiS_Pr->SiS_LCDTypeInfo == 0x0c) {
+            crt2crtc &= 0x1f;
+            tempcx = 0;
+            if(!(SiS_Pr->SiS_VBInfo & SetNotSimuMode)) {
+               if(SiS_Pr->SiS_VBInfo & SetInSlaveMode) {
+                  tempcx += 7;
+               }
+            }
+            tempcx += crt2crtc;
+            if(crt2crtc >= 4) {
+               SiS_SetReg(SiS_Pr->SiS_Part2Port,0x06,0xff);
+            }
+
+            if(!(SiS_Pr->SiS_VBInfo & SetNotSimuMode)) {
+               if(SiS_Pr->SiS_VBInfo & SetInSlaveMode) {
+                  if(crt2crtc == 4) {
+                     SiS_SetReg(SiS_Pr->SiS_Part2Port,0x01,0x28);
+                  }
+               }
+            }
+            SiS_SetReg(SiS_Pr->SiS_Part2Port,0x02,0x18);
+            SiS_SetReg(SiS_Pr->SiS_Part2Port,0x04,atable[tempcx]);
+         }
+      }
+   }
+}
+
 /* For ECS A907. Highly preliminary. */
 static void
 SiS_Set300Part2Regs(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo,
@@ -7232,15 +6635,81 @@
 	if(!(SiS_Pr->SiS_VBInfo & SetCRT2ToYPbPr525750)) {
 	   if(SiS_Pr->SiS_TVMode & TVSetPALM) {
 	      SiS_SetReg(SiS_Pr->SiS_Part2Port,0x01,0x14);
+	      SiS_SetReg(SiS_Pr->SiS_Part2Port,0x02,0x1b);
 	   } else {
-	      SiS_SetReg(SiS_Pr->SiS_Part2Port,0x01,0x15);
+	      SiS_SetReg(SiS_Pr->SiS_Part2Port,0x01,0x14);  /* 15 */
+	      SiS_SetReg(SiS_Pr->SiS_Part2Port,0x02,0x1a);  /* 1b */
+	   }
+	}
+     }
+  } else {
+     if((ModeNo == 0x38) || (ModeNo == 0x4a) || (ModeNo == 0x64) ||
+        (ModeNo == 0x52) || (ModeNo == 0x58) || (ModeNo == 0x5c)) {
+        SiS_SetReg(SiS_Pr->SiS_Part2Port,0x01,0x1b);  /* 21 */
+        SiS_SetReg(SiS_Pr->SiS_Part2Port,0x02,0x54);  /* 5a */
+     } else {
+        SiS_SetReg(SiS_Pr->SiS_Part2Port,0x01,0x1a);  /* 21 */
+        SiS_SetReg(SiS_Pr->SiS_Part2Port,0x02,0x53);  /* 5a */
+     }
+  }
+}
+
+static void
+SiS_SetGroup2_Tail(SiS_Private *SiS_Pr, USHORT ModeNo)
+{
+  USHORT temp;
+
+  if(!(SiS_Pr->SiS_SetFlag & LCDVESATiming)) {
+     if(SiS_Pr->SiS_VGAVDE == 525) {
+	temp = 0xc3;
+	if(SiS_Pr->SiS_ModeType <= ModeVGA) {
+	   temp++;
+	   if(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) temp += 2;
+	}
+	SiS_SetReg(SiS_Pr->SiS_Part2Port,0x2f,temp);
+	SiS_SetReg(SiS_Pr->SiS_Part2Port,0x30,0xb3);
+     } else if(SiS_Pr->SiS_VGAVDE == 420) {
+	temp = 0x4d;
+	if(SiS_Pr->SiS_ModeType <= ModeVGA) {
+	   temp++;
+	   if(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) temp++;
+	}
+	SiS_SetReg(SiS_Pr->SiS_Part2Port,0x2f,temp);
+     }
+  }
+
+  if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCD) {
+     if(SiS_Pr->SiS_LCDResInfo == Panel_1400x1050) {
+	if(SiS_Pr->SiS_VBType & VB_SIS301B302B) {
+	   SiS_SetRegOR(SiS_Pr->SiS_Part2Port,0x1a,0x03);
+	   /* Not always for LV, see SetGrp2 */
+	}
+	temp = 1;
+	if(ModeNo <= 0x13) temp = 3;
+	SiS_SetReg(SiS_Pr->SiS_Part2Port,0x0b,temp);
+     }
+#if 0
+     /* 651+301C, for 1280x768 - do I really need that? */
+     if((SiS_Pr->SiS_PanelXRes == 1280) && (SiS_Pr->SiS_PanelYRes == 768)) {
+        if(SiS_Pr->SiS_VBInfo & SetSimuScanMode) {
+	   if(((SiS_Pr->SiS_HDE == 640) && (SiS_Pr->SiS_VDE == 480)) ||
+	      ((SiS_Pr->SiS_HDE == 320) && (SiS_Pr->SiS_VDE == 240))) {
+	      SiS_SetReg(SiS_Part2Port,0x01,0x2b);
+	      SiS_SetReg(SiS_Part2Port,0x02,0x13);
+	      SiS_SetReg(SiS_Part2Port,0x04,0xe5);
+	      SiS_SetReg(SiS_Part2Port,0x05,0x08);
+	      SiS_SetReg(SiS_Part2Port,0x06,0xe2);
+	      SiS_SetReg(SiS_Part2Port,0x1c,0x21);
+	      SiS_SetReg(SiS_Part2Port,0x1d,0x45);
+	      SiS_SetReg(SiS_Part2Port,0x1f,0x0b);
+	      SiS_SetReg(SiS_Part2Port,0x20,0x00);
+	      SiS_SetReg(SiS_Part2Port,0x21,0xa9);
+	      SiS_SetReg(SiS_Part2Port,0x23,0x0b);
+	      SiS_SetReg(SiS_Part2Port,0x25,0x04);
 	   }
-	   SiS_SetReg(SiS_Pr->SiS_Part2Port,0x02,0x1b);
 	}
      }
-  } else {
-     SiS_SetReg(SiS_Pr->SiS_Part2Port,0x01,0x21);
-     SiS_SetReg(SiS_Pr->SiS_Part2Port,0x02,0x5a);
+#endif
   }
 }
 
@@ -7248,37 +6717,27 @@
 SiS_SetGroup2(SiS_Private *SiS_Pr, USHORT ModeNo, USHORT ModeIdIndex,USHORT RefreshRateTableIndex,
 	      PSIS_HW_INFO HwInfo)
 {
-  USHORT      i, j, tempax, tempbx, tempcx, temp;
-  USHORT      push1, push2, modeflag, crt2crtc;
-  ULONG       longtemp, tempeax;
+  USHORT      i, j, tempax, tempbx, tempcx, tempch, tempcl, temp;
+  USHORT      push2, modeflag, crt2crtc, bridgeoffset;
+  ULONG       longtemp;
   const       UCHAR *PhasePoint;
   const       UCHAR *TimingPoint;
 #ifdef SIS315H
   USHORT      resindex, CRT2Index;
   const       SiS_Part2PortTblStruct *CRT2Part2Ptr = NULL;
-#endif
-#ifdef SIS300
-  const UCHAR atable[] = {
-       0xc3,0x9e,0xc3,0x9e,0x02,0x02,0x02,
-       0xab,0x87,0xab,0x9e,0xe7,0x02,0x02
-  };
-#endif
 
-#ifdef SIS315H   
   if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCDA) return;
 #endif
 
   if(ModeNo <= 0x13) {
      modeflag = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_ModeFlag;
      crt2crtc = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_CRT2CRTC;
+  } else if(SiS_Pr->UseCustomMode) {
+     modeflag = SiS_Pr->CModeFlag;
+     crt2crtc = 0;
   } else {
-     if(SiS_Pr->UseCustomMode) {
-        modeflag = SiS_Pr->CModeFlag;
-	crt2crtc = 0;
-     } else {
-        modeflag = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag;
-    	crt2crtc = SiS_Pr->SiS_RefIndex[RefreshRateTableIndex].Ext_CRT2CRTC;
-     }
+     modeflag = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag;
+     crt2crtc = SiS_Pr->SiS_RefIndex[RefreshRateTableIndex].Ext_CRT2CRTC;
   }
 
   temp = 0;
@@ -7395,7 +6854,7 @@
 
   if(SiS_Pr->SiS_VBInfo & SetCRT2ToHiVision) 	tempax = 950;
   else if(SiS_Pr->SiS_TVMode & TVSetPAL)      	tempax = 520;
-  else 			            		tempax = 440;
+  else 			            		tempax = 440; /* NTSC, YPbPr 525, 750 */
 
   if( ( (!(SiS_Pr->SiS_VBInfo & SetCRT2ToTVNoHiVision)) && (SiS_Pr->SiS_VDE <= tempax) ) ||
       ( (SiS_Pr->SiS_VBInfo & SetCRT2ToTVNoHiVision) &&
@@ -7411,10 +6870,10 @@
      temp = tempax + (USHORT)TimingPoint[1];
      SiS_SetReg(SiS_Pr->SiS_Part2Port,0x02,temp);
 
-     if((SiS_Pr->SiS_VBInfo & SetCRT2ToTVNoHiVision) && (SiS_Pr->SiS_VGAHDE >= 1024)) {
+     if((SiS_Pr->SiS_VBInfo & SetCRT2ToTVNoYPbPrHiVision) && (SiS_Pr->SiS_VGAHDE >= 1024)) {
         if(SiS_Pr->SiS_TVMode & TVSetPAL) {
-           SiS_SetReg(SiS_Pr->SiS_Part2Port,0x01,0x19);
-           SiS_SetReg(SiS_Pr->SiS_Part2Port,0x02,0x52);
+           SiS_SetReg(SiS_Pr->SiS_Part2Port,0x01,0x1b);  /* 19 */
+           SiS_SetReg(SiS_Pr->SiS_Part2Port,0x02,0x54);  /* 52 */
         } else {
            SiS_SetReg(SiS_Pr->SiS_Part2Port,0x01,0x17);
            SiS_SetReg(SiS_Pr->SiS_Part2Port,0x02,0x1d);
@@ -7427,199 +6886,157 @@
   if(SiS_IsDualLink(SiS_Pr, HwInfo)) tempcx >>= 1;
   tempcx--;
   if(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) tempcx--;
-  temp = tempcx & 0x00FF;
-  SiS_SetReg(SiS_Pr->SiS_Part2Port,0x1B,temp);
-  temp = (tempcx & 0xFF00) >> 8;
-  SiS_SetRegANDOR(SiS_Pr->SiS_Part2Port,0x1D,0xF0,temp);
-
-  tempcx++;
-  if(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) tempcx++;
-  tempcx >>= 1;
-
-  push1 = tempcx;
+  SiS_SetReg(SiS_Pr->SiS_Part2Port,0x1B,tempcx);
+  SiS_SetRegANDOR(SiS_Pr->SiS_Part2Port,0x1D,0xF0,((tempcx >> 8) & 0x0f));
 
+  tempcx = SiS_Pr->SiS_HT >> 1;
+  if(SiS_IsDualLink(SiS_Pr, HwInfo)) tempcx >>= 1;
   tempcx += 7;
   if(SiS_Pr->SiS_VBInfo & SetCRT2ToHiVision) tempcx -= 4;
-  temp = (tempcx & 0x00FF) << 4;
-  SiS_SetRegANDOR(SiS_Pr->SiS_Part2Port,0x22,0x0F,temp);
+  SiS_SetRegANDOR(SiS_Pr->SiS_Part2Port,0x22,0x0F,((tempcx << 4) & 0xf0));
 
-  tempbx = TimingPoint[j] | ((TimingPoint[j+1]) << 8);
+  tempbx = TimingPoint[j] | (TimingPoint[j+1] << 8);
   tempbx += tempcx;
-
-  temp = tempbx & 0x00FF;
-  SiS_SetReg(SiS_Pr->SiS_Part2Port,0x24,temp);
-  temp = ((tempbx & 0xFF00) >> 8) << 4;
-  SiS_SetRegANDOR(SiS_Pr->SiS_Part2Port,0x25,0x0F,temp);
+  SiS_SetReg(SiS_Pr->SiS_Part2Port,0x24,tempbx);
+  SiS_SetRegANDOR(SiS_Pr->SiS_Part2Port,0x25,0x0F,((tempbx >> 4) & 0xf0));
 
   tempbx += 8;
   if(SiS_Pr->SiS_VBInfo & SetCRT2ToHiVision) {
      tempbx -= 4;
      tempcx = tempbx;
   }
-  temp = (tempbx & 0x00FF) << 4;
-  SiS_SetRegANDOR(SiS_Pr->SiS_Part2Port,0x29,0x0F,temp);
+  SiS_SetRegANDOR(SiS_Pr->SiS_Part2Port,0x29,0x0F,((tempbx << 4) & 0xf0));
 
   j += 2;
-  tempcx += ((TimingPoint[j] | ((TimingPoint[j+1]) << 8)));
-  temp = tempcx & 0x00FF;
-  SiS_SetReg(SiS_Pr->SiS_Part2Port,0x27,temp);
-  temp = ((tempcx & 0xFF00) >> 8) << 4;
-  SiS_SetRegANDOR(SiS_Pr->SiS_Part2Port,0x28,0x0F,temp);
+  tempcx += (TimingPoint[j] | (TimingPoint[j+1] << 8));
+  SiS_SetReg(SiS_Pr->SiS_Part2Port,0x27,tempcx);
+  SiS_SetRegANDOR(SiS_Pr->SiS_Part2Port,0x28,0x0F,((tempcx >> 4) & 0xf0));
 
   tempcx += 8;
   if(SiS_Pr->SiS_VBInfo & SetCRT2ToHiVision) tempcx -= 4;
-  temp = (tempcx & 0x00FF) << 4;
-  SiS_SetRegANDOR(SiS_Pr->SiS_Part2Port,0x2A,0x0F,temp);
-
-  tempcx = push1;
+  SiS_SetRegANDOR(SiS_Pr->SiS_Part2Port,0x2A,0x0F,((tempcx << 4) & 0xf0));
 
+  tempcx = SiS_Pr->SiS_HT >> 1;
+  if(SiS_IsDualLink(SiS_Pr, HwInfo)) tempcx >>= 1;
   j += 2;
   tempcx -= (TimingPoint[j] | ((TimingPoint[j+1]) << 8));
-  temp = (tempcx & 0x00FF) << 4;
-  SiS_SetRegANDOR(SiS_Pr->SiS_Part2Port,0x2D,0x0F,temp);
+  SiS_SetRegANDOR(SiS_Pr->SiS_Part2Port,0x2D,0x0F,((tempcx << 4) & 0xf0));
 
   tempcx -= 11;
   if(!(SiS_Pr->SiS_VBInfo & SetCRT2ToTV)) {
      tempcx = SiS_GetVGAHT2(SiS_Pr) - 1;
   }
-  temp = tempcx & 0x00FF;
-  SiS_SetReg(SiS_Pr->SiS_Part2Port,0x2E,temp);
+  SiS_SetReg(SiS_Pr->SiS_Part2Port,0x2E,tempcx);
 
   tempbx = SiS_Pr->SiS_VDE;
-  if(SiS_Pr->SiS_VGAVDE == 360) tempbx = 746;
-  if(SiS_Pr->SiS_VGAVDE == 375) tempbx = 746;
-  if(SiS_Pr->SiS_VGAVDE == 405) tempbx = 853;
-  if(HwInfo->jChipType < SIS_315H) {
-     if(SiS_Pr->SiS_VBInfo & SetCRT2ToTV) tempbx >>= 1;
-  } else {
-     if( (SiS_Pr->SiS_VBInfo & SetCRT2ToTV) &&
-         (!(SiS_Pr->SiS_TVMode & (TVSetYPbPr525p|TVSetYPbPr750p))) ) {
-	tempbx >>= 1;
-	if(SiS_Pr->SiS_TVMode & TVSetTVSimuMode) {
-	   if(ModeNo <= 0x13) {
-	      if(crt2crtc == 1) tempbx++;
-	   }
+  if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCD) {
+     if(SiS_Pr->SiS_VGAVDE == 360) tempbx = 746;
+     if(SiS_Pr->SiS_VGAVDE == 375) tempbx = 746;
+     if(SiS_Pr->SiS_VGAVDE == 405) tempbx = 853;
+  } else if( (SiS_Pr->SiS_VBInfo & SetCRT2ToTV) &&
+             (!(SiS_Pr->SiS_TVMode & (TVSetYPbPr525p|TVSetYPbPr750p))) ) {
+     tempbx >>= 1;
+     if(HwInfo->jChipType >= SIS_315H) {
+        if(SiS_Pr->SiS_TVMode & TVSetTVSimuMode) {
+	   if((ModeNo <= 0x13) && (crt2crtc == 1)) tempbx++;
 	} else if(SiS_Pr->SiS_VBInfo & SetInSlaveMode) {
-	   if(crt2crtc == 4) {
-              if(SiS_Pr->SiS_ModeType <= 3) tempbx++;
+	   if(SiS_Pr->SiS_ModeType <= ModeVGA) {
+	      if(crt2crtc == 4) tempbx++;
 	   }
 	}
      }
-  }
-  tempbx -= 2;
-  temp = tempbx & 0x00FF;
-  if(SiS_Pr->SiS_VBInfo & SetCRT2ToHiVision) {
      if(SiS_Pr->SiS_VBInfo & SetInSlaveMode) {
-        if((ModeNo == 0x2f) || (ModeNo == 0x5d) || (ModeNo == 0x5e)) temp++;
-     }
-  }
-
-  if(HwInfo->jChipType < SIS_661) {
-     /* From 1.10.7w - doesn't make sense */
-     if(SiS_Pr->SiS_VBInfo & SetCRT2ToTV) {
-        if(SiS_Pr->SiS_VBInfo & SetInSlaveMode) {
-           if(!(SiS_Pr->SiS_TVMode & TVSetPAL)) {
-	      if(!(SiS_Pr->SiS_SetFlag & LCDVESATiming)) {   /* SetFlag?? */
-	         if(ModeNo == 0x03) temp++;
-	      }
-	   }
+        if(SiS_Pr->SiS_VBInfo & SetCRT2ToHiVision) {
+	   if((ModeNo == 0x2f) || (ModeNo == 0x5d) || (ModeNo == 0x5e)) tempbx++;
+	}
+	if(!(SiS_Pr->SiS_TVMode & TVSetPAL)) {
+	   if(ModeNo == 0x03) tempbx++; /* From 1.10.7w - doesn't make sense */
         }
      }
   }
-  SiS_SetReg(SiS_Pr->SiS_Part2Port,0x2F,temp);
+  tempbx -= 2;
+  SiS_SetReg(SiS_Pr->SiS_Part2Port,0x2F,tempbx);
 
   temp = (tempcx >> 8) & 0x0F;
-  temp |= (((tempbx >> 8) << 6) & 0xC0);
-  if(!(SiS_Pr->SiS_VBInfo & (SetCRT2ToHiVision | SetCRT2ToYPbPr525750 | SetCRT2ToSCART))) {
+  temp |= ((tempbx >> 2) & 0xC0);
+  if(SiS_Pr->SiS_VBInfo & (SetCRT2ToSVIDEO | SetCRT2ToAVIDEO)) {
      temp |= 0x10;
-     if(!(SiS_Pr->SiS_VBInfo & SetCRT2ToSVIDEO)) temp |= 0x20;
+     if(SiS_Pr->SiS_VBInfo & SetCRT2ToAVIDEO) temp |= 0x20;
   }
   SiS_SetReg(SiS_Pr->SiS_Part2Port,0x30,temp);
 
-  if((HwInfo->jChipType > SIS_315H) && (HwInfo->jChipType < SIS_661)) {
-     if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCD) {
-        if(SiS_Pr->SiS_VBType & (VB_SIS301C | VB_SIS302LV | VB_SIS302ELV)) {
-           if( (SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1400x1050) ||
-               (SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1600x1200) ) {
-              SiS_SetRegOR(SiS_Pr->SiS_Part4Port,0x10,0x60);
-	   }
-        }
+  if(SiS_Pr->SiS_VBType & (VB_SIS301C | VB_SIS302LV | VB_SIS302ELV)) {
+     SiS_SetRegANDOR(SiS_Pr->SiS_Part4Port,0x10,0xdf,((tempbx & 0x0400) >> 5));
+  }
+
+#if 0
+  /* TEST qqqq */
+  if(SiS_Pr->SiS_VBInfo & SetCRT2ToYPbPr525750) {
+     for(i=0x01, j=0; i<=0x2D; i++, j++) {
+        SiS_SetReg(SiS_Pr->SiS_Part2Port,i,TimingPoint[j]);
+     }
+     for(i=0x39; i<=0x45; i++, j++) {
+        SiS_SetReg(SiS_Pr->SiS_Part2Port,i,TimingPoint[j]);
      }
   }
+#endif
 
   if(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) {
      tempbx = SiS_Pr->SiS_VDE;
-     if(SiS_Pr->SiS_VBInfo & SetCRT2ToTV) {
-        if(!(SiS_Pr->SiS_TVMode & (TVSetYPbPr525p | TVSetYPbPr750p))) {
-           tempbx >>= 1;
-	}
+     if( (SiS_Pr->SiS_VBInfo & SetCRT2ToTV) &&
+         (!(SiS_Pr->SiS_TVMode & (TVSetYPbPr525p | TVSetYPbPr750p))) ) {
+        tempbx >>= 1;
      }
      tempbx -= 3;
-     if(HwInfo->jChipType >= SIS_661) {
-        if(SiS_Pr->SiS_VBType & (VB_SIS301C | VB_SIS302LV | VB_SIS302ELV)) {  /* Why not 301B/LV? */
-           temp = 0;
-	   if(tempcx & 0x0400) temp |= 0x20;
-	   if(tempbx & 0x0400) temp |= 0x40;
-	   SiS_SetReg(SiS_Pr->SiS_Part4Port,0x10,temp);
-	}
-     }
-     tempbx &= 0x03ff;
-     temp = ((tempbx & 0xFF00) >> 8) << 5;
-     temp |= 0x18;
+     temp = ((tempbx >> 3) & 0x60) | 0x18;
      SiS_SetReg(SiS_Pr->SiS_Part2Port,0x46,temp);
-     temp = tempbx & 0x00FF;
-     SiS_SetReg(SiS_Pr->SiS_Part2Port,0x47,temp);
+     SiS_SetReg(SiS_Pr->SiS_Part2Port,0x47,tempbx);
 
+     if(SiS_Pr->SiS_VBType & (VB_SIS301C | VB_SIS302LV | VB_SIS302ELV)) {
+	SiS_SetRegANDOR(SiS_Pr->SiS_Part4Port,0x10,0xbf,((tempbx & 0x0400) >> 4));
+     }
   }
 
   tempbx = 0;
   if(!(modeflag & HalfDCLK)) {
      if(SiS_Pr->SiS_VGAHDE >= SiS_Pr->SiS_HDE) {
         tempax = 0;
-        tempbx |= 0x2000;
+        tempbx |= 0x20;
      }
   }
 
-  tempcx = 0x0101;
+  tempch = tempcl = 0x01;
   if(SiS_Pr->SiS_VBInfo & SetCRT2ToTV) {
      if(SiS_Pr->SiS_VGAHDE >= 1024) {
         if((!(modeflag & HalfDCLK)) || (HwInfo->jChipType < SIS_315H)) {
-           tempcx = 0x1920;
+           tempch = 0x19;
+	   tempcl = 0x20;
            if(SiS_Pr->SiS_VGAHDE >= 1280) {
-              tempcx = 0x1420;
-              tempbx &= ~0x2000;
+              tempch = 0x14;
+              tempbx &= ~0x20;
            }
         }
      }
   }
 
-  if(!(tempbx & 0x2000)) {
-     if(modeflag & HalfDCLK) {
-        tempcx = (tempcx & 0xFF00) | ((tempcx << 1) & 0x00FF);
-     }
-     longtemp = (SiS_Pr->SiS_VGAHDE * ((tempcx & 0xFF00) >> 8)) / (tempcx & 0x00FF);
-     longtemp <<= 13;
-     if(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) {
-     	longtemp <<= 3;
-     }
-     tempeax = longtemp / SiS_Pr->SiS_HDE;
-     if(longtemp % SiS_Pr->SiS_HDE) tempeax++;
-     tempax = (USHORT)tempeax;
-     tempbx |= (tempax & 0x1F00);
-     tempcx = (tempax & 0xFF00) >> (8 + 5);
+  if(!(tempbx & 0x20)) {
+     if(modeflag & HalfDCLK) tempcl <<= 1;
+     longtemp = ((SiS_Pr->SiS_VGAHDE * tempch) / tempcl) << 13;
+     if(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) longtemp <<= 3;
+     tempax = longtemp / SiS_Pr->SiS_HDE;
+     if(longtemp % SiS_Pr->SiS_HDE) tempax++;
+     tempbx |= ((tempax >> 8) & 0x1F);
+     tempcx = tempax >> 13;
   }
 
   SiS_SetReg(SiS_Pr->SiS_Part2Port,0x44,tempax);
-  SiS_SetRegANDOR(SiS_Pr->SiS_Part2Port,0x45,0xC0,(tempbx >> 8));
+  SiS_SetRegANDOR(SiS_Pr->SiS_Part2Port,0x45,0xC0,tempbx);
 
   if(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) {
 
-     temp = tempcx & 0x0007;
-     if(tempbx & 0x2000) temp = 0;
-     if((HwInfo->jChipType < SIS_661) || (!(SiS_Pr->SiS_VBInfo & SetCRT2ToLCD))) {
-        temp |= 0x18;
-     }
-     SiS_SetRegANDOR(SiS_Pr->SiS_Part2Port,0x46,0xE0,temp);
+     tempcx &= 0x07;
+     if(tempbx & 0x20) tempcx = 0;
+     SiS_SetRegANDOR(SiS_Pr->SiS_Part2Port,0x46,0xF8,tempcx);
 
      if(SiS_Pr->SiS_TVMode & TVSetPAL) {
         tempbx = 0x0382;
@@ -7628,11 +7045,9 @@
         tempbx = 0x0369;
         tempcx = 0x0061;
      }
-     temp = (tempbx & 0x00FF) ;
-     SiS_SetReg(SiS_Pr->SiS_Part2Port,0x4B,temp);
-     temp = (tempcx & 0x00FF) ;
-     SiS_SetReg(SiS_Pr->SiS_Part2Port,0x4C,temp);
-     temp = (tempcx & 0x0300) >> (8 - 2);
+     SiS_SetReg(SiS_Pr->SiS_Part2Port,0x4B,tempbx);
+     SiS_SetReg(SiS_Pr->SiS_Part2Port,0x4C,tempcx);
+     temp = (tempcx & 0x0300) >> 6;
      temp |= ((tempbx >> 8) & 0x03);
      if(SiS_Pr->SiS_VBInfo & SetCRT2ToYPbPr525750) {
         temp |= 0x10;
@@ -7642,7 +7057,7 @@
      SiS_SetReg(SiS_Pr->SiS_Part2Port,0x4D,temp);
 
      temp = SiS_GetReg(SiS_Pr->SiS_Part2Port,0x43);
-     SiS_SetReg(SiS_Pr->SiS_Part2Port,0x43,(USHORT)(temp - 3));
+     SiS_SetReg(SiS_Pr->SiS_Part2Port,0x43,(temp - 3));
 
      SiS_SetTVSpecial(SiS_Pr, ModeNo);
 
@@ -7657,7 +7072,7 @@
   if(SiS_Pr->SiS_TVMode & TVSetPALM) {
      if(!(SiS_Pr->SiS_TVMode & TVSetNTSC1024)) {
         temp = SiS_GetReg(SiS_Pr->SiS_Part2Port,0x01);
-        SiS_SetReg(SiS_Pr->SiS_Part2Port,0x01,temp - 1);
+        SiS_SetReg(SiS_Pr->SiS_Part2Port,0x01,(temp - 1));
      }
      SiS_SetRegAND(SiS_Pr->SiS_Part2Port,0x00,0xEF);
   }
@@ -7675,13 +7090,11 @@
   tempbx = SiS_Pr->SiS_HDE;
   if(SiS_IsDualLink(SiS_Pr, HwInfo)) tempbx >>= 1;
   tempbx--;			         	/* RHACTE = HDE - 1 */
-  temp = tempbx & 0x00FF;
-  SiS_SetReg(SiS_Pr->SiS_Part2Port,0x2C,temp);
-  temp = (tempbx & 0xFF00) >> 4;
-  SiS_SetRegANDOR(SiS_Pr->SiS_Part2Port,0x2B,0x0F,temp);
+  SiS_SetReg(SiS_Pr->SiS_Part2Port,0x2C,tempbx);
+  SiS_SetRegANDOR(SiS_Pr->SiS_Part2Port,0x2B,0x0F,((tempbx >> 4) & 0xf0));
 
   temp = 0x01;
-  if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1280x1024) {
+  if(SiS_Pr->SiS_LCDResInfo == Panel_1280x1024) {
      if(SiS_Pr->SiS_ModeType == ModeEGA) {
         if(SiS_Pr->SiS_VGAHDE >= 1024) {
            temp = 0x02;
@@ -7696,49 +7109,19 @@
   SiS_SetReg(SiS_Pr->SiS_Part2Port,0x0B,temp);
 
   tempbx = SiS_Pr->SiS_VDE - 1;
-  temp = tempbx & 0x00FF;
-  SiS_SetReg(SiS_Pr->SiS_Part2Port,0x03,temp);
-  temp = ((tempbx & 0xFF00) >> 8) & 0x07;
-  SiS_SetRegANDOR(SiS_Pr->SiS_Part2Port,0x0C,0xF8,temp);
+  SiS_SetReg(SiS_Pr->SiS_Part2Port,0x03,tempbx);
+  SiS_SetRegANDOR(SiS_Pr->SiS_Part2Port,0x0C,0xF8,((tempbx >> 8) & 0x07));
 
   tempcx = SiS_Pr->SiS_VT - 1;
-  temp = tempcx & 0x00FF;
-  SiS_SetReg(SiS_Pr->SiS_Part2Port,0x19,temp);
-
-  temp = ((tempcx & 0xFF00) >> 8) << 5;
-
-  /* Enable dithering; only do this for 32bpp mode */
+  SiS_SetReg(SiS_Pr->SiS_Part2Port,0x19,tempcx);
+  temp = (tempcx >> 3) & 0xE0;
   if(SiS_Pr->SiS_LCDInfo & LCDRGB18Bit) {
+     /* Enable dithering; only do this for 32bpp mode */
      if(SiS_GetReg(SiS_Pr->SiS_Part1Port,0x00) & 0x01) {
         temp |= 0x10;
      }
   }
-
-  /* Must do special for Compaq1280; Acer1280 OK, Clevo1400 OK, COMPAL1400 OK */
-  /* Compaq1280 panel loses sync if using CR37 sync info. */
-  if((SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) && (SiS_Pr->SiS_VBInfo & SetCRT2ToLCD)) {
-     if((HwInfo->jChipType >= SIS_315H) && (SiS_Pr->SiS_VBType & VB_SIS301LV302LV)) {
-	if((SiS_Pr->SiS_CustomT == CUT_COMPAQ1280) &&
-	   (SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1280x1024)) {
-	   if(SiS_Pr->SiS_LCDInfo & LCDSync) {
-	      temp |= ((SiS_Pr->SiS_LCDInfo & 0xc0) >> 6);
-	   }
-	} else if((SiS_Pr->SiS_CustomT == CUT_CLEVO1400) &&
-	          (SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1400x1050)) {
-	   temp |= 0x03;
-	} else {
-           temp |= (SiS_GetReg(SiS_Pr->SiS_P3d4,0x37) >> 6);
-	   temp |= 0x08;
-	   if(!(SiS_Pr->SiS_LCDInfo & LCDRGB18Bit)) temp |= 0x04;
-	}
-     } else {
-        if(SiS_Pr->SiS_LCDInfo & LCDSync) {
-	   temp |= ((SiS_Pr->SiS_LCDInfo & 0xc0) >> 6);
-	}
-     }
-  }
-
-  SiS_SetReg(SiS_Pr->SiS_Part2Port,0x1A,temp);
+  SiS_SetRegANDOR(SiS_Pr->SiS_Part2Port,0x1A,0x0f,temp);
 
   SiS_SetRegAND(SiS_Pr->SiS_Part2Port,0x09,0xF0);
   SiS_SetRegAND(SiS_Pr->SiS_Part2Port,0x0A,0xF0);
@@ -7746,154 +7129,13 @@
   SiS_SetRegAND(SiS_Pr->SiS_Part2Port,0x17,0xFB);
   SiS_SetRegAND(SiS_Pr->SiS_Part2Port,0x18,0xDF);
 
-#if 0  /* Use the 315/330 series code for now */
-  if((HwInfo->jChipType >= SIS_661)          &&
-     (SiS_Pr->SiS_VBType & VB_SIS301LV302LV) &&
-     (ROMAddr && SiS_Pr->SiS_UseROM)) {
-
-      /* This is done for the LVDS bridges only, since
-       * the TMDS panels already work correctly with
-       * the old code. Besides, we only do that if
-       * we can get the data from the ROM, I am tired
-       * of carrying a lot of tables around.
-       */
-
-#ifdef SIS315H 							/* ------------ 661/741/760 series --------- */
-      UCHAR *myptr = NULL, myptr1 = NULL;
-
-      myptr = (UCHAR *)GetLCDPtr661(SiS_Pr, HwInfo, 6, ModeNo, ModeIdIndex, RefreshRateTableIndex);
-      myptr1 = (UCHAR *)GetLCDStructPtr661(SiS_Pr, HwInfo);
-
-      tempbx = (myptr[3] | (myptr[4] << 8)) & 0x0fff;
-      tempcx = SiS_Pr->PanelYRes;
-      if(SiS_Pr->SiS_LCDInfo & LCDPass11) {
-         tempcx = SiS_Pr->SiS_VDE;
-      }
-
-      tempcx += tempbx;
-      if(tempcx >= SiS_Pr->SiS_VT) tempcx -= SiS_Pr->SiS_VT;
-
-      SiS_SetReg(SiS_Pr->SiS_Part2Port,0x05,tempbx);
-      SiS_SetReg(SiS_Pr->SiS_Part2Port,0x06,tempcx);
-
-      tempcx &= 0x07ff;
-      tempbx &= 0x07ff;
-      temp = (tempcx >> 8) << 3;
-      temp |= (tempbx >> 8);
-      SiS_SetReg(SiS_Pr->SiS_Part2Port,0x02,temp);
-
-      tempbx = (myptr[4] | (myptr[5] << 8)) >> 4;
-      tempcx = myptr1[6];
-      if(SiS_Pr->SiS_LCDInfo & LCDPass11) tempcx = myptr[7];
-
-      tempcx += tempbx;
-      if(tempcx >= SiS_Pr->SiS_VT) tempcx -= SiS_Pr->SiS_VT;
-
-      SiS_SetReg(SiS_Pr->SiS_Part2Port,0x04,tempbx);
-      temp = tempcx & 0x000f;
-      temp |= ((tempbx & 0x0f00) >> 4);
-      SiS_SetReg(SiS_Pr->SiS_Part2Port,0x01,temp);
-
-      tempax = SiS_Pr->SiS_HT;
-      tempbx = (myptr[0] | (myptr[1] << 8)) & 0x0fff;
-      tempcx = SiS_Pr->PanelXRes;
-      if(SiS_Pr->SiS_LCDInfo & LCDPass11) tempcx = SiS_Pr->SiS_HDE;
-
-      if(SiS_IsDualLink(SiS_Pr, HwInfo)) {
-         tempax >>= 1;
-	 tempbx >>= 1;
-	 tempcx >>= 1;
-      }
-      if(SiS_Pr->SiS_VBType & VB_SIS302LV)                 tempbx++;
-      if(SiS_Pr->SiS_VBType & (VB_SIS301C | VB_SIS302ELV)) tempbx++;
-
-      tempcx += tempbx;
-      if(tempcx >= tempax) tempcx -= tempax;
-
-      SiS_SetReg(SiS_Pr->SiS_Part2Port,0x1f,tempbx);
-      temp = ((tempbx & 0xff00) >> 8) << 4;
-      SiS_SetReg(SiS_Pr->SiS_Part2Port,0x20,temp);
-      SiS_SetReg(SiS_Pr->SiS_Part2Port,0x23,tempcx);
-      temp = tempcx >> 8;
-      SiS_SetReg(SiS_Pr->SiS_Part2Port,0x25,temp);
-
-      tempax = SiS_Pr->SiS_HT;
-      tempbx = (myptr[1] | (myptr[2] << 8)) >> 4;
-      tempcx = myptr1[5];
-      if(SiS_Pr->SiS_LCDInfo & LCDPass11) {
-         tempcx = myptr[6];
-      }
-      if(SiS_IsDualLink(SiS_Pr, HwInfo)) {
-         tempax >>= 1;
-	 tempbx >>= 1;
-	 tempcx >>= 1;
-      }
-      if(SiS_Pr->SiS_VBType & VB_SIS302LV) tempbx++;
-
-      tempcx += tempbx;
-      if(tempcx >= tempax) tempcx -= tempax;
-
-      SiS_SetReg(SiS_Pr->SiS_Part2Port,0x1c,tempbx);
-      temp = (tempbx & 0x0f00) >> 4;
-      SiS_SetRegANDOR(SiS_Pr->SiS_Part2Port,0x1d,0x0f,temp);
-      SiS_SetReg(SiS_Pr->SiS_Part2Port,0x21,tempcx);
-
-      if(!(SiS_Pr->SiS_SetFlag & LCDVESATiming)) {
-         if(SiS_Pr->SiS_VGAVDE == 525) {
-	    temp = 0xc3;
-	    if(SiS_Pr->SiS_ModeType <= ModeVGA) {
-	       temp++;
-	       if(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) temp += 2;
-	    }
-	    SiS_SetReg(SiS_Pr->SiS_Part2Port,0x2f,temp);
-	    SiS_SetReg(SiS_Pr->SiS_Part2Port,0x30,0xb3);
-	 } else if(SiS_Pr->SiS_VGAVDE == 420) {
-	    temp = 0x4d;
-	    if(SiS_Pr->SiS_ModeType <= ModeVGA) {
-	       temp++;
-	       if(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) temp++;
-	    }
-	    SiS_SetReg(SiS_Pr->SiS_Part2Port,0x2f,temp);
-	 }
-      }
-
-#endif
-
-  } else
-#endif
-         if((HwInfo->jChipType >= SIS_315H)                    &&
-            (SiS_Pr->SiS_VBType & VB_SIS301LV302LV)            &&
-            ((SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1024x768)  ||
-             (SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1280x1024) ||
-             (SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1400x1050) ||
-             (SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1600x1200)) ) {
-
-#ifdef SIS315H 							/* ------------- 315/330 series ------------ */
-
-      SiS_GetCRT2Part2Ptr(SiS_Pr, ModeNo, ModeIdIndex, RefreshRateTableIndex,
-                          &CRT2Index, &resindex, HwInfo);
-
+#ifdef SIS315H
+  if(SiS_GetCRT2Part2Ptr(SiS_Pr, ModeNo, ModeIdIndex, RefreshRateTableIndex,
+                          			&CRT2Index, &resindex, HwInfo)) {
       switch(CRT2Index) {
-        case Panel_1024x768      : CRT2Part2Ptr = SiS_Pr->SiS_CRT2Part2_1024x768_1;  break;  /* "Normal" */
-        case Panel_1280x1024     : CRT2Part2Ptr = SiS_Pr->SiS_CRT2Part2_1280x1024_1; break;
-	case Panel_1400x1050     : CRT2Part2Ptr = SiS_Pr->SiS_CRT2Part2_1400x1050_1; break;
-	case Panel_1600x1200     : CRT2Part2Ptr = SiS_Pr->SiS_CRT2Part2_1600x1200_1; break;
-        case Panel_1024x768  + 16: CRT2Part2Ptr = SiS_Pr->SiS_CRT2Part2_1024x768_2;  break;  /* Non-Expanding */
-        case Panel_1280x1024 + 16: CRT2Part2Ptr = SiS_Pr->SiS_CRT2Part2_1280x1024_2; break;
-	case Panel_1400x1050 + 16: CRT2Part2Ptr = SiS_Pr->SiS_CRT2Part2_1400x1050_2; break;
-	case Panel_1600x1200 + 16: CRT2Part2Ptr = SiS_Pr->SiS_CRT2Part2_1600x1200_2; break;
-        case Panel_1024x768  + 32: CRT2Part2Ptr = SiS_Pr->SiS_CRT2Part2_1024x768_3;  break;  /* VESA Timing */
-        case Panel_1280x1024 + 32: CRT2Part2Ptr = SiS_Pr->SiS_CRT2Part2_1280x1024_3; break;
-	case Panel_1400x1050 + 32: CRT2Part2Ptr = SiS_Pr->SiS_CRT2Part2_1400x1050_3; break;
-	case Panel_1600x1200 + 32: CRT2Part2Ptr = SiS_Pr->SiS_CRT2Part2_1600x1200_3; break;
-	case 100:		   CRT2Part2Ptr = (SiS_Part2PortTblStruct *)SiS310_CRT2Part2_Compaq1280x1024_1; break;  /* Custom */
-	case 101:		   CRT2Part2Ptr = (SiS_Part2PortTblStruct *)SiS310_CRT2Part2_Compaq1280x1024_2; break;
-	case 102:		   CRT2Part2Ptr = (SiS_Part2PortTblStruct *)SiS310_CRT2Part2_Compaq1280x1024_3; break;
-	case 103:		   CRT2Part2Ptr = (SiS_Part2PortTblStruct *)SiS310_CRT2Part2_Clevo1024x768_1; break;    /* Custom */
-	case 104:		   CRT2Part2Ptr = (SiS_Part2PortTblStruct *)SiS310_CRT2Part2_Clevo1024x768_2; break;
-	case 105:		   CRT2Part2Ptr = (SiS_Part2PortTblStruct *)SiS310_CRT2Part2_Clevo1024x768_3; break;
-	case 106:		   CRT2Part2Ptr = (SiS_Part2PortTblStruct *)SiS310_CRT2Part2_Asus1024x768_3; break;
-	default:                   CRT2Part2Ptr = SiS_Pr->SiS_CRT2Part2_1024x768_3;  break;
+        case 200: CRT2Part2Ptr = SiS_Pr->SiS_CRT2Part2_1024x768_1;   break;
+	case 206: CRT2Part2Ptr = SiS310_CRT2Part2_Asus1024x768_3;    break;
+	default:  CRT2Part2Ptr = SiS_Pr->SiS_CRT2Part2_1024x768_3;   break;
       }
 
       SiS_SetRegANDOR(SiS_Pr->SiS_Part2Port,0x01,0x80,(CRT2Part2Ptr+resindex)->CR[0]);
@@ -7910,58 +7152,34 @@
       SiS_SetReg(SiS_Pr->SiS_Part2Port,0x23,(CRT2Part2Ptr+resindex)->CR[10]);
       SiS_SetRegANDOR(SiS_Pr->SiS_Part2Port,0x25,0x0f,(CRT2Part2Ptr+resindex)->CR[11]);
 
-      if(!(SiS_Pr->SiS_SetFlag & LCDVESATiming)) {
-        if(SiS_Pr->SiS_VGAVDE == 525) {
-	  temp = 0xc3;
-	  if(SiS_Pr->SiS_ModeType <= ModeVGA) {
-	     temp++;
-	     if(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) temp += 2;
-	  }
-	  SiS_SetReg(SiS_Pr->SiS_Part2Port,0x2f,temp);
-	  SiS_SetReg(SiS_Pr->SiS_Part2Port,0x30,0xb3);
-	} else if(SiS_Pr->SiS_VGAVDE == 420) {
-	  temp = 0x4d;
-	  if(SiS_Pr->SiS_ModeType <= ModeVGA) {
-	     temp++;
-	     if(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) temp++;
-	  }
-	  SiS_SetReg(SiS_Pr->SiS_Part2Port,0x2f,temp);
-	}
-     }
-
-     if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCD) {
-        if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1400x1050) {
-	   /* See Sync above, 0x1a */
-	   temp = 1;
-	   if(ModeNo <= 0x13) temp = 3;
-	   SiS_SetReg(SiS_Pr->SiS_Part2Port,0x0b,temp);
-	}
-     }
-#endif
+      SiS_SetGroup2_Tail(SiS_Pr, ModeNo);
 
-  } else {   /* ------ 300 series and other bridges, other LCD resolutions ------ */
 
-      /* Using this on the 301B with an auto-expanding 1024 panel (CR37=1) makes
-       * the panel scale at modes < 1024 (no black bars); if the panel is non-expanding,
-       * the bridge scales all modes to 1024.
-       * !!! Malfunction at 640x480 and 640x400 when panel is auto-expanding - black screen !!!
-       */
+  } else {
+#endif
 
-    tempcx = SiS_Pr->SiS_VT;
-    tempbx = SiS_Pr->PanelYRes;
+    /* Checked for 1024x768, 1280x1024, 1400x1050, 1600x1200 */
+    /*             Clevo dual-link 1024x768 */
+    /* 		   Compaq 1280x1024 has HT 1696 sometimes (calculation OK, if given HT is correct)  */
+    /*		   Acer: OK, but uses different setting for VESA timing at 640/800/1024 and 640x400 */
 
     if(SiS_Pr->SiS_LCDInfo & DontExpandLCD) {
-       tempbx = SiS_Pr->SiS_VDE - 1;
-       tempcx--;
-    }
-
-    tempax = 1;
-    if(!(SiS_Pr->SiS_LCDInfo & DontExpandLCD)) {
-       if(tempbx != SiS_Pr->SiS_VDE) {
-          tempax = tempbx;
-          if(tempax < SiS_Pr->SiS_VDE) {
-             tempax = 0;
-             tempcx = 0;
+       if((SiS_Pr->SiS_LCDInfo & LCDPass11) || (SiS_Pr->PanelYRes == SiS_Pr->SiS_VDE)) {
+          tempbx = SiS_Pr->SiS_VDE - 1;
+          tempcx = SiS_Pr->SiS_VT - 1;
+       } else {
+          tempbx = SiS_Pr->SiS_VDE + ((SiS_Pr->PanelYRes - SiS_Pr->SiS_VDE) / 2);
+	  tempcx = SiS_Pr->SiS_VT - ((SiS_Pr->PanelYRes - SiS_Pr->SiS_VDE) / 2);
+       }
+    } else {
+       tempbx = SiS_Pr->PanelYRes;
+       tempcx = SiS_Pr->SiS_VT;
+       tempax = 1;
+       if(SiS_Pr->PanelYRes != SiS_Pr->SiS_VDE) {
+          tempax = SiS_Pr->PanelYRes;
+	  /* if(SiS_Pr->SiS_VGAVDE == 525) tempax += 0x3c;   */  /* 651+301C */
+          if(SiS_Pr->PanelYRes < SiS_Pr->SiS_VDE) {
+             tempax = tempcx = 0;
           } else {
              tempax -= SiS_Pr->SiS_VDE;
           }
@@ -7971,29 +7189,55 @@
        tempbx -= tempax; /* lcdvdee */
     }
 
-    /* Non-expanding: lcdvdees = tempcx = VT-1; lcdvdee = tempbx = VDE-1 */
+    /* Non-expanding: lcdvdes = tempcx = VT-1; lcdvdee = tempbx = VDE-1 */
 
 #ifdef TWDEBUG
     xf86DrvMsg(0, X_INFO, "lcdvdes 0x%x lcdvdee 0x%x\n", tempcx, tempbx);
 #endif
 
-    temp = tempcx & 0x00FF;   				/* RVEQ1EQ=lcdvdes */
-    SiS_SetReg(SiS_Pr->SiS_Part2Port,0x05,temp);
-    temp = tempbx & 0x00FF;   				/* RVEQ2EQ=lcdvdee */
-    SiS_SetReg(SiS_Pr->SiS_Part2Port,0x06,temp);
+    SiS_SetReg(SiS_Pr->SiS_Part2Port,0x05,tempcx);	/* lcdvdes  */
+    SiS_SetReg(SiS_Pr->SiS_Part2Port,0x06,tempbx);	/* lcdvdee  */
 
-    temp = ((tempbx & 0xFF00) >> 8) << 3;
-    temp |= ((tempcx & 0xFF00) >> 8);
+    temp = (tempbx >> 5) & 0x38;
+    temp |= ((tempcx >> 8) & 0x07);
     SiS_SetReg(SiS_Pr->SiS_Part2Port,0x02,temp);
 
-    tempbx = SiS_Pr->SiS_VT;    /* push2; */
-    tempax = SiS_Pr->SiS_VDE;   /* push1; */
-    tempcx = (tempbx - tempax) >> 4;
-    tempbx += tempax;
-    tempbx >>= 1;
-    if(SiS_Pr->SiS_LCDInfo & DontExpandLCD) tempbx -= 10;
+    tempax = SiS_Pr->SiS_VDE;
+    if((SiS_Pr->SiS_LCDInfo & DontExpandLCD) && (!(SiS_Pr->SiS_LCDInfo & LCDPass11))) {
+       tempax = SiS_Pr->PanelYRes;
+    }
+    tempcx = (SiS_Pr->SiS_VT - tempax) >> 4;
+    if((SiS_Pr->SiS_LCDInfo & DontExpandLCD) && (!(SiS_Pr->SiS_LCDInfo & LCDPass11))) {
+       if(SiS_Pr->PanelYRes != SiS_Pr->SiS_VDE) {
+	  tempcx = (SiS_Pr->SiS_VT - tempax) / 10;
+       }
+    }
+
+    tempbx = ((SiS_Pr->SiS_VT + SiS_Pr->SiS_VDE) >> 1) - 1;
+    if(SiS_Pr->SiS_LCDInfo & DontExpandLCD) {
+       if(SiS_Pr->PanelYRes != SiS_Pr->SiS_VDE) {
+          if(!(SiS_Pr->SiS_LCDInfo & LCDPass11)) { /* ? */
+             tempax = SiS_Pr->SiS_VT - SiS_Pr->PanelYRes;
+	     if(tempax % 4) { tempax >>= 2; tempax++; }
+	     else           { tempax >>= 2;           }
+             tempbx -= (tempax - 1);
+	  } else {
+	     tempbx -= 10;
+	     if(tempbx <= SiS_Pr->SiS_VDE) tempbx = SiS_Pr->SiS_VDE + 1;
+	  }
+       }
+    }
+    if(SiS_Pr->SiS_LCDResInfo == Panel_1024x768) {
+       tempbx++;
+       if((!(SiS_Pr->SiS_LCDInfo & DontExpandLCD)) || (crt2crtc == 6)) {
+          if(SiS_Pr->SiS_SetFlag & LCDVESATiming) {
+	     tempbx = 770;
+	     tempcx = 3;
+	  }
+       }
+    }
 
-    /* non-expanding: lcdvrs = tempbx = ((VT + VDE) / 2) - 10 */
+    /* non-expanding: lcdvrs = ((VT + VDE) / 2) - 10 */
 
     if(SiS_Pr->UseCustomMode) {
        tempbx = SiS_Pr->CVSyncStart;
@@ -8003,12 +7247,11 @@
     xf86DrvMsg(0, X_INFO, "lcdvrs 0x%x\n", tempbx);
 #endif
 
-    temp = tempbx & 0x00FF;   				/* RTVACTEE = lcdvrs */
-    SiS_SetReg(SiS_Pr->SiS_Part2Port,0x04,temp);
+    SiS_SetReg(SiS_Pr->SiS_Part2Port,0x04,tempbx);	    /* lcdvrs */
 
-    temp = ((tempbx & 0xFF00) >> 8) << 4;
+    temp = (tempbx >> 4) & 0xF0;
     tempbx += (tempcx + 1);
-    temp |= (tempbx & 0x000F);
+    temp |= (tempbx & 0x0F);
 
     if(SiS_Pr->UseCustomMode) {
        temp &= 0xf0;
@@ -8021,149 +7264,103 @@
 
     SiS_SetReg(SiS_Pr->SiS_Part2Port,0x01,temp);
 
-    /* Code from 630/301B (I+II) BIOS */
-
 #ifdef SIS300
-    if(!SiS_Pr->UseCustomMode) {
-       if( ( ( (HwInfo->jChipType == SIS_630) ||
-               (HwInfo->jChipType == SIS_730) ) &&
-             (HwInfo->jChipRevision > 2) )  &&
-           (SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1024x768) &&
-           (!(SiS_Pr->SiS_SetFlag & LCDVESATiming))  &&
-           (!(SiS_Pr->SiS_LCDInfo & DontExpandLCD)) ) {
-          if(ModeNo == 0x13) {
-             SiS_SetReg(SiS_Pr->SiS_Part2Port,0x04,0xB9);
-             SiS_SetReg(SiS_Pr->SiS_Part2Port,0x05,0xCC);
-             SiS_SetReg(SiS_Pr->SiS_Part2Port,0x06,0xA6);
-          } else {
-             if((crt2crtc & 0x3F) == 4) {
-                SiS_SetReg(SiS_Pr->SiS_Part2Port,0x01,0x2B);
-                SiS_SetReg(SiS_Pr->SiS_Part2Port,0x02,0x13);
-                SiS_SetReg(SiS_Pr->SiS_Part2Port,0x04,0xE5);
-                SiS_SetReg(SiS_Pr->SiS_Part2Port,0x05,0x08);
-                SiS_SetReg(SiS_Pr->SiS_Part2Port,0x06,0xE2);
-             }
-          }
-       }
-
-       if(HwInfo->jChipType < SIS_315H) {
-          if(SiS_Pr->SiS_LCDTypeInfo == 0x0c) {
-             crt2crtc &= 0x1f;
-             tempcx = 0;
-             if(!(SiS_Pr->SiS_VBInfo & SetNotSimuMode)) {
-                if(SiS_Pr->SiS_VBInfo & SetInSlaveMode) {
-                   tempcx += 7;
-                }
-             }
-             tempcx += crt2crtc;
-             if(crt2crtc >= 4) {
-                SiS_SetReg(SiS_Pr->SiS_Part2Port,0x06,0xff);
-             }
+    SiS_Group2LCDSpecial(SiS_Pr, HwInfo, ModeNo, crt2crtc);
+#endif
 
-             if(!(SiS_Pr->SiS_VBInfo & SetNotSimuMode)) {
-                if(SiS_Pr->SiS_VBInfo & SetInSlaveMode) {
-                   if(crt2crtc == 4) {
-                      SiS_SetReg(SiS_Pr->SiS_Part2Port,0x01,0x28);
-                   }
-                }
-             }
-             SiS_SetReg(SiS_Pr->SiS_Part2Port,0x02,0x18);
-             SiS_SetReg(SiS_Pr->SiS_Part2Port,0x04,atable[tempcx]);
-          }
+    bridgeoffset = 7;
+    if(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV)          bridgeoffset += 2;
+    if(SiS_Pr->SiS_VBType & (VB_SIS301C | VB_SIS302ELV)) bridgeoffset++;
+    if(SiS_IsDualLink(SiS_Pr, HwInfo))        		 bridgeoffset++;
+
+    temp = 0;
+    if((SiS_Pr->SiS_LCDInfo & DontExpandLCD) && (!(SiS_Pr->SiS_LCDInfo & LCDPass11))) {
+       if(SiS_Pr->PanelXRes != SiS_Pr->SiS_HDE) {
+          temp = SiS_Pr->SiS_HT - ((SiS_Pr->PanelXRes - SiS_Pr->SiS_HDE) / 2);
+	  if(SiS_IsDualLink(SiS_Pr, HwInfo)) temp >>= 1;
        }
     }
-#endif
-
-    tempcx = (SiS_Pr->SiS_HT - SiS_Pr->SiS_HDE) >> 2;     /* (HT - HDE) >> 2 */
-    tempbx = SiS_Pr->SiS_HDE + 7;            		  /* lcdhdee         */
-    if(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) {
-       tempbx += 2;
+    temp += bridgeoffset;
+    SiS_SetReg(SiS_Pr->SiS_Part2Port,0x1F,temp);  	     /* lcdhdes */
+    SiS_SetRegANDOR(SiS_Pr->SiS_Part2Port,0x20,0x0F,((temp >> 4) & 0xf0));
+
+    tempcx = SiS_Pr->SiS_HT;
+    tempax = tempbx = SiS_Pr->SiS_HDE;
+    if((SiS_Pr->SiS_LCDInfo & DontExpandLCD) && (!(SiS_Pr->SiS_LCDInfo & LCDPass11))) {
+       if(SiS_Pr->PanelXRes != SiS_Pr->SiS_HDE) {
+          tempax = SiS_Pr->PanelXRes;
+          tempbx = SiS_Pr->PanelXRes - ((SiS_Pr->PanelXRes - SiS_Pr->SiS_HDE) / 2);
+       }
+    }
+    if(SiS_IsDualLink(SiS_Pr, HwInfo)) {
+       tempcx >>= 1;
+       tempbx >>= 1;
+       tempax >>= 1;
     }
-    push1 = tempbx;
 
 #ifdef TWDEBUG
     xf86DrvMsg(0, X_INFO, "lcdhdee 0x%x\n", tempbx);
 #endif
 
-    temp = tempbx & 0x00FF;    			          /* RHEQPLE = lcdhdee */
-    SiS_SetReg(SiS_Pr->SiS_Part2Port,0x23,temp);
-    temp = (tempbx & 0xFF00) >> 8;
-    SiS_SetRegANDOR(SiS_Pr->SiS_Part2Port,0x25,0xF0,temp);
-
-    temp = 7;
-    if(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) {
-       temp += 2;
-    }
-    SiS_SetReg(SiS_Pr->SiS_Part2Port,0x1F,temp);  	  /* RHBLKE = lcdhdes[7:0] */
-    SiS_SetRegAND(SiS_Pr->SiS_Part2Port,0x20,0x0F);	  /* lcdhdes [11:8] */
+    tempbx += bridgeoffset;
+
+    SiS_SetReg(SiS_Pr->SiS_Part2Port,0x23,tempbx);	    /* lcdhdee */
+    SiS_SetRegANDOR(SiS_Pr->SiS_Part2Port,0x25,0xF0,((tempbx >> 8) & 0x0f));
+
+    tempcx = (tempcx - tempax) >> 2;
 
     tempbx += tempcx;
     push2 = tempbx;
 
-    if(SiS_Pr->UseCustomMode) {
-       tempbx = SiS_Pr->CHSyncStart + 7;
-       if(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) {
-          tempbx += 2;
+    if(SiS_Pr->SiS_LCDResInfo == Panel_1280x1024) {
+       if(SiS_Pr->SiS_LCDInfo & DontExpandLCD) {
+          if(SiS_Pr->SiS_LCDInfo & LCDPass11) {
+             if(SiS_Pr->SiS_HDE == 1280) tempbx = (tempbx & 0xff00) | 0x47;
+	  }
        }
     }
 
+    if(SiS_Pr->UseCustomMode) {
+       tempbx = SiS_Pr->CHSyncStart;
+       if(SiS_IsDualLink(SiS_Pr, HwInfo)) tempbx >>= 1;
+       tempbx += bridgeoffset;
+    }
+
 #ifdef TWDEBUG
     xf86DrvMsg(0, X_INFO, "lcdhrs 0x%x\n", tempbx);
 #endif
 
-    temp = tempbx & 0x00FF;            		          /* RHBURSTS = lcdhrs */
-    if(!SiS_Pr->UseCustomMode) {
-       if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1280x1024) {
-          if(SiS_Pr->SiS_LCDInfo & DontExpandLCD) {
-             if(SiS_Pr->SiS_HDE == 1280) temp = 0x47;
-          }
-       }
-    }
-    SiS_SetReg(SiS_Pr->SiS_Part2Port,0x1C,temp);
-    temp = (tempbx & 0x0F00) >> 4;
-    SiS_SetRegANDOR(SiS_Pr->SiS_Part2Port,0x1D,0x0F,temp);
+    SiS_SetReg(SiS_Pr->SiS_Part2Port,0x1C,tempbx);	    /* lcdhrs */
+    SiS_SetRegANDOR(SiS_Pr->SiS_Part2Port,0x1D,0x0F,((tempbx >> 4) & 0xf0));
 
     tempbx = push2;
+
     tempcx <<= 1;
+    if((SiS_Pr->SiS_LCDInfo & DontExpandLCD) && (!(SiS_Pr->SiS_LCDInfo & LCDPass11))) {
+       if(SiS_Pr->PanelXRes != SiS_Pr->SiS_HDE) tempcx >>= 2;
+    }
     tempbx += tempcx;
 
     if(SiS_Pr->UseCustomMode) {
-       tempbx = SiS_Pr->CHSyncEnd + 7;
-       if(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) {
-          tempbx += 2;
-       }
+       tempbx = SiS_Pr->CHSyncEnd;
+       if(SiS_IsDualLink(SiS_Pr, HwInfo)) tempbx >>= 1;
+       tempbx += bridgeoffset;
     }
 
 #ifdef TWDEBUG
     xf86DrvMsg(0, X_INFO, "lcdhre 0x%x\n", tempbx);
 #endif
 
-    temp = tempbx & 0x00FF;            		          /* RHSYEXP2S = lcdhre */
-    SiS_SetReg(SiS_Pr->SiS_Part2Port,0x21,temp);
+    SiS_SetReg(SiS_Pr->SiS_Part2Port,0x21,tempbx);	    /* lcdhre */
 
-    if(!(SiS_Pr->SiS_SetFlag & LCDVESATiming)) {
-       if(SiS_Pr->SiS_VGAVDE == 525) {
-          if(SiS_Pr->SiS_ModeType <= ModeVGA)
-    	     temp=0xC6;
-          else
-       	     temp=0xC3;
-          SiS_SetReg(SiS_Pr->SiS_Part2Port,0x2f,temp);
-          SiS_SetReg(SiS_Pr->SiS_Part2Port,0x30,0xB3);
-       } else if(SiS_Pr->SiS_VGAVDE == 420) {
-          if(SiS_Pr->SiS_ModeType <= ModeVGA)
-	     temp=0x4F;
-          else
-       	     temp=0x4D;
-          SiS_SetReg(SiS_Pr->SiS_Part2Port,0x2f,temp);
-       }
-    }
+    SiS_SetGroup2_Tail(SiS_Pr, ModeNo);
 
 #ifdef SIS300
-    SiS_Set300Part2Regs(SiS_Pr, HwInfo, ModeIdIndex,
-                        RefreshRateTableIndex, ModeNo);
+    SiS_Set300Part2Regs(SiS_Pr, HwInfo, ModeIdIndex, RefreshRateTableIndex, ModeNo);
+#endif
+#ifdef SIS315H
+  } /* CRT2-LCD from table */
 #endif
-
-  } /* HwInfo */
 }
 
 /*********************************************/
@@ -8174,26 +7371,14 @@
 SiS_SetGroup3(SiS_Private *SiS_Pr, USHORT ModeNo, USHORT ModeIdIndex,
               PSIS_HW_INFO HwInfo)
 {
-  USHORT modeflag, i;
-  const UCHAR  *tempdi;
+  USHORT 	i;
+  const UCHAR  	*tempdi;
 
   if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCDA) return;
 
-  if(ModeNo<=0x13) {
-     modeflag = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_ModeFlag;
-  } else {
-     if(SiS_Pr->UseCustomMode) {
-        modeflag = SiS_Pr->CModeFlag;
-     } else {
-    	modeflag = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag;
-     }
-  }
-
 #ifndef SIS_CP
   SiS_SetReg(SiS_Pr->SiS_Part3Port,0x00,0x00);
-#endif
-
-#ifdef SIS_CP
+#else
   SIS_CP_INIT301_CP
 #endif
 
@@ -8216,11 +7401,6 @@
      tempdi = SiS_Pr->SiS_HiTVGroup3Data;
      if(SiS_Pr->SiS_TVMode & TVSetTVSimuMode) {
         tempdi = SiS_Pr->SiS_HiTVGroup3Simu;
-#if 0
-        if(!(modeflag & Charx8Dot)) {
-           tempdi = SiS_Pr->SiS_HiTVGroup3Text;
-        }
-#endif
      }
   } else if(SiS_Pr->SiS_VBInfo & SetCRT2ToYPbPr525750) {
      if(!(SiS_Pr->SiS_TVMode & TVSetYPbPr525i)) {
@@ -8229,7 +7409,7 @@
      }
   }
   if(tempdi) {
-     for(i=0; i<=0x3E; i++){
+     for(i=0; i<=0x3E; i++) {
         SiS_SetReg(SiS_Pr->SiS_Part3Port,i,tempdi[i]);
      }
      if(SiS_Pr->SiS_VBType & (VB_SIS301C | VB_SIS302ELV)) {
@@ -8239,11 +7419,9 @@
      }
   }
 
-  if(!(SiS_Pr->SiS_VBInfo & (SetCRT2ToHiVision | SetCRT2ToYPbPr525750))) {
 #ifdef SIS_CP
-     SIS_CP_INIT301_CP2
+  SIS_CP_INIT301_CP2
 #endif
-  }
 }
 
 /*********************************************/
@@ -8252,11 +7430,37 @@
 
 #ifdef SIS315H
 static void
-SiS_SetGroup4_C_ELV(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo)
+SiS_ShiftXPos(SiS_Private *SiS_Pr, int shift)
 {
-   USHORT temp, temp1;
+   USHORT temp, temp1, temp2;
 
-   if(!(SiS_Pr->SiS_VBType & (VB_SIS301C | VB_SIS302ELV))) return;
+   temp1 = SiS_GetReg(SiS_Pr->SiS_Part2Port,0x1f);
+   temp2 = SiS_GetReg(SiS_Pr->SiS_Part2Port,0x20);
+   temp = (USHORT)((int)((temp1 | ((temp2 & 0xf0) << 4))) + shift);
+   SiS_SetReg(SiS_Pr->SiS_Part2Port,0x1f,temp);
+   SiS_SetRegANDOR(SiS_Pr->SiS_Part2Port,0x20,0x0f,((temp >> 4) & 0xf0));
+   temp = SiS_GetReg(SiS_Pr->SiS_Part2Port,0x2b) & 0x0f;
+   temp = (USHORT)((int)(temp) + shift);
+   SiS_SetRegANDOR(SiS_Pr->SiS_Part2Port,0x2b,0xf0,(temp & 0x0f));
+   temp1 = SiS_GetReg(SiS_Pr->SiS_Part2Port,0x43);
+   temp2 = SiS_GetReg(SiS_Pr->SiS_Part2Port,0x42);
+   temp = (USHORT)((int)((temp1 | ((temp2 & 0xf0) << 4))) + shift);
+   SiS_SetReg(SiS_Pr->SiS_Part2Port,0x43,temp);
+   SiS_SetRegANDOR(SiS_Pr->SiS_Part2Port,0x42,0x0f,((temp >> 4) & 0xf0));
+}
+
+static void
+SiS_SetGroup4_C_ELV(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo,
+                    USHORT ModeNo, USHORT ModeIdIndex)
+{
+   USHORT temp, temp1, resinfo = 0;
+
+   if(!(SiS_Pr->SiS_VBType & VB_SIS301C)) return;
+   if(!(SiS_Pr->SiS_VBInfo & (SetCRT2ToHiVision | SetCRT2ToYPbPr525750))) return;
+
+   if(ModeNo > 0x13) {
+      resinfo = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_RESINFO;
+   }
 
    SiS_SetRegOR(SiS_Pr->SiS_Part4Port,0x3a,0x08);
    temp = SiS_GetReg(SiS_Pr->SiS_Part4Port,0x3a);
@@ -8267,28 +7471,37 @@
          SiS_SetRegAND(SiS_Pr->SiS_Part4Port,0x25,0xf8);
       }
       SiS_SetRegAND(SiS_Pr->SiS_Part4Port,0x0f,0xfb);
-      temp = 0;
-      if(!(SiS_Pr->SiS_TVMode & TVSetYPbPr750p)) {
-         temp |= 0x0002;
-         if(!(SiS_Pr->SiS_TVMode & TVSetYPbPr525p)) {
-	    temp ^= 0x0402;
-	    if(!(SiS_Pr->SiS_TVMode & TVSetHiVision)) {
-	       temp ^= 0x0002;
-	    }
-	 }
-      }
+      if(SiS_Pr->SiS_TVMode & TVSetYPbPr750p)      temp = 0x0000;
+      else if(SiS_Pr->SiS_TVMode & TVSetYPbPr525p) temp = 0x0002;
+      else if(SiS_Pr->SiS_TVMode & TVSetHiVision)  temp = 0x0400;
+      else					   temp = 0x0402;
       if(HwInfo->jChipType >= SIS_661) {
-         temp1 = SiS_GetReg(SiS_Pr->SiS_P3d4,0x39);
-         if(temp1 & 0x01) temp |= 0x10;
-         if(temp1 & 0x02) temp |= 0x01;
-	 SiS_SetRegANDOR(SiS_Pr->SiS_Part4Port,0x26,0xec,(temp & 0xff));
+         temp1 = 0;
+	 if(SiS_Pr->SiS_TVMode & TVAspect43) temp1 = 4;
+	 SiS_SetRegANDOR(SiS_Pr->SiS_Part4Port,0x0f,0xfb,temp1);
+	 if(SiS_Pr->SiS_TVMode & TVAspect43LB) temp |= 0x01;
+	 SiS_SetRegANDOR(SiS_Pr->SiS_Part4Port,0x26,0x7c,(temp & 0xff));
       } else {
          temp1 = SiS_GetReg(SiS_Pr->SiS_P3d4,0x3b) & 0x03;
 	 if(temp1 == 0x01) temp |= 0x01;
 	 if(temp1 == 0x03) temp |= 0x04;  /* ? why not 0x10? */
-	 SiS_SetRegANDOR(SiS_Pr->SiS_Part4Port,0x26,0xea,(temp & 0xff));
+	 SiS_SetRegANDOR(SiS_Pr->SiS_Part4Port,0x26,0xf8,(temp & 0xff));
       }
       SiS_SetRegANDOR(SiS_Pr->SiS_Part4Port,0x3a,0xfb,(temp >> 8));
+
+      if(HwInfo->jChipType >= SIS_661) { 		/* ? */
+         if(SiS_Pr->SiS_TVMode & TVAspect43) {
+            if(SiS_Pr->SiS_TVMode & TVSetYPbPr750p) {
+	       if(resinfo == SIS_RI_1024x768) {
+	          SiS_ShiftXPos(SiS_Pr, 97);
+	       } else {
+	          SiS_ShiftXPos(SiS_Pr, 111);
+	       }
+	    } else if(SiS_Pr->SiS_TVMode & TVSetHiVision) {
+	       SiS_ShiftXPos(SiS_Pr, 136);
+	    }
+         }
+      }
    }
 }
 #endif
@@ -8330,25 +7543,22 @@
   SiS_SetRegOR(SiS_Pr->SiS_Part4Port,0x12,temp);
 }
 
-/* Set 301 VGA2 registers */
 static void
 SiS_SetGroup4(SiS_Private *SiS_Pr, USHORT ModeNo, USHORT ModeIdIndex,
   	      USHORT RefreshRateTableIndex, PSIS_HW_INFO HwInfo)
 {
-  USHORT tempax,tempcx,tempbx,modeflag,temp,temp2,resinfo;
+  USHORT tempax,tempcx,tempbx,modeflag,temp,resinfo;
   ULONG tempebx,tempeax,templong;
 
   if(ModeNo <= 0x13) {
      modeflag = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_ModeFlag;
      resinfo = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_ResInfo;
+  } else if(SiS_Pr->UseCustomMode) {
+     modeflag = SiS_Pr->CModeFlag;
+     resinfo = 0;
   } else {
-     if(SiS_Pr->UseCustomMode) {
-        modeflag = SiS_Pr->CModeFlag;
-	resinfo = 0;
-     } else {
-    	modeflag = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag;
-	resinfo = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_RESINFO;
-     }
+     modeflag = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag;
+     resinfo = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_RESINFO;
   }
 
   if(HwInfo->jChipType >= SIS_315H) {
@@ -8371,186 +7581,151 @@
 	   if(SiS_IsDualLink(SiS_Pr, HwInfo)) {
 	      SiS_SetRegOR(SiS_Pr->SiS_Part4Port,0x27,0x2c);
 	   }
-#ifdef SET_EMI
+
 	   if(SiS_Pr->SiS_VBType & (VB_SIS302LV | VB_SIS302ELV)) {
 	      SiS_SetReg(SiS_Pr->SiS_Part4Port,0x2a,0x00);
+#ifdef SET_EMI
 	      SiS_SetRegAND(SiS_Pr->SiS_Part4Port,0x30,0x0c);
+#endif
 	      SiS_SetReg(SiS_Pr->SiS_Part4Port,0x34,0x10);
 	   }
-#endif
 	}
    	return;
      }
   }
 
-  temp = SiS_Pr->SiS_RVBHCFACT;
-  SiS_SetReg(SiS_Pr->SiS_Part4Port,0x13,temp);
+  SiS_SetReg(SiS_Pr->SiS_Part4Port,0x13,SiS_Pr->SiS_RVBHCFACT);
 
   tempbx = SiS_Pr->SiS_RVBHCMAX;
-  temp = tempbx & 0x00FF;
-  SiS_SetReg(SiS_Pr->SiS_Part4Port,0x14,temp);
+  SiS_SetReg(SiS_Pr->SiS_Part4Port,0x14,tempbx);
 
-  temp2 = (((tempbx & 0xFF00) >> 8) << 7) & 0x00ff;
+  temp = (tempbx >> 1) & 0x80;
 
   tempcx = SiS_Pr->SiS_VGAHT - 1;
-  temp = tempcx & 0x00FF;
-  SiS_SetReg(SiS_Pr->SiS_Part4Port,0x16,temp);
+  SiS_SetReg(SiS_Pr->SiS_Part4Port,0x16,tempcx);
 
-  temp = (((tempcx & 0xFF00) >> 8) << 3) & 0x00ff;
-  temp2 |= temp;
+  temp |= ((tempcx >> 5) & 0x78);
 
   tempcx = SiS_Pr->SiS_VGAVT - 1;
-  if(!(SiS_Pr->SiS_VBInfo & SetCRT2ToTV))  tempcx -= 5;
-
-  temp = tempcx & 0x00FF;
-  SiS_SetReg(SiS_Pr->SiS_Part4Port,0x17,temp);
+  if(!(SiS_Pr->SiS_VBInfo & SetCRT2ToTV)) tempcx -= 5;
+  SiS_SetReg(SiS_Pr->SiS_Part4Port,0x17,tempcx);
 
-  temp = temp2 | ((tempcx & 0xFF00) >> 8);
+  temp |= ((tempcx >> 8) & 0x07);
   SiS_SetReg(SiS_Pr->SiS_Part4Port,0x15,temp);
 
   tempbx = SiS_Pr->SiS_VGAHDE;
-  if(modeflag & HalfDCLK)  tempbx >>= 1;
-  if(HwInfo->jChipType >= SIS_661) {
-     if(SiS_IsDualLink(SiS_Pr, HwInfo)) tempbx >>= 1;
-  }
+  if(modeflag & HalfDCLK)            tempbx >>= 1;
+  if(SiS_IsDualLink(SiS_Pr, HwInfo)) tempbx >>= 1;
 
-  temp = 0xA0;
-  if(SiS_Pr->SiS_VBInfo & SetCRT2ToHiVision) {
+  if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCD) {
      temp = 0;
-     if(tempbx > 800) {
-        temp = 0xA0;
-        if(tempbx != 1024) {
-           temp = 0xC0;
-           if(tempbx != 1280) temp = 0;
-	}
-     }
-  } else if(SiS_Pr->SiS_VBInfo & SetCRT2ToTV) {
-     if(tempbx <= 800) {
-        temp = 0x80;
-     }
+     if(tempbx > 800)        temp = 0x60;
+  } else if(SiS_Pr->SiS_VBInfo & SetCRT2ToHiVision) {
+     temp = 0;
+     if(tempbx == 1024)      temp = 0xA0;
+     else if(tempbx > 1024)  temp = 0xC0;
+  } else if(SiS_Pr->SiS_TVMode & (TVSetYPbPr525p | TVSetYPbPr750p)) {
+     temp = 0;
+     if(tempbx >= 1280)      temp = 0x40;
+     else if(tempbx >= 1024) temp = 0x20;
   } else {
      temp = 0x80;
-     if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCD) {
-        temp = 0;
-        if(tempbx > 800) temp = 0x60;
-     }
-  }
-
-  if(SiS_Pr->SiS_TVMode & (TVSetYPbPr525p | TVSetYPbPr750p)) {
-     temp = 0;
-     if(SiS_Pr->SiS_VGAHDE == 1024) temp = 0x20;
-  }
-
-  if(HwInfo->jChipType < SIS_661) {
-     if(SiS_IsDualLink(SiS_Pr, HwInfo)) temp = 0;
+     if(tempbx >= 1024)      temp = 0xA0;
   }
 
   if(SiS_Pr->SiS_VBType & VB_SIS301) {
-     if(SiS_Pr->SiS_LCDResInfo != SiS_Pr->SiS_Panel1280x1024)
-        temp |= 0x0A;
+     if(SiS_Pr->SiS_LCDResInfo != Panel_1280x1024) temp |= 0x0A;
   }
 
   SiS_SetRegANDOR(SiS_Pr->SiS_Part4Port,0x0E,0x10,temp);
 
+  tempeax = SiS_Pr->SiS_VGAVDE;
   tempebx = SiS_Pr->SiS_VDE;
-
   if(SiS_Pr->SiS_VBInfo & SetCRT2ToHiVision) {
      if(!(temp & 0xE0)) tempebx >>=1;
   }
 
   tempcx = SiS_Pr->SiS_RVBHRS;
-  temp = tempcx & 0x00FF;
-  SiS_SetReg(SiS_Pr->SiS_Part4Port,0x18,temp);
+  SiS_SetReg(SiS_Pr->SiS_Part4Port,0x18,tempcx);
+  tempcx >>= 8;
+  tempcx |= 0x40;
 
-  tempeax = SiS_Pr->SiS_VGAVDE;
-  tempcx |= 0x4000;
   if(tempeax <= tempebx) {
-     tempcx ^= 0x4000;
+     tempcx ^= 0x40;
   } else {
      tempeax -= tempebx;
   }
 
-  templong = (tempeax * 256 * 1024) % tempebx;
-  tempeax = (tempeax * 256 * 1024) / tempebx;
-  tempebx = tempeax;
-  if(templong != 0) tempebx++;
+  tempeax *= (256 * 1024);
+  templong = tempeax % tempebx;
+  tempeax /= tempebx;
+  if(templong) tempeax++;
 
-  temp = (USHORT)(tempebx & 0x000000FF);
+  temp = (USHORT)(tempeax & 0x000000FF);
   SiS_SetReg(SiS_Pr->SiS_Part4Port,0x1B,temp);
-  temp = (USHORT)((tempebx & 0x0000FF00) >> 8);
+  temp = (USHORT)((tempeax & 0x0000FF00) >> 8);
   SiS_SetReg(SiS_Pr->SiS_Part4Port,0x1A,temp);
-
-  tempbx = (USHORT)(tempebx >> 16);
-  temp = tempbx & 0x00FF;
-  temp <<= 4;
-  temp |= ((tempcx & 0xFF00) >> 8);
+  temp = (USHORT)((tempeax >> 12) & 0x70); /* sic! */
+  temp |= (tempcx & 0x4F);
   SiS_SetReg(SiS_Pr->SiS_Part4Port,0x19,temp);
 
   if(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) {
 
      SiS_SetReg(SiS_Pr->SiS_Part4Port,0x1C,0x28);
 
+     /* Calc Linebuffer max address and set/clear decimode */
      tempbx = 0;
+     if(SiS_Pr->SiS_TVMode & (TVSetHiVision | TVSetYPbPr750p)) tempbx = 0x08;
      tempax = SiS_Pr->SiS_VGAHDE;
-     if(modeflag & HalfDCLK) 		tempax >>= 1;
+     if(modeflag & HalfDCLK)            tempax >>= 1;
      if(SiS_IsDualLink(SiS_Pr, HwInfo)) tempax >>= 1;
-     if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCD) {
-	if(tempax > 800) tempax -= 800;
-     } else {
-        if(tempax > 800) {
-	   tempbx = 8;
-           if(tempax == 1024)
-	      tempax *= 25;
-           else
-	      tempax *= 20;
-
+     if(tempax > 800) {
+        if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCD) {
+	   tempax -= 800;
+	} else {  /* 651+301C: Only if TVNoHiviNoYPbPr */
+	   tempbx = 0x08;
+           if(tempax == 1024) tempax *= 25;
+           else	              tempax *= 20;
 	   temp = tempax % 32;
 	   tempax /= 32;
-	   tempax--;
-	   if (temp!=0) tempax++;
-        }
+	   if(temp) tempax++;
+	   tempax++;
+	   if((SiS_Pr->SiS_VBInfo & SetCRT2ToTVNoYPbPrHiVision) ||
+	      (SiS_Pr->SiS_TVMode & TVSetYPbPr525i)) {
+	      if(resinfo == SIS_RI_1024x768) {
+	         /* Otherwise white line at right edge */
+	         tempax = (tempax & 0xff00) | 0x20;
+	      }
+	   }
+	}
      }
      tempax--;
-     temp = ((tempax & 0xFF00) >> 8) & 0x03;
-     if(SiS_Pr->SiS_VBInfo & SetCRT2ToTV) {			/* From 1.10.7w */
-	if(ModeNo > 0x13) {					/* From 1.10.7w */
-	   if(resinfo == SIS_RI_1024x768) tempax = 0x1f;	/* From 1.10.7w */
-	}							/* From 1.10.7w */
-     }								/* From 1.10.7w */
-     SiS_SetReg(SiS_Pr->SiS_Part4Port,0x1D,tempax & 0x00FF);
-     temp <<= 4;
-     temp |= tempbx;
+     temp = ((tempax >> 4) & 0x30) | tempbx;
+     SiS_SetReg(SiS_Pr->SiS_Part4Port,0x1D,tempax);
      SiS_SetReg(SiS_Pr->SiS_Part4Port,0x1E,temp);
 
-     if(SiS_Pr->SiS_VBType & VB_SIS301LV302LV) {
-	if(IS_SIS550650740660) {
-	   temp = 0x0026;  /* 1.10.7w; 1.10.8r; needs corresponding code in Dis/EnableBridge! */
-	} else {
-	   temp = 0x0036;
-	}
-     } else {
-	temp = 0x0036;
+     temp = 0x0036; tempbx = 0xD0;
+     if((IS_SIS550650740660) && (SiS_Pr->SiS_VBType & VB_SIS301LV302LV)) {
+	temp = 0x0026; tempbx = 0xC0; /* See En/DisableBridge() */
      }
      if(SiS_Pr->SiS_VBInfo & SetCRT2ToTV) {
         if(!(SiS_Pr->SiS_TVMode & (TVSetNTSC1024 | TVSetHiVision | TVSetYPbPr750p | TVSetYPbPr525p))) {
 	   temp |= 0x01;
 	   if(SiS_Pr->SiS_VBInfo & SetInSlaveMode) {
 	      if(!(SiS_Pr->SiS_TVMode & TVSetTVSimuMode)) {
-  	         temp &= 0xFE;
+  	         temp &= ~0x01;
 	      }
 	   }
 	}
      }
-     SiS_SetRegANDOR(SiS_Pr->SiS_Part4Port,0x1F,0xC0,temp);
+     SiS_SetRegANDOR(SiS_Pr->SiS_Part4Port,0x1F,tempbx,temp);
 
-     tempbx = SiS_Pr->SiS_HT;
+     tempbx = SiS_Pr->SiS_HT >> 1;
      if(SiS_IsDualLink(SiS_Pr, HwInfo)) tempbx >>= 1;
-     tempbx >>= 1;
      tempbx -= 2;
-     temp = ((tempbx & 0x0700) >> 8) << 3;
+     SiS_SetReg(SiS_Pr->SiS_Part4Port,0x22,tempbx);
+     temp = (tempbx >> 5) & 0x38;
      SiS_SetRegANDOR(SiS_Pr->SiS_Part4Port,0x21,0xC0,temp);
-     temp = tempbx & 0x00FF;
-     SiS_SetReg(SiS_Pr->SiS_Part4Port,0x22,temp);
 
      if(SiS_Pr->SiS_VBType & VB_SIS301LV302LV) {
 	if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCD) {
@@ -8562,13 +7737,13 @@
 	      SiS_SetRegOR(SiS_Pr->SiS_Part4Port,0x27,0x2c);
 	   }
 	}
-#ifdef SET_EMI
 	if(SiS_Pr->SiS_VBType & (VB_SIS302LV | VB_SIS302ELV)) {
 	   SiS_SetReg(SiS_Pr->SiS_Part4Port,0x2a,0x00);
+#ifdef SET_EMI
 	   SiS_SetRegAND(SiS_Pr->SiS_Part4Port,0x30,0x0c);
+#endif
 	   SiS_SetReg(SiS_Pr->SiS_Part4Port,0x34,0x10);
 	}
-#endif
      }
 
   }  /* 301B */
@@ -8580,7 +7755,6 @@
 /*         SET PART 5 REGISTER GROUP         */
 /*********************************************/
 
-/* Set 301 Palette address port registers */
 static void
 SiS_SetGroup5(SiS_Private *SiS_Pr, USHORT ModeNo, USHORT ModeIdIndex,
               PSIS_HW_INFO HwInfo)
@@ -8590,7 +7764,7 @@
 
   if(SiS_Pr->SiS_ModeType == ModeVGA) {
      if(!(SiS_Pr->SiS_VBInfo & (SetInSlaveMode | LoadDACFlag))) {
-        SiS_EnableCRT2(SiS_Pr);
+        SiS_SetRegOR(SiS_Pr->SiS_P3c4,0x1E,0x20);
         SiS_LoadDAC(SiS_Pr, HwInfo, ModeNo, ModeIdIndex);
      }
   }
@@ -8608,11 +7782,8 @@
   USHORT ResIndex,DisplayType;
   const SiS_LVDSCRT1DataStruct *LVDSCRT1Ptr=NULL;
 
-  if(ModeNo <= 0x13) {
-     modeflag = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_ModeFlag;
-  } else {
-     modeflag = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag;
-  }
+  if(ModeNo <= 0x13) modeflag = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_ModeFlag;
+  else               modeflag = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag;
 
   if((SiS_Pr->SiS_CustomT == CUT_BARCO1366) ||
      (SiS_Pr->SiS_CustomT == CUT_BARCO1024) ||
@@ -8620,7 +7791,9 @@
      return;
 
   if(!(SiS_GetLVDSCRT1Ptr(SiS_Pr, ModeNo, ModeIdIndex, RefreshRateTableIndex,
-                          &ResIndex, &DisplayType))) return;
+                          &ResIndex, &DisplayType))) {
+     return;
+  }
 
   if(HwInfo->jChipType < SIS_315H) {
      if(SiS_Pr->SiS_SetFlag & SetDOSMode) return;
@@ -8628,16 +7801,16 @@
 
   switch(DisplayType) {
     case 0 : LVDSCRT1Ptr = SiS_Pr->SiS_LVDSCRT1800x600_1;           break;
-    case 1 : LVDSCRT1Ptr = SiS_Pr->SiS_LVDSCRT11024x768_1;          break;
-    case 2 : LVDSCRT1Ptr = SiS_Pr->SiS_LVDSCRT11280x1024_1;         break;
-    case 3 : LVDSCRT1Ptr = SiS_Pr->SiS_LVDSCRT1800x600_1_H;         break;
-    case 4 : LVDSCRT1Ptr = SiS_Pr->SiS_LVDSCRT11024x768_1_H;        break;
-    case 5 : LVDSCRT1Ptr = SiS_Pr->SiS_LVDSCRT11280x1024_1_H;       break;
-    case 6 : LVDSCRT1Ptr = SiS_Pr->SiS_LVDSCRT1800x600_2;           break;
-    case 7 : LVDSCRT1Ptr = SiS_Pr->SiS_LVDSCRT11024x768_2;          break;
-    case 8 : LVDSCRT1Ptr = SiS_Pr->SiS_LVDSCRT11280x1024_2;         break;
-    case 9 : LVDSCRT1Ptr = SiS_Pr->SiS_LVDSCRT1800x600_2_H;         break;
-    case 10: LVDSCRT1Ptr = SiS_Pr->SiS_LVDSCRT11024x768_2_H;        break;
+    case 1 : LVDSCRT1Ptr = SiS_Pr->SiS_LVDSCRT1800x600_1_H;         break;
+    case 2 : LVDSCRT1Ptr = SiS_Pr->SiS_LVDSCRT1800x600_2;           break;
+    case 3 : LVDSCRT1Ptr = SiS_Pr->SiS_LVDSCRT1800x600_2_H;         break;
+    case 4 : LVDSCRT1Ptr = SiS_Pr->SiS_LVDSCRT11024x768_1;          break;
+    case 5 : LVDSCRT1Ptr = SiS_Pr->SiS_LVDSCRT11024x768_1_H;        break;
+    case 6 : LVDSCRT1Ptr = SiS_Pr->SiS_LVDSCRT11024x768_2;          break;
+    case 7 : LVDSCRT1Ptr = SiS_Pr->SiS_LVDSCRT11024x768_2_H;        break;
+    case 8 : LVDSCRT1Ptr = SiS_Pr->SiS_LVDSCRT11280x1024_1;         break;
+    case 9 : LVDSCRT1Ptr = SiS_Pr->SiS_LVDSCRT11280x1024_1_H;       break;
+    case 10: LVDSCRT1Ptr = SiS_Pr->SiS_LVDSCRT11280x1024_2;         break;
     case 11: LVDSCRT1Ptr = SiS_Pr->SiS_LVDSCRT11280x1024_2_H;       break;
     case 12: LVDSCRT1Ptr = SiS_Pr->SiS_LVDSCRT1XXXxXXX_1;           break;
     case 13: LVDSCRT1Ptr = SiS_Pr->SiS_LVDSCRT1XXXxXXX_1_H;         break;
@@ -8676,7 +7849,7 @@
     default: LVDSCRT1Ptr = SiS_Pr->SiS_LVDSCRT11024x768_1;          break;
   }
 
-  SiS_SetRegAND(SiS_Pr->SiS_P3d4,0x11,0x7f);                        /*unlock cr0-7  */
+  SiS_SetRegAND(SiS_Pr->SiS_P3d4,0x11,0x7f);
 
   tempah = (LVDSCRT1Ptr + ResIndex)->CR[0];
   SiS_SetReg(SiS_Pr->SiS_P3d4,0x00,tempah);
@@ -8711,12 +7884,6 @@
   tempah <<= 5;
   if(modeflag & DoubleScanMode)  tempah |= 0x080;
   SiS_SetRegANDOR(SiS_Pr->SiS_P3d4,0x09,~0x020,tempah);
-
-  /* 650/LVDS BIOS - doesn't make sense */
-  if(SiS_Pr->SiS_VBInfo & SetCRT2ToTV) {
-     if(modeflag & HalfDCLK)
-        SiS_SetRegAND(SiS_Pr->SiS_P3d4,0x11,0x7f);
-  }
 }
 
 /*********************************************/
@@ -8731,7 +7898,7 @@
   USHORT clkbase, vclkindex=0;
   UCHAR  sr2b, sr2c;
 
-  if((SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel640x480) || (SiS_Pr->SiS_IF_DEF_TRUMPION == 1)) {
+  if((SiS_Pr->SiS_LCDResInfo == Panel_640x480) || (SiS_Pr->SiS_LCDInfo & LCDPass11)) {
 	SiS_Pr->SiS_SetFlag &= (~ProgrammingCRT2);
         if((SiS_Pr->SiS_RefIndex[RefreshRateTableIndex].Ext_CRTVCLK & 0x3f) == 2) {
 	   RefreshRateTableIndex--;
@@ -8748,7 +7915,7 @@
   sr2c = SiS_Pr->SiS_VCLKData[vclkindex].SR2C;
 
   if((SiS_Pr->SiS_CustomT == CUT_BARCO1366) || (SiS_Pr->SiS_CustomT == CUT_BARCO1024)) {
-     if((ROMAddr) && SiS_Pr->SiS_UseROM) {
+     if(SiS_Pr->SiS_UseROM) {
 	if(ROMAddr[0x220] & 0x01) {
            sr2b = ROMAddr[0x227];
 	   sr2c = ROMAddr[0x228];
@@ -8763,7 +7930,6 @@
      }
   }
 
-  SiS_SetReg(SiS_Pr->SiS_P3c4,0x05,0x86);
   SiS_SetReg(SiS_Pr->SiS_P3c4,0x31,0x20);
   SiS_SetReg(SiS_Pr->SiS_P3c4,clkbase,sr2b);
   SiS_SetReg(SiS_Pr->SiS_P3c4,clkbase+1,sr2c);
@@ -8783,14 +7949,17 @@
 SiS_SetCHTVReg(SiS_Private *SiS_Pr, USHORT ModeNo, USHORT ModeIdIndex,
                USHORT RefreshRateTableIndex)
 {
-  USHORT temp, tempbx, tempcl;
+#if defined(SIS300) || defined(SIS315H)
+  USHORT temp, tempbx;
+#endif
+  USHORT tempcl;
   USHORT TVType, resindex;
   const SiS_CHTVRegDataStruct *CHTVRegData = NULL;
 
   if(ModeNo <= 0x13)
-    	tempcl = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_CRT2CRTC;
+     tempcl = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_CRT2CRTC;
   else
-    	tempcl = SiS_Pr->SiS_RefIndex[RefreshRateTableIndex].Ext_CRT2CRTC;
+     tempcl = SiS_Pr->SiS_RefIndex[RefreshRateTableIndex].Ext_CRT2CRTC;
 
   TVType = 0;
   if(SiS_Pr->SiS_TVMode & TVSetCHOverScan) TVType += 1;
@@ -8808,16 +7977,16 @@
 	}
   }
   switch(TVType) {
-    	case  0: CHTVRegData = SiS_Pr->SiS_CHTVReg_UNTSC; break;
-    	case  1: CHTVRegData = SiS_Pr->SiS_CHTVReg_ONTSC; break;
-    	case  2: CHTVRegData = SiS_Pr->SiS_CHTVReg_UPAL;  break;
-    	case  3: CHTVRegData = SiS_Pr->SiS_CHTVReg_OPAL;  break;
-	case  4: CHTVRegData = SiS_Pr->SiS_CHTVReg_UPALM; break;
-    	case  5: CHTVRegData = SiS_Pr->SiS_CHTVReg_OPALM; break;
-    	case  6: CHTVRegData = SiS_Pr->SiS_CHTVReg_UPALN; break;
-    	case  7: CHTVRegData = SiS_Pr->SiS_CHTVReg_OPALN; break;
-	case  8: CHTVRegData = SiS_Pr->SiS_CHTVReg_SOPAL; break;
-	default: CHTVRegData = SiS_Pr->SiS_CHTVReg_OPAL;  break;
+     case  0: CHTVRegData = SiS_Pr->SiS_CHTVReg_UNTSC; break;
+     case  1: CHTVRegData = SiS_Pr->SiS_CHTVReg_ONTSC; break;
+     case  2: CHTVRegData = SiS_Pr->SiS_CHTVReg_UPAL;  break;
+     case  3: CHTVRegData = SiS_Pr->SiS_CHTVReg_OPAL;  break;
+     case  4: CHTVRegData = SiS_Pr->SiS_CHTVReg_UPALM; break;
+     case  5: CHTVRegData = SiS_Pr->SiS_CHTVReg_OPALM; break;
+     case  6: CHTVRegData = SiS_Pr->SiS_CHTVReg_UPALN; break;
+     case  7: CHTVRegData = SiS_Pr->SiS_CHTVReg_OPALN; break;
+     case  8: CHTVRegData = SiS_Pr->SiS_CHTVReg_SOPAL; break;
+     default: CHTVRegData = SiS_Pr->SiS_CHTVReg_OPAL;  break;
   }
   resindex = tempcl & 0x3F;
 
@@ -9089,21 +8258,21 @@
   /* Set up Power up/down timing */
 
   if(HwInfo->jChipType == SIS_740) {
-     if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1024x768) {
+     if(SiS_Pr->SiS_LCDResInfo == Panel_1024x768) {
         if(SiS_Pr->SiS_CustomT == CUT_ASUSL3000D) tableptr = asus1024_740;
         else    			          tableptr = table1024_740;
-     } else if((SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1280x1024) ||
-               (SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1400x1050) ||
-	       (SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1600x1200)) {
+     } else if((SiS_Pr->SiS_LCDResInfo == Panel_1280x1024) ||
+               (SiS_Pr->SiS_LCDResInfo == Panel_1400x1050) ||
+	       (SiS_Pr->SiS_LCDResInfo == Panel_1600x1200)) {
 	if(SiS_Pr->SiS_CustomT == CUT_ASUSL3000D) tableptr = asus1400_740;
         else					  tableptr = table1400_740;
      } else return;
   } else {
-     if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1024x768) {
+     if(SiS_Pr->SiS_LCDResInfo == Panel_1024x768) {
         tableptr = table1024_650;
-     } else if((SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1280x1024) ||
-               (SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1400x1050) ||
-	       (SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1600x1200)) {
+     } else if((SiS_Pr->SiS_LCDResInfo == Panel_1280x1024) ||
+               (SiS_Pr->SiS_LCDResInfo == Panel_1400x1050) ||
+	       (SiS_Pr->SiS_LCDResInfo == Panel_1600x1200)) {
         tableptr = table1400_650;
      } else return;
   }
@@ -9139,45 +8308,35 @@
   int i;
 
   if(HwInfo->jChipType == SIS_740) {
-     if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1024x768) {
-        tableptr = table1024_740;
-     } else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1280x1024) {
-        tableptr = table1280_740;
-     } else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1400x1050) {
-        tableptr = table1400_740;
-     } else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1600x1200) {
-        tableptr = table1600_740;
-     } else return;
-  } else {
-     if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1024x768) {
-        tableptr = table1024_650;
-     } else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1280x1024) {
-        tableptr = table1280_650;
-     } else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1400x1050) {
-        tableptr = table1400_650;
-     } else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1600x1200) {
-        tableptr = table1600_650;
-     } else return;
+     if(SiS_Pr->SiS_LCDResInfo == Panel_1024x768)       tableptr = table1024_740;
+     else if(SiS_Pr->SiS_LCDResInfo == Panel_1280x1024) tableptr = table1280_740;
+     else if(SiS_Pr->SiS_LCDResInfo == Panel_1400x1050) tableptr = table1400_740;
+     else if(SiS_Pr->SiS_LCDResInfo == Panel_1600x1200) tableptr = table1600_740;
+     else return;
+  } else {
+     if(SiS_Pr->SiS_LCDResInfo == Panel_1024x768)       tableptr = table1024_650;
+     else if(SiS_Pr->SiS_LCDResInfo == Panel_1280x1024) tableptr = table1280_650;
+     else if(SiS_Pr->SiS_LCDResInfo == Panel_1400x1050) tableptr = table1400_650;
+     else if(SiS_Pr->SiS_LCDResInfo == Panel_1600x1200) tableptr = table1600_650;
+     else return;
   }
 
   tempbh = SiS_GetCH701x(SiS_Pr,0x74);
   if((tempbh == 0xf6) || (tempbh == 0xc7)) {
      tempbh = SiS_GetCH701x(SiS_Pr,0x73);
      if(tempbh == 0xc8) {
-        if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1024x768) return;
+        if(SiS_Pr->SiS_LCDResInfo == Panel_1024x768) return;
      } else if(tempbh == 0xdb) {
-        if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1280x1024) return;
-	if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1400x1050) return;
+        if(SiS_Pr->SiS_LCDResInfo == Panel_1280x1024) return;
+	if(SiS_Pr->SiS_LCDResInfo == Panel_1400x1050) return;
      } else if(tempbh == 0xde) {
-        if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1600x1200) return;
+        if(SiS_Pr->SiS_LCDResInfo == Panel_1600x1200) return;
      }
   }
 
-  if(HwInfo->jChipType == SIS_740) {
-     tempbh = 0x0d;
-  } else {
-     tempbh = 0x0c;
-  }
+  if(HwInfo->jChipType == SIS_740) tempbh = 0x0d;
+  else     			   tempbh = 0x0c;
+
   for(i = 0; i < tempbh; i++) {
      SiS_SetCH701x(SiS_Pr,(tableptr[i] << 8) | regtable[i]);
   }
@@ -9564,13 +8723,12 @@
 
    SiS_GetCRT2Data(SiS_Pr, ModeNo, ModeIdIndex, RefreshRateTableIndex, HwInfo);
 
-   /* Set up Panel Link for LVDS, 301BDH and 30xLV(for LCDA) */
+   /* Set up Panel Link for LVDS and LCDA */
+   SiS_Pr->SiS_LCDHDES = SiS_Pr->SiS_LCDVDES = 0;
    if( (SiS_Pr->SiS_IF_DEF_LVDS == 1) ||
        ((SiS_Pr->SiS_VBType & VB_NoLCD) && (SiS_Pr->SiS_VBInfo & SetCRT2ToLCD)) ||
        ((HwInfo->jChipType >= SIS_315H) && (SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV)) ) {
       SiS_GetLVDSDesData(SiS_Pr, ModeNo, ModeIdIndex, RefreshRateTableIndex, HwInfo);
-   } else {
-      SiS_Pr->SiS_LCDHDES = SiS_Pr->SiS_LCDVDES = 0;
    }
 
 #ifdef LINUX_XF86
@@ -9598,13 +8756,15 @@
       	   SiS_SetGroup3(SiS_Pr, ModeNo, ModeIdIndex, HwInfo);
       	   SiS_SetGroup4(SiS_Pr, ModeNo, ModeIdIndex, RefreshRateTableIndex, HwInfo);
 #ifdef SIS315H
-	   SiS_SetGroup4_C_ELV(SiS_Pr, HwInfo);
+	   SiS_SetGroup4_C_ELV(SiS_Pr, HwInfo, ModeNo, ModeIdIndex);
 #endif
       	   SiS_SetGroup5(SiS_Pr, ModeNo, ModeIdIndex, HwInfo);
 
+	   SiS_SetCRT2Sync(SiS_Pr, ModeNo, RefreshRateTableIndex, HwInfo);
+
 	   /* For 301BDH (Panel link initialization): */
 	   if((SiS_Pr->SiS_VBType & VB_NoLCD) && (SiS_Pr->SiS_VBInfo & SetCRT2ToLCD)) {
-	      if(SiS_Pr->SiS_LCDResInfo != SiS_Pr->SiS_Panel640x480) {
+	      if(SiS_Pr->SiS_LCDResInfo != Panel_640x480) {
 		 if(!((SiS_Pr->SiS_SetFlag & SetDOSMode) && ((ModeNo == 0x03) || (ModeNo == 0x10)))) {
 		    if(SiS_Pr->SiS_VBInfo & SetInSlaveMode) {
 		       SiS_ModCRT1CRTC(SiS_Pr,ModeNo,ModeIdIndex,
@@ -9619,15 +8779,13 @@
 
    } else {
 
-        if(SiS_Pr->SiS_LCDResInfo != SiS_Pr->SiS_Panel640x480) {
-	   if(SiS_Pr->SiS_IF_DEF_TRUMPION == 0) {
-    	      SiS_ModCRT1CRTC(SiS_Pr,ModeNo,ModeIdIndex,
-	                      RefreshRateTableIndex,HwInfo);
-	   }
+        SiS_SetCRT2Sync(SiS_Pr, ModeNo, RefreshRateTableIndex, HwInfo);
+
+        if(!(SiS_Pr->SiS_LCDInfo & LCDPass11)) {
+    	   SiS_ModCRT1CRTC(SiS_Pr,ModeNo,ModeIdIndex,RefreshRateTableIndex,HwInfo);
 	}
 
-        SiS_SetCRT2ECLK(SiS_Pr,ModeNo,ModeIdIndex,
-	                RefreshRateTableIndex,HwInfo);
+        SiS_SetCRT2ECLK(SiS_Pr,ModeNo,ModeIdIndex,RefreshRateTableIndex,HwInfo);
 
 	if(SiS_Pr->SiS_SetFlag & LowModeTests) {
      	   if(SiS_Pr->SiS_IF_DEF_CH70xx != 0) {
@@ -9639,8 +8797,7 @@
 		 }
 	      }
 	      if(SiS_Pr->SiS_VBInfo & SetCRT2ToTV) {
-       		 SiS_SetCHTVReg(SiS_Pr,ModeNo,ModeIdIndex,
-		               RefreshRateTableIndex);
+       		 SiS_SetCHTVReg(SiS_Pr,ModeNo,ModeIdIndex,RefreshRateTableIndex);
 	      }
      	   }
 	}
@@ -9651,7 +8808,7 @@
    if(HwInfo->jChipType < SIS_315H) {
       if(SiS_Pr->SiS_SetFlag & LowModeTests) {
 	 if(SiS_Pr->SiS_UseOEM) {
-	    if((SiS_Pr->SiS_UseROM) && ROMAddr && (SiS_Pr->SiS_UseOEM == -1)) {
+	    if((SiS_Pr->SiS_UseROM) && (SiS_Pr->SiS_UseOEM == -1)) {
 	       if((ROMAddr[0x233] == 0x12) && (ROMAddr[0x234] == 0x34)) {
 	          SiS_OEM300Setting(SiS_Pr,HwInfo,ModeNo,ModeIdIndex,
 	       			    RefreshRateTableIndex);
@@ -9684,13 +8841,11 @@
       if(SiS_Pr->SiS_SetFlag & LowModeTests) {
 	 if(HwInfo->jChipType < SIS_661) {
 	    SiS_FinalizeLCD(SiS_Pr, ModeNo, ModeIdIndex, HwInfo);
-            if(SiS_Pr->SiS_UseOEM) {
-               SiS_OEM310Setting(SiS_Pr, HwInfo, ModeNo, ModeIdIndex);
-            }
+            SiS_OEM310Setting(SiS_Pr, HwInfo, ModeNo, ModeIdIndex);
 	 } else {
 	    SiS_OEM661Setting(SiS_Pr, HwInfo, ModeNo, ModeIdIndex, RefreshRateTableIndex);
 	 }
-         SiS_CRT2AutoThreshold(SiS_Pr);
+         SiS_SetRegOR(SiS_Pr->SiS_Part1Port,0x01,0x40);
       }
    }
 #endif
@@ -9761,6 +8916,63 @@
   }
 }
 
+#ifdef SIS300
+static UCHAR *
+SiS_SetTrumpBlockLoop(SiS_Private *SiS_Pr, UCHAR *dataptr)
+{
+  int i, j, num;
+  USHORT tempah,temp;
+  UCHAR *mydataptr;
+
+  for(i=0; i<20; i++) {				/* Do 20 attempts to write */
+     mydataptr = dataptr;
+     num = *mydataptr++;
+     if(!num) return mydataptr;
+     if(i) {
+        SiS_SetStop(SiS_Pr);
+	SiS_DDC2Delay(SiS_Pr,SiS_I2CDELAYSHORT*2);
+     }
+     if(SiS_SetStart(SiS_Pr)) continue;		/* Set start condition */
+     tempah = SiS_Pr->SiS_DDC_DeviceAddr;
+     temp = SiS_WriteDDC2Data(SiS_Pr,tempah);	/* Write DAB (S0=0=write) */
+     if(temp) continue;				/*    (ERROR: no ack) */
+     tempah = *mydataptr++;
+     temp = SiS_WriteDDC2Data(SiS_Pr,tempah);	/* Write register number */
+     if(temp) continue;				/*    (ERROR: no ack) */
+     for(j=0; j<num; j++) {
+        tempah = *mydataptr++;
+        temp = SiS_WriteDDC2Data(SiS_Pr,tempah);/* Write DAB (S0=0=write) */
+	if(temp) break;
+     }
+     if(temp) continue;
+     if(SiS_SetStop(SiS_Pr)) continue;
+     return mydataptr;
+  }
+  return NULL;
+}
+
+static BOOLEAN
+SiS_SetTrumpionBlock(SiS_Private *SiS_Pr, UCHAR *dataptr)
+{
+  SiS_Pr->SiS_DDC_DeviceAddr = 0xF0;  		/* DAB (Device Address Byte) */
+  SiS_Pr->SiS_DDC_Index = 0x11;			/* Bit 0 = SC;  Bit 1 = SD */
+  SiS_Pr->SiS_DDC_Data  = 0x02;              	/* Bitmask in IndexReg for Data */
+  SiS_Pr->SiS_DDC_Clk   = 0x01;              	/* Bitmask in IndexReg for Clk */
+  SiS_SetupDDCN(SiS_Pr);
+
+  SiS_SetSwitchDDC2(SiS_Pr);
+
+  while(*dataptr) {
+     dataptr = SiS_SetTrumpBlockLoop(SiS_Pr, dataptr);
+     if(!dataptr) return FALSE;
+  }
+#ifdef TWDEBUG
+  xf86DrvMsg(0, X_INFO, "Trumpion block success\n");
+#endif
+  return TRUE;
+}
+#endif
+
 /* The Chrontel 700x is connected to the 630/730 via
  * the 630/730's DDC/I2C port.
  *
@@ -9796,6 +9008,20 @@
   return FALSE;
 }
 
+#ifdef SIS300
+/* Write Trumpion register */
+void
+SiS_SetTrumpReg(SiS_Private *SiS_Pr, USHORT tempbx)
+{
+  SiS_Pr->SiS_DDC_DeviceAddr = 0xF0;  		/* DAB (Device Address Byte) */
+  SiS_Pr->SiS_DDC_Index = 0x11;			/* Bit 0 = SC;  Bit 1 = SD */
+  SiS_Pr->SiS_DDC_Data  = 0x02;              	/* Bitmask in IndexReg for Data */
+  SiS_Pr->SiS_DDC_Clk   = 0x01;              	/* Bitmask in IndexReg for Clk */
+  SiS_SetupDDCN(SiS_Pr);
+  SiS_SetChReg(SiS_Pr, tempbx, 0);
+}
+#endif
+
 /* Write to Chrontel 700x */
 /* Parameter is [Data (S15-S8) | Register no (S7-S0)] */
 void
@@ -9831,17 +9057,16 @@
   SiS_Pr->SiS_DDC_Clk   = 0x04;                 /* Bitmask in IndexReg for Clk */
   SiS_SetupDDCN(SiS_Pr);
   SiS_Pr->SiS_DDC_DeviceAddr = 0xEA;  		/* DAB (Device Address Byte) */
-
   SiS_SetChReg(SiS_Pr, tempbx, 0);
 }
 
 void
 SiS_SetCH70xx(SiS_Private *SiS_Pr, USHORT tempbx)
 {
-   if(SiS_Pr->SiS_IF_DEF_CH70xx == 1)
-      SiS_SetCH700x(SiS_Pr,tempbx);
-   else
-      SiS_SetCH701x(SiS_Pr,tempbx);
+  if(SiS_Pr->SiS_IF_DEF_CH70xx == 1)
+     SiS_SetCH700x(SiS_Pr,tempbx);
+  else
+     SiS_SetCH701x(SiS_Pr,tempbx);
 }
 
 static USHORT
@@ -9873,6 +9098,21 @@
   return 0xFFFF;
 }
 
+#ifdef SIS300
+/* Read from Trumpion */
+USHORT
+SiS_GetTrumpReg(SiS_Private *SiS_Pr, USHORT tempbx)
+{
+  SiS_Pr->SiS_DDC_DeviceAddr = 0xF0;	/* DAB */
+  SiS_Pr->SiS_DDC_Index = 0x11;		/* Bit 0 = SC;  Bit 1 = SD */
+  SiS_Pr->SiS_DDC_Data  = 0x02;         /* Bitmask in IndexReg for Data */
+  SiS_Pr->SiS_DDC_Clk   = 0x01;         /* Bitmask in IndexReg for Clk */
+  SiS_SetupDDCN(SiS_Pr);
+  SiS_Pr->SiS_DDC_ReadAddr = tempbx;
+  return(SiS_GetChReg(SiS_Pr,0));
+}
+#endif
+
 /* Read from Chrontel 700x */
 /* Parameter is [Register no (S7-S0)] */
 USHORT
@@ -9925,10 +9165,10 @@
 USHORT
 SiS_GetCH70xx(SiS_Private *SiS_Pr, USHORT tempbx)
 {
-   if(SiS_Pr->SiS_IF_DEF_CH70xx == 1)
-      return(SiS_GetCH700x(SiS_Pr, tempbx));
-   else
-      return(SiS_GetCH701x(SiS_Pr, tempbx));
+  if(SiS_Pr->SiS_IF_DEF_CH70xx == 1)
+     return(SiS_GetCH700x(SiS_Pr, tempbx));
+  else
+     return(SiS_GetCH701x(SiS_Pr, tempbx));
 }
 
 /* Our own DDC functions */
@@ -10315,6 +9555,8 @@
    for(i=0; i<7; i++) SiS_Pr->CP_DataValid[i] = FALSE;
    SiS_Pr->CP_HaveCustomData = FALSE;
    SiS_Pr->CP_MaxX = SiS_Pr->CP_MaxY = SiS_Pr->CP_MaxClock = 0;
+   SiS_Pr->CP_PreferredX = SiS_Pr->CP_PreferredY = 0;
+   SiS_Pr->CP_PreferredIndex = -1;
 
    if(!(pSiS->VBFlags & (VB_301|VB_301B|VB_301C|VB_302B))) return 0;
    if(pSiS->VBFlags & VB_30xBDH) return 0;
@@ -10409,12 +9651,14 @@
 	 SiS_Pr->CP_PreferredY = yres;
 
          switch(xres) {
+#if 0	    /* Treat as custom */
             case 800:
 	        if(yres == 600) {
 	     	   paneltype = Panel_800x600;
 	     	   checkexpand = TRUE;
 	        }
 	        break;
+#endif
             case 1024:
 	        if(yres == 768) {
 	     	   paneltype = Panel_1024x768;
@@ -10452,9 +9696,11 @@
 #if 0	    /* Treat this as custom, as we have no valid timing data yet */
 	    case 1600:
 	        if(pSiS->VGAEngine == SIS_315_VGA) {
-	           if(yres == 1200) {
-	              paneltype = Panel310_1600x1200;
-		      checkexpand = TRUE;
+		   if(pSiS->VBFlags & VB_301C) {
+	              if(yres == 1200) {
+	                 paneltype = Panel310_1600x1200;
+		         checkexpand = TRUE;
+		      }
 	           }
 	        }
       	        break;
@@ -10580,6 +9826,10 @@
 	          if(yres > SiS_Pr->CP_MaxY) SiS_Pr->CP_MaxY = yres;
 		  if(SiS_Pr->CP_Clock[i] > SiS_Pr->CP_MaxClock) SiS_Pr->CP_MaxClock = SiS_Pr->CP_Clock[i];
 
+		  if((SiS_Pr->CP_PreferredX == xres) && (SiS_Pr->CP_PreferredY == yres)) {
+	             SiS_Pr->CP_PreferredIndex = i;
+	          }
+
 		  SiS_Pr->CP_Vendor = buffer[9] | (buffer[8] << 8);
 		  SiS_Pr->CP_Product = buffer[10] | (buffer[11] << 8);
 
@@ -10660,28 +9910,20 @@
       SiS_Pr->CP_MaxX = xres = buffer[0x76] | (buffer[0x77] << 8);
       SiS_Pr->CP_MaxY = yres = buffer[0x78] | (buffer[0x79] << 8);
       switch(xres) {
+#if 0
          case 800:
 	     if(yres == 600) {
 	     	paneltype = Panel_800x600;
 	     	checkexpand = TRUE;
 	     }
 	     break;
+#endif
          case 1024:
 	     if(yres == 768) {
 	     	paneltype = Panel_1024x768;
 	     	checkexpand = TRUE;
 	     }
 	     break;
-	 case 1152:
-	     if(yres == 768) {
-	        if(pSiS->VGAEngine == SIS_300_VGA) {
-		   paneltype = Panel300_1152x768;
-		} else {
-		   paneltype = Panel310_1152x768;
-		}
-	     	checkexpand = TRUE;
-	     }
-	     break;
 	 case 1280:
 	     if(yres == 960) {
 	        if(pSiS->VGAEngine == SIS_315_VGA) {
@@ -10706,9 +9948,11 @@
 #if 0    /* Treat this one as custom since we have no timing data yet */
 	 case 1600:
 	     if(pSiS->VGAEngine == SIS_315_VGA) {
-	        if(yres == 1200) {
-	           paneltype = Panel310_1600x1200;
-		   checkexpand = TRUE;
+	        if(pSiS->VBFlags & VB_301C) {
+	           if(yres == 1200) {
+	              paneltype = Panel310_1600x1200;
+		      checkexpand = TRUE;
+		   }
 	        }
 	     }
       	     break;
@@ -10810,6 +10054,10 @@
 
 	       if(SiS_Pr->CP_Clock[i] > SiS_Pr->CP_MaxClock) SiS_Pr->CP_MaxClock = SiS_Pr->CP_Clock[i];
 
+	       if((SiS_Pr->CP_MaxX == xres) && (SiS_Pr->CP_MaxY == yres)) {
+	          SiS_Pr->CP_PreferredIndex = i;
+	       }
+
 	       SiS_Pr->CP_HSync_P[i] = (buffer[index + 17] & 0x02) ? TRUE : FALSE;
 	       SiS_Pr->CP_VSync_P[i] = (buffer[index + 17] & 0x04) ? TRUE : FALSE;
 	       SiS_Pr->CP_SyncValid[i] = TRUE;
@@ -10864,14 +10112,18 @@
    if(paneltype) {
        if(!SiS_Pr->CP_PreferredX) SiS_Pr->CP_PreferredX = SiS_Pr->CP_MaxX;
        if(!SiS_Pr->CP_PreferredY) SiS_Pr->CP_PreferredY = SiS_Pr->CP_MaxY;
-       cr37 &= 0xf1;
-       SiS_SetRegANDOR(SiS_Pr->SiS_P3d4,0x36,0xf0,paneltype);
-       SiS_SetRegANDOR(SiS_Pr->SiS_P3d4,0x37,0xf1,cr37);
        SiS_SetRegOR(SiS_Pr->SiS_P3d4,0x32,0x08);
+       SiS_SetReg(SiS_Pr->SiS_P3d4,0x36,paneltype);
+       cr37 &= 0xf1;
+       SiS_SetRegANDOR(SiS_Pr->SiS_P3d4,0x37,0x0c,cr37);
+       SiS_Pr->PanelSelfDetected = TRUE;
 #ifdef TWDEBUG
        xf86DrvMsgVerb(pSiS->pScrn->scrnIndex, X_PROBED, 3, 
-       	"CRT2: [DDC LCD results: 0x%02x, 0x%02x]\n", paneltype, cr37);
+       	   "CRT2: [DDC LCD results: 0x%02x, 0x%02x]\n", paneltype, cr37);
 #endif	
+   } else {
+       SiS_SetRegAND(SiS_Pr->SiS_P3d4,0x32,~0x08);
+       SiS_SetReg(SiS_Pr->SiS_P3d4,0x36,0x00);
    }
    return 0;
 }
@@ -11148,13 +10400,13 @@
   USHORT romptr;
 
   if(HwInfo->jChipType < SIS_330) {
-     romptr = ROMAddr[0x128] | (ROMAddr[0x129] << 8);
+     romptr = SISGETROMW(0x128);
      if(SiS_Pr->SiS_VBType & VB_SIS301B302B)
-        romptr = ROMAddr[0x12a] | (ROMAddr[0x12b] << 8);
+        romptr = SISGETROMW(0x12a);
   } else {
-     romptr = ROMAddr[0x1a8] | (ROMAddr[0x1a9] << 8);
+     romptr = SISGETROMW(0x1a8);
      if(SiS_Pr->SiS_VBType & VB_SIS301B302B)
-        romptr = ROMAddr[0x1aa] | (ROMAddr[0x1ab] << 8);
+        romptr = SISGETROMW(0x1aa);
   }
   return(romptr);
 }
@@ -11166,13 +10418,13 @@
   USHORT romptr;
 
   if(HwInfo->jChipType < SIS_330) {
-     romptr = ROMAddr[0x120] | (ROMAddr[0x121] << 8);
+     romptr = SISGETROMW(0x120);
      if(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV)
-        romptr = ROMAddr[0x122] | (ROMAddr[0x123] << 8);
+        romptr = SISGETROMW(0x122);
   } else {
-     romptr = ROMAddr[0x1a0] | (ROMAddr[0x1a1] << 8);
+     romptr = SISGETROMW(0x1a0);
      if(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV)
-        romptr = ROMAddr[0x1a2] | (ROMAddr[0x1a3] << 8);
+        romptr = SISGETROMW(0x1a2);
   }
   return(romptr);
 }
@@ -11184,13 +10436,13 @@
   USHORT romptr;
 
   if(HwInfo->jChipType < SIS_330) {
-     romptr = ROMAddr[0x114] | (ROMAddr[0x115] << 8);
+     romptr = SISGETROMW(0x114);
      if(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV)
-        romptr = ROMAddr[0x11a] | (ROMAddr[0x11b] << 8);
+        romptr = SISGETROMW(0x11a);
   } else {
-     romptr = ROMAddr[0x194] | (ROMAddr[0x195] << 8);
+     romptr = SISGETROMW(0x194);
      if(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV)
-        romptr = ROMAddr[0x19a] | (ROMAddr[0x19b] << 8);
+        romptr = SISGETROMW(0x19a);
   }
   return(romptr);
 }
@@ -11212,9 +10464,9 @@
      }
   }
 
-  index = SiS_Pr->SiS_LCDResInfo & 0x0F;
-  if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1400x1050)      index -= 5;
-  else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1600x1200) index -= 6;
+  index = SiS_GetBIOSLCDResInfo(SiS_Pr) & 0x0F;
+  if(SiS_Pr->SiS_LCDResInfo == Panel_1400x1050)      index -= 5;
+  else if(SiS_Pr->SiS_LCDResInfo == Panel_1600x1200) index -= 6;
   index--;
   index *= 3;
   if(SiS_Pr->SiS_LCDInfo & DontExpandLCD) index += 2;
@@ -11227,12 +10479,9 @@
 {
   USHORT index;
 
-  index = SiS_Pr->SiS_LCDResInfo & 0x0F;
-  index--;
-  index *= 3;
-  if(SiS_Pr->SiS_LCDInfo & DontExpandLCD) index += 2;
+  index = ((SiS_GetBIOSLCDResInfo(SiS_Pr) & 0x0F) - 1) * 3;
+  if(SiS_Pr->SiS_LCDInfo & DontExpandLCD)         index += 2;
   else if(!(SiS_Pr->SiS_SetFlag & LCDVESATiming)) index++;
-
   return index;
 }
 
@@ -11258,7 +10507,7 @@
 }
 
 static ULONG
-GetOEMTVPtr661_2(SiS_Private *SiS_Pr)
+GetOEMTVPtr661_2_GEN(SiS_Private *SiS_Pr, int addme)
 {
    USHORT index = 0, temp = 0;
 
@@ -11275,7 +10524,7 @@
    if(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) {
       if((!(SiS_Pr->SiS_VBInfo & SetInSlaveMode)) ||
          (SiS_Pr->SiS_TVMode & TVSetTVSimuMode)) {
-	 index += 8;
+	 index += addme;
 	 temp++;
       }
       temp += 0x0100;
@@ -11283,16 +10532,37 @@
    return(ULONG)(index | (temp << 16));
 }
 
+static ULONG
+GetOEMTVPtr661_2_OLD(SiS_Private *SiS_Pr)
+{
+   return(GetOEMTVPtr661_2_GEN(SiS_Pr, 8));
+}
+
+#if 0
+static ULONG
+GetOEMTVPtr661_2_NEW(SiS_Private *SiS_Pr)
+{
+   return(GetOEMTVPtr661_2_GEN(SiS_Pr, 6));
+}
+#endif
+
 static int
 GetOEMTVPtr661(SiS_Private *SiS_Pr)
 {
    int index = 0;
 
-   if(SiS_Pr->SiS_TVMode & TVSetPAL)       index = 2;
-   if(SiS_Pr->SiS_TVMode & TVSetHiVision)  index = 4;
-   if(SiS_Pr->SiS_TVMode & TVSetYPbPr525i) index = 6;
-   if(SiS_Pr->SiS_TVMode & TVSetYPbPr525p) index = 8;
-   if(SiS_Pr->SiS_TVMode & TVSetYPbPr750p) index = 10;
+   if(SiS_Pr->SiS_TVMode & TVSetPAL)          index = 2;
+   if(SiS_Pr->SiS_ROMNew) {
+      if(SiS_Pr->SiS_TVMode & TVSetYPbPr525i) index = 4;
+      if(SiS_Pr->SiS_TVMode & TVSetYPbPr525p) index = 6;
+      if(SiS_Pr->SiS_TVMode & TVSetYPbPr750p) index = 8;
+      if(SiS_Pr->SiS_TVMode & TVSetHiVision)  index = 10;
+   } else {
+      if(SiS_Pr->SiS_TVMode & TVSetHiVision)  index = 4;
+      if(SiS_Pr->SiS_TVMode & TVSetYPbPr525i) index = 6;
+      if(SiS_Pr->SiS_TVMode & TVSetYPbPr525p) index = 8;
+      if(SiS_Pr->SiS_TVMode & TVSetYPbPr750p) index = 10;
+   }
 
    if(SiS_Pr->SiS_TVMode & TVSetTVSimuMode) index++;
 
@@ -11306,15 +10576,21 @@
   USHORT delay=0,index,myindex,temp,romptr=0;
   BOOLEAN dochiptest = TRUE;
 
+  if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCDA) {
+     SiS_SetRegAND(SiS_Pr->SiS_Part1Port,0x20,0xbf);
+  } else {
+     SiS_SetRegAND(SiS_Pr->SiS_Part1Port,0x35,0x7f);
+  }
+
   /* Find delay (from ROM, internal tables, PCI subsystem) */
 
   if(SiS_Pr->SiS_VBInfo & SetCRT2ToRAMDAC) {			/* ------------ VGA */
      
-     if((ROMAddr) && SiS_Pr->SiS_UseROM) {
+     if((SiS_Pr->SiS_UseROM) && (!(SiS_Pr->SiS_ROMNew))) {
         romptr = GetRAMDACromptr(SiS_Pr, HwInfo);
-	if(!romptr) return;
-	delay = ROMAddr[romptr];
-     } else {
+     }
+     if(romptr) delay = ROMAddr[romptr];
+     else {
         delay = 0x04;
         if(SiS_Pr->SiS_VBType & VB_SIS301B302B) {
 	   if(IS_SIS650) {
@@ -11326,8 +10602,7 @@
 	   } else {
 	      delay = 0x0c;
 	   }
-	}
-        if(SiS_Pr->SiS_IF_DEF_LVDS == 1) {
+	} else if(SiS_Pr->SiS_IF_DEF_LVDS == 1) {
            delay = 0x00;
 	}
      }
@@ -11336,13 +10611,39 @@
 
      BOOLEAN gotitfrompci = FALSE;
 
-     if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_PanelCustom) return;
+     /* Could we detect a PDC for LCD or did we get a user-defined? If yes, use it */
+
+     if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCD) {
+	if(SiS_Pr->PDC != -1) {
+           SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x2d,0xf0,((SiS_Pr->PDC >> 1) & 0x0f));
+	   SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x35,0x7f,((SiS_Pr->PDC & 0x01) << 7));
+	   return;
+	}
+     } else {
+	if(SiS_Pr->PDCA != -1) {
+	   SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x2d,0x0f,((SiS_Pr->PDCA << 3) & 0xf0));
+	   SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x20,0xbf,((SiS_Pr->PDCA & 0x01) << 6));
+	   return;
+	}
+     }
 
-     /* Could we detect a PDC for LCD? If yes, use it */
+     /* Custom Panel? */
 
-     if(SiS_Pr->PDC) {
+     if(SiS_Pr->SiS_LCDResInfo == Panel_Custom) {
         if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCDA) {
-	   SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x2d,0x0f,((SiS_Pr->PDC & 0x0f) << 4));
+	   delay = 0x00;
+	   if((SiS_Pr->PanelXRes <= 1280) && (SiS_Pr->PanelYRes <= 1024)) {
+	      delay = 0x20;
+	   }
+	   SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x2d,0x0f,delay);
+	} else {
+	   delay = 0x0c;
+	   if(SiS_Pr->SiS_VBType & VB_SIS301C) delay = 0x03;
+	   else if(SiS_Pr->SiS_VBType & VB_SIS301LV302LV) {
+	      if(IS_SIS740) delay = 0x01;
+	      else          delay = 0x03;
+	   }
+	   SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x2d,0xf0,delay);
 	}
         return;
      }
@@ -11355,7 +10656,7 @@
      switch(SiS_Pr->SiS_CustomT) {
      case CUT_COMPAQ1280:
      case CUT_COMPAQ12802:
-	if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1280x1024) {
+	if(SiS_Pr->SiS_LCDResInfo == Panel_1280x1024) {
 	   gotitfrompci = TRUE;
 	   dochiptest = FALSE;
 	   delay = 0x03;
@@ -11363,15 +10664,13 @@
 	break;
      case CUT_CLEVO1400:
      case CUT_CLEVO14002:
-	/* if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1400x1050) { */
-	   gotitfrompci = TRUE;
-	   dochiptest = FALSE;
-	   delay = 0x02;
-	/* } */
+	gotitfrompci = TRUE;
+	dochiptest = FALSE;
+	delay = 0x02;
 	break;
      case CUT_CLEVO1024:
      case CUT_CLEVO10242:
-        if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1024x768) {
+        if(SiS_Pr->SiS_LCDResInfo == Panel_1024x768) {
 	   gotitfrompci = TRUE;
 	   dochiptest = FALSE;
 	   delay = 0x33;
@@ -11392,12 +10691,12 @@
 
            if(SiS_IsNotM650orLater(SiS_Pr, HwInfo)) {
 
-              if((ROMAddr) && SiS_Pr->SiS_UseROM) {
+              if((SiS_Pr->SiS_UseROM) && (!(SiS_Pr->SiS_ROMNew))) {
 	         /* Always use the second pointer on 650; some BIOSes */
                  /* still carry old 301 data at the first location    */
-	         /* romptr = ROMAddr[0x120] | (ROMAddr[0x121] << 8);  */
+	         /* romptr = SISGETROMW(0x120);                       */
 	         /* if(SiS_Pr->SiS_VBType & VB_SIS302LV)              */
-	         romptr = ROMAddr[0x122] | (ROMAddr[0x123] << 8);
+	         romptr = SISGETROMW(0x122);
 	         if(!romptr) return;
 	         delay = ROMAddr[(romptr + index)];
 	      } else {
@@ -11412,10 +10711,13 @@
 
           }
 
-        } else if((ROMAddr) && SiS_Pr->SiS_UseROM &&
-	          (SiS_Pr->SiS_LCDResInfo != SiS_Pr->SiS_Panel1280x1024)) {
+        } else if(SiS_Pr->SiS_UseROM 			      &&
+		  (!(SiS_Pr->SiS_ROMNew))		      &&
+	          (SiS_Pr->SiS_LCDResInfo != Panel_1280x1024) &&
+		  (SiS_Pr->SiS_LCDResInfo != Panel_1280x768)  &&
+		  (SiS_Pr->SiS_LCDResInfo != Panel_1280x960)) {
 
-	   /* Data for 1280x1024 wrong in BIOS */
+	   /* Data for 1280x1024 wrong in 301B BIOS */
            romptr = GetLCDromptr(SiS_Pr, HwInfo);
 	   if(!romptr) return;
 	   delay = ROMAddr[(romptr + index)];
@@ -11430,7 +10732,11 @@
            delay = SiS310_LCDDelayCompensation_301[myindex];
 	   if(SiS_Pr->SiS_VBType & VB_SIS301LV302LV) {
 	      if(IS_SIS740) delay = 0x01;
+	      else if(HwInfo->jChipType <= SIS_315PRO) delay = SiS310_LCDDelayCompensation_3xx301LV[myindex];
 	      else          delay = SiS310_LCDDelayCompensation_650301LV[myindex];
+	   } else if(SiS_Pr->SiS_VBType & VB_SIS301C) {
+	      if(IS_SIS740) delay = 0x01;  /* ? */
+	      else          delay = 0x03;
 	   } else if(SiS_Pr->SiS_VBType & VB_SIS301B302B) {
 	      if(IS_SIS740) delay = 0x01;
 	      else          delay = SiS310_LCDDelayCompensation_3xx301B[myindex];
@@ -11453,12 +10759,12 @@
 
         if(SiS_IsNotM650orLater(SiS_Pr,HwInfo)) {
 
-           if((ROMAddr) && SiS_Pr->SiS_UseROM) {
+           if((SiS_Pr->SiS_UseROM) && (!(SiS_Pr->SiS_ROMNew))) {
 	      /* Always use the second pointer on 650; some BIOSes */
               /* still carry old 301 data at the first location    */
-              /* romptr = ROMAddr[0x114] | (ROMAddr[0x115] << 8);  */
-	      /* if(SiS_Pr->SiS_VBType & VB_SIS302LV) */
-	      romptr = ROMAddr[0x11a] | (ROMAddr[0x11b] << 8);
+              /* romptr = SISGETROMW(0x114);			   */
+	      /* if(SiS_Pr->SiS_VBType & VB_SIS302LV)              */
+	      romptr = SISGETROMW(0x11a);
 	      if(!romptr) return;
 	      delay = ROMAddr[romptr + index];
 
@@ -11491,7 +10797,7 @@
 	   }
         }
 
-     } else if((ROMAddr) && SiS_Pr->SiS_UseROM) {
+     } else if((SiS_Pr->SiS_UseROM) && (!(SiS_Pr->SiS_ROMNew))) {
 
         romptr = GetTVromptr(SiS_Pr, HwInfo);
 	if(!romptr) return;
@@ -11507,14 +10813,16 @@
         if(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) {
 	   if(IS_SIS740) {
 	      delay = SiS310_TVDelayCompensation_740301B[index];
+	      /* LV: use 301 data? BIOS bug? */
 	   } else {
               delay = SiS310_TVDelayCompensation_301B[index];
+	      if(SiS_Pr->SiS_VBType & VB_SIS301C) delay = 0x02;
 	   }
 	}
 
      }
 
-     if(SiS_GetReg(SiS_Pr->SiS_Part1Port,0x13) & 0x04) {  /* LCDA */
+     if(SiS_LCDAEnabled(SiS_Pr, HwInfo)) {
 	delay &= 0x0f;
 	dochiptest = FALSE;
      }
@@ -11580,15 +10888,18 @@
   temp >>= 1;  	  /* 0: NTSC/YPbPr, 1: PAL, 2: HiTV */
   temp1 = temp;
 
-  if(ROMAddr && SiS_Pr->SiS_UseROM) {
+  if(SiS_Pr->SiS_UseROM && (!(SiS_Pr->SiS_ROMNew))) {
      if(HwInfo->jChipType >= SIS_661) {
-	romptr = ROMAddr[0x260] | (ROMAddr[0x261] << 8);
-	temp1 = GetOEMTVPtr661(SiS_Pr);
+        temp1 = GetOEMTVPtr661(SiS_Pr);
         temp1 >>= 1;
+        romptr = SISGETROMW(0x260);
+        if(HwInfo->jChipType >= SIS_760) {
+	   romptr = SISGETROMW(0x360);
+	}
      } else if(HwInfo->jChipType >= SIS_330) {
-        romptr = ROMAddr[0x192] | (ROMAddr[0x193] << 8);
+        romptr = SISGETROMW(0x192);
      } else {
-        romptr = ROMAddr[0x112] | (ROMAddr[0x113] << 8);
+        romptr = SISGETROMW(0x112);
      }
   }
 
@@ -11610,24 +10921,25 @@
   UCHAR  *ROMAddr = HwInfo->pjVirtualRomBase;
   USHORT index,temp,temp1,romptr=0;
 
-  temp = GetTVPtrIndex(SiS_Pr);
-  temp >>= 1;              	/* 0: NTSC/YPbPr, 1: PAL, 2: HiTV */
-  temp1 = temp;
+  temp = temp1 = GetTVPtrIndex(SiS_Pr) >> 1; 	/* 0: NTSC/YPbPr, 1: PAL, 2: HiTV */
 
-  if(ModeNo<=0x13)
+  if(ModeNo <= 0x13)
      index = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].VB_StTVEdgeIndex;
   else
      index = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].VB_ExtTVEdgeIndex;
 
-  if(ROMAddr && SiS_Pr->SiS_UseROM) {
+  if(SiS_Pr->SiS_UseROM && (!(SiS_Pr->SiS_ROMNew))) {
      if(HwInfo->jChipType >= SIS_661) {
-	romptr = ROMAddr[0x26c] | (ROMAddr[0x26d] << 8);
+        romptr = SISGETROMW(0x26c);
+        if(HwInfo->jChipType >= SIS_760) {
+	   romptr = SISGETROMW(0x36c);
+	}
 	temp1 = GetOEMTVPtr661(SiS_Pr);
         temp1 >>= 1;
      } else if(HwInfo->jChipType >= SIS_330) {
-        romptr = ROMAddr[0x1a4] | (ROMAddr[0x1a5] << 8);
+        romptr = SISGETROMW(0x1a4);
      } else {
-        romptr = ROMAddr[0x124] | (ROMAddr[0x125] << 8);
+        romptr = SISGETROMW(0x124);
      }
   }
 
@@ -11645,62 +10957,15 @@
 SetYFilter(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo,
            USHORT ModeNo,USHORT ModeIdIndex)
 {
-  UCHAR  *ROMAddr = HwInfo->pjVirtualRomBase;
-  USHORT index, myindex, oldindex,temp, i, j, flag1 = 0, flag2 = 0, romptr = 0;
-  ULONG  lindex;
+  USHORT index, temp, i, j;
 
-  if(ModeNo<=0x13) {
-    index =  SiS_Pr->SiS_SModeIDTable[ModeIdIndex].VB_StTVYFilterIndex;
+  if(ModeNo <= 0x13) {
+     index = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].VB_StTVYFilterIndex;
   } else {
-    index =  SiS_Pr->SiS_EModeIDTable[ModeIdIndex].VB_ExtTVYFilterIndex;
-  }
-
-  oldindex = index;
-
-  if((HwInfo->jChipType >= SIS_661) && ROMAddr && SiS_Pr->SiS_UseROM) {
-     if(ModeNo > 0x13) {
-        index =  SiS_Pr->SiS_EModeIDTable[ModeIdIndex].VB_ExtTVYFilterIndexROM661;
-     }
-     lindex = GetOEMTVPtr661_2(SiS_Pr);
-     if(lindex & 0x00ff0000) flag1 = 1;
-     if(lindex & 0xff000000) flag2 = 1;
-     lindex &= 0xffff;
-
-     /* NTSC-J: Use PAL filters */
-     if(SiS_Pr->SiS_TVMode & TVSetNTSCJ) lindex = 1;
-
-     romptr = ROMAddr[0x268] | (ROMAddr[0x269] << 8);
-     if(flag1) myindex = index * 7;
-     else      myindex = index << 2;
-
-     if(romptr) {
-        romptr += (lindex << 1);
-        romptr = (ROMAddr[romptr] | (ROMAddr[romptr+1] << 8)) + myindex;
-	if(romptr) {
-           if((!flag1) && (flag2)) {
-	      SiS_SetReg(SiS_Pr->SiS_Part2Port,0x35,0x00);
-	      SiS_SetReg(SiS_Pr->SiS_Part2Port,0x36,0x00);
-	      SiS_SetReg(SiS_Pr->SiS_Part2Port,0x37,0x00);
-	      SiS_SetReg(SiS_Pr->SiS_Part2Port,0x38,ROMAddr[romptr++]);
-           } else {
-	      for(i=0x35; i<=0x38; i++) {
-                 SiS_SetReg(SiS_Pr->SiS_Part2Port,i,ROMAddr[romptr++]);
-              }
-           }
-           if(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) {
-	      for(j=0, i=0x48; i<=0x4a; i++, j++) {
-                 SiS_SetReg(SiS_Pr->SiS_Part2Port,i,ROMAddr[romptr++]);
-              }
-           }
-           return;
-	}
-     }
+     index = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].VB_ExtTVYFilterIndex;
   }
 
-  index = oldindex;
-
-  temp = GetTVPtrIndex(SiS_Pr);
-  temp >>= 1;  			/* 0: NTSC/YPbPr, 1: PAL, 2: HiTV */
+  temp = GetTVPtrIndex(SiS_Pr) >> 1;  /* 0: NTSC/YPbPr, 1: PAL, 2: HiTV */
 
   if(SiS_Pr->SiS_TVMode & TVSetNTSCJ)	     temp = 1;  /* NTSC-J uses PAL */
   else if(SiS_Pr->SiS_TVMode & TVSetPALM)    temp = 3;  /* PAL-M */
@@ -11734,21 +10999,11 @@
   /* NTSC-J data not in BIOS, and already set in SetGroup2 */
   if(SiS_Pr->SiS_TVMode & TVSetNTSCJ) return;
 
-  if(HwInfo->jChipType >= SIS_661) {
-     lindex = GetOEMTVPtr661_2(SiS_Pr) & 0xffff;
+  if((HwInfo->jChipType >= SIS_661) || SiS_Pr->SiS_ROMNew) {
+     lindex = GetOEMTVPtr661_2_OLD(SiS_Pr) & 0xffff;
      lindex <<= 2;
-     if((ROMAddr) && SiS_Pr->SiS_UseROM) {
-        romptr = ROMAddr[0x264] | (ROMAddr[0x265] << 8);
-     }
-     if(romptr) {
-	romptr += lindex;
-	for(j=0, i=0x31; i<=0x34; i++, j++) {
-           SiS_SetReg(SiS_Pr->SiS_Part2Port,i,ROMAddr[romptr + j]);
-        }
-     } else {
-        for(j=0, i=0x31; i<=0x34; i++, j++) {
-           SiS_SetReg(SiS_Pr->SiS_Part2Port,i,SiS661_TVPhase[lindex + j]);
-        }
+     for(j=0, i=0x31; i<=0x34; i++, j++) {
+        SiS_SetReg(SiS_Pr->SiS_Part2Port,i,SiS661_TVPhase[lindex + j]);
      }
      return;
   }
@@ -11766,20 +11021,20 @@
   /* 0: NTSC Graphics, 1: NTSC Text,    2: PAL Graphics,
    * 3: PAL Text,      4: HiTV Graphics 5: HiTV Text
    */
-  if((ROMAddr) && SiS_Pr->SiS_UseROM) {
-     romptr = ROMAddr[0x116] | (ROMAddr[0x117] << 8);
+  if(SiS_Pr->SiS_UseROM) {
+     romptr = SISGETROMW(0x116);
      if(HwInfo->jChipType >= SIS_330) {
-        romptr = ROMAddr[0x196] | (ROMAddr[0x197] << 8);
+        romptr = SISGETROMW(0x196);
      }
      if(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) {
-        romptr = ROMAddr[0x11c] | (ROMAddr[0x11d] << 8);
+        romptr = SISGETROMW(0x11c);
 	if(HwInfo->jChipType >= SIS_330) {
-	   romptr = ROMAddr[0x19c] | (ROMAddr[0x19d] << 8);
+	   romptr = SISGETROMW(0x19c);
 	}
 	if((SiS_Pr->SiS_VBInfo & SetInSlaveMode) && (!(SiS_Pr->SiS_TVMode & TVSetTVSimuMode))) {
-	   romptr = ROMAddr[0x116] | (ROMAddr[0x117] << 8);
+	   romptr = SISGETROMW(0x116);
 	   if(HwInfo->jChipType >= SIS_330) {
-              romptr = ROMAddr[0x196] | (ROMAddr[0x197] << 8);
+              romptr = SISGETROMW(0x196);
            }
 	}
      }
@@ -11832,7 +11087,7 @@
       SetAntiFlicker(SiS_Pr,HwInfo,ModeNo,ModeIdIndex);
       SetPhaseIncr(SiS_Pr,HwInfo,ModeNo,ModeIdIndex);
       SetYFilter(SiS_Pr,HwInfo,ModeNo,ModeIdIndex);
-      if(!(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV)) {
+      if(SiS_Pr->SiS_VBType & VB_SIS301) {
          SetEdgeEnhance(SiS_Pr,HwInfo,ModeNo,ModeIdIndex);
       }
    }
@@ -11842,65 +11097,108 @@
 SetDelayComp661(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo, USHORT ModeNo,
                 USHORT ModeIdIndex, USHORT RTI)
 {
-   UCHAR  *ROMAddr = HwInfo->pjVirtualRomBase;
    USHORT delay = 0, romptr = 0, index;
-   UCHAR  *myptr = NULL;
-   UCHAR  temp;
+   UCHAR  *ROMAddr = HwInfo->pjVirtualRomBase;
 
    if(!(SiS_Pr->SiS_VBInfo & (SetCRT2ToTV | SetCRT2ToLCD | SetCRT2ToLCDA | SetCRT2ToRAMDAC)))
       return;
 
-   delay = SiS_Pr->SiS_RefIndex[RTI].Ext_PDC;
+   /* 1. New ROM: VGA2 and LCD/LCDA-Pass1:1 */
+
+   if(SiS_Pr->SiS_ROMNew) {
+      if((SiS_Pr->SiS_VBInfo & SetCRT2ToRAMDAC) 			||
+         ((SiS_Pr->SiS_VBInfo & (SetCRT2ToLCD | SetCRT2ToLCDA)) &&
+	  (SiS_Pr->SiS_LCDInfo & LCDPass11))) {
+         index = 25;
+         if(SiS_Pr->UseCustomMode) {
+	    index = SiS_Pr->CSRClock;
+         } else if(ModeNo > 0x13) {
+            index = SiS_GetVCLK2Ptr(SiS_Pr,ModeNo,ModeIdIndex,RTI,HwInfo);
+            index = SiS_Pr->SiS_VCLKData[index].CLOCK;
+         }
+	 if(index < 25) index = 25;
+         index = ((index / 25) - 1) << 1;
+         if((ROMAddr[0x5b] & 0x80) || (SiS_Pr->SiS_VBInfo & (SetCRT2ToRAMDAC | SetCRT2ToLCD))) {
+	    index++;
+	 }
+	 romptr = SISGETROMW(0x104);  /* 0x4ae */
+         delay = ROMAddr[romptr + index];
+         if(SiS_Pr->SiS_VBInfo & (SetCRT2ToRAMDAC | SetCRT2ToLCD)) {
+            SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x2d,0xf0,((delay >> 1) & 0x0f));
+            SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x35,0x7f,((delay & 0x01) << 7));
+         } else {
+            SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x2d,0x0f,((delay << 3) & 0xf0));
+	    SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x20,0xbf,((delay & 0x01) << 6));
+         }
+         return;
+      }
+   }
+
+   /* 2. Old ROM: VGA2 and LCD/LCDA-Pass 1:1 */
 
-   delay &= 0xf0;
-   delay >>= 4;
-   if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCDA) delay <<= 12;  /* BIOS: 8, wrong */
+   if(SiS_Pr->UseCustomMode) delay = 0x04;
+   else if(ModeNo <= 0x13)   delay = 0x04;
+   else                      delay = (SiS_Pr->SiS_RefIndex[RTI].Ext_PDC >> 4);
+   delay |= (delay << 8);
 
    if(SiS_Pr->SiS_VBInfo & SetCRT2ToTV) {
+
+      /* 3. TV */
+
       index = GetOEMTVPtr661(SiS_Pr);
-      if((ROMAddr) && SiS_Pr->SiS_UseROM) {
-         romptr = ROMAddr[0x25c] | (ROMAddr[0x25d] << 8);
-         if(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) {
-            romptr = ROMAddr[0x25e] | (ROMAddr[0x25f] << 8);
-         }
-      }
-      if(romptr) myptr = &ROMAddr[romptr];
-      if(!myptr) {
-         myptr = (UCHAR *)SiS_TVDelay661_301;
-	 if(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) {
-	    myptr = (UCHAR *)SiS_TVDelay661_301B;
-	 }
+      if(SiS_Pr->SiS_ROMNew) {
+         romptr = SISGETROMW(0x106);  /* 0x4ba */
+         delay = ROMAddr[romptr + index];
+      } else {
+         delay = 0x04;
       }
-      delay = myptr[index];
-      if(SiS_GetReg(SiS_Pr->SiS_Part1Port,0x13) & 0x04) delay >>= 4;  /* Should test dual edge */
+
    } else if(SiS_Pr->SiS_VBInfo & (SetCRT2ToLCD | SetCRT2ToLCDA)) {
-      if(SiS_Pr->PDC) {
-         delay = SiS_Pr->PDC & 0x0f;
-	 if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCDA) {
-            delay |= (delay << 12);
+
+      /* 4. LCD, LCDA (for new ROM only LV and non-Pass 1:1) */
+
+      if( (SiS_Pr->SiS_LCDResInfo != Panel_Custom) &&
+          ((romptr = GetLCDStructPtr661_2(SiS_Pr, HwInfo))) ) {
+
+	 /* For LV, the BIOS must know about the correct value */
+	 delay = ROMAddr[romptr + 0x0d];		/* LCD  */
+	 delay |= (ROMAddr[romptr + 0x0c] << 8);	/* LCDA */
+
+      } else {
+
+         /* TMDS: Set our own, since BIOS has no idea - TODO: Find out about values */
+         if(!(SiS_Pr->SiS_LCDInfo & LCDPass11)) {
+            if((SiS_Pr->PanelXRes <= 1024) && (SiS_Pr->PanelYRes <= 768)) {
+	       delay = 0x0404;
+            } else if((SiS_Pr->PanelXRes <= 1280) && (SiS_Pr->PanelYRes <= 1024)) {
+	       delay = 0x0404;
+            } else if((SiS_Pr->PanelXRes <= 1400) && (SiS_Pr->PanelYRes <= 1050)) {
+	       delay = 0x1004;
+            } else
+	       delay = 0x0000;
+         }
+
+	 /* Override by detected or user-set values */
+	 /* (but only if, for some reason, we can't read value from BIOS) */
+         if((SiS_Pr->SiS_VBInfo & SetCRT2ToLCD) && (SiS_Pr->PDC != -1)) {
+            delay = SiS_Pr->PDC & 0x1f;
          }
-      } else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_PanelCustom) {
-         delay = 0x4444;  /* TEST THIS */
-      } else if(!(SiS_Pr->SiS_LCDInfo & LCDPass11)) {
-         myptr = GetLCDStructPtr661(SiS_Pr, HwInfo);
-         if(myptr) delay = myptr[4];
-         else delay = 0x44;
-         if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCDA) {
-            delay |= (delay << 8);
+         if((SiS_Pr->SiS_VBInfo & SetCRT2ToLCDA) && (SiS_Pr->PDCA != -1)) {
+            delay = (SiS_Pr->PDCA & 0x1f) << 8;
          }
+
       }
-   }
 
-   temp = SiS_GetReg(SiS_Pr->SiS_Part1Port,0x2d);
-   if(SiS_Pr->SiS_VBInfo & (SetCRT2ToTV | SetCRT2ToLCD | SetCRT2ToRAMDAC)) {
-      temp &= 0xf0;
-      temp |= (delay & 0x000f);
    }
+
    if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCDA) {
-      temp &= 0x0f;
-      temp |= ((delay & 0xf000) >> 8);
+      delay >>= 8;
+      SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x2d,0x0f,((delay << 3) & 0xf0));
+      SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x20,0xbf,((delay & 0x01) << 6));
+   } else {
+      SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x2d,0xf0,((delay >> 1) & 0x0f));
+      SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x35,0x7f,((delay & 0x01) << 7));
    }
-   SiS_SetReg(SiS_Pr->SiS_Part1Port,0x2d,temp);
 }
 
 static void
@@ -11909,38 +11207,50 @@
    USHORT infoflag;
    UCHAR temp;
 
-   infoflag = SiS_Pr->SiS_RefIndex[RTI].Ext_InfoFlag;
-   if(ModeNo <= 0x13) {
-      infoflag = SiS_GetRegByte(SiS_Pr->SiS_P3ca+2);
-   }
-   infoflag &= 0xc0;
    if(SiS_Pr->SiS_VBInfo & (SetCRT2ToLCD | SetCRT2ToLCDA)) {
+
+      if(ModeNo <= 0x13) {
+         infoflag = SiS_GetRegByte(SiS_Pr->SiS_P3ca+2);
+      } else if(SiS_Pr->UseCustomMode) {
+         infoflag = SiS_Pr->CInfoFlag;
+      } else {
+         infoflag = SiS_Pr->SiS_RefIndex[RTI].Ext_InfoFlag;
+      }
+      infoflag &= 0xc0;
+
       temp = SiS_GetReg(SiS_Pr->SiS_P3d4,0x37);
-      if(temp & 0x20) infoflag = temp;
+      if(SiS_Pr->SiS_LCDInfo & LCDPass11) {
+         temp &= 0x3f;
+	 temp |= infoflag;
+      } else {
+         if(temp & 0x20) infoflag = temp;
+      }
       if(temp & 0x01) infoflag |= 0x01;
-   }
-   if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCD) {
-      temp = 0x0c;
-      if(infoflag & 0x01) temp ^= 0x14;  /* BIOS: 18, wrong */
-      temp |= (infoflag >> 6);
-      SiS_SetRegANDOR(SiS_Pr->SiS_Part2Port,0x1a,0xe0,temp);
-   }
-   if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCDA) {
-      temp = 0;
-      if(infoflag & 0x01) temp |= 0x80;
-      SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x1a,0x7f,temp);
-      temp = 0x30;
-      if(infoflag & 0x01) temp = 0x20;
-      infoflag &= 0xc0;
-      temp |= infoflag;
-      SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x19,0x0f,temp);
+
+      if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCD) {
+         temp = 0x0c;
+         if(infoflag & 0x01) temp ^= 0x14;  /* BIOS: 18, wrong */
+         temp |= (infoflag >> 6);
+         SiS_SetRegANDOR(SiS_Pr->SiS_Part2Port,0x1a,0xe0,temp);
+      } else {
+         temp = 0;
+         if(infoflag & 0x01) temp |= 0x80;
+         SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x1a,0x7f,temp);
+         temp = 0x30;
+         if(infoflag & 0x01) temp = 0x20;
+         infoflag &= 0xc0;
+         temp |= infoflag;
+         SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x19,0x0f,temp);
+      }
+
    }
 }
 
 static void
 SetPanelParms661(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo)
 {
-   UCHAR *myptr;
+   UCHAR  *ROMAddr = HwInfo->pjVirtualRomBase;
+   USHORT romptr, temp1, temp2;
 
    if(SiS_Pr->SiS_VBType & (VB_SIS301LV | VB_SIS302LV | VB_SIS302ELV)) {
       if(SiS_Pr->LVDSHL != -1) {
@@ -11948,16 +11258,24 @@
       }
    }
 
-   myptr = GetLCDStructPtr661(SiS_Pr, HwInfo);
-   if(myptr) {
-      if(SiS_Pr->SiS_VBType & (VB_SIS301LV | VB_SIS302LV | VB_SIS302ELV)) {
-         if(SiS_Pr->LVDSHL == -1) {
-            SiS_SetRegANDOR(SiS_Pr->SiS_Part4Port,0x24,0xE0,myptr[1] & 0x1f);
-	 } else {
-	    SiS_SetRegANDOR(SiS_Pr->SiS_Part4Port,0x24,0xE3,myptr[1] & 0x1c);
+   if(SiS_Pr->SiS_ROMNew) {
+
+      if((romptr = GetLCDStructPtr661_2(SiS_Pr, HwInfo))) {
+         if(SiS_Pr->SiS_VBType & (VB_SIS301LV | VB_SIS302LV | VB_SIS302ELV)) {
+            temp1 = (ROMAddr[romptr] & 0x03) | 0x0c;
+	    temp2 = 0xfc;
+	    if(SiS_Pr->LVDSHL != -1) {
+	      temp1 &= 0xfc;
+	      temp2 = 0xf3;
+	    }
+	    SiS_SetRegANDOR(SiS_Pr->SiS_Part4Port,0x24,temp2,temp1);
+         }
+	 if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCD) {
+            temp1 = (ROMAddr[romptr + 1] & 0x80) >> 1;
+            SiS_SetRegANDOR(SiS_Pr->SiS_Part4Port,0x0d,0xbf,temp1);
 	 }
       }
-      SiS_SetRegANDOR(SiS_Pr->SiS_Part4Port,0x0d,0x3f,myptr[2] & 0xc0);
+
    }
 }
 
@@ -11978,7 +11296,7 @@
          SetPhaseIncr(SiS_Pr,HwInfo,ModeNo,ModeIdIndex);
          SetYFilter(SiS_Pr,HwInfo,ModeNo,ModeIdIndex);
          SetAntiFlicker(SiS_Pr,HwInfo,ModeNo,ModeIdIndex);
-         if(!(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV)) {
+         if(SiS_Pr->SiS_VBType & VB_SIS301) {
             SetEdgeEnhance(SiS_Pr,HwInfo,ModeNo,ModeIdIndex);
          }
       }
@@ -12007,7 +11325,7 @@
      }
   }
 
-  if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_PanelCustom) return;
+  if(SiS_Pr->SiS_LCDResInfo == Panel_Custom) return;
   if(SiS_Pr->UseCustomMode) return;
 
   switch(SiS_Pr->SiS_CustomT) {
@@ -12037,7 +11355,7 @@
   }
 
   if(SiS_Pr->SiS_CustomT == CUT_CLEVO1024) {
-     if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1024x768) {
+     if(SiS_Pr->SiS_LCDResInfo == Panel_1024x768) {
         /* Maybe all panels? */
         if(SiS_Pr->LVDSHL == -1) {
            SiS_SetRegANDOR(SiS_Pr->SiS_Part4Port,0x24,0xfc,0x01);
@@ -12048,7 +11366,7 @@
 
   if(SiS_Pr->SiS_CustomT == CUT_CLEVO10242) {
      if(SiS_Pr->SiS_VBInfo & (SetCRT2ToLCD | SetCRT2ToLCDA)) {
-        if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1024x768) {
+        if(SiS_Pr->SiS_LCDResInfo == Panel_1024x768) {
 	   if(SiS_Pr->LVDSHL == -1) {
 	      /* Maybe all panels? */
               SiS_SetRegANDOR(SiS_Pr->SiS_Part4Port,0x24,0xfc,0x01);
@@ -12068,15 +11386,15 @@
   }
 
   if(SiS_Pr->SiS_VBInfo & (SetCRT2ToLCD | SetCRT2ToLCDA)) {
-     if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1024x768) {
-#ifdef SET_EMI
+     if(SiS_Pr->SiS_LCDResInfo == Panel_1024x768) {
 	if(SiS_Pr->SiS_VBType & (VB_SIS302LV | VB_SIS302ELV)) {
 	   SiS_SetReg(SiS_Pr->SiS_Part4Port,0x2a,0x00);
+#ifdef SET_EMI
 	   SiS_SetRegAND(SiS_Pr->SiS_Part4Port,0x30,0x0c);
+#endif
 	   SiS_SetReg(SiS_Pr->SiS_Part4Port,0x34,0x10);
 	}
-#endif
-     } else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1280x1024) {
+     } else if(SiS_Pr->SiS_LCDResInfo == Panel_1280x1024) {
         if(SiS_Pr->LVDSHL == -1) {
            /* Maybe ACER only? */
            SiS_SetRegANDOR(SiS_Pr->SiS_Part4Port,0x24,0xfc,0x01);
@@ -12084,9 +11402,9 @@
      }
      tempch = SiS_GetReg(SiS_Pr->SiS_P3d4,0x36) >> 4;
      if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCDA) {
-	if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1400x1050) {
+	if(SiS_Pr->SiS_LCDResInfo == Panel_1400x1050) {
 	   SiS_SetReg(SiS_Pr->SiS_Part1Port,0x1f,0x76);
-	} else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1024x768) {
+	} else if(SiS_Pr->SiS_LCDResInfo == Panel_1024x768) {
 	   if(tempch == 0x03) {
 	      SiS_SetReg(SiS_Pr->SiS_Part1Port,0x18,0x02);
 	      SiS_SetReg(SiS_Pr->SiS_Part1Port,0x1b,0x25);
@@ -12167,7 +11485,7 @@
 	tempbh >>= 4;
 	tempbl = SiS_GetReg(SiS_Pr->SiS_Part2Port,0x04);
 	tempbx = (tempbh << 8) | tempbl;
-	if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1024x768) {
+	if(SiS_Pr->SiS_LCDResInfo == Panel_1024x768) {
 	   if((resinfo == SIS_RI_1024x768) || (!(SiS_Pr->SiS_LCDInfo & DontExpandLCD))) {
 	      if(SiS_Pr->SiS_SetFlag & LCDVESATiming) {
 	      	 tempbx = 770;
@@ -12258,19 +11576,16 @@
 
     tempbx = (SiS_GetReg(SiS_Pr->SiS_P3d4,0x36) & 0x0f) - 2;
     if(!(SiS_Pr->SiS_SetFlag & LCDVESATiming)) tempbx += 4;
-    if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1024x768) {
+    if(SiS_Pr->SiS_LCDResInfo == Panel_1024x768) {
        if(SiS_Pr->SiS_LCDInfo & DontExpandLCD) tempbx += 3;
     }
-    if((ROMAddr) && SiS_Pr->SiS_UseROM) {
+    if(SiS_Pr->SiS_UseROM) {
        if(ROMAddr[0x235] & 0x80) {
           tempbx = SiS_Pr->SiS_LCDTypeInfo;
           if(Flag) {
-	     romptr = ROMAddr[0x255] | (ROMAddr[0x256] << 8);
-	     if(romptr) {
-	        tempbx = ROMAddr[romptr + SiS_Pr->SiS_LCDTypeInfo];
-	     } else {
-	        tempbx = customtable300[SiS_Pr->SiS_LCDTypeInfo];
-	     }
+	     romptr = SISGETROMW(0x255);
+	     if(romptr) tempbx = ROMAddr[romptr + SiS_Pr->SiS_LCDTypeInfo];
+	     else       tempbx = customtable300[SiS_Pr->SiS_LCDTypeInfo];
              if(tempbx == 0xFF) return 0xFFFF;
           }
 	  tempbx <<= 1;
@@ -12281,13 +11596,10 @@
   } else {
 
     if(Flag) {
-       if((ROMAddr) && SiS_Pr->SiS_UseROM) {
-          romptr = ROMAddr[0x255] | (ROMAddr[0x256] << 8);
-	  if(romptr) {
-	     tempbx = ROMAddr[romptr + SiS_Pr->SiS_LCDTypeInfo];
-	  } else {
-	     tempbx = 0xff;
-	  }
+       if(SiS_Pr->SiS_UseROM) {
+          romptr = SISGETROMW(0x255);
+	  if(romptr) tempbx = ROMAddr[romptr + SiS_Pr->SiS_LCDTypeInfo];
+	  else 	     tempbx = 0xff;
        } else {
           tempbx = customtable630[SiS_Pr->SiS_LCDTypeInfo];
        }
@@ -12311,12 +11623,12 @@
   UCHAR  *ROMAddr = HwInfo->pjVirtualRomBase;
   USHORT index,temp,romptr=0;
 
-  if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_PanelCustom) return;
+  if(SiS_Pr->SiS_LCDResInfo == Panel_Custom) return;
 
-  if((ROMAddr) && SiS_Pr->SiS_UseROM) {
+  if(SiS_Pr->SiS_UseROM) {
      if(!(ROMAddr[0x237] & 0x01)) return;
      if(!(ROMAddr[0x237] & 0x02)) return;
-     romptr = ROMAddr[0x24b] | (ROMAddr[0x24c] << 8);
+     romptr = SISGETROMW(0x24b);
   }
 
   /* The Panel Compensation Delay should be set according to tables
@@ -12326,7 +11638,7 @@
    * Thus we don't set this if the user select a custom pdc or if
    * we otherwise detected a valid pdc.
    */
-  if(SiS_Pr->PDC) return;
+  if(SiS_Pr->PDC != -1) return;
 
   temp = GetOEMLCDPtr(SiS_Pr,HwInfo, 0);
 
@@ -12338,7 +11650,7 @@
   if(HwInfo->jChipType != SIS_300) {
      if(romptr) {
 	romptr += (temp * 2);
-	romptr = ROMAddr[romptr] | (ROMAddr[romptr + 1] << 8);
+	romptr = SISGETROMW(romptr);
 	romptr += index;
 	temp = ROMAddr[romptr];
      } else {
@@ -12349,21 +11661,21 @@
         }
      }
   } else {
-     if((ROMAddr) && SiS_Pr->SiS_UseROM && (ROMAddr[0x235] & 0x80)) {
+     if(SiS_Pr->SiS_UseROM && (ROMAddr[0x235] & 0x80)) {
 	if(romptr) {
 	   romptr += (temp * 2);
-	   romptr = ROMAddr[romptr] | (ROMAddr[romptr + 1] << 8);
+	   romptr = SISGETROMW(romptr);
 	   romptr += index;
 	   temp = ROMAddr[romptr];
 	} else {
 	   temp = SiS300_OEMLCDDelay5[temp][index];
 	}
      } else {
-        if((ROMAddr) && SiS_Pr->SiS_UseROM) {
+        if(SiS_Pr->SiS_UseROM) {
 	   romptr = ROMAddr[0x249] | (ROMAddr[0x24a] << 8);
 	   if(romptr) {
 	      romptr += (temp * 2);
-	      romptr = ROMAddr[romptr] | (ROMAddr[romptr + 1] << 8);
+	      romptr = SISGETROMW(romptr);
 	      romptr += index;
 	      temp = ROMAddr[romptr];
 	   } else {
@@ -12386,7 +11698,7 @@
   UCHAR  *ROMAddr = HwInfo->pjVirtualRomBase;
   USHORT index,temp;
 
-  if((ROMAddr) && SiS_Pr->SiS_UseROM) {
+  if((SiS_Pr->SiS_UseROM) {
      if(!(ROMAddr[0x237] & 0x01)) return;
      if(!(ROMAddr[0x237] & 0x04)) return;
      /* No rom pointer in BIOS header! */
@@ -12436,10 +11748,10 @@
   UCHAR  *ROMAddr = HwInfo->pjVirtualRomBase;
   USHORT index,temp,romptr=0;
 
-  if((ROMAddr) && SiS_Pr->SiS_UseROM) {
+  if(SiS_Pr->SiS_UseROM) {
      if(!(ROMAddr[0x238] & 0x01)) return;
      if(!(ROMAddr[0x238] & 0x02)) return;
-     romptr = ROMAddr[0x241] | (ROMAddr[0x242] << 8);
+     romptr = SISGETROMW(0x241);
   }
 
   temp = GetOEMTVPtr(SiS_Pr);
@@ -12448,7 +11760,7 @@
 
   if(romptr) {
      romptr += (temp * 2);
-     romptr = ROMAddr[romptr] | (ROMAddr[romptr + 1] << 8);
+     romptr = SISGETROMW(romptr);
      romptr += index;
      temp = ROMAddr[romptr];
   } else {
@@ -12459,7 +11771,7 @@
      }
   }
   temp &= 0x3c;
-  SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x13,~0x3C,temp);  /* index 0A D[6:4] */
+  SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x13,~0x3C,temp);
 }
 
 static void
@@ -12469,10 +11781,10 @@
   UCHAR  *ROMAddr = HwInfo->pjVirtualRomBase;
   USHORT index,temp,romptr=0;
 
-  if((ROMAddr) && SiS_Pr->SiS_UseROM) {
+  if(SiS_Pr->SiS_UseROM) {
      if(!(ROMAddr[0x238] & 0x01)) return;
      if(!(ROMAddr[0x238] & 0x04)) return;
-     romptr = ROMAddr[0x243] | (ROMAddr[0x244] << 8);
+     romptr = SISGETROMW(0x243);
   }
 
   temp = GetOEMTVPtr(SiS_Pr);
@@ -12481,14 +11793,14 @@
 
   if(romptr) {
      romptr += (temp * 2);
-     romptr = ROMAddr[romptr] | (ROMAddr[romptr + 1] << 8);
+     romptr = SISGETROMW(romptr);
      romptr += index;
      temp = ROMAddr[romptr];
   } else {
      temp = SiS300_OEMTVFlicker[temp][index];
   }
   temp &= 0x70;
-  SiS_SetRegANDOR(SiS_Pr->SiS_Part2Port,0x0A,0x8F,temp);  /* index 0A D[6:4] */
+  SiS_SetRegANDOR(SiS_Pr->SiS_Part2Port,0x0A,0x8F,temp);
 }
 
 static void
@@ -12502,10 +11814,10 @@
 
   if(SiS_Pr->SiS_TVMode & (TVSetNTSC1024 | TVSetNTSCJ | TVSetPALM | TVSetPALN)) return;
 
-  if((ROMAddr) && SiS_Pr->SiS_UseROM) {
+  if(SiS_Pr->SiS_UseROM) {
      if(!(ROMAddr[0x238] & 0x01)) return;
      if(!(ROMAddr[0x238] & 0x08)) return;
-     romptr = ROMAddr[0x245] | (ROMAddr[0x246] << 8);
+     romptr = SISGETROMW(0x245);
   }
 
   temp = GetOEMTVPtr(SiS_Pr);
@@ -12519,7 +11831,7 @@
   } else {
      if(romptr) {
         romptr += (temp * 2);
-	romptr = ROMAddr[romptr] | (ROMAddr[romptr + 1] << 8);
+	romptr = SISGETROMW(romptr);
 	romptr += (index * 4);
         for(i=0x31, j=0; i<=0x34; i++, j++) {
 	   SiS_SetReg(SiS_Pr->SiS_Part2Port,i,ROMAddr[romptr + j]);
@@ -12541,10 +11853,10 @@
 
   if(SiS_Pr->SiS_VBInfo & (SetCRT2ToSCART | SetCRT2ToHiVision | SetCRT2ToYPbPr525750)) return;
 
-  if((ROMAddr) && SiS_Pr->SiS_UseROM) {
+  if(SiS_Pr->SiS_UseROM) {
      if(!(ROMAddr[0x238] & 0x01)) return;
      if(!(ROMAddr[0x238] & 0x10)) return;
-     romptr = ROMAddr[0x247] | (ROMAddr[0x248] << 8);
+     romptr = SISGETROMW(0x247);
   }
 
   temp = GetOEMTVPtr(SiS_Pr);
@@ -12565,7 +11877,7 @@
   } else {
       if((romptr) && (!(SiS_Pr->SiS_TVMode & (TVSetPALM|TVSetPALN)))) {
          romptr += (temp * 2);
-	 romptr = ROMAddr[romptr] | (ROMAddr[romptr + 1] << 8);
+	 romptr = SISGETROMW(romptr);
 	 romptr += (index * 4);
 	 for(i=0x35, j=0; i<=0x38; i++, j++) {
        	    SiS_SetReg(SiS_Pr->SiS_Part2Port,i,ROMAddr[romptr + j]);
--- diff/drivers/video/sis/init301.h	2004-05-19 22:12:23.000000000 +0100
+++ source/drivers/video/sis/init301.h	2004-06-11 19:22:05.000000000 +0100
@@ -1,4 +1,5 @@
 /* $XFree86$ */
+/* $XdotOrg$ */
 /*
  * Data and prototypes for init301.c
  *
@@ -31,13 +32,10 @@
  * * 2) Redistributions in binary form must reproduce the above copyright
  * *    notice, this list of conditions and the following disclaimer in the
  * *    documentation and/or other materials provided with the distribution.
- * * 3) All advertising materials mentioning features or use of this software
- * *    must display the following acknowledgement: "This product includes
- * *    software developed by Thomas Winischhofer, Vienna, Austria."
- * * 4) The name of the author may not be used to endorse or promote products
+ * * 3) The name of the author may not be used to endorse or promote products
  * *    derived from this software without specific prior written permission.
  * *
- * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESSED OR
  * * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
  * * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
  * * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
@@ -91,29 +89,41 @@
     0x06,0x14,0x0d,0x04,0x0a,0x00,0x85,0x1b,
     0x0c,0x50,0x00,0x97,0x00,0xda,0x4a,0x17,
     0x7d,0x05,0x4b,0x00,0x00,0xe2,0x00,0x02,
-    0x03,0x0a,0x65,0x9d,0x08,0x92,0x8f,0x40,
-    0x60,0x80,0x14,0x90,0x8c,0x60,0x14,0x53,
+    0x03,0x0a,0x65,0x9d /*0x8d*/,0x08,0x92,0x8f,0x40,
+    0x60,0x80,0x14,0x90,0x8c,0x60,0x14,0x53 /*0x50*/,
     0x00,0x40,0x44,0x00,0xdb,0x02,0x3b,0x00
   },
   {
     0x1d,0x11,0x06,0x09,0x0b,0x0c,0x0c,0x0c,
     0x98,0x0a,0x01,0x0d,0x06,0x0d,0x04,0x0a,
     0x06,0x14,0x0d,0x04,0x0a,0x00,0x85,0x3f,
-    0x0c,0x50,0xb2,0x9f,0x16,0x59,0x4f,0x13,
+    0x0c,0x50,0xb2,0x9f,0x16,0x59,0x4c /*0x4f*/,0x13,
     0xad,0x11,0xad,0x1d,0x40,0x8a,0x3d,0xb8,
-    0x51,0x5e,0x60,0x49,0x7d,0x92,0x0f,0x40,
+    0x51,0x5e,0x60,0x57 /*0x49*/,0x7b /*0x7d*/,0x92,0x0f,0x40,
     0x60,0x80,0x14,0x90,0x8c,0x60,0x14,0x4b,
     0x43,0x41,0x11,0x00,0xfc,0xff,0x32,0x00
   },
   {
+#if 1
     0x13,0x1d,0xe8,0x09,0x09,0xed,0x0c,0x0c,
     0x98,0x0a,0x01,0x0c,0x06,0x0d,0x04,0x0a,
     0x06,0x14,0x0d,0x04,0x0a,0x00,0x85,0x3f,
-    0xed,0x50,0x70,0x9f,0x16,0x59,0x2b,0x13,
+    0xed,0x50,0x70,0x9f,0x16,0x59,0x21 /*0x2b*/,0x13,
     0x27,0x0b,0x27,0xfc,0x30,0x27,0x1c,0xb0,
-    0x4b,0x4b,0x6f,0x2f,0x63,0x92,0x0f,0x40,
+    0x4b,0x4b,0x65 /*0x6f*/,0x2f,0x63,0x92,0x0f,0x40,
     0x60,0x80,0x14,0x90,0x8c,0x60,0x14,0x27,
     0x00,0x40,0x11,0x00,0xfc,0xff,0x32,0x00
+#endif
+#if 0
+    0x2a,0x14,0xe8,0x09,0x09,0xed,0x0c,0x0c,  /* TEST (0.93) - BAD */
+    0x98,0x0a,0x01,0x0c,0x06,0x0d,0x04,0x0a,
+    0x06,0x14,0x0d,0x04,0x0a,0x00,0x85,0x3f,
+    0xed,0x50,0x70,0x9e,0x16,0x57,0x6c,0x13,
+    0x27,0x0b,0x27,0xfb,0x30,0x27,0x15,0xb0,
+    0x3b,0xdb,0x61,0x24,0x78,0x92,0x0f,0xff,
+    0xff,0xff,0xff,0xff,0xff,0xff,0x14,0x6f,
+    0x00,0x52,0xbb,0x00,0xd5,0xf7,0xa2,0x00
+#endif
   }
 };
 
@@ -139,7 +149,7 @@
     0x18, 0x1d, 0x23, 0x28, 0x4c, 0xaa, 0x01
 };
 
-/* 301C / 302ELV (?) extended Part2 TV registers */
+/* 301C / 302ELV extended Part2 TV registers */
 
 static const UCHAR SiS_Part2CLVX_1[] = {
     0x00,0x00,
@@ -208,28 +218,84 @@
     0x00,0x04,
     0x04,0x1A,0x04,0x7E,0x02,0x1B,0x05,0x7E,0x01,0x1A,0x07,0x7E,0x00,0x1A,0x09,0x7D,
     0x7F,0x19,0x0B,0x7D,0x7E,0x18,0x0D,0x7D,0x7D,0x17,0x10,0x7C,0x7D,0x15,0x12,0x7C,
-    0x7C,0x14,0x14,0x7C,0x7C,0x12,0x15,0x7D,0x7C,0x10,0x17,0x1D /* 0x7D? */ ,0x7C,0x0D,0x18,0x7F,
+    0x7C,0x14,0x14,0x7C,0x7C,0x12,0x15,0x7D,0x7C,0x10,0x17,0x7D,0x7C,0x0D,0x18,0x7F,
     0x7D,0x0B,0x19,0x7F,0x7D,0x09,0x1A,0x00,0x7D,0x07,0x1A,0x02,0x7E,0x05,0x1B,0x02,
     0xFF,0xFF,
 };
 
-
 #ifdef SIS315H
-/* 661 et al LCD data structure */
+/* 661 et al LCD data structure (0.94.0) */
 static const UCHAR SiS_LCDStruct661[] = {
-    /* 1600x1200 */
-    0x0B,0xEA,0x81,0x10,0x00,0xC0,0x03,0x21,0x5A,0x23,0x5A,0x23,0x02,
-    0x14,0x0A,0x02,0x00,0x30,0x10,0x5A,0x10,0x10,0x0A,0xC0,0x30,0x10,
-    /* 1400x1050 */
-    0x09,0xEA,0x81,0x80,0xA3,0x70,0x03,0x19,0xD2,0x2A,0xF8,0x2F,0x02,
-    0x14,0x0A,0x02,0x00,0x30,0x10,0x5A,0x10,0x10,0x0A,0xC0,0x30,0x10,
-    /* 1280x1024 */
-    0x03,0xEA,0x81,0x40,0xA1,0x70,0x03,0x19,0xD2,0x2A,0xF8,0x2F,0x02,
-    0x14,0x0A,0x02,0x00,0x30,0x10,0x5A,0x10,0x10,0x0A,0xC0,0x30,0x10,
     /* 1024x768 */
-    0x02,0xEA,0x80,0x00,0x11,0x88,0x06,0x0B,0xF5,0x6C,0x35,0x62,0x02,
-    0x14,0x0A,0x02,0x00,0x30,0x10,0x5A,0x10,0x10,0x0A,0xC0,0x28,0x10,
-    0xFF,
+/*  type|CR37|   HDE   |   VDE   |    HT   |    VT   |   hss    | hse   */
+    0x02,0xC0,0x00,0x04,0x00,0x03,0x40,0x05,0x26,0x03,0x10,0x00,0x88,
+    0x00,0x02,0x00,0x06,0x00,0x41,0x5A,0x64,0x00,0x00,0x00,0x00,0x04,
+    /*  | vss      |   vse  |clck|  clock  |CRT2DataP|CRT2DataP|idx     */
+    /*					      VESA    non-VESA  noscale */
+    /* 1280x1024 */
+    0x03,0xC0,0x00,0x05,0x00,0x04,0x98,0x06,0x2A,0x04,0x30,0x00,0x70,
+    0x00,0x01,0x00,0x03,0x00,0x6C,0xF8,0x2F,0x00,0x00,0x00,0x00,0x08,
+    /* 1400x1050 */
+    0x09,0x20,0x78,0x05,0x1A,0x04,0x98,0x06,0x2A,0x04,0x18,0x00,0x38,
+    0x00,0x01,0x00,0x03,0x00,0x6C,0xF8,0x2F,0x00,0x00,0x00,0x00,0x09,
+    /* 1600x1200 */
+    0x0B,0xC0,0x40,0x06,0xB0,0x04,0x70,0x08,0xE2,0x04,0x40,0x00,0xC0,
+    0x00,0x01,0x00,0x03,0x00,0xA2,0x70,0x24,0x00,0x00,0x00,0x00,0x0B,
+    /* 1280x768 */
+    0x0A,0xC0,0x00,0x05,0x00,0x03,0x80,0x05,0x26,0x03,0x10,0x00,0x40,
+    0x00,0x03,0x00,0x06,0x00,0x44,0x63,0x46,0x00,0x00,0x00,0x00,0x06,
+    /* 1280x720 */
+    0x0E,0xE0,0x00,0x05,0xD0,0x02,0x80,0x05,0x26,0x03,0x10,0x00,0x02,
+    0x00,0x01,0x00,0x06,0x00,0x45,0x9C,0x62,0x00,0x00,0x00,0x00,0x05,
+    /* 1280x800 */
+    0x0C,0xE0,0x00,0x05,0x20,0x03,0x80,0x05,0x30,0x03,0x10,0x00,0x40,
+    0x00,0x04,0x00,0x03,0x00,0x45,0x9C,0x62,0x00,0x00,0x00,0x00,0x07,
+    /* 1680x1050 */
+    0x0D,0xE0,0x90,0x06,0x1A,0x04,0x6C,0x07,0x2A,0x04,0x1A,0x00,0x4C,
+    0x00,0x03,0x00,0x06,0x00,0x79,0xBE,0x44,0x00,0x00,0x00,0x00,0x06,
+    /* 1280x768 (not in 0.93) */
+    0x0A,0xC0,0x00,0x05,0x00,0x03,0x80,0x06,0x1E,0x03,0x40,0x00,0x80,
+    0x00,0x03,0x00,0x07,0x00,0x4F,0x00,0x00,0x00,0x00,0x00,0x00,0x06
+};
+#endif
+
+#ifdef SIS300
+static UCHAR SiS300_TrumpionData[7][80] = {
+  { 0x02,0x0A,0x0A,0x01,0x04,0x01,0x00,0x03,0x0D,0x00,0x0D,0x10,0x7F,0x00,0x80,0x02,
+    0x20,0x03,0x0B,0x00,0x90,0x01,0xC1,0x01,0x60,0x0C,0x30,0x10,0x00,0x00,0x04,0x23,
+    0x00,0x00,0x03,0x28,0x03,0x10,0x05,0x08,0x40,0x10,0x00,0x10,0x04,0x23,0x00,0x23,
+    0x03,0x11,0x60,0xBC,0x01,0xFF,0x03,0xFF,0x19,0x01,0x00,0x05,0x09,0x04,0x04,0x05,
+    0x04,0x0C,0x09,0x05,0x02,0xB0,0x00,0x00,0x02,0xBA,0xF0,0x5A,0x01,0xBE,0x01,0x00 },
+  { 0x02,0x0A,0x0A,0x01,0x04,0x01,0x00,0x03,0x0D,0x00,0x0D,0x10,0x27,0x00,0x80,0x02,
+    0x20,0x03,0x07,0x00,0x5E,0x01,0x0D,0x02,0x60,0x0C,0x30,0x11,0x00,0x00,0x04,0x23,
+    0x00,0x00,0x03,0x80,0x03,0x28,0x06,0x08,0x40,0x11,0x00,0x11,0x04,0x23,0x00,0x23,
+    0x03,0x11,0x60,0x90,0x01,0xFF,0x0F,0xF4,0x19,0x01,0x00,0x05,0x01,0x00,0x04,0x05,
+    0x04,0x0C,0x02,0x01,0x02,0xB0,0x00,0x00,0x02,0xBA,0xEC,0x57,0x01,0xBE,0x01,0x00 },
+  { 0x02,0x0A,0x0A,0x01,0x04,0x01,0x00,0x03,0x0D,0x00,0x0D,0x10,0x8A,0x00,0xD8,0x02,
+    0x84,0x03,0x16,0x00,0x90,0x01,0xC1,0x01,0x60,0x0C,0x30,0x1C,0x00,0x20,0x04,0x23,
+    0x00,0x01,0x03,0x53,0x03,0x28,0x06,0x08,0x40,0x1C,0x00,0x16,0x04,0x23,0x00,0x23,
+    0x03,0x11,0x60,0xD9,0x01,0xFF,0x0F,0xF4,0x18,0x07,0x05,0x05,0x13,0x04,0x04,0x05,
+    0x01,0x0B,0x13,0x0A,0x02,0xB0,0x00,0x00,0x02,0xBA,0xF0,0x59,0x01,0xBE,0x01,0x00 },
+  { 0x02,0x0A,0x0A,0x01,0x04,0x01,0x00,0x03,0x0D,0x00,0x0D,0x10,0x72,0x00,0xD8,0x02,
+    0x84,0x03,0x16,0x00,0x90,0x01,0xC1,0x01,0x60,0x0C,0x30,0x1C,0x00,0x20,0x04,0x23,
+    0x00,0x01,0x03,0x53,0x03,0x28,0x06,0x08,0x40,0x1C,0x00,0x16,0x04,0x23,0x00,0x23,
+    0x03,0x11,0x60,0xDA,0x01,0xFF,0x0F,0xF4,0x18,0x07,0x05,0x05,0x13,0x04,0x04,0x05,
+    0x01,0x0B,0x13,0x0A,0x02,0xB0,0x00,0x00,0x02,0xBA,0xF0,0x55,0x01,0xBE,0x01,0x00 },
+  { 0x02,0x0A,0x02,0x00,0x04,0x01,0x00,0x03,0x0D,0x00,0x0D,0x10,0x7F,0x00,0x80,0x02,
+    0x20,0x03,0x16,0x00,0xE0,0x01,0x0D,0x02,0x60,0x0C,0x30,0x98,0x00,0x00,0x04,0x23,
+    0x00,0x01,0x03,0x45,0x03,0x48,0x06,0x08,0x40,0x98,0x00,0x98,0x04,0x23,0x00,0x23,
+    0x03,0x11,0x60,0xF4,0x01,0xFF,0x0F,0xF4,0x18,0x01,0x00,0x05,0x01,0x00,0x05,0x05,
+    0x04,0x0C,0x08,0x05,0x02,0xB0,0x00,0x00,0x02,0xBA,0xF0,0x5B,0x01,0xBE,0x01,0x00 },
+  { 0x02,0x0A,0x02,0x01,0x04,0x01,0x00,0x03,0x0D,0x00,0x0D,0x10,0xBF,0x00,0x20,0x03,
+    0x20,0x04,0x0D,0x00,0x58,0x02,0x71,0x02,0x80,0x0C,0x30,0x9A,0x00,0xFA,0x03,0x1D,
+    0x00,0x01,0x03,0x22,0x03,0x28,0x06,0x08,0x40,0x98,0x00,0x98,0x04,0x1D,0x00,0x1D,
+    0x03,0x11,0x60,0x39,0x03,0x40,0x05,0xF4,0x18,0x07,0x02,0x06,0x04,0x01,0x06,0x0B,
+    0x02,0x0A,0x20,0x19,0x02,0xB0,0x00,0x00,0x02,0xBA,0xF0,0x5B,0x01,0xBE,0x01,0x00 },
+  { 0x02,0x0A,0x0A,0x01,0x04,0x01,0x00,0x03,0x0D,0x00,0x0D,0x10,0xEF,0x00,0x00,0x04,
+    0x40,0x05,0x13,0x00,0x00,0x03,0x26,0x03,0x88,0x0C,0x30,0x90,0x00,0x00,0x04,0x23,
+    0x00,0x01,0x03,0x24,0x03,0x28,0x06,0x08,0x40,0x90,0x00,0x90,0x04,0x23,0x00,0x23,
+    0x03,0x11,0x60,0x40,0x05,0xFF,0x0F,0xF4,0x18,0x01,0x00,0x08,0x01,0x00,0x08,0x01,
+    0x00,0x08,0x01,0x01,0x02,0xB0,0x00,0x00,0x02,0xBA,0xF0,0x5B,0x01,0xBE,0x01,0x00 }
 };
 #endif
 
@@ -271,46 +337,51 @@
 void   	SiS_Chrontel701xBLOn(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo);
 void   	SiS_Chrontel701xBLOff(SiS_Private *SiS_Pr);
 #endif /* 315 */
+#ifdef SIS300
+void    SiS_SetTrumpReg(SiS_Private *SiS_Pr, USHORT tempbx);
+USHORT  SiS_GetTrumpReg(SiS_Private *SiS_Pr, USHORT tempbx);
+static  BOOLEAN SiS_SetTrumpionBlock(SiS_Private *SiS_Pr, UCHAR *dataptr);
+#endif
 
-USHORT   SiS_ReadDDC1Bit(SiS_Private *SiS_Pr);
-void     SiS_SetSwitchDDC2(SiS_Private *SiS_Pr);
-USHORT   SiS_SetStart(SiS_Private *SiS_Pr);
-USHORT   SiS_SetStop(SiS_Private *SiS_Pr);
-void     SiS_DDC2Delay(SiS_Private *SiS_Pr, USHORT delaytime);
-USHORT   SiS_SetSCLKLow(SiS_Private *SiS_Pr);
-USHORT   SiS_SetSCLKHigh(SiS_Private *SiS_Pr);
-USHORT   SiS_ReadDDC2Data(SiS_Private *SiS_Pr, USHORT tempax);
-USHORT   SiS_WriteDDC2Data(SiS_Private *SiS_Pr, USHORT tempax);
-USHORT   SiS_CheckACK(SiS_Private *SiS_Pr);
-
-USHORT   SiS_InitDDCRegs(SiS_Private *SiS_Pr, unsigned long VBFlags, int VGAEngine,
-                         USHORT adaptnum, USHORT DDCdatatype, BOOLEAN checkcr32);
-USHORT   SiS_WriteDABDDC(SiS_Private *SiS_Pr);
-USHORT   SiS_PrepareReadDDC(SiS_Private *SiS_Pr);
-USHORT   SiS_PrepareDDC(SiS_Private *SiS_Pr);
-void     SiS_SendACK(SiS_Private *SiS_Pr, USHORT yesno);
-USHORT   SiS_DoProbeDDC(SiS_Private *SiS_Pr);
-USHORT   SiS_ProbeDDC(SiS_Private *SiS_Pr);
-USHORT   SiS_ReadDDC(SiS_Private *SiS_Pr, USHORT DDCdatatype, unsigned char *buffer);
-USHORT   SiS_HandleDDC(SiS_Private *SiS_Pr, unsigned long VBFlags, int VGAEngine,
-		       USHORT adaptnum, USHORT DDCdatatype, unsigned char *buffer);
+USHORT  SiS_ReadDDC1Bit(SiS_Private *SiS_Pr);
+void    SiS_SetSwitchDDC2(SiS_Private *SiS_Pr);
+USHORT  SiS_SetStart(SiS_Private *SiS_Pr);
+USHORT  SiS_SetStop(SiS_Private *SiS_Pr);
+void    SiS_DDC2Delay(SiS_Private *SiS_Pr, USHORT delaytime);
+USHORT  SiS_SetSCLKLow(SiS_Private *SiS_Pr);
+USHORT  SiS_SetSCLKHigh(SiS_Private *SiS_Pr);
+USHORT  SiS_ReadDDC2Data(SiS_Private *SiS_Pr, USHORT tempax);
+USHORT  SiS_WriteDDC2Data(SiS_Private *SiS_Pr, USHORT tempax);
+USHORT  SiS_CheckACK(SiS_Private *SiS_Pr);
+
+USHORT  SiS_InitDDCRegs(SiS_Private *SiS_Pr, unsigned long VBFlags, int VGAEngine,
+                        USHORT adaptnum, USHORT DDCdatatype, BOOLEAN checkcr32);
+USHORT  SiS_WriteDABDDC(SiS_Private *SiS_Pr);
+USHORT  SiS_PrepareReadDDC(SiS_Private *SiS_Pr);
+USHORT  SiS_PrepareDDC(SiS_Private *SiS_Pr);
+void    SiS_SendACK(SiS_Private *SiS_Pr, USHORT yesno);
+USHORT  SiS_DoProbeDDC(SiS_Private *SiS_Pr);
+USHORT  SiS_ProbeDDC(SiS_Private *SiS_Pr);
+USHORT  SiS_ReadDDC(SiS_Private *SiS_Pr, USHORT DDCdatatype, unsigned char *buffer);
+USHORT  SiS_HandleDDC(SiS_Private *SiS_Pr, unsigned long VBFlags, int VGAEngine,
+		      USHORT adaptnum, USHORT DDCdatatype, unsigned char *buffer);
 #ifdef LINUX_XF86
-USHORT   SiS_SenseLCDDDC(SiS_Private *SiS_Pr, SISPtr pSiS);
-USHORT   SiS_SenseVGA2DDC(SiS_Private *SiS_Pr, SISPtr pSiS);
+USHORT  SiS_SenseLCDDDC(SiS_Private *SiS_Pr, SISPtr pSiS);
+USHORT  SiS_SenseVGA2DDC(SiS_Private *SiS_Pr, SISPtr pSiS);
 #endif
 
 #ifdef SIS315H
-void     SiS_OEM310Setting(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo,
-                           USHORT ModeNo,USHORT ModeIdIndex);
-void     SiS_OEM661Setting(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo,
-                           USHORT ModeNo,USHORT ModeIdIndex, USHORT RRTI);
-void     SiS_FinalizeLCD(SiS_Private *, USHORT, USHORT, PSIS_HW_INFO);
+void    SiS_OEM310Setting(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo,
+                          USHORT ModeNo,USHORT ModeIdIndex);
+void    SiS_OEM661Setting(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo,
+                          USHORT ModeNo,USHORT ModeIdIndex, USHORT RRTI);
+void    SiS_FinalizeLCD(SiS_Private *, USHORT, USHORT, PSIS_HW_INFO);
 #endif
 #ifdef SIS300
-void     SiS_OEM300Setting(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo,
-                           USHORT ModeNo, USHORT ModeIdIndex, USHORT RefTabindex);
-void     SetOEMLCDData2(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo,
-			USHORT ModeNo, USHORT ModeIdIndex,USHORT RefTableIndex);
+void    SiS_OEM300Setting(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo,
+                          USHORT ModeNo, USHORT ModeIdIndex, USHORT RefTabindex);
+void    SetOEMLCDData2(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo,
+		       USHORT ModeNo, USHORT ModeIdIndex,USHORT RefTableIndex);
 #endif
 
 extern void     SiS_SetReg(SISIOADDRESS, USHORT, USHORT);
@@ -338,5 +409,6 @@
 extern void     SiS_LoadDAC(SiS_Private *SiS_Pr, PSIS_HW_INFO,USHORT ModeNo,
                             USHORT ModeIdIndex);
 
+extern void	SiS_CalcLCDACRT1Timing(SiS_Private *SiS_Pr,USHORT ModeNo,USHORT ModeIdIndex);
 
 #endif
--- diff/drivers/video/sis/initdef.h	2004-05-19 22:12:23.000000000 +0100
+++ source/drivers/video/sis/initdef.h	2004-06-11 19:22:05.000000000 +0100
@@ -1,4 +1,5 @@
 /* $XFree86$ */
+/* $XdotOrg$ */
 /*
  * Global definitions for init.c and init301.c
  *
@@ -31,13 +32,10 @@
  * * 2) Redistributions in binary form must reproduce the above copyright
  * *    notice, this list of conditions and the following disclaimer in the
  * *    documentation and/or other materials provided with the distribution.
- * * 3) All advertising materials mentioning features or use of this software
- * *    must display the following acknowledgement: "This product includes
- * *    software developed by Thomas Winischhofer, Vienna, Austria."
- * * 4) The name of the author may not be used to endorse or promote products
+ * * 3) The name of the author may not be used to endorse or promote products
  * *    derived from this software without specific prior written permission.
  * *
- * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESSED OR
  * * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
  * * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
  * * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
@@ -72,6 +70,8 @@
 #define IS_SIS650740660         (IS_SIS650 || IS_SIS740 || IS_SIS661741660760)
 #define IS_SIS550650740660      (IS_SIS550 || IS_SIS650740660)
 
+#define SISGETROMW(x)		(ROMAddr[(x)] | (ROMAddr[(x)+1] << 8))
+
 /* SiS_VBType */
 #define VB_SIS301	      	0x0001
 #define VB_SIS301B        	0x0002
@@ -85,6 +85,8 @@
 #define VB_SIS301B302B          (VB_SIS301B|VB_SIS301C|VB_SIS302B)
 #define VB_SIS301LV302LV        (VB_SIS301LV|VB_SIS302LV|VB_SIS302ELV)
 #define VB_SISVB		(VB_SIS301 | VB_SIS301BLV302BLV)
+#define VB_SISTMDS		(VB_SIS301 | VB_SIS301B302B)
+#define VB_SISLVDS		VB_SIS301LV302LV
 
 /* VBInfo */
 #define SetSimuScanMode         0x0001   /* CR 30 */
@@ -137,6 +139,7 @@
 #define CRT2Mode                0x0800
 #define HalfDCLK                0x1000
 #define NoSupportSimuTV         0x2000
+#define NoSupportLCDScale	0x4000 /* TMDS: No scaling possible (no matter what panel) */
 #define DoubleScanMode          0x8000
 
 /* Infoflag */
@@ -145,7 +148,7 @@
 #define SupportCHTV 		0x0800
 #define Support64048060Hz       0x0800  /* Special for 640x480 LCD */
 #define SupportHiVision         0x0010
-#define SupportYPbPr            0x1000  /* TODO */
+#define SupportYPbPr750p        0x1000
 #define SupportLCD              0x0020
 #define SupportRAMDAC2          0x0040	/* All           (<= 100Mhz) */
 #define SupportRAMDAC2_135      0x0100  /* All except DH (<= 135Mhz) */
@@ -174,19 +177,22 @@
 #define TVSetPALM		0x0004
 #define TVSetPALN		0x0008
 #define TVSetCHOverScan		0x0010
-#define TVSetYPbPr525i		0x0020
-#define TVSetYPbPr525p		0x0040
-#define TVSetYPbPr750p		0x0080
-#define TVSetHiVision		0x0100  /* = 1080i, software-wise identical */
-#define TVSetTVSimuMode		0x0800
-#define TVRPLLDIV2XO		0x1000
-#define TVSetNTSC1024		0x2000
-
-/* YPbPr flag (>=315, <661) */
-#define YPbPr525p               0x0001	/* 525p */
-#define YPbPr750p               0x0002	/* 750p */
-#define YPbPr525i               0x0004	/* 525p */
-#define YPbPrHiVision           0x0008	/* HiVision or 1080i (bridge type dependent) */
+#define TVSetYPbPr525i		0x0020 /* new 0x10 */
+#define TVSetYPbPr525p		0x0040 /* new 0x20 */
+#define TVSetYPbPr750p		0x0080 /* new 0x40 */
+#define TVSetHiVision		0x0100 /* new 0x80; = 1080i, software-wise identical */
+#define TVSetTVSimuMode		0x0200 /* new 0x200, prev. 0x800 */
+#define TVRPLLDIV2XO		0x0400 /* prev 0x1000 */
+#define TVSetNTSC1024		0x0800 /* new 0x100, prev. 0x2000 */
+#define TVAspect43		0x2000
+#define TVAspect169		0x4000
+#define TVAspect43LB		0x8000
+
+/* YPbPr flag (>=315, <661; converted to TVMode) */
+#define YPbPr525p               0x0001
+#define YPbPr750p               0x0002
+#define YPbPr525i               0x0004
+#define YPbPrHiVision           0x0008
 #define YPbPrModeMask           (YPbPr750p | YPbPr525p | YPbPr525i | YPbPrHiVision)
 
 /* SysFlags (to identify special versions) */
@@ -198,6 +204,7 @@
 #define SF_IsM661		0x0020
 #define SF_IsM741		0x0040
 #define SF_IsM760		0x0080
+#define SF_760LFB		0x8000  /* 760: We have LFB */
 
 /* CR32 (Newer 630, and 315 series)
 
@@ -269,7 +276,7 @@
 #define LCDRGB18Bit           0x0001
 #define LCDNonExpanding       0x0010
 #define LCDSync               0x0020
-#define LCDPass11             0x0100
+#define LCDPass11             0x0100   /* 0: center screen, 1: Pass 1:1 data */
 #define LCDDualLink	      0x0200
 
 #define DontExpandLCD	      LCDNonExpanding
@@ -305,7 +312,7 @@
 #define EnablePALMN             0x40   /* Romflag: 1 = Allow PALM/PALN */
 
 /* CR39 (650 only) */
-#define LCDPass1_1		0x01   /* LVDS only; set by driver to pass 1:1 data to LVDS output  */
+#define LCDPass1_1		0x01   /* 0: center screen, 1: pass 1:1 data output  */
 #define Enable302LV_DualLink    0x04   /* 302LV only; enable dual link */
 
 /* CR39 (661 and later)
@@ -348,7 +355,7 @@
 #define Panel300_1024x600       0x06
 #define Panel300_1152x768       0x07
 #define Panel300_1280x768       0x0a
-#define Panel300_320x480        0x0e 	/* fstn - TW: This is fake, can be any */
+#define Panel300_320x480        0x0e 	/* fstn - This is fake, can be any */
 #define Panel300_Custom		0x0f
 #define Panel300_Barco1366      0x10
 
@@ -368,8 +375,24 @@
 #define Panel310_320x480        0x0e    /* fstn - TW: This is fake, can be any */
 #define Panel310_Custom		0x0f
 
+#define Panel661_800x600        0x01
+#define Panel661_1024x768       0x02
+#define Panel661_1280x1024      0x03
+#define Panel661_640x480        0x04
+#define Panel661_1024x600       0x05
+#define Panel661_1152x864       0x06
+#define Panel661_1280x960       0x07
+#define Panel661_1152x768       0x08
+#define Panel661_1400x1050      0x09
+#define Panel661_1280x768       0x0a
+#define Panel661_1600x1200      0x0b
+#define Panel661_1280x800       0x0c
+#define Panel661_1680x1050      0x0d
+#define Panel661_1280x720       0x0e
+#define Panel661_Custom		0x0f
+
 #define Panel_800x600           0x01	/* Unified values */
-#define Panel_1024x768          0x02
+#define Panel_1024x768          0x02    /* MUST match BIOS values from 0-e */
 #define Panel_1280x1024         0x03
 #define Panel_640x480           0x04
 #define Panel_1024x600          0x05
@@ -377,16 +400,19 @@
 #define Panel_1280x960          0x07
 #define Panel_1152x768          0x08	/* LVDS only */
 #define Panel_1400x1050         0x09
-#define Panel_1280x768          0x0a    /* LVDS only */
+#define Panel_1280x768          0x0a    /* 30xB/C and LVDS only (BIOS: all) */
 #define Panel_1600x1200         0x0b
-#define Panel_640x480_2		0x0c
-#define Panel_640x480_3		0x0d
-#define Panel_320x480           0x0e    /* fstn - TW: This is fake, can be any */
-#define Panel_Custom		0x0f
-#define Panel_Barco1366         0x10
-#define Panel_848x480		0x11
-#define Panel_1280x800		0x12    /* 661etc: 0x0c */
-#define Panel_1680x1050         0x13    /* 661etc: 0x0d */
+#define Panel_1280x800		0x0c    /* 661etc  */
+#define Panel_1680x1050         0x0d    /* 661etc  */
+#define Panel_1280x720		0x0e    /* 661etc  */
+#define Panel_Custom		0x0f	/* MUST BE 0x0f (for DVI DDC detection */
+#define Panel_320x480           0x10    /* SiS 550 fstn - TW: This is fake, can be any */
+#define Panel_Barco1366         0x11
+#define Panel_848x480		0x12
+#define Panel_640x480_2		0x13    /* SiS 550 */
+#define Panel_640x480_3		0x14    /* SiS 550 */
+#define Panel_1280x768_2        0x15	/* 30xLV */
+#define Panel_1280x768_3        0x16    /* 30xLV */
 
 /* Index in ModeResInfo table */
 #define SIS_RI_320x200    0
@@ -411,13 +437,17 @@
 #define SIS_RI_856x480   19
 #define SIS_RI_1280x768  20
 #define SIS_RI_1400x1050 21
-#define SIS_RI_1152x864  22  /* Up to this SiS conforming */
+#define SIS_RI_1152x864  22  /* Up to here SiS conforming */
 #define SIS_RI_848x480   23
 #define SIS_RI_1360x768  24
 #define SIS_RI_1024x600  25
 #define SIS_RI_1152x768  26
 #define SIS_RI_768x576   27
 #define SIS_RI_1360x1024 28
+#define SIS_RI_1680x1050 29
+#define SIS_RI_1280x800  30
+#define SIS_RI_1920x1080 31
+#define SIS_RI_960x540   32
 
 /* CR5F */
 #define IsM650                  0x80
@@ -445,14 +475,32 @@
 #define VCLK108_3_300           0x42   /* Index in VCLKData table (300) */
 #define VCLK100_300             0x43   /* Index in VCLKData table (300) */
 #define VCLK34_300              0x3d   /* Index in VCLKData table (300) */
+#define VCLK_CUSTOM_300		0x46
 #define VCLK65_315              0x0b   /* Index in (VB)VCLKData table (315) */
 #define VCLK108_2_315           0x19   /* Index in (VB)VCLKData table (315) */
 #define VCLK81_315		0x5b   /* Index in (VB)VCLKData table (315) */
-#define VCLK162_315             0x21   /* Index in (VB)VCLKData table (315) */
+#define VCLK162_315             0x5e   /* Index in (VB)VCLKData table (315) */
 #define VCLK108_3_315           0x45   /* Index in VBVCLKData table (315) */
 #define VCLK100_315             0x46   /* Index in VBVCLKData table (315) */
-#define VCLK34_315              0x55   /* Index in VBVCLKData table (315) */
+#define VCLK34_315              0x55
 #define VCLK68_315		0x0d
+#define VCLK69_315		0x5c   /* deprecated ! Index in VBVCLKData table (315) */
+#define VCLK83_315		0x5c   /* Index in VBVCLKData table (315) */
+#define VCLK121_315		0x5d   /* Index in VBVCLKData table (315) */
+#define VCLK_1280x720		0x5f
+#define VCLK_1280x768_2		0x60
+#define VCLK_1280x768_3		0x61
+#define VCLK_CUSTOM_315		0x62
+#define VCLK_1280x720_2		0x63
+#define VCLK_720x480		0x67
+#define VCLK_720x576		0x68
+#define VCLK_768x576		0x68
+#define VCLK_848x480		0x65
+#define VCLK_856x480		0x66
+#define VCLK_800x480		0x65
+#define VCLK_1024x576		0x51
+#define VCLK_1152x864		0x64
+#define VCLK_1360x768		0x58
 
 #define TVCLKBASE_300		0x21   /* Indices on TV clocks in VCLKData table (300) */
 #define TVCLKBASE_315	        0x3a   /* Indices on TV clocks in (VB)VCLKData table (315) */
@@ -462,7 +510,7 @@
 #define HiTVVCLK                0x03   /* Index relative to TVCLKBASE */
 #define HiTVSimuVCLK            0x04   /* Index relative to TVCLKBASE */
 #define HiTVTextVCLK            0x05   /* Index relative to TVCLKBASE */
-#define YPbPr750pVCLK		0x0f   /* NOT relative to TVCLKBASE ! */
+#define YPbPr750pVCLK		0x25   /* Index relative to TVCLKBASE; was 0x0f NOT relative */
 
 /* ------------------------------ */
 
@@ -563,7 +611,7 @@
 
 /*
   =============================================================
-   			  for 315 series
+   		  for 315 series (old data layout)
   =============================================================
 */
 #define SoftDRAMType        0x80
--- diff/drivers/video/sis/oem300.h	2004-05-19 22:12:23.000000000 +0100
+++ source/drivers/video/sis/oem300.h	2004-06-11 19:22:05.000000000 +0100
@@ -1,4 +1,5 @@
 /* $XFree86$ */
+/* $XdotOrg$ */
 /*
  * OEM Data for 300 series
  *
@@ -31,13 +32,10 @@
  * * 2) Redistributions in binary form must reproduce the above copyright
  * *    notice, this list of conditions and the following disclaimer in the
  * *    documentation and/or other materials provided with the distribution.
- * * 3) All advertising materials mentioning features or use of this software
- * *    must display the following acknowledgement: "This product includes
- * *    software developed by Thomas Winischhofer, Vienna, Austria."
- * * 4) The name of the author may not be used to endorse or promote products
+ * * 3) The name of the author may not be used to endorse or promote products
  * *    derived from this software without specific prior written permission.
  * *
- * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESSED OR
  * * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
  * * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
  * * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
--- diff/drivers/video/sis/oem310.h	2004-05-19 22:12:23.000000000 +0100
+++ source/drivers/video/sis/oem310.h	2004-06-11 19:22:05.000000000 +0100
@@ -1,4 +1,5 @@
 /* $XFree86$ */
+/* $XdotOrg$ */
 /*
  * OEM Data for 315/330 series
  *
@@ -31,13 +32,10 @@
  * * 2) Redistributions in binary form must reproduce the above copyright
  * *    notice, this list of conditions and the following disclaimer in the
  * *    documentation and/or other materials provided with the distribution.
- * * 3) All advertising materials mentioning features or use of this software
- * *    must display the following acknowledgement: "This product includes
- * *    software developed by Thomas Winischhofer, Vienna, Austria."
- * * 4) The name of the author may not be used to endorse or promote products
+ * * 3) The name of the author may not be used to endorse or promote products
  * *    derived from this software without specific prior written permission.
  * *
- * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESSED OR
  * * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
  * * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
  * * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
@@ -91,7 +89,7 @@
 		 0x02,0x02,0x02
 };
 
-static const UCHAR SiS310_LCDDelayCompensation_651301LV[] =	  /* M650/651 301LV */
+static const UCHAR SiS310_LCDDelayCompensation_651301LV[] =	  	/* M650/651 301LV */
 {
                  0x33,0x33,0x33,    /*   800x600 (guessed) - new: PanelType, not PanelRes ! */
 		 0x33,0x33,0x33,    /*  1024x768 */
@@ -110,7 +108,7 @@
 		 0x33,0x33,0x33
 };
 
-static const UCHAR SiS310_LCDDelayCompensation_651302LV[] =	   /* M650/651 302LV */
+static const UCHAR SiS310_LCDDelayCompensation_651302LV[] =	   	/* M650/651 302LV */
 {
                  0x33,0x33,0x33,    /*   800x600 (guessed) */
 		 0x33,0x33,0x33,    /*  1024x768 */
@@ -129,7 +127,7 @@
 		 0x33,0x33,0x33
 };
 
-static const UCHAR SiS310_LCDDelayCompensation_3xx301B[] =	   	/* 30xB,LV */
+static const UCHAR SiS310_LCDDelayCompensation_3xx301B[] =	   	/* 30xB */
 {
 		 0x01,0x01,0x01,    /*   800x600 */
 		 0x0C,0x0C,0x0C,    /*  1024x768 */
@@ -148,6 +146,25 @@
 		 0x02,0x02,0x02
 };
 
+static const UCHAR SiS310_LCDDelayCompensation_3xx301LV[] =	   	/* 315+30xLV */
+{
+		 0x01,0x01,0x01,    /*   800x600 */
+		 0x04,0x04,0x04,    /*  1024x768 (A531/BIOS 1.14.05f: 4 - works with 6 */
+		 0x0C,0x0C,0x0C,    /* 1280x1024 */
+                 0x08,0x08,0x08,    /*   640x480 */
+		 0x0C,0x0C,0x0C,    /*  1024x600 (guessed) */
+		 0x0C,0x0C,0x0C,    /*  1152x864 (guessed) */
+		 0x0C,0x0C,0x0C,    /*  1280x960 (guessed) */
+		 0x0C,0x0C,0x0C,    /*  1152x768 (guessed) */
+		 0x0C,0x0C,0x0C,    /* 1400x1050 (guessed) */
+		 0x0C,0x0C,0x0C,    /*  1280x768 (guessed) */
+		 0x0C,0x0C,0x0C,    /* 1600x1200 (guessed) */
+		 0x02,0x02,0x02,
+		 0x02,0x02,0x02,
+		 0x02,0x02,0x02,
+		 0x02,0x02,0x02
+};
+
 static const UCHAR SiS310_TVDelayCompensation_301[] = 		/* 301 */
 {
 		 0x02,0x02,    /* NTSC Enhanced, Standard */
@@ -169,13 +186,6 @@
 		 0x05,0x05
 };
 
-static const UCHAR SiS310_TVDelayCompensation_LVDS[] =		/* LVDS */
-{
-		 0x0a,0x0a,
-		 0x0a,0x0a,
-		 0x0a,0x0a
-};
-
 static const UCHAR SiS310_TVDelayCompensation_651301LV[] =	/* M650, 651, 301LV */
 {
 		 0x33,0x33,
@@ -210,6 +220,13 @@
 		 0x44,0x44
 };
 
+static const UCHAR SiS310_TVDelayCompensation_LVDS[] =		/* LVDS */
+{
+		 0x0a,0x0a,
+		 0x0a,0x0a,
+		 0x0a,0x0a
+};
+
 static const UCHAR SiS310_TVAntiFlick1[6][2] =
 {
             {0x4,0x0},
@@ -412,141 +429,6 @@
 	{    1,   1,1696,1066,1696,1066}
 };
 
-static const SiS_Part2PortTblStruct SiS310_CRT2Part2_Compaq1280x1024_1[] =
-{
- {{0x3F,0x1B,0xD0,0xF0,0xB0,0xB8,0x23,0x0A,0x07,0x14,0x8A,0x12}},
- {{0x35,0x1B,0xA0,0xC0,0x80,0xB8,0x23,0x0A,0x07,0x14,0x8A,0x12}},
- {{0x3F,0x1B,0xD0,0xF0,0xB0,0xB8,0x23,0x0A,0x07,0x14,0x8A,0x12}},
- {{0x3F,0x1B,0xD0,0xF0,0xB0,0xB8,0x23,0x0A,0x07,0x14,0x8A,0x12}},
- {{0x45,0x1C,0x20,0x3F,0xFF,0xB8,0x23,0x0A,0x07,0x14,0x8A,0x12}},
- {{0x49,0x1C,0x40,0x7F,0xFF,0xAD,0x23,0x0A,0x07,0xF3,0x8A,0x12}},
- {{0x4C,0x1C,0x18,0x2F,0xFF,0xBD,0x23,0x0A,0x07,0x23,0x8A,0x12}},
- {{0x48,0x1C,0x15,0x29,0xFF,0xBD,0x23,0x0A,0x07,0x23,0x8A,0x12}}
-};
-
-static const SiS_Part2PortTblStruct SiS310_CRT2Part2_Compaq1280x1024_2[] =
-{
- {{0x2B,0x12,0xD9,0xE5,0xD5,0x2C,0x23,0x98,0x27,0x3E,0x08,0x42}},
- {{0x22,0x12,0xC0,0xCC,0xBC,0x2C,0x23,0x98,0x27,0x3E,0x08,0x42}},
- {{0x2B,0x12,0xD9,0xE5,0xD5,0x2C,0x23,0x98,0x27,0x3E,0x08,0x42}},
- {{0x22,0x12,0xC0,0xCC,0xBC,0x2C,0x23,0x98,0x27,0x3E,0x08,0x42}},
- {{0x33,0x13,0x01,0x0D,0xFD,0x2C,0x23,0x98,0x27,0x3E,0x08,0x42}},
- {{0x3F,0x1B,0x3D,0x49,0x39,0x54,0x23,0xC0,0x27,0x66,0x30,0x42}},
- {{0x33,0x1B,0x91,0x9D,0x8D,0x8C,0x23,0xF8,0x27,0x9E,0x68,0x42}},
- {{0x43,0x24,0x11,0x1D,0x0D,0xCC,0x23,0x38,0x37,0xDE,0xA8,0x42}},
- {{0x43,0x24,0x21,0x29,0x19,0xEA,0x23,0x0A,0x07,0x32,0xC6,0x42}}
-};
-
-static const SiS_Part2PortTblStruct SiS310_CRT2Part2_Compaq1280x1024_3[] =
-{
- {{0x47,0x1C,0x14,0x29,0xFF,0xBD,0x23,0x0A,0x07,0x23,0x8A,0x12}},
- {{0x47,0x1C,0x14,0x29,0xFF,0xBD,0x23,0x0A,0x07,0x23,0x8A,0x12}},
- {{0x47,0x1C,0x14,0x29,0xFF,0xBD,0x23,0x0A,0x07,0x23,0x8A,0x12}},
- {{0x47,0x1C,0x14,0x29,0xFF,0xBD,0x23,0x0A,0x07,0x23,0x8A,0x12}},
- {{0x47,0x1C,0x14,0x29,0xFF,0xBE,0x23,0x0A,0x07,0x26,0x8A,0x42}},
- {{0x47,0x1C,0x14,0x29,0xFF,0xBE,0x23,0x0A,0x07,0x26,0x8A,0x42}},
- {{0x47,0x1C,0x14,0x29,0xFF,0xBE,0x23,0x0A,0x07,0x26,0x8A,0x42}},
- {{0x47,0x1C,0x14,0x29,0xFF,0xBE,0x23,0x0A,0x07,0x26,0x8A,0x42}}
-};
-
-/* LCDA CRT2 data is std */
-
-static const SiS_LVDSDesStruct Compaq1280x1024Des_1[] =
-{
-  { 0, 0 },
-  { 0, 0 },
-  { 0, 0 },
-  { 0, 0 },
-  { 0, 0 },
-  { 0, 0 },
-  { 0, 0 },
-  { 0, 0 }
-};
-
-static const SiS_LVDSDesStruct Compaq1280x1024Des_2[] =
-{
-  { 0, 0 },
-  { 0, 0 },
-  { 0, 0 },
-  { 0, 0 },
-  { 0, 0 },
-  { 0, 0 },
-  { 0, 0 },
-  { 0, 0 }
-};
-
-/* Clevo L285/287 (dual-link 1024x768) */
-
-static const SiS_Part2PortTblStruct SiS310_CRT2Part2_Clevo1024x768_1[] =
-{
- {{0x25,0x12,0xC9,0xDC,0xB6,0x59,0x45,0x09,0x07,0xF9,0x09,0x24}},
- {{0x2C,0x12,0x9A,0xAE,0x88,0x59,0x45,0x09,0x07,0xF9,0x09,0x24}},
- {{0x25,0x12,0xC9,0xDC,0xB6,0x59,0x45,0x09,0x07,0xF9,0x09,0x24}},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}},
- {{0x38,0x13,0x16,0x0C,0xE6,0x59,0x45,0x09,0x07,0xF9,0x09,0x24}},
- {{0x38,0x18,0x16,0x00,0x00,0x59,0x45,0x09,0x07,0xF9,0x09,0x24}},
- {{0x36,0x13,0x13,0x25,0xFF,0x59,0x45,0x09,0x07,0xF9,0x09,0x24}},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}},
- {{0x25,0x12,0xC9,0xDC,0xB6,0x59,0x45,0x09,0x07,0xF9,0x09,0x24}}
-};
-
-static const SiS_Part2PortTblStruct SiS310_CRT2Part2_Clevo1024x768_2[] =
-{
- {{0x25,0x12,0x51,0x6E,0x48,0xCC,0x12,0x89,0x47,0x1C,0x49,0x33}},
- {{0x2C,0x12,0x38,0x55,0x2F,0xCC,0x12,0x89,0x47,0x1C,0x49,0x33}},
- {{0x25,0x12,0x51,0x6E,0x48,0xCC,0x12,0x89,0x47,0x1C,0x49,0x33}},
- {{0x2C,0x12,0x38,0x55,0x2F,0xE0,0x12,0xB1,0x47,0x30,0x71,0x33}},
- {{0x2D,0x12,0x79,0x96,0x70,0xCC,0x12,0x89,0x47,0x1C,0x49,0x33}},
- {{0x29,0x12,0xB5,0xD2,0xAC,0xF4,0x12,0xD9,0x47,0x44,0x99,0x33}},
- {{0x36,0x13,0x13,0x25,0xFF,0x32,0x22,0x0A,0x07,0x82,0x0A,0x12}},
-#if 0
- {{0x25,0x12,0x51,0x6E,0x48,0x99,0x35,0x89,0x47,0xC1,0x49,0x33}},
- {{0x2C,0x12,0x38,0x55,0x2F,0x99,0x35,0x89,0x47,0xC1,0x49,0x33}},
- {{0x25,0x12,0x51,0x6E,0x48,0x99,0x35,0x89,0x47,0xC1,0x49,0x33}},
- {{0x2C,0x12,0x38,0x55,0x2F,0xC1,0x35,0xB1,0x47,0xE9,0x71,0x33}},
- {{0x2D,0x12,0x79,0x96,0x70,0x99,0x35,0x89,0x47,0xC1,0x49,0x33}},
- {{0x29,0x12,0xB5,0xD2,0xAC,0xE9,0x35,0xD9,0x47,0x11,0x99,0x33}},
- {{0x36,0x13,0x13,0x25,0xFF,0x59,0x45,0x09,0x07,0xF9,0x09,0x24}}
-#endif
-};
-
-static const SiS_Part2PortTblStruct SiS310_CRT2Part2_Clevo1024x768_3[] =
-{
- {{0x36,0x13,0x13,0x25,0xFF,0x32,0x22,0x0A,0x07,0x82,0x0A,0x12}}, /* Corrected */
- {{0x36,0x13,0x13,0x25,0xFF,0x32,0x22,0x0A,0x07,0x82,0x0A,0x12}},
- {{0x36,0x13,0x13,0x25,0xFF,0x32,0x22,0x0A,0x07,0x82,0x0A,0x12}},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}},
- {{0x36,0x13,0x13,0x25,0xFF,0x32,0x22,0x0A,0x07,0x82,0x0A,0x12}},
- {{0x36,0x13,0x13,0x25,0xFF,0x32,0x22,0x0A,0x07,0x82,0x0A,0x12}},
- {{0x36,0x13,0x13,0x25,0xFF,0x32,0x22,0x0A,0x07,0x82,0x0A,0x12}},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}},
- {{0x25,0x13,0xC9,0x25,0xFF,0x59,0x45,0x09,0x07,0xF9,0x09,0x24}}
-};
-
-/* CRT2 data is std */
-
-static const SiS_LVDSDesStruct Clevo1024x768Des_1[] =
-{
-  { 0, 0 },
-  { 0, 0 },
-  { 0, 0 },
-  { 0, 0 },
-  { 0, 0 },
-  { 0, 0 },
-  { 0, 0 }
-};
-
-static const SiS_LVDSDesStruct Clevo1024x768Des_2[] =
-{
-  { 1184, 622 },
-  { 1184, 597 },
-  { 1184, 622 },
-  { 1184, 597 },
-  { 1152, 622 },
-  { 1232, 722 },
-  {    0,   0 }
-};
-
 /* Asus A2xxxH _2 */
 
 static const SiS_Part2PortTblStruct SiS310_CRT2Part2_Asus1024x768_3[] =
@@ -562,52 +444,6 @@
  {{0x25,0x13,0xc9,0x25,0xff,0x59,0x45,0x09,0x07,0xf9,0x09,0x24}}
 };
 
-static const SiS_LVDSDesStruct Asus1024x768Des_1[] =
-{
-  { 0, 0 },
-  { 0, 0 },
-  { 0, 0 },
-  { 0, 0 },
-  { 0, 0 },
-  { 0, 0 },
-  { 0, 0 }
-};
 
-static const SiS_LVDSDesStruct Asus1024x768Des_2[] =
-{
-  { 1184, 622 },
-  { 1184, 597 },
-  { 1184, 622 },
-  { 1184, 597 },
-  { 1152, 622 },
-  { 1232, 722 },
-  {    0,   0 }
-};
-
-/* CRT2 data is std */
-
-/* Uniwill N243S9, ECS A928 */
-
-static const SiS_LVDSDesStruct Uniwill1024x768Des_1[] =
-{
-  { 0, 0 },
-  { 0, 0 },
-  { 0, 0 },
-  { 0, 0 },
-  { 0, 0 },
-  { 0, 0 },
-  { 0, 805 }
-};
-
-static const SiS_LVDSDesStruct Uniwill1024x768Des_2[] =
-{
-  { 1184, 622 },
-  { 1184, 597 },
-  { 1184, 622 },
-  { 1184, 597 },
-  { 1152, 650 },
-  { 1232, 722 },
-  {    0, 805 },
-};
 
 
--- diff/drivers/video/sis/osdef.h	2004-05-19 22:12:23.000000000 +0100
+++ source/drivers/video/sis/osdef.h	2004-06-11 19:22:05.000000000 +0100
@@ -1,4 +1,5 @@
 /* $XFree86$ */
+/* $XdotOrg$ */
 /*
  * OS depending defines
  *
@@ -31,13 +32,10 @@
  * * 2) Redistributions in binary form must reproduce the above copyright
  * *    notice, this list of conditions and the following disclaimer in the
  * *    documentation and/or other materials provided with the distribution.
- * * 3) All advertising materials mentioning features or use of this software
- * *    must display the following acknowledgement: "This product includes
- * *    software developed by Thomas Winischhofer, Vienna, Austria."
- * * 4) The name of the author may not be used to endorse or promote products
+ * * 3) The name of the author may not be used to endorse or promote products
  * *    derived from this software without specific prior written permission.
  * *
- * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESSED OR
  * * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
  * * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
  * * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
@@ -54,95 +52,77 @@
  */
 
 /* The choices are: */
-
 #define LINUX_KERNEL	   /* Kernel framebuffer */
 /* #define LINUX_XF86 */   /* XFree86 */
 
-/**********************************************************************/
-#ifdef LINUX_KERNEL  /* -------------------------- */
-#include <linux/config.h>
-#include <linux/version.h>
-
-#ifdef CONFIG_FB_SIS_300
-#define SIS300
-#endif
-
-#ifdef CONFIG_FB_SIS_315
-#define SIS315H
-#endif
-
-#if 1
-#define SISFBACCEL	/* Include 2D acceleration */
-#endif
-
-#endif
-
-#ifdef LINUX_XF86 /* ----------------------------- */
-#define SIS300
-#define SIS315H
-#endif
-
-/**********************************************************************/
-#ifdef LINUX_XF86
-#define SiS_SetMemory(MemoryAddress,MemorySize,value) memset(MemoryAddress, value, MemorySize)
-#define SiS_MemoryCopy(Destination,Soruce,Length) memcpy(Destination,Soruce,Length)
-#endif
-
-#ifdef LINUX_KERNEL
-#define SiS_SetMemory(MemoryAddress,MemorySize,value) memset(MemoryAddress, value, MemorySize)
-#define SiS_MemoryCopy(Destination,Soruce,Length) memcpy(Destination,Soruce,Length)
-#endif
-
-/**********************************************************************/
-
 #ifdef OutPortByte
 #undef OutPortByte
-#endif /* OutPortByte */
+#endif
 
 #ifdef OutPortWord
 #undef OutPortWord
-#endif /* OutPortWord */
+#endif
 
 #ifdef OutPortLong
 #undef OutPortLong
-#endif /* OutPortLong */
+#endif
 
 #ifdef InPortByte
 #undef InPortByte
-#endif /* InPortByte */
+#endif
 
 #ifdef InPortWord
 #undef InPortWord
-#endif /* InPortWord */
+#endif
 
 #ifdef InPortLong
 #undef InPortLong
-#endif /* InPortLong */
+#endif
 
 /**********************************************************************/
-/*  LINUX XF86                                                        */
+/*  LINUX KERNEL                                                      */
 /**********************************************************************/
 
-#ifdef LINUX_XF86
-#define OutPortByte(p,v) outb((CARD16)(p),(CARD8)(v))
-#define OutPortWord(p,v) outw((CARD16)(p),(CARD16)(v))
-#define OutPortLong(p,v) outl((CARD16)(p),(CARD32)(v))
-#define InPortByte(p)    inb((CARD16)(p))
-#define InPortWord(p)    inw((CARD16)(p))
-#define InPortLong(p)    inl((CARD16)(p))
+#ifdef LINUX_KERNEL
+#include <linux/config.h>
+
+#ifdef CONFIG_FB_SIS_300
+#define SIS300
+#endif
+
+#ifdef CONFIG_FB_SIS_315
+#define SIS315H
+#endif
+
+#if !defined(SIS300) && !defined(SIS315H)
+#warning Neither CONFIG_FB_SIS_300 nor CONFIG_FB_SIS_315 is set
+#warning sisfb will not work!
+#endif
+
+#define OutPortByte(p,v) outb((u8)(v),(SISIOADDRESS)(p))
+#define OutPortWord(p,v) outw((u16)(v),(SISIOADDRESS)(p))
+#define OutPortLong(p,v) outl((u32)(v),(SISIOADDRESS)(p))
+#define InPortByte(p)    inb((SISIOADDRESS)(p))
+#define InPortWord(p)    inw((SISIOADDRESS)(p))
+#define InPortLong(p)    inl((SISIOADDRESS)(p))
+#define SiS_SetMemory(MemoryAddress,MemorySize,value) memset_io(MemoryAddress, value, MemorySize)
 #endif
 
 /**********************************************************************/
-/*  LINUX KERNEL                                                      */
+/*  XFree86, X.org                                                    */
 /**********************************************************************/
 
-#ifdef LINUX_KERNEL
-#define OutPortByte(p,v) outb((u8)(v),(u16)(p))
-#define OutPortWord(p,v) outw((u16)(v),(u16)(p))
-#define OutPortLong(p,v) outl((u32)(v),(u16)(p))
-#define InPortByte(p)    inb((u16)(p))
-#define InPortWord(p)    inw((u16)(p))
-#define InPortLong(p)    inl((u16)(p))
+#ifdef LINUX_XF86
+#define SIS300
+#define SIS315H
+
+#define OutPortByte(p,v) outb((IOADDRESS)(p),(CARD8)(v))
+#define OutPortWord(p,v) outw((IOADDRESS)(p),(CARD16)(v))
+#define OutPortLong(p,v) outl((IOADDRESS)(p),(CARD32)(v))
+#define InPortByte(p)    inb((IOADDRESS)(p))
+#define InPortWord(p)    inw((IOADDRESS)(p))
+#define InPortLong(p)    inl((IOADDRESS)(p))
+#define SiS_SetMemory(MemoryAddress,MemorySize,value) memset(MemoryAddress, value, MemorySize)
 #endif
 
 
--- diff/drivers/video/sis/sis.h	2004-05-19 22:12:23.000000000 +0100
+++ source/drivers/video/sis/sis.h	2004-06-11 19:22:05.000000000 +0100
@@ -1,10 +1,505 @@
+/*
+ * SiS 300/630/730/540/315/550/650/651/M650/661FX/M661FX/740/741/330/760
+ * frame buffer driver for Linux kernels >=2.4.14 and >=2.6.3
+ *
+ * Copyright (C) 2001-2004 Thomas Winischhofer, Vienna, Austria.
+ *
+ * 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 named License,
+ * or 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
+ */
+
 #ifndef _SIS_H
 #define _SIS_H
 
-#if 1
-#define TWDEBUG(x)
+#include <linux/config.h>
+#include <linux/version.h>
+
+#include "osdef.h"
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
+#include <video/sisfb.h>
 #else
+#include <linux/sisfb.h>
+#endif
+
+#include "vgatypes.h"
+#include "vstruct.h"
+
+#define VER_MAJOR                 1
+#define VER_MINOR                 7
+#define VER_LEVEL                 12
+
+#undef SIS_CONFIG_COMPAT
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
+#include <linux/spinlock.h>
+#ifdef CONFIG_COMPAT
+#include <linux/ioctl32.h>
+#define SIS_CONFIG_COMPAT
+#endif
+#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,19)
+#ifdef __x86_64__
+/* Shouldn't we check for CONFIG_IA32_EMULATION here? */
+#include <asm/ioctl32.h>
+#define SIS_CONFIG_COMPAT
+#endif
+#endif
+
+#undef SISFBDEBUG
+
+#ifdef SISFBDEBUG
+#define DPRINTK(fmt, args...) printk(KERN_DEBUG "%s: " fmt, __FUNCTION__ , ## args)
 #define TWDEBUG(x) printk(KERN_INFO x "\n");
+#else
+#define DPRINTK(fmt, args...)
+#define TWDEBUG(x)
+#endif
+
+#define SISFAIL(x) do { printk(x "\n"); return -EINVAL; } while(0)
+
+/* To be included in pci_ids.h */
+#ifndef PCI_DEVICE_ID_SI_650_VGA
+#define PCI_DEVICE_ID_SI_650_VGA  0x6325
+#endif
+#ifndef PCI_DEVICE_ID_SI_650
+#define PCI_DEVICE_ID_SI_650      0x0650
+#endif
+#ifndef PCI_DEVICE_ID_SI_651
+#define PCI_DEVICE_ID_SI_651      0x0651
+#endif
+#ifndef PCI_DEVICE_ID_SI_740
+#define PCI_DEVICE_ID_SI_740      0x0740
+#endif
+#ifndef PCI_DEVICE_ID_SI_330
+#define PCI_DEVICE_ID_SI_330      0x0330
+#endif
+#ifndef PCI_DEVICE_ID_SI_660_VGA
+#define PCI_DEVICE_ID_SI_660_VGA  0x6330
+#endif
+#ifndef PCI_DEVICE_ID_SI_661
+#define PCI_DEVICE_ID_SI_661      0x0661
+#endif
+#ifndef PCI_DEVICE_ID_SI_741
+#define PCI_DEVICE_ID_SI_741      0x0741
+#endif
+#ifndef PCI_DEVICE_ID_SI_660
+#define PCI_DEVICE_ID_SI_660      0x0660
+#endif
+#ifndef PCI_DEVICE_ID_SI_760
+#define PCI_DEVICE_ID_SI_760      0x0760
+#endif
+
+/* To be included in fb.h */
+#ifndef FB_ACCEL_SIS_GLAMOUR_2
+#define FB_ACCEL_SIS_GLAMOUR_2	  40	/* SiS 315, 65x, 740, 661, 741  */
+#endif
+#ifndef FB_ACCEL_SIS_XABRE
+#define FB_ACCEL_SIS_XABRE        41	/* SiS 330 ("Xabre"), 760 	*/
+#endif
+
+#define MAX_ROM_SCAN              0x10000
+
+/* ivideo->caps */
+#define HW_CURSOR_CAP             0x80
+#define TURBO_QUEUE_CAP           0x40
+#define AGP_CMD_QUEUE_CAP         0x20
+#define VM_CMD_QUEUE_CAP          0x10
+#define MMIO_CMD_QUEUE_CAP        0x08
+
+/* For 300 series */
+#define TURBO_QUEUE_AREA_SIZE     0x80000 /* 512K */
+#define HW_CURSOR_AREA_SIZE_300   0x1000  /* 4K */
+
+/* For 315/Xabre series */
+#define COMMAND_QUEUE_AREA_SIZE   0x80000 /* 512K */
+#define COMMAND_QUEUE_THRESHOLD   0x1F
+#define HW_CURSOR_AREA_SIZE_315   0x4000  /* 16K */
+
+#define SIS_OH_ALLOC_SIZE         4000
+#define SENTINEL                  0x7fffffff
+
+#define SEQ_ADR                   0x14
+#define SEQ_DATA                  0x15
+#define DAC_ADR                   0x18
+#define DAC_DATA                  0x19
+#define CRTC_ADR                  0x24
+#define CRTC_DATA                 0x25
+#define DAC2_ADR                  (0x16-0x30)
+#define DAC2_DATA                 (0x17-0x30)
+#define VB_PART1_ADR              (0x04-0x30)
+#define VB_PART1_DATA             (0x05-0x30)
+#define VB_PART2_ADR              (0x10-0x30)
+#define VB_PART2_DATA             (0x11-0x30)
+#define VB_PART3_ADR              (0x12-0x30)
+#define VB_PART3_DATA             (0x13-0x30)
+#define VB_PART4_ADR              (0x14-0x30)
+#define VB_PART4_DATA             (0x15-0x30)
+
+#define SISSR			  ivideo->SiS_Pr.SiS_P3c4
+#define SISCR                     ivideo->SiS_Pr.SiS_P3d4
+#define SISDACA                   ivideo->SiS_Pr.SiS_P3c8
+#define SISDACD                   ivideo->SiS_Pr.SiS_P3c9
+#define SISPART1                  ivideo->SiS_Pr.SiS_Part1Port
+#define SISPART2                  ivideo->SiS_Pr.SiS_Part2Port
+#define SISPART3                  ivideo->SiS_Pr.SiS_Part3Port
+#define SISPART4                  ivideo->SiS_Pr.SiS_Part4Port
+#define SISPART5                  ivideo->SiS_Pr.SiS_Part5Port
+#define SISDAC2A                  SISPART5
+#define SISDAC2D                  (SISPART5 + 1)
+#define SISMISCR                  (ivideo->SiS_Pr.RelIO + 0x1c)
+#define SISMISCW                  ivideo->SiS_Pr.SiS_P3c2
+#define SISINPSTAT		  (ivideo->SiS_Pr.RelIO + 0x2a)
+#define SISPEL			  ivideo->SiS_Pr.SiS_P3c6
+
+#define IND_SIS_PASSWORD          0x05  /* SRs */
+#define IND_SIS_COLOR_MODE        0x06
+#define IND_SIS_RAMDAC_CONTROL    0x07
+#define IND_SIS_DRAM_SIZE         0x14
+#define IND_SIS_MODULE_ENABLE     0x1E
+#define IND_SIS_PCI_ADDRESS_SET   0x20
+#define IND_SIS_TURBOQUEUE_ADR    0x26
+#define IND_SIS_TURBOQUEUE_SET    0x27
+#define IND_SIS_POWER_ON_TRAP     0x38
+#define IND_SIS_POWER_ON_TRAP2    0x39
+#define IND_SIS_CMDQUEUE_SET      0x26
+#define IND_SIS_CMDQUEUE_THRESHOLD  0x27
+
+#define IND_SIS_AGP_IO_PAD        0x48
+
+#define SIS_CRT2_WENABLE_300 	  0x24  /* Part1 */
+#define SIS_CRT2_WENABLE_315 	  0x2F
+
+#define SIS_PASSWORD              0x86  /* SR05 */
+#define SIS_INTERLACED_MODE       0x20  /* SR06 */
+#define SIS_8BPP_COLOR_MODE       0x0
+#define SIS_15BPP_COLOR_MODE      0x1
+#define SIS_16BPP_COLOR_MODE      0x2
+#define SIS_32BPP_COLOR_MODE      0x4
+
+#define SIS_ENABLE_2D             0x40  /* SR1E */
+
+#define SIS_MEM_MAP_IO_ENABLE     0x01  /* SR20 */
+#define SIS_PCI_ADDR_ENABLE       0x80
+
+#define SIS_AGP_CMDQUEUE_ENABLE   0x80  /* 315/330 series SR26 */
+#define SIS_VRAM_CMDQUEUE_ENABLE  0x40
+#define SIS_MMIO_CMD_ENABLE       0x20
+#define SIS_CMD_QUEUE_SIZE_512k   0x00
+#define SIS_CMD_QUEUE_SIZE_1M     0x04
+#define SIS_CMD_QUEUE_SIZE_2M     0x08
+#define SIS_CMD_QUEUE_SIZE_4M     0x0C
+#define SIS_CMD_QUEUE_RESET       0x01
+#define SIS_CMD_AUTO_CORR	  0x02
+
+#define SIS_SIMULTANEOUS_VIEW_ENABLE  0x01  /* CR30 */
+#define SIS_MODE_SELECT_CRT2      0x02
+#define SIS_VB_OUTPUT_COMPOSITE   0x04
+#define SIS_VB_OUTPUT_SVIDEO      0x08
+#define SIS_VB_OUTPUT_SCART       0x10
+#define SIS_VB_OUTPUT_LCD         0x20
+#define SIS_VB_OUTPUT_CRT2        0x40
+#define SIS_VB_OUTPUT_HIVISION    0x80
+
+#define SIS_VB_OUTPUT_DISABLE     0x20  /* CR31 */
+#define SIS_DRIVER_MODE           0x40
+
+#define SIS_VB_COMPOSITE          0x01  /* CR32 */
+#define SIS_VB_SVIDEO             0x02
+#define SIS_VB_SCART              0x04
+#define SIS_VB_LCD                0x08
+#define SIS_VB_CRT2               0x10
+#define SIS_CRT1                  0x20
+#define SIS_VB_HIVISION           0x40
+#define SIS_VB_YPBPR              0x80
+#define SIS_VB_TV                 (SIS_VB_COMPOSITE | SIS_VB_SVIDEO | \
+                                   SIS_VB_SCART | SIS_VB_HIVISION | SIS_VB_YPBPR)
+
+#define SIS_EXTERNAL_CHIP_MASK    	   0x0E  /* CR37 (< SiS 660) */
+#define SIS_EXTERNAL_CHIP_SIS301           0x01  /* in CR37 << 1 ! */
+#define SIS_EXTERNAL_CHIP_LVDS             0x02
+#define SIS_EXTERNAL_CHIP_TRUMPION         0x03
+#define SIS_EXTERNAL_CHIP_LVDS_CHRONTEL    0x04
+#define SIS_EXTERNAL_CHIP_CHRONTEL         0x05
+#define SIS310_EXTERNAL_CHIP_LVDS          0x02
+#define SIS310_EXTERNAL_CHIP_LVDS_CHRONTEL 0x03
+
+#define SIS_AGP_2X                0x20  /* CR48 */
+
+#define HW_DEVICE_EXTENSION	  SIS_HW_INFO
+#define PHW_DEVICE_EXTENSION      PSIS_HW_INFO
+
+/* Useful macros */
+#define inSISREG(base)          inb(base)
+#define outSISREG(base,val)     outb(val,base)
+#define orSISREG(base,val)      do { \
+                                  u8 __Temp = inb(base); \
+                                  outSISREG(base, __Temp | (val)); \
+                                } while (0)
+#define andSISREG(base,val)     do { \
+                                  u8 __Temp = inb(base); \
+                                  outSISREG(base, __Temp & (val)); \
+                                } while (0)
+#define inSISIDXREG(base,idx,var)   do { \
+                                      outb(idx,base); var=inb((base)+1); \
+                                    } while (0)
+#define outSISIDXREG(base,idx,val)  do { \
+                                      outb(idx,base); outb((val),(base)+1); \
+                                    } while (0)
+#define orSISIDXREG(base,idx,val)   do { \
+                                      u8 __Temp; \
+                                      outb(idx,base);   \
+                                      __Temp = inb((base)+1)|(val); \
+                                      outSISIDXREG(base,idx,__Temp); \
+                                    } while (0)
+#define andSISIDXREG(base,idx,and)  do { \
+                                      u8 __Temp; \
+                                      outb(idx,base);   \
+                                      __Temp = inb((base)+1)&(and); \
+                                      outSISIDXREG(base,idx,__Temp); \
+                                    } while (0)
+#define setSISIDXREG(base,idx,and,or)   do { \
+                                          u8 __Temp; \
+                                          outb(idx,base);   \
+                                          __Temp = (inb((base)+1)&(and))|(or); \
+                                          outSISIDXREG(base,idx,__Temp); \
+                                        } while (0)
+
+/* MMIO access macros */
+#define MMIO_IN8(base, offset)  readb((base+offset))
+#define MMIO_IN16(base, offset) readw((base+offset))
+#define MMIO_IN32(base, offset) readl((base+offset))
+
+#define MMIO_OUT8(base, offset, val)  writeb(((u8)(val)), (base+offset))
+#define MMIO_OUT16(base, offset, val) writew(((u16)(val)), (base+offset))
+#define MMIO_OUT32(base, offset, val) writel(((u32)(val)), (base+offset))
+
+/* Queue control MMIO registers */
+#define Q_BASE_ADDR		0x85C0  /* Base address of software queue */
+#define Q_WRITE_PTR		0x85C4  /* Current write pointer */
+#define Q_READ_PTR		0x85C8  /* Current read pointer */
+#define Q_STATUS		0x85CC  /* queue status */
+
+#define MMIO_QUEUE_PHYBASE      Q_BASE_ADDR
+#define MMIO_QUEUE_WRITEPORT    Q_WRITE_PTR
+#define MMIO_QUEUE_READPORT     Q_READ_PTR
+
+enum _SIS_CMDTYPE {
+	MMIO_CMD = 0,
+	AGP_CMD_QUEUE,
+	VM_CMD_QUEUE,
+};
+typedef unsigned int SIS_CMDTYPE;
+
+/* Our "par" */
+struct sis_video_info {
+	int		cardnumber;
+	struct fb_info  *memyselfandi;
+
+	SIS_HW_INFO 	sishw_ext;
+	SiS_Private  	SiS_Pr;
+
+	sisfb_info 	sisfbinfo;	/* For ioctl SISFB_GET_INFO */
+
+	struct fb_var_screeninfo default_var;
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
+	struct fb_fix_screeninfo sisfb_fix;
+	u32 		pseudo_palette[17];
+#endif
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
+	struct display 		 sis_disp;
+	struct display_switch 	 sisfb_sw;
+	struct {
+		u16 red, green, blue, pad;
+	} 		sis_palette[256];
+	union {
+#ifdef FBCON_HAS_CFB16
+		u16 cfb16[16];
+#endif
+#ifdef FBCON_HAS_CFB32
+		u32 cfb32[16];
+#endif
+	} 		sis_fbcon_cmap;
+#endif
+
+        struct sisfb_monitor {
+		u16 hmin;
+		u16 hmax;
+		u16 vmin;
+		u16 vmax;
+		u32 dclockmax;
+		u8  feature;
+		BOOLEAN datavalid;
+	} 		sisfb_thismonitor;
+
+	int           	chip_id;
+	char		myid[40];
+
+	struct pci_dev  *nbridge;
+
+	int		mni;	/* Mode number index */
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
+	int  		currcon;
+#endif
+
+	unsigned long	video_size;
+	unsigned long 	video_base;
+	unsigned long	mmio_size;
+	unsigned long 	mmio_base;
+	unsigned long 	vga_base;
+
+	unsigned long  	video_vbase;
+	unsigned long 	mmio_vbase;
+	char  *	      	bios_vbase;
+	char  *	      	bios_abase;
+
+	int 		mtrr;
+
+	u32		sisfb_mem;
+
+	u32 		sisfb_parm_mem;
+	int 	   	sisfb_accel;
+	int 		sisfb_ypan;
+	int 		sisfb_max;
+	int 		sisfb_userom;
+	int 		sisfb_useoem;
+	int		sisfb_mode_idx;
+	int		sisfb_parm_rate;
+	int		sisfb_crt1off;
+	int		sisfb_forcecrt1;
+	int		sisfb_crt2type;
+	int		sisfb_crt2flags;
+	int 		sisfb_dstn;
+	int 		sisfb_fstn;
+	int		sisfb_tvplug;
+	int		sisfb_tvstd;
+	int		sisfb_filter;
+	int		sisfb_nocrt2rate;
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
+	int		sisfb_inverse;
+#endif
+
+	u32 		heapstart;        /* offset  */
+	unsigned long  	sisfb_heap_start; /* address */
+	unsigned long  	sisfb_heap_end;   /* address */
+	u32 	      	sisfb_heap_size;
+	int		havenoheap;
+#if 0
+	SIS_HEAP       	sisfb_heap;
 #endif
 
+
+	int    		video_bpp;
+	int    		video_cmap_len;
+	int    		video_width;
+	int    		video_height;
+	unsigned int 	refresh_rate;
+
+	unsigned int 	chip;
+	u8   		revision_id;
+
+	int    		video_linelength;	/* real pitch */
+	int		scrnpitchCRT1;		/* pitch regarding interlace */
+
+        u16 		DstColor;		/* For 2d acceleration */
+	u32  		SiS310_AccelDepth;
+	u32  		CommandReg;
+	int		cmdqueuelength;
+
+	spinlock_t     	lockaccel;		/* Do not use outside of kernel! */
+
+        unsigned int   	pcibus;
+	unsigned int   	pcislot;
+	unsigned int   	pcifunc;
+
+	int 	       	accel;
+
+	u16 		subsysvendor;
+	u16 		subsysdevice;
+
+	u32  		vbflags;		/* Replacing deprecated stuff from above */
+	u32  		currentvbflags;
+
+	int		lcdxres, lcdyres;
+	int		lcddefmodeidx, tvdefmodeidx, defmodeidx;
+
+	int    		current_bpp;
+	int    		current_width;
+	int    		current_height;
+	int    		current_htotal;
+	int    		current_vtotal;
+	int		current_linelength;
+	__u32  		current_pixclock;
+	int    		current_refresh_rate;
+
+	u8  		mode_no;
+	u8  		rate_idx;
+	int    		modechanged;
+	unsigned char 	modeprechange;
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
+	u8 		sisfb_lastrates[128];
+#endif
+
+	int  		newrom;
+	int  		registered;
+#ifdef SIS_CONFIG_COMPAT
+	int		ioctl32registered;
+	int		ioctl32vblankregistered;
+#endif
+
+	int 		sisvga_engine;
+	int 		hwcursor_size;
+	int 		CRT2_write_enable;
+	u8            	caps;
+
+	u8 		detectedpdc;
+	u8 		detectedpdca;
+	u8 		detectedlcda;
+
+	unsigned long 	hwcursor_vbase;
+
+	int 		chronteltype;
+	int    		tvxpos, tvypos;
+	u8              p2_1f,p2_20,p2_2b,p2_42,p2_43,p2_01,p2_02;
+	int		tvx, tvy;
+
+	u8 		sisfblocked;
+
+	struct sis_video_info *next;
+};
+
+typedef struct _SIS_OH {
+	struct _SIS_OH *poh_next;
+	struct _SIS_OH *poh_prev;
+	u32            offset;
+	u32            size;
+} SIS_OH;
+
+typedef struct _SIS_OHALLOC {
+	struct _SIS_OHALLOC *poha_next;
+	SIS_OH aoh[1];
+} SIS_OHALLOC;
+
+typedef struct _SIS_HEAP {
+	SIS_OH      oh_free;
+	SIS_OH      oh_used;
+	SIS_OH      *poh_freelist;
+	SIS_OHALLOC *poha_chain;
+	u32         max_freesize;
+	struct sis_video_info *vinfo;
+} SIS_HEAP;
+
 #endif
--- diff/drivers/video/sis/sis_accel.c	2004-05-19 22:12:23.000000000 +0100
+++ source/drivers/video/sis/sis_accel.c	2004-06-11 19:22:05.000000000 +0100
@@ -18,9 +18,7 @@
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA
  *
- * Based on the XFree86 driver's sis300_accel.c which is
- *     Copyright (C) 2001-2004 by Thomas Winischhofer, Vienna, Austria
- * and sis310_accel.c which is
+ * Based on the XFree86/X.org driver which is
  *     Copyright (C) 2001-2004 by Thomas Winischhofer, Vienna, Austria
  *
  * Author: Thomas Winischhofer <thomas@winischhofer.net>
@@ -33,36 +31,16 @@
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/errno.h>
-#include <linux/string.h>
-#include <linux/mm.h>
-#include <linux/tty.h>
-#include <linux/slab.h>
-#include <linux/delay.h>
 #include <linux/fb.h>
 #include <linux/console.h>
 #include <linux/selection.h>
 #include <linux/ioport.h>
-#include <linux/init.h>
-#include <linux/pci.h>
-#include <linux/vt_kern.h>
 #include <linux/capability.h>
 #include <linux/fs.h>
-#include <linux/agp_backend.h>
-
 #include <linux/types.h>
 
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
-#include <linux/sisfb.h>
-#else
-#include <video/sisfb.h>
-#endif
-
 #include <asm/io.h>
 
-#ifdef CONFIG_MTRR
-#include <asm/mtrr.h>
-#endif
-
 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
 #include <video/fbcon.h>
 #include <video/fbcon-cfb8.h>
@@ -71,17 +49,10 @@
 #include <video/fbcon-cfb32.h>
 #endif
 
-#include "osdef.h"
-#include "vgatypes.h"
-#include "vstruct.h"
-#include "sis_accel.h"
 #include "sis.h"
+#include "sis_accel.h"
 
-extern struct     video_info ivideo;
-extern VGA_ENGINE sisvga_engine;
-extern int sisfb_accel;
-
-static const int sisALUConv[] =
+static const u8 sisALUConv[] =
 {
     0x00,       /* dest = 0;            0,      GXclear,        0 */
     0x88,       /* dest &= src;         DSa,    GXand,          0x1 */
@@ -101,7 +72,7 @@
     0xFF,       /* dest = 0xFF;         1,      GXset,          0xF */
 };
 /* same ROP but with Pattern as Source */
-static const int sisPatALUConv[] =
+static const u8 sisPatALUConv[] =
 {
     0x00,       /* dest = 0;            0,      GXclear,        0 */
     0xA0,       /* dest &= src;         DPa,    GXand,          0x1 */
@@ -122,26 +93,26 @@
 };
 
 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,34)
-static const unsigned char myrops[] = {
+static const int myrops[] = {
    	3, 10, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3
-   };
+};
 #endif
 
 /* 300 series ----------------------------------------------------- */
 #ifdef CONFIG_FB_SIS_300
 static void
-SiS300Sync(void)
+SiS300Sync(struct sis_video_info *ivideo)
 {
 	SiS300Idle
 }
 
 static void
-SiS300SetupForScreenToScreenCopy(int xdir, int ydir, int rop,
-                                unsigned int planemask, int trans_color)
+SiS300SetupForScreenToScreenCopy(struct sis_video_info *ivideo, int xdir, int ydir,
+                                 int rop, int trans_color)
 {
-	SiS300SetupDSTColorDepth(ivideo.DstColor);
-	SiS300SetupSRCPitch(ivideo.video_linelength)
-	SiS300SetupDSTRect(ivideo.video_linelength, -1)
+	SiS300SetupDSTColorDepth(ivideo->DstColor);
+	SiS300SetupSRCPitch(ivideo->video_linelength)
+	SiS300SetupDSTRect(ivideo->video_linelength, 0xffff)
 
 	if(trans_color != -1) {
 		SiS300SetupROP(0x0A)
@@ -159,29 +130,28 @@
 }
 
 static void
-SiS300SubsequentScreenToScreenCopy(int src_x, int src_y, int dst_x, int dst_y,
-                                int width, int height)
+SiS300SubsequentScreenToScreenCopy(struct sis_video_info *ivideo, int src_x,
+				   int src_y, int dst_x, int dst_y, int width, int height)
 {
-	long srcbase, dstbase;
+	u32 srcbase = 0, dstbase = 0;
 
-	srcbase = dstbase = 0;
-	if (src_y >= 2048) {
-		srcbase = ivideo.video_linelength * src_y;
+	if(src_y >= 2048) {
+		srcbase = ivideo->video_linelength * src_y;
 		src_y = 0;
 	}
-	if (dst_y >= 2048) {
-		dstbase = ivideo.video_linelength * dst_y;
+	if(dst_y >= 2048) {
+		dstbase = ivideo->video_linelength * dst_y;
 		dst_y = 0;
 	}
 
 	SiS300SetupSRCBase(srcbase);
 	SiS300SetupDSTBase(dstbase);
 
-	if(!(ivideo.CommandReg & X_INC))  {
+	if(!(ivideo->CommandReg & X_INC))  {
 		src_x += width-1;
 		dst_x += width-1;
 	}
-	if(!(ivideo.CommandReg & Y_INC))  {
+	if(!(ivideo->CommandReg & Y_INC))  {
 		src_y += height-1;
 		dst_y += height-1;
 	}
@@ -192,23 +162,22 @@
 }
 
 static void
-SiS300SetupForSolidFill(int color, int rop, unsigned int planemask)
+SiS300SetupForSolidFill(struct sis_video_info *ivideo, u32 color, int rop)
 {
 	SiS300SetupPATFG(color)
-	SiS300SetupDSTRect(ivideo.video_linelength, -1)
-	SiS300SetupDSTColorDepth(ivideo.DstColor);
+	SiS300SetupDSTRect(ivideo->video_linelength, 0xffff)
+	SiS300SetupDSTColorDepth(ivideo->DstColor);
 	SiS300SetupROP(sisPatALUConv[rop])
 	SiS300SetupCMDFlag(PATFG)
 }
 
 static void
-SiS300SubsequentSolidFillRect(int x, int y, int w, int h)
+SiS300SubsequentSolidFillRect(struct sis_video_info *ivideo, int x, int y, int w, int h)
 {
-	long dstbase;
+	u32 dstbase = 0;
 
-	dstbase = 0;
 	if(y >= 2048) {
-		dstbase = ivideo.video_linelength * y;
+		dstbase = ivideo->video_linelength * y;
 		y = 0;
 	}
 	SiS300SetupDSTBase(dstbase)
@@ -223,19 +192,18 @@
 
 #ifdef CONFIG_FB_SIS_315
 static void
-SiS310Sync(void)
+SiS310Sync(struct sis_video_info *ivideo)
 {
 	SiS310Idle
 }
 
 static void
-SiS310SetupForScreenToScreenCopy(int xdir, int ydir, int rop,
-                                unsigned int planemask, int trans_color)
+SiS310SetupForScreenToScreenCopy(struct sis_video_info *ivideo, int rop, int trans_color)
 {
-	SiS310SetupDSTColorDepth(ivideo.DstColor);
-	SiS310SetupSRCPitch(ivideo.video_linelength)
-	SiS310SetupDSTRect(ivideo.video_linelength, -1)
-	if (trans_color != -1) {
+	SiS310SetupDSTColorDepth(ivideo->DstColor);
+	SiS310SetupSRCPitch(ivideo->video_linelength)
+	SiS310SetupDSTRect(ivideo->video_linelength, 0xffff)
+	if(trans_color != -1) {
 		SiS310SetupROP(0x0A)
 		SiS310SetupSRCTrans(trans_color)
 		SiS310SetupCMDFlag(TRANSPARENT_BITBLT)
@@ -244,20 +212,17 @@
 		/* Set command - not needed, both 0 */
 		/* SiSSetupCMDFlag(BITBLT | SRCVIDEO) */
 	}
-	SiS310SetupCMDFlag(ivideo.SiS310_AccelDepth)
+	SiS310SetupCMDFlag(ivideo->SiS310_AccelDepth)
 	/* The 315 series is smart enough to know the direction */
 }
 
 static void
-SiS310SubsequentScreenToScreenCopy(int src_x, int src_y, int dst_x, int dst_y,
-                                int width, int height)
+SiS310SubsequentScreenToScreenCopy(struct sis_video_info *ivideo, int src_x, int src_y,
+			 int dst_x, int dst_y, int width, int height)
 {
-	long srcbase, dstbase;
-	int mymin, mymax;
-
-	srcbase = dstbase = 0;
-	mymin = min(src_y, dst_y);
-	mymax = max(src_y, dst_y);
+	u32 srcbase = 0, dstbase = 0;
+	int mymin = min(src_y, dst_y);
+	int mymax = max(src_y, dst_y);
 	
 	/* Although the chip knows the direction to use
 	 * if the source and destination areas overlap, 
@@ -271,18 +236,18 @@
 	 */
 	if((mymax - mymin) < height) { 
 	   if((src_y >= 2048) || (dst_y >= 2048)) {	      
-	      srcbase = ivideo.video_linelength * mymin;
-	      dstbase = ivideo.video_linelength * mymin;
+	      srcbase = ivideo->video_linelength * mymin;
+	      dstbase = ivideo->video_linelength * mymin;
 	      src_y -= mymin;
 	      dst_y -= mymin;
 	   }
 	} else {
 	   if(src_y >= 2048) {
-	      srcbase = ivideo.video_linelength * src_y;
+	      srcbase = ivideo->video_linelength * src_y;
 	      src_y = 0;
 	   }
 	   if(dst_y >= 2048) {
-	      dstbase = ivideo.video_linelength * dst_y;
+	      dstbase = ivideo->video_linelength * dst_y;
 	      dst_y = 0;
 	   }
 	}
@@ -296,23 +261,22 @@
 }
 
 static void
-SiS310SetupForSolidFill(int color, int rop, unsigned int planemask)
+SiS310SetupForSolidFill(struct sis_video_info *ivideo, u32 color, int rop)
 {
 	SiS310SetupPATFG(color)
-	SiS310SetupDSTRect(ivideo.video_linelength, -1)
-	SiS310SetupDSTColorDepth(ivideo.DstColor);
+	SiS310SetupDSTRect(ivideo->video_linelength, 0xffff)
+	SiS310SetupDSTColorDepth(ivideo->DstColor);
 	SiS310SetupROP(sisPatALUConv[rop])
-	SiS310SetupCMDFlag(PATFG | ivideo.SiS310_AccelDepth)
+	SiS310SetupCMDFlag(PATFG | ivideo->SiS310_AccelDepth)
 }
 
 static void
-SiS310SubsequentSolidFillRect(int x, int y, int w, int h)
+SiS310SubsequentSolidFillRect(struct sis_video_info *ivideo, int x, int y, int w, int h)
 {
-	long dstbase;
+	u32 dstbase = 0;
 
-	dstbase = 0;
 	if(y >= 2048) {
-		dstbase = ivideo.video_linelength * y;
+		dstbase = ivideo->video_linelength * y;
 		y = 0;
 	}
 	SiS310SetupDSTBase(dstbase)
@@ -327,23 +291,23 @@
 
 /* The exported routines */
 
-int sisfb_initaccel(void)
+int sisfb_initaccel(struct sis_video_info *ivideo)
 {
 #ifdef SISFB_USE_SPINLOCKS
-    spin_lock_init(&ivideo.lockaccel);
+    spin_lock_init(&ivideo->lockaccel);
 #endif
     return(0);
 }
 
-void sisfb_syncaccel(void)
+void sisfb_syncaccel(struct sis_video_info *ivideo)
 {
-    if(sisvga_engine == SIS_300_VGA) {
+    if(ivideo->sisvga_engine == SIS_300_VGA) {
 #ifdef CONFIG_FB_SIS_300
-    	SiS300Sync();
+    	SiS300Sync(ivideo);
 #endif
     } else {
 #ifdef CONFIG_FB_SIS_315
-    	SiS310Sync();
+    	SiS310Sync(ivideo);
 #endif
     }
 }
@@ -352,18 +316,19 @@
 
 int fbcon_sis_sync(struct fb_info *info)
 {
+   struct sis_video_info *ivideo = (struct sis_video_info *)info->par;
    CRITFLAGS
 
-   if(!ivideo.accel)
+   if(!ivideo->accel)
    	return 0;
 
-   if(sisvga_engine == SIS_300_VGA) {
+   if(ivideo->sisvga_engine == SIS_300_VGA) {
 #ifdef CONFIG_FB_SIS_300
-      SiS300Sync();
+      SiS300Sync(ivideo);
 #endif
    } else {
 #ifdef CONFIG_FB_SIS_315
-      SiS310Sync();
+      SiS310Sync(ivideo);
 #endif
    }
    CRITEND
@@ -372,42 +337,53 @@
 
 void fbcon_sis_fillrect(struct fb_info *info, const struct fb_fillrect *rect)
 {
-   int col=0;
+   struct sis_video_info *ivideo = (struct sis_video_info *)info->par;
+   u32 col = 0;
+   u32 vxres = info->var.xres_virtual;
+   u32 vyres = info->var.yres_virtual;
+   int width, height;
    CRITFLAGS
 
-   TWDEBUG("Inside sis_fillrect");
-   if(!rect->width || !rect->height)
-   	return;
+   if(info->state != FBINFO_STATE_RUNNING) {
+	return;
+   }
 
-   if(!ivideo.accel) {
+   if(!ivideo->accel) {
 	cfb_fillrect(info, rect);
 	return;
    }
    
+   if(!rect->width || !rect->height || rect->dx >= vxres || rect->dy >= vyres) {
+	return;
+   }
+
+   /* Clipping */
+   width = ((rect->dx + rect->width) > vxres) ? (vxres - rect->dx) : rect->width;
+   height = ((rect->dy + rect->height) > vyres) ? (vyres - rect->dy) : rect->height;
+
    switch(info->var.bits_per_pixel) {
 	case 8:  col = rect->color;
 		 break;
-	case 16: col = ((u32 *)(info->pseudo_palette))[rect->color];
-		 break;
+	case 16:
 	case 32: col = ((u32 *)(info->pseudo_palette))[rect->color];
 		 break;
    }
 
-   if(sisvga_engine == SIS_300_VGA) {
+   if(ivideo->sisvga_engine == SIS_300_VGA) {
 #ifdef CONFIG_FB_SIS_300
       CRITBEGIN
-      SiS300SetupForSolidFill(col, myrops[rect->rop], 0);
-      SiS300SubsequentSolidFillRect(rect->dx, rect->dy, rect->width, rect->height);
+      SiS300SetupForSolidFill(ivideo, col, myrops[rect->rop]);
+      SiS300SubsequentSolidFillRect(ivideo, rect->dx, rect->dy, width, height);
       CRITEND
-      SiS300Sync();
+      SiS300Sync(ivideo);
 #endif
    } else {
 #ifdef CONFIG_FB_SIS_315
       CRITBEGIN
-      SiS310SetupForSolidFill(col, myrops[rect->rop], 0);
-      SiS310SubsequentSolidFillRect(rect->dx, rect->dy, rect->width, rect->height);
+      SiS310SetupForSolidFill(ivideo, col, myrops[rect->rop]);
+      SiS310SubsequentSolidFillRect(ivideo, rect->dx, rect->dy, width, height);
       CRITEND
-      SiS310Sync();
+      SiS310Sync(ivideo);
 #endif
    }
 
@@ -415,38 +391,58 @@
 
 void fbcon_sis_copyarea(struct fb_info *info, const struct fb_copyarea *area)
 {
-   int xdir, ydir;
+   struct sis_video_info *ivideo = (struct sis_video_info *)info->par;
+   u32 vxres = info->var.xres_virtual;
+   u32 vyres = info->var.yres_virtual;
+   int width = area->width;
+   int height = area->height;
    CRITFLAGS
 
-   TWDEBUG("Inside sis_copyarea");
-   if(!ivideo.accel) {
+   if(info->state != FBINFO_STATE_RUNNING) {
+	return;
+   }
+
+   if(!ivideo->accel) {
    	cfb_copyarea(info, area);
 	return;
    }
 
-   if(!area->width || !area->height)
+   if(!width || !height ||
+      area->sx >= vxres || area->sy >= vyres ||
+      area->dx >= vxres || area->dy >= vyres) {
    	return;
+   }
 
-   if(area->sx < area->dx) xdir = 0;
-   else                    xdir = 1;
-   if(area->sy < area->dy) ydir = 0;
-   else                    ydir = 1;
+   /* Clipping */
+   if((area->sx + width) > vxres) width = vxres - area->sx;
+   if((area->dx + width) > vxres) width = vxres - area->dx;
+   if((area->sy + height) > vyres) height = vyres - area->sy;
+   if((area->dy + height) > vyres) height = vyres - area->dy;
 
-   if(sisvga_engine == SIS_300_VGA) {
+   if(ivideo->sisvga_engine == SIS_300_VGA) {
 #ifdef CONFIG_FB_SIS_300
+      int xdir, ydir;
+
+      if(area->sx < area->dx) xdir = 0;
+      else                    xdir = 1;
+      if(area->sy < area->dy) ydir = 0;
+      else                    ydir = 1;
+
       CRITBEGIN
-      SiS300SetupForScreenToScreenCopy(xdir, ydir, 3, 0, -1);
-      SiS300SubsequentScreenToScreenCopy(area->sx, area->sy, area->dx, area->dy, area->width, area->height);
+      SiS300SetupForScreenToScreenCopy(ivideo, xdir, ydir, 3, -1);
+      SiS300SubsequentScreenToScreenCopy(ivideo, area->sx, area->sy, area->dx, area->dy,
+      					 width, height);
       CRITEND
-      SiS300Sync();
+      SiS300Sync(ivideo);
 #endif
    } else {
 #ifdef CONFIG_FB_SIS_315
       CRITBEGIN
-      SiS310SetupForScreenToScreenCopy(xdir, ydir, 3, 0, -1);
-      SiS310SubsequentScreenToScreenCopy(area->sx, area->sy, area->dx, area->dy, area->width, area->height);
+      SiS310SetupForScreenToScreenCopy(ivideo, 3, -1);
+      SiS310SubsequentScreenToScreenCopy(ivideo, area->sx, area->sy, area->dx, area->dy,
+      					 width, height);
       CRITEND
-      SiS310Sync();
+      SiS310Sync(ivideo);
 #endif
    }
 }
@@ -458,11 +454,12 @@
 void fbcon_sis_bmove(struct display *p, int srcy, int srcx,
 			    int dsty, int dstx, int height, int width)
 {
-        int xdir, ydir;
+	struct sis_video_info *ivideo = (struct sis_video_info *)p->fb_info->par;
+
 	CRITFLAGS
 
-	if(!ivideo.accel) {
-	    switch(ivideo.video_bpp) {
+	if(!ivideo->accel) {
+	    switch(ivideo->video_bpp) {
 	    case 8:
 #ifdef FBCON_HAS_CFB8
 	       fbcon_cfb8_bmove(p, srcy, srcx, dsty, dstx, height, width);
@@ -489,30 +486,28 @@
 	width *= fontwidth(p);
 	height *= fontheight(p);
 
-	if(srcx < dstx) xdir = 0;
-	else            xdir = 1;
-	if(srcy < dsty) ydir = 0;
-	else            ydir = 1;
-
-	if(sisvga_engine == SIS_300_VGA) {
+	if(ivideo->sisvga_engine == SIS_300_VGA) {
 #ifdef CONFIG_FB_SIS_300
+	   int xdir, ydir;
+
+	   if(srcx < dstx) xdir = 0;
+	   else            xdir = 1;
+	   if(srcy < dsty) ydir = 0;
+	   else            ydir = 1;
+
 	   CRITBEGIN
-	   SiS300SetupForScreenToScreenCopy(xdir, ydir, 3, 0, -1);
-	   SiS300SubsequentScreenToScreenCopy(srcx, srcy, dstx, dsty, width, height);
+	   SiS300SetupForScreenToScreenCopy(ivideo, xdir, ydir, 3, -1);
+	   SiS300SubsequentScreenToScreenCopy(ivideo, srcx, srcy, dstx, dsty, width, height);
 	   CRITEND
-	   SiS300Sync();
+	   SiS300Sync(ivideo);
 #endif
 	} else {
 #ifdef CONFIG_FB_SIS_315
 	   CRITBEGIN
-	   SiS310SetupForScreenToScreenCopy(xdir, ydir, 3, 0, -1);
-	   SiS310SubsequentScreenToScreenCopy(srcx, srcy, dstx, dsty, width, height);
+	   SiS310SetupForScreenToScreenCopy(ivideo, 3, -1);
+	   SiS310SubsequentScreenToScreenCopy(ivideo, srcx, srcy, dstx, dsty, width, height);
 	   CRITEND
-	   SiS310Sync();
-#if 0
-	   printk(KERN_INFO "sis_bmove sx %d sy %d dx %d dy %d w %d h %d\n",
-		srcx, srcy, dstx, dsty, width, height);
-#endif
+	   SiS310Sync(ivideo);
 #endif
 	}
 }
@@ -520,6 +515,7 @@
 static void fbcon_sis_clear(struct vc_data *conp, struct display *p,
 			int srcy, int srcx, int height, int width, int color)
 {
+        struct sis_video_info *ivideo = (struct sis_video_info *)p->fb_info->par;
 	CRITFLAGS
 
 	srcx *= fontwidth(p);
@@ -527,21 +523,21 @@
 	width *= fontwidth(p);
 	height *= fontheight(p);
 
-	if(sisvga_engine == SIS_300_VGA) {
+	if(ivideo->sisvga_engine == SIS_300_VGA) {
 #ifdef CONFIG_FB_SIS_300
 	   CRITBEGIN
-	   SiS300SetupForSolidFill(color, 3, 0);
-	   SiS300SubsequentSolidFillRect(srcx, srcy, width, height);
+	   SiS300SetupForSolidFill(ivideo, color, 3);
+	   SiS300SubsequentSolidFillRect(ivideo, srcx, srcy, width, height);
 	   CRITEND
-	   SiS300Sync();
+	   SiS300Sync(ivideo);
 #endif
 	} else {
 #ifdef CONFIG_FB_SIS_315
 	   CRITBEGIN
-	   SiS310SetupForSolidFill(color, 3, 0);
-	   SiS310SubsequentSolidFillRect(srcx, srcy, width, height);
+	   SiS310SetupForSolidFill(ivideo, color, 3);
+	   SiS310SubsequentSolidFillRect(ivideo, srcx, srcy, width, height);
 	   CRITEND
-	   SiS310Sync();
+	   SiS310Sync(ivideo);
 #endif
 	}
 }
@@ -549,9 +545,10 @@
 void fbcon_sis_clear8(struct vc_data *conp, struct display *p,
 			int srcy, int srcx, int height, int width)
 {
+	struct sis_video_info *ivideo = (struct sis_video_info *)p->fb_info->par;
 	u32 bgx;
 
-	if(!ivideo.accel) {
+	if(!ivideo->accel) {
 #ifdef FBCON_HAS_CFB8
 	    fbcon_cfb8_clear(conp, p, srcy, srcx, height, width);
 #endif
@@ -565,8 +562,10 @@
 void fbcon_sis_clear16(struct vc_data *conp, struct display *p,
 			int srcy, int srcx, int height, int width)
 {
+        struct sis_video_info *ivideo = (struct sis_video_info *)p->fb_info->par;
 	u32 bgx;
-	if(!ivideo.accel) {
+
+	if(!ivideo->accel) {
 #ifdef FBCON_HAS_CFB16
 	    fbcon_cfb16_clear(conp, p, srcy, srcx, height, width);
 #endif
@@ -580,9 +579,10 @@
 void fbcon_sis_clear32(struct vc_data *conp, struct display *p,
 			int srcy, int srcx, int height, int width)
 {
+	struct sis_video_info *ivideo = (struct sis_video_info *)p->fb_info->par;
 	u32 bgx;
 
-	if(!ivideo.accel) {
+	if(!ivideo->accel) {
 #ifdef FBCON_HAS_CFB32
 	    fbcon_cfb32_clear(conp, p, srcy, srcx, height, width);
 #endif
@@ -595,10 +595,11 @@
 
 void fbcon_sis_revc(struct display *p, int srcx, int srcy)
 {
+	struct sis_video_info *ivideo = (struct sis_video_info *)p->fb_info->par;
 	CRITFLAGS
 
-	if(!ivideo.accel) {
-	    switch(ivideo.video_bpp) {
+	if(!ivideo->accel) {
+	    switch(ivideo->video_bpp) {
 	    case 16:
 #ifdef FBCON_HAS_CFB16
 	       fbcon_cfb16_revc(p, srcx, srcy);
@@ -616,59 +617,59 @@
 	srcx *= fontwidth(p);
 	srcy *= fontheight(p);
 
-	if(sisvga_engine == SIS_300_VGA) {
+	if(ivideo->sisvga_engine == SIS_300_VGA) {
 #ifdef CONFIG_FB_SIS_300
 	   CRITBEGIN
-	   SiS300SetupForSolidFill(0, 0x0a, 0);
-	   SiS300SubsequentSolidFillRect(srcx, srcy, fontwidth(p), fontheight(p));
+	   SiS300SetupForSolidFill(ivideo, 0, 0x0a);
+	   SiS300SubsequentSolidFillRect(ivideo, srcx, srcy, fontwidth(p), fontheight(p));
 	   CRITEND
-	   SiS300Sync();
+	   SiS300Sync(ivideo);
 #endif
 	} else {
 #ifdef CONFIG_FB_SIS_315
 	   CRITBEGIN
-	   SiS310SetupForSolidFill(0, 0x0a, 0);
-	   SiS310SubsequentSolidFillRect(srcx, srcy, fontwidth(p), fontheight(p));
+	   SiS310SetupForSolidFill(ivideo, 0, 0x0a);
+	   SiS310SubsequentSolidFillRect(ivideo, srcx, srcy, fontwidth(p), fontheight(p));
 	   CRITEND
-	   SiS310Sync();
+	   SiS310Sync(ivideo);
 #endif
 	}
 }
 
 #ifdef FBCON_HAS_CFB8
 struct display_switch fbcon_sis8 = {
-	.setup			= fbcon_cfb8_setup,
-	.bmove			= fbcon_sis_bmove,
-	.clear			= fbcon_sis_clear8,
-	.putc			= fbcon_cfb8_putc,
-	.putcs			= fbcon_cfb8_putcs,
-	.revc			= fbcon_cfb8_revc,
-	.clear_margins		= fbcon_cfb8_clear_margins,
-	.fontwidthmask		= FONTWIDTH(4)|FONTWIDTH(8)|FONTWIDTH(12)|FONTWIDTH(16)
+	.setup		= fbcon_cfb8_setup,
+	.bmove		= fbcon_sis_bmove,
+	.clear		= fbcon_sis_clear8,
+	.putc		= fbcon_cfb8_putc,
+	.putcs		= fbcon_cfb8_putcs,
+	.revc		= fbcon_cfb8_revc,
+	.clear_margins	= fbcon_cfb8_clear_margins,
+	.fontwidthmask	= FONTWIDTH(4)|FONTWIDTH(8)|FONTWIDTH(12)|FONTWIDTH(16)
 };
 #endif
 #ifdef FBCON_HAS_CFB16
 struct display_switch fbcon_sis16 = {
-	.setup			= fbcon_cfb16_setup,
-	.bmove			= fbcon_sis_bmove,
-	.clear			= fbcon_sis_clear16,
-	.putc			= fbcon_cfb16_putc,
-	.putcs			= fbcon_cfb16_putcs,
-	.revc			= fbcon_sis_revc,
-	.clear_margins		= fbcon_cfb16_clear_margins,
-	.fontwidthmask		= FONTWIDTH(4)|FONTWIDTH(8)|FONTWIDTH(12)|FONTWIDTH(16)
+	.setup		= fbcon_cfb16_setup,
+	.bmove		= fbcon_sis_bmove,
+	.clear		= fbcon_sis_clear16,
+	.putc		= fbcon_cfb16_putc,
+	.putcs		= fbcon_cfb16_putcs,
+	.revc		= fbcon_sis_revc,
+	.clear_margins	= fbcon_cfb16_clear_margins,
+	.fontwidthmask	= FONTWIDTH(4)|FONTWIDTH(8)|FONTWIDTH(12)|FONTWIDTH(16)
 };
 #endif
 #ifdef FBCON_HAS_CFB32
 struct display_switch fbcon_sis32 = {
-	.setup			= fbcon_cfb32_setup,
-	.bmove			= fbcon_sis_bmove,
-	.clear			= fbcon_sis_clear32,
-	.putc			= fbcon_cfb32_putc,
-	.putcs			= fbcon_cfb32_putcs,
-	.revc			= fbcon_sis_revc,
-	.clear_margins		= fbcon_cfb32_clear_margins,
-	.fontwidthmask		= FONTWIDTH(4)|FONTWIDTH(8)|FONTWIDTH(12)|FONTWIDTH(16)
+	.setup		= fbcon_cfb32_setup,
+	.bmove		= fbcon_sis_bmove,
+	.clear		= fbcon_sis_clear32,
+	.putc		= fbcon_cfb32_putc,
+	.putcs		= fbcon_cfb32_putcs,
+	.revc		= fbcon_sis_revc,
+	.clear_margins	= fbcon_cfb32_clear_margins,
+	.fontwidthmask	= FONTWIDTH(4)|FONTWIDTH(8)|FONTWIDTH(12)|FONTWIDTH(16)
 };
 #endif
 
--- diff/drivers/video/sis/sis_accel.h	2004-05-19 22:12:23.000000000 +0100
+++ source/drivers/video/sis/sis_accel.h	2004-06-11 19:22:05.000000000 +0100
@@ -36,8 +36,8 @@
 
 #ifdef SISFB_USE_SPINLOCKS
 #include <linux/spinlock.h>
-#define CRITBEGIN  spin_lock_irqsave(&ivideo.lockaccel), critflags);
-#define CRITEND	   spin_unlock_irqrestore(&ivideo.lockaccel), critflags);
+#define CRITBEGIN  spin_lock_irqsave(&ivideo->lockaccel, critflags);
+#define CRITEND	   spin_unlock_irqrestore(&ivideo->lockaccel, critflags);
 #define CRITFLAGS  unsigned long critflags;
 #else
 #define CRITBEGIN
@@ -65,7 +65,6 @@
 #define A3D_FUNCTION		0x00000008  /* 3D command ? */
 #define	CLEAR_Z_BUFFER		0x00000009  /* ? */
 #define GRADIENT_FILL		0x0000000A  /* Gradient fill */
-#define STRETCH_BITBLT		0x0000000B  /* Stretched Blit */
 
 /* source select */
 #define SRCVIDEO                0x00000000  /* source is video RAM */
@@ -98,11 +97,6 @@
 #define DSTAGP                  0x02000000
 #define DSTVIDEO                0x02000000
 
-/* Line */
-#define LINE_STYLE              0x00800000
-#define NO_RESET_COUNTER        0x00400000
-#define NO_LAST_PIXEL           0x00200000
-
 /* Subfunctions for Color/Enhanced Color Expansion (315 only) */
 #define COLOR_TO_MONO		0x00100000
 #define AA_TEXT			0x00200000
@@ -134,212 +128,142 @@
 
 #define PATTERN_REG		0x8300  /* 384 bytes pattern buffer */
 
-/* Line registers */
-#define LINE_X0			SRC_Y
-#define LINE_X1			DST_Y
-#define LINE_Y0			SRC_X
-#define LINE_Y1			DST_X
-#define LINE_COUNT		RECT_WIDTH
-#define LINE_STYLE_PERIOD	RECT_HEIGHT
-#define LINE_STYLE_0		MONO_MASK
-#define LINE_STYLE_1		0x8230
-#define LINE_XN			PATTERN_REG
-#define LINE_YN			PATTERN_REG+2
-
 /* Transparent bitblit registers */
 #define TRANS_DST_KEY_HIGH	PAT_FGCOLOR
 #define TRANS_DST_KEY_LOW	PAT_BGCOLOR
 #define TRANS_SRC_KEY_HIGH	SRC_FGCOLOR
 #define TRANS_SRC_KEY_LOW	SRC_BGCOLOR
 
-/* Queue */
-#define Q_BASE_ADDR		0x85C0  /* Base address of software queue (?) */
-#define Q_WRITE_PTR		0x85C4  /* Current write pointer (?) */
-#define Q_READ_PTR		0x85C8  /* Current read pointer (?) */
-#define Q_STATUS		0x85CC  /* queue status */
-
-
-#define MMIO_IN8(base, offset) \
-	*(volatile u8 *)(((u8*)(base)) + (offset))
-#define MMIO_IN16(base, offset) \
-	*(volatile u16 *)(void *)(((u8*)(base)) + (offset))
-#define MMIO_IN32(base, offset) \
-	*(volatile u32 *)(void *)(((u8*)(base)) + (offset))
-#define MMIO_OUT8(base, offset, val) \
-	*(volatile u8 *)(((u8*)(base)) + (offset)) = (val)
-#define MMIO_OUT16(base, offset, val) \
-	*(volatile u16 *)(void *)(((u8*)(base)) + (offset)) = (val)
-#define MMIO_OUT32(base, offset, val) \
-	*(volatile u32 *)(void *)(((u8*)(base)) + (offset)) = (val)
+/* Store queue length in par */
+#define CmdQueLen ivideo->cmdqueuelength
 
 /* ------------- SiS 300 series -------------- */
 
-/* Macros to do useful things with the SIS BitBLT engine */
-
-/* BR(16) (0x8420):
+/* BR(16) (0x8240):
 
    bit 31 2D engine: 1 is idle,
    bit 30 3D engine: 1 is idle,
    bit 29 Command queue: 1 is empty
-
    bits 28:24: Current CPU driven BitBlt buffer stage bit[4:0]
-
    bits 15:0:  Current command queue length
 
 */
 
-/* TW: BR(16)+2 = 0x8242 */
-
-int     CmdQueLen;
-
 #define SiS300Idle \
   { \
-  while( (MMIO_IN16(ivideo.mmio_vbase, BR(16)+2) & 0xE000) != 0xE000){}; \
-  while( (MMIO_IN16(ivideo.mmio_vbase, BR(16)+2) & 0xE000) != 0xE000){}; \
-  while( (MMIO_IN16(ivideo.mmio_vbase, BR(16)+2) & 0xE000) != 0xE000){}; \
-  CmdQueLen=MMIO_IN16(ivideo.mmio_vbase, 0x8240); \
+  	while((MMIO_IN16(ivideo->mmio_vbase, BR(16)+2) & 0xE000) != 0xE000){}; \
+  	while((MMIO_IN16(ivideo->mmio_vbase, BR(16)+2) & 0xE000) != 0xE000){}; \
+  	while((MMIO_IN16(ivideo->mmio_vbase, BR(16)+2) & 0xE000) != 0xE000){}; \
+  	CmdQueLen = MMIO_IN16(ivideo->mmio_vbase, 0x8240); \
   }
-/* TW: (do three times, because 2D engine seems quite unsure about whether or not it's idle) */
+/* (do three times, because 2D engine seems quite unsure about whether or not it's idle) */
 
 #define SiS300SetupSRCBase(base) \
-                if (CmdQueLen <= 0)  SiS300Idle;\
-                MMIO_OUT32(ivideo.mmio_vbase, BR(0), base);\
-                CmdQueLen --;
+	if(CmdQueLen <= 0) SiS300Idle;\
+	MMIO_OUT32(ivideo->mmio_vbase, BR(0), base);\
+	CmdQueLen--;
 
 #define SiS300SetupSRCPitch(pitch) \
-                if (CmdQueLen <= 0)  SiS300Idle;\
-                MMIO_OUT16(ivideo.mmio_vbase, BR(1), pitch);\
-                CmdQueLen --;
+	if(CmdQueLen <= 0) SiS300Idle;\
+	MMIO_OUT16(ivideo->mmio_vbase, BR(1), pitch);\
+	CmdQueLen--;
 
 #define SiS300SetupSRCXY(x,y) \
-                if (CmdQueLen <= 0)  SiS300Idle;\
-                MMIO_OUT32(ivideo.mmio_vbase, BR(2), (x)<<16 | (y) );\
-                CmdQueLen --;
+	if(CmdQueLen <= 0) SiS300Idle;\
+	MMIO_OUT32(ivideo->mmio_vbase, BR(2), (x)<<16 | (y) );\
+	CmdQueLen--;
 
 #define SiS300SetupDSTBase(base) \
-                if (CmdQueLen <= 0)  SiS300Idle;\
-                MMIO_OUT32(ivideo.mmio_vbase, BR(4), base);\
-                CmdQueLen --;
+	if(CmdQueLen <= 0) SiS300Idle;\
+	MMIO_OUT32(ivideo->mmio_vbase, BR(4), base);\
+	CmdQueLen--;
 
 #define SiS300SetupDSTXY(x,y) \
-                if (CmdQueLen <= 0)  SiS300Idle;\
-                MMIO_OUT32(ivideo.mmio_vbase, BR(3), (x)<<16 | (y) );\
-                CmdQueLen --;
+	if(CmdQueLen <= 0) SiS300Idle;\
+	MMIO_OUT32(ivideo->mmio_vbase, BR(3), (x)<<16 | (y) );\
+	CmdQueLen--;
 
 #define SiS300SetupDSTRect(x,y) \
-                if (CmdQueLen <= 0)  SiS300Idle;\
-                MMIO_OUT32(ivideo.mmio_vbase, BR(5), (y)<<16 | (x) );\
-                CmdQueLen --;
+	if(CmdQueLen <= 0) SiS300Idle;\
+	MMIO_OUT32(ivideo->mmio_vbase, BR(5), (y)<<16 | (x) );\
+	CmdQueLen--;
 
 #define SiS300SetupDSTColorDepth(bpp) \
-                if (CmdQueLen <= 0)  SiS300Idle;\
-                MMIO_OUT16(ivideo.mmio_vbase, BR(1)+2, bpp);\
-                CmdQueLen --;
+	if(CmdQueLen <= 0) SiS300Idle;\
+	MMIO_OUT16(ivideo->mmio_vbase, BR(1)+2, bpp);\
+	CmdQueLen--;
 
 #define SiS300SetupRect(w,h) \
-                if (CmdQueLen <= 0)  SiS300Idle;\
-                MMIO_OUT32(ivideo.mmio_vbase, BR(6), (h)<<16 | (w) );\
-                CmdQueLen --;
+	if(CmdQueLen <= 0) SiS300Idle;\
+	MMIO_OUT32(ivideo->mmio_vbase, BR(6), (h)<<16 | (w) );\
+	CmdQueLen--;
 
 #define SiS300SetupPATFG(color) \
-                if (CmdQueLen <= 0)  SiS300Idle;\
-                MMIO_OUT32(ivideo.mmio_vbase, BR(7), color);\
-                CmdQueLen --;
+	if(CmdQueLen <= 0) SiS300Idle;\
+	MMIO_OUT32(ivideo->mmio_vbase, BR(7), color);\
+	CmdQueLen--;
 
 #define SiS300SetupPATBG(color) \
-                if (CmdQueLen <= 0)  SiS300Idle;\
-                MMIO_OUT32(ivideo.mmio_vbase, BR(8), color);\
-                CmdQueLen --;
+	if(CmdQueLen <= 0) SiS300Idle;\
+	MMIO_OUT32(ivideo->mmio_vbase, BR(8), color);\
+	CmdQueLen--;
 
 #define SiS300SetupSRCFG(color) \
-                if (CmdQueLen <= 0)  SiS300Idle;\
-                MMIO_OUT32(ivideo.mmio_vbase, BR(9), color);\
-                CmdQueLen --;
+	if(CmdQueLen <= 0) SiS300Idle;\
+	MMIO_OUT32(ivideo->mmio_vbase, BR(9), color);\
+	CmdQueLen--;
 
 #define SiS300SetupSRCBG(color) \
-                if (CmdQueLen <= 0)  SiS300Idle;\
-                MMIO_OUT32(ivideo.mmio_vbase, BR(10), color);\
-                CmdQueLen --;
+	if(CmdQueLen <= 0) SiS300Idle;\
+	MMIO_OUT32(ivideo->mmio_vbase, BR(10), color);\
+	CmdQueLen--;
 
 /* 0x8224 src colorkey high */
 /* 0x8228 src colorkey low */
 /* 0x821c dest colorkey high */
 /* 0x8220 dest colorkey low */
 #define SiS300SetupSRCTrans(color) \
-                if (CmdQueLen <= 1)  SiS300Idle;\
-                MMIO_OUT32(ivideo.mmio_vbase, 0x8224, color);\
-		MMIO_OUT32(ivideo.mmio_vbase, 0x8228, color);\
-		CmdQueLen -= 2;
+	if(CmdQueLen <= 1) SiS300Idle;\
+	MMIO_OUT32(ivideo->mmio_vbase, 0x8224, color);\
+	MMIO_OUT32(ivideo->mmio_vbase, 0x8228, color);\
+	CmdQueLen -= 2;
 
 #define SiS300SetupDSTTrans(color) \
-		if (CmdQueLen <= 1)  SiS300Idle;\
-		MMIO_OUT32(ivideo.mmio_vbase, 0x821C, color); \
-		MMIO_OUT32(ivideo.mmio_vbase, 0x8220, color); \
-                CmdQueLen -= 2;
+	if(CmdQueLen <= 1) SiS300Idle;\
+	MMIO_OUT32(ivideo->mmio_vbase, 0x821C, color); \
+	MMIO_OUT32(ivideo->mmio_vbase, 0x8220, color); \
+	CmdQueLen -= 2;
 
 #define SiS300SetupMONOPAT(p0,p1) \
-                if (CmdQueLen <= 1)  SiS300Idle;\
-                MMIO_OUT32(ivideo.mmio_vbase, BR(11), p0);\
-                MMIO_OUT32(ivideo.mmio_vbase, BR(12), p1);\
-                CmdQueLen -= 2;
+	if(CmdQueLen <= 1) SiS300Idle;\
+	MMIO_OUT32(ivideo->mmio_vbase, BR(11), p0);\
+	MMIO_OUT32(ivideo->mmio_vbase, BR(12), p1);\
+	CmdQueLen -= 2;
 
 #define SiS300SetupClipLT(left,top) \
-                if (CmdQueLen <= 0)  SiS300Idle;\
-                MMIO_OUT32(ivideo.mmio_vbase, BR(13), ((left) & 0xFFFF) | (top)<<16 );\
-                CmdQueLen--;
+	if(CmdQueLen <= 0) SiS300Idle;\
+	MMIO_OUT32(ivideo->mmio_vbase, BR(13), ((left) & 0xFFFF) | (top)<<16 );\
+	CmdQueLen--;
 
 #define SiS300SetupClipRB(right,bottom) \
-                if (CmdQueLen <= 0)  SiS300Idle;\
-                MMIO_OUT32(ivideo.mmio_vbase, BR(14), ((right) & 0xFFFF) | (bottom)<<16 );\
-                CmdQueLen--;
+	if(CmdQueLen <= 0) SiS300Idle;\
+	MMIO_OUT32(ivideo->mmio_vbase, BR(14), ((right) & 0xFFFF) | (bottom)<<16 );\
+	CmdQueLen--;
 
 /* General */
 #define SiS300SetupROP(rop) \
-                ivideo.CommandReg = (rop) << 8;
+	ivideo->CommandReg = (rop) << 8;
 
 #define SiS300SetupCMDFlag(flags) \
-                ivideo.CommandReg |= (flags);
+	ivideo->CommandReg |= (flags);
 
 #define SiS300DoCMD \
-                if (CmdQueLen <= 1)  SiS300Idle;\
-                MMIO_OUT32(ivideo.mmio_vbase, BR(15), ivideo.CommandReg); \
-                MMIO_OUT32(ivideo.mmio_vbase, BR(16), 0);\
-                CmdQueLen -= 2;
-
-/* Line */
-#define SiS300SetupX0Y0(x,y) \
-                if (CmdQueLen <= 0)  SiS300Idle;\
-                MMIO_OUT32(ivideo.mmio_vbase, BR(2), (y)<<16 | (x) );\
-                CmdQueLen--;
-
-#define SiS300SetupX1Y1(x,y) \
-                if (CmdQueLen <= 0)  SiS300Idle;\
-                MMIO_OUT32(ivideo.mmio_vbase, BR(3), (y)<<16 | (x) );\
-                CmdQueLen--;
-
-#define SiS300SetupLineCount(c) \
-                if (CmdQueLen <= 0)  SiS300Idle;\
-                MMIO_OUT16(ivideo.mmio_vbase, BR(6), c);\
-                CmdQueLen--;
-
-#define SiS300SetupStylePeriod(p) \
-                if (CmdQueLen <= 0)  SiS300Idle;\
-                MMIO_OUT16(ivideo.mmio_vbase, BR(6)+2, p);\
-                CmdQueLen--;
-
-#define SiS300SetupStyleLow(ls) \
-                if (CmdQueLen <= 0)  SiS300Idle;\
-                MMIO_OUT32(ivideo.mmio_vbase, BR(11), ls);\
-                CmdQueLen--;
-
-#define SiS300SetupStyleHigh(ls) \
-                if (CmdQueLen <= 0)  SiS300Idle;\
-                MMIO_OUT32(ivideo.mmio_vbase, BR(12), ls);\
-                CmdQueLen--;
-
+	if(CmdQueLen <= 1) SiS300Idle;\
+	MMIO_OUT32(ivideo->mmio_vbase, BR(15), ivideo->CommandReg); \
+	MMIO_OUT32(ivideo->mmio_vbase, BR(16), 0);\
+	CmdQueLen -= 2;
 
-
-/* -------------- SiS 315 series --------------- */
+/* -------------- SiS 315/330 series --------------- */
 
 /* Q_STATUS:
    bit 31 = 1: All engines idle and all queues empty
@@ -353,179 +277,131 @@
    bits 23:16: 2D counter 3
    bits 15:8:  2D counter 2
    bits 7:0:   2D counter 1
-
-   Where is the command queue length (current amount of commands the queue
-   can accept) on the 315 series?
 */
 
-/* TW: FIXME: CmdQueLen is... where....? */
-/* We assume a length of 4 bytes per command; since 512K of
- * of RAM are allocated, the number of commands is easily
- * calculated (assuming that there is no 3D support yet)
- * We calculate it very cautiously (128K only) and let the
- * rest to the (never?)-to-come (?) 3D engine. (The 3D engine
- * can use a similar technique, using the remaining 384K,
- * hence a queue overflow is avoided)
- * UPDATE: This technique causes a terrible system latency
- * on integrated chipsets. Disable the queue handling for
- * now.
- */
 #define SiS310Idle \
   { \
-  while( (MMIO_IN16(ivideo.mmio_vbase, Q_STATUS+2) & 0x8000) != 0x8000){}; \
-  while( (MMIO_IN16(ivideo.mmio_vbase, Q_STATUS+2) & 0x8000) != 0x8000){}; \
-  CmdQueLen = 0; \
-  /*CmdQueLen = ((128 * 1024) / 4) - 64; */ \
+  	while( (MMIO_IN16(ivideo->mmio_vbase, Q_STATUS+2) & 0x8000) != 0x8000){}; \
+  	while( (MMIO_IN16(ivideo->mmio_vbase, Q_STATUS+2) & 0x8000) != 0x8000){}; \
+  	CmdQueLen = 0; \
   }
 
 #define SiS310SetupSRCBase(base) \
-      if (CmdQueLen <= 0)  SiS310Idle;\
-      MMIO_OUT32(ivideo.mmio_vbase, SRC_ADDR, base);\
-      CmdQueLen--;
+	if(CmdQueLen <= 0) SiS310Idle;\
+	MMIO_OUT32(ivideo->mmio_vbase, SRC_ADDR, base);\
+	CmdQueLen--;
 
 #define SiS310SetupSRCPitch(pitch) \
-      if (CmdQueLen <= 0)  SiS310Idle;\
-      MMIO_OUT16(ivideo.mmio_vbase, SRC_PITCH, pitch);\
-      CmdQueLen--;
+	if(CmdQueLen <= 0) SiS310Idle;\
+	MMIO_OUT16(ivideo->mmio_vbase, SRC_PITCH, pitch);\
+	CmdQueLen--;
 
 #define SiS310SetupSRCXY(x,y) \
-      if (CmdQueLen <= 0)  SiS310Idle;\
-      MMIO_OUT32(ivideo.mmio_vbase, SRC_Y, (x)<<16 | (y) );\
-      CmdQueLen--;
+	if(CmdQueLen <= 0) SiS310Idle;\
+	MMIO_OUT32(ivideo->mmio_vbase, SRC_Y, (x)<<16 | (y) );\
+	CmdQueLen--;
 
 #define SiS310SetupDSTBase(base) \
-      if (CmdQueLen <= 0)  SiS310Idle;\
-      MMIO_OUT32(ivideo.mmio_vbase, DST_ADDR, base);\
-      CmdQueLen--;
+	if(CmdQueLen <= 0) SiS310Idle;\
+	MMIO_OUT32(ivideo->mmio_vbase, DST_ADDR, base);\
+	CmdQueLen--;
 
 #define SiS310SetupDSTXY(x,y) \
-      if (CmdQueLen <= 0)  SiS310Idle;\
-      MMIO_OUT32(ivideo.mmio_vbase, DST_Y, (x)<<16 | (y) );\
-      CmdQueLen--;
+	if(CmdQueLen <= 0) SiS310Idle;\
+	MMIO_OUT32(ivideo->mmio_vbase, DST_Y, (x)<<16 | (y) );\
+	CmdQueLen--;
 
 #define SiS310SetupDSTRect(x,y) \
-      if (CmdQueLen <= 0)  SiS310Idle;\
-      MMIO_OUT32(ivideo.mmio_vbase, DST_PITCH, (y)<<16 | (x) );\
-      CmdQueLen--;
+	if(CmdQueLen <= 0) SiS310Idle;\
+	MMIO_OUT32(ivideo->mmio_vbase, DST_PITCH, (y)<<16 | (x) );\
+	CmdQueLen--;
 
 #define SiS310SetupDSTColorDepth(bpp) \
-      if (CmdQueLen <= 0)  SiS310Idle;\
-      MMIO_OUT16(ivideo.mmio_vbase, AGP_BASE, bpp);\
-      CmdQueLen--;
+	if(CmdQueLen <= 0) SiS310Idle;\
+	MMIO_OUT16(ivideo->mmio_vbase, AGP_BASE, bpp);\
+	CmdQueLen--;
 
 #define SiS310SetupRect(w,h) \
-      if (CmdQueLen <= 0)  SiS310Idle;\
-      MMIO_OUT32(ivideo.mmio_vbase, RECT_WIDTH, (h)<<16 | (w) );\
-      CmdQueLen--;
+	if(CmdQueLen <= 0) SiS310Idle;\
+	MMIO_OUT32(ivideo->mmio_vbase, RECT_WIDTH, (h)<<16 | (w) );\
+	CmdQueLen--;
 
 #define SiS310SetupPATFG(color) \
-      if (CmdQueLen <= 0)  SiS310Idle;\
-      MMIO_OUT32(ivideo.mmio_vbase, PAT_FGCOLOR, color);\
-      CmdQueLen--;
+	if(CmdQueLen <= 0) SiS310Idle;\
+	MMIO_OUT32(ivideo->mmio_vbase, PAT_FGCOLOR, color);\
+	CmdQueLen--;
 
 #define SiS310SetupPATBG(color) \
-      if (CmdQueLen <= 0)  SiS310Idle;\
-      MMIO_OUT32(ivideo.mmio_vbase, PAT_BGCOLOR, color);\
-      CmdQueLen--;
+	if(CmdQueLen <= 0) SiS310Idle;\
+	MMIO_OUT32(ivideo->mmio_vbase, PAT_BGCOLOR, color);\
+	CmdQueLen--;
 
 #define SiS310SetupSRCFG(color) \
-      if (CmdQueLen <= 0)  SiS310Idle;\
-      MMIO_OUT32(ivideo.mmio_vbase, SRC_FGCOLOR, color);\
-      CmdQueLen--;
+	if(CmdQueLen <= 0) SiS310Idle;\
+	MMIO_OUT32(ivideo->mmio_vbase, SRC_FGCOLOR, color);\
+	CmdQueLen--;
 
 #define SiS310SetupSRCBG(color) \
-      if (CmdQueLen <= 0)  SiS310Idle;\
-      MMIO_OUT32(ivideo.mmio_vbase, SRC_BGCOLOR, color);\
-      CmdQueLen--;
+	if(CmdQueLen <= 0) SiS310Idle;\
+	MMIO_OUT32(ivideo->mmio_vbase, SRC_BGCOLOR, color);\
+	CmdQueLen--;
 
 #define SiS310SetupSRCTrans(color) \
-      if (CmdQueLen <= 1)  SiS310Idle;\
-      MMIO_OUT32(ivideo.mmio_vbase, TRANS_SRC_KEY_HIGH, color);\
-      MMIO_OUT32(ivideo.mmio_vbase, TRANS_SRC_KEY_LOW, color);\
-      CmdQueLen -= 2;
+	if(CmdQueLen <= 1) SiS310Idle;\
+	MMIO_OUT32(ivideo->mmio_vbase, TRANS_SRC_KEY_HIGH, color);\
+	MMIO_OUT32(ivideo->mmio_vbase, TRANS_SRC_KEY_LOW, color);\
+	CmdQueLen -= 2;
 
 #define SiS310SetupDSTTrans(color) \
-      if (CmdQueLen <= 1)  SiS310Idle;\
-      MMIO_OUT32(ivideo.mmio_vbase, TRANS_DST_KEY_HIGH, color); \
-      MMIO_OUT32(ivideo.mmio_vbase, TRANS_DST_KEY_LOW, color); \
-      CmdQueLen -= 2;
+	if(CmdQueLen <= 1) SiS310Idle;\
+	MMIO_OUT32(ivideo->mmio_vbase, TRANS_DST_KEY_HIGH, color); \
+	MMIO_OUT32(ivideo->mmio_vbase, TRANS_DST_KEY_LOW, color); \
+	CmdQueLen -= 2;
 
 #define SiS310SetupMONOPAT(p0,p1) \
-      if (CmdQueLen <= 1)  SiS310Idle;\
-      MMIO_OUT32(ivideo.mmio_vbase, MONO_MASK, p0);\
-      MMIO_OUT32(ivideo.mmio_vbase, MONO_MASK+4, p1);\
-      CmdQueLen -= 2;
+	if(CmdQueLen <= 1) SiS310Idle;\
+	MMIO_OUT32(ivideo->mmio_vbase, MONO_MASK, p0);\
+	MMIO_OUT32(ivideo->mmio_vbase, MONO_MASK+4, p1);\
+	CmdQueLen -= 2;
 
 #define SiS310SetupClipLT(left,top) \
-      if (CmdQueLen <= 0)  SiS310Idle;\
-      MMIO_OUT32(ivideo.mmio_vbase, LEFT_CLIP, ((left) & 0xFFFF) | (top)<<16 );\
-      CmdQueLen--;
+	if(CmdQueLen <= 0) SiS310Idle;\
+	MMIO_OUT32(ivideo->mmio_vbase, LEFT_CLIP, ((left) & 0xFFFF) | (top)<<16 );\
+	CmdQueLen--;
 
 #define SiS310SetupClipRB(right,bottom) \
-      if (CmdQueLen <= 0)  SiS310Idle;\
-      MMIO_OUT32(ivideo.mmio_vbase, RIGHT_CLIP, ((right) & 0xFFFF) | (bottom)<<16 );\
-      CmdQueLen--;
+	if(CmdQueLen <= 0) SiS310Idle;\
+	MMIO_OUT32(ivideo->mmio_vbase, RIGHT_CLIP, ((right) & 0xFFFF) | (bottom)<<16 );\
+	CmdQueLen--;
 
 #define SiS310SetupROP(rop) \
-      ivideo.CommandReg = (rop) << 8;
+	ivideo->CommandReg = (rop) << 8;
 
 #define SiS310SetupCMDFlag(flags) \
-      ivideo.CommandReg |= (flags);
+	ivideo->CommandReg |= (flags);
 
 #define SiS310DoCMD \
-      if (CmdQueLen <= 1)  SiS310Idle;\
-      MMIO_OUT32(ivideo.mmio_vbase, COMMAND_READY, ivideo.CommandReg); \
-      MMIO_OUT32(ivideo.mmio_vbase, FIRE_TRIGGER, 0); \
-      CmdQueLen -= 2;
-
-#define SiS310SetupX0Y0(x,y) \
-      if (CmdQueLen <= 0)  SiS310Idle;\
-      MMIO_OUT32(ivideo.mmio_vbase, LINE_X0, (y)<<16 | (x) );\
-      CmdQueLen--;
-
-#define SiS310SetupX1Y1(x,y) \
-      if (CmdQueLen <= 0)  SiS310Idle;\
-      MMIO_OUT32(ivideo.mmio_vbase, LINE_X1, (y)<<16 | (x) );\
-      CmdQueLen--;
-
-#define SiS310SetupLineCount(c) \
-      if (CmdQueLen <= 0)  SiS310Idle;\
-      MMIO_OUT16(ivideo.mmio_vbase, LINE_COUNT, c);\
-      CmdQueLen--;
-
-#define SiS310SetupStylePeriod(p) \
-      if (CmdQueLen <= 0)  SiS310Idle;\
-      MMIO_OUT16(ivideo.mmio_vbase, LINE_STYLE_PERIOD, p);\
-      CmdQueLen--;
-
-#define SiS310SetupStyleLow(ls) \
-      if (CmdQueLen <= 0)  SiS310Idle;\
-      MMIO_OUT32(ivideo.mmio_vbase, LINE_STYLE_0, ls);\
-      CmdQueLen--;
-
-#define SiS310SetupStyleHigh(ls) \
-      if (CmdQueLen <= 0)  SiS310Idle;\
-      MMIO_OUT32(ivideo.mmio_vbase, LINE_STYLE_1, ls);\
-      CmdQueLen--;
+	if(CmdQueLen <= 1) SiS310Idle;\
+	MMIO_OUT32(ivideo->mmio_vbase, COMMAND_READY, ivideo->CommandReg); \
+	MMIO_OUT32(ivideo->mmio_vbase, FIRE_TRIGGER, 0); \
+	CmdQueLen -= 2;
 
-int  sisfb_initaccel(void);
-void sisfb_syncaccel(void);
 
-extern struct video_info ivideo;
+int  sisfb_initaccel(struct sis_video_info *ivideo);
+void sisfb_syncaccel(struct sis_video_info *ivideo);
 
 #if LINUX_VERSION_CODE <= KERNEL_VERSION(2,5,33)
 void fbcon_sis_bmove(struct display *p, int srcy, int srcx, int dsty,
-                     int dstx, int height, int width);
+			int dstx, int height, int width);
 void fbcon_sis_revc(struct display *p, int srcy, int srcx);
 void fbcon_sis_clear8(struct vc_data *conp, struct display *p, int srcy,
-                      int srcx, int height, int width);
+			int srcx, int height, int width);
 void fbcon_sis_clear16(struct vc_data *conp, struct display *p, int srcy,
-                       int srcx, int height, int width);
+			int srcx, int height, int width);
 void fbcon_sis_clear32(struct vc_data *conp, struct display *p, int srcy,
-                       int srcx, int height, int width);
+			int srcx, int height, int width);
 #endif
 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,34)
-extern int sisfb_accel;
 void fbcon_sis_fillrect(struct fb_info *info, const struct fb_fillrect *rect);
 void fbcon_sis_copyarea(struct fb_info *info, const struct fb_copyarea *area);
 #endif
--- diff/drivers/video/sis/sis_main.c	2004-05-19 22:12:23.000000000 +0100
+++ source/drivers/video/sis/sis_main.c	2004-06-11 19:22:05.000000000 +0100
@@ -1,6 +1,7 @@
 /*
- * SiS 300/630/730/540/315/550/650/651/M650/661FX/M661FX/740/741/M741/330/760
- * frame buffer driver for Linux kernels 2.4.x and 2.5.x
+ * SiS 300/305/540/630(S)/730(S)
+ * SiS 315(H/PRO)/55x/(M)65x/(M)661(F/M)X/740/741(GX)/330/(M)760
+ * frame buffer driver for Linux kernels >= 2.4.14 and >=2.6.3
  *
  * Copyright (C) 2001-2004 Thomas Winischhofer, Vienna, Austria.
  *
@@ -20,8 +21,8 @@
  *
  * Author:   	Thomas Winischhofer <thomas@winischhofer.net>
  *
- * Author of code base:
- *		SiS (www.sis.com.tw)
+ * Author of (practically wiped) code base:
+ *		SiS (www.sis.com)
  *	 	Copyright (C) 1999 Silicon Integrated Systems, Inc.
  *
  * See http://www.winischhofer.net/ for more information and updates
@@ -34,7 +35,11 @@
 #include <linux/config.h>
 #include <linux/version.h>
 #include <linux/module.h>
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
+#include <linux/moduleparam.h>
+#endif
 #include <linux/kernel.h>
+#include <linux/spinlock.h>
 #include <linux/errno.h>
 #include <linux/string.h>
 #include <linux/mm.h>
@@ -47,28 +52,12 @@
 #include <linux/ioport.h>
 #include <linux/init.h>
 #include <linux/pci.h>
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
 #include <linux/vmalloc.h>
-#endif
 #include <linux/vt_kern.h>
 #include <linux/capability.h>
 #include <linux/fs.h>
-#include <linux/agp_backend.h>
 #include <linux/types.h>
 #include <asm/uaccess.h>
-
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
-#include <linux/spinlock.h>
-#endif
-
-#include "osdef.h"
-
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
-#include <video/sisfb.h>
-#else
-#include <linux/sisfb.h>
-#endif
-
 #include <asm/io.h>
 #ifdef CONFIG_MTRR
 #include <asm/mtrr.h>
@@ -82,32 +71,16 @@
 #include <video/fbcon-cfb32.h>
 #endif
 
-#include "vgatypes.h"
-#include "sis_main.h"
 #include "sis.h"
+#include "sis_main.h"
 
 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)
-#error "This version of sisfb requires at least 2.6.0"
-#else
-#if 0
-#define NEWFBDEV		/* Define this as soon as new fvdev code has been merged */
-#endif
-#endif
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,3)
+#error "This version of sisfb requires at least 2.6.3"
 #endif
-
-/* -------------------- Macro definitions ---------------------------- */
-
-#undef SISFBDEBUG 	/* TW: no debugging */
-
-#ifdef SISFBDEBUG
-#define DPRINTK(fmt, args...) printk(KERN_DEBUG "%s: " fmt, __FUNCTION__ , ## args)
-#else
-#define DPRINTK(fmt, args...)
 #endif
 
 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
-#ifdef SISFBACCEL
 #ifdef FBCON_HAS_CFB8
 extern struct display_switch fbcon_sis8;
 #endif
@@ -118,174 +91,289 @@
 extern struct display_switch fbcon_sis32;
 #endif
 #endif
-#endif
 
-/* --------------- Hardware Access Routines -------------------------- */
+/* ------------------ Internal helper routines ----------------- */
 
-void sisfb_set_reg4(u16 port, unsigned long data)
+static void __init
+sisfb_setdefaultparms(void)
 {
-	outl((u32) (data & 0xffffffff), port);
+	sisfb_off 		= 0;
+	sisfb_parm_mem 		= 0;
+	sisfb_accel 		= -1;
+	sisfb_ypan      	= -1;
+	sisfb_max 		= -1;
+	sisfb_userom    	= -1;
+        sisfb_useoem    	= -1;
+#ifdef MODULE
+	/* Module: "None" for 2.4, default mode for 2.5+ */
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
+	sisfb_mode_idx 		= -1;
+#else
+	sisfb_mode_idx  	= MODE_INDEX_NONE;
+#endif
+#else
+	/* Static: Default mode */
+	sisfb_mode_idx  	= -1;
+#endif
+	sisfb_parm_rate 	= -1;
+	sisfb_crt1off 		= 0;
+	sisfb_forcecrt1 	= -1;
+	sisfb_crt2type  	= -1;
+	sisfb_crt2flags 	= 0;
+	sisfb_pdc 		= 0xff;
+	sisfb_pdca 		= 0xff;
+	sisfb_scalelcd  	= -1;
+	sisfb_specialtiming 	= CUT_NONE;
+	sisfb_lvdshl 		= -1;
+	sisfb_dstn     		= 0;
+	sisfb_fstn 		= 0;
+	sisfb_tvplug    	= -1;
+	sisfb_tvstd     	= -1;
+	sisfb_tvxposoffset 	= 0;
+	sisfb_tvyposoffset 	= 0;
+	sisfb_filter 		= -1;
+	sisfb_nocrt2rate 	= 0;
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
+	sisfb_inverse   	= 0;
+	sisfb_fontname[0] 	= 0;
+#endif
+#if !defined(__i386__) && !defined(__x86_64__)
+	sisfb_resetcard 	= 0;
+	sisfb_videoram  	= 0;
+#endif
 }
 
-u32 sisfb_get_reg3(u16 port)
+static void __init
+sisfb_search_vesamode(unsigned int vesamode, BOOLEAN quiet)
 {
-	u32 data;
+	int i = 0, j = 0;
 
-	data = inl(port);
-	return (data);
-}
+	/* BEWARE: We don't know the hardware specs yet and there is no ivideo */
+
+	if(vesamode == 0) {
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
+		sisfb_mode_idx = MODE_INDEX_NONE;
+#else
+		if(!quiet) {
+		   printk(KERN_ERR "sisfb: Invalid mode. Using default.\n");
+		}
+		sisfb_mode_idx = DEFAULT_MODE;
+#endif
+		return;
+	}
+
+	vesamode &= 0x1dff;  /* Clean VESA mode number from other flags */
 
-/* ------------ Interface for init & mode switching code ------------- */
+	while(sisbios_mode[i++].mode_no[0] != 0) {
+		if( (sisbios_mode[i-1].vesa_mode_no_1 == vesamode) ||
+		    (sisbios_mode[i-1].vesa_mode_no_2 == vesamode) ) {
+		    if(sisfb_fstn) {
+		       if(sisbios_mode[i-1].mode_no[1] == 0x50 ||
+		          sisbios_mode[i-1].mode_no[1] == 0x56 ||
+		          sisbios_mode[i-1].mode_no[1] == 0x53) continue;
+	            } else {
+		       if(sisbios_mode[i-1].mode_no[1] == 0x5a ||
+		          sisbios_mode[i-1].mode_no[1] == 0x5b) continue;
+		    }
+		    sisfb_mode_idx = i - 1;
+		    j = 1;
+		    break;
+		}
+	}
+	if((!j) && !quiet) printk(KERN_ERR "sisfb: Invalid VESA mode 0x%x'\n", vesamode);
+}
 
-BOOLEAN
-sisfb_query_VGA_config_space(PSIS_HW_INFO psishw_ext,
-	unsigned long offset, unsigned long set, unsigned long *value)
+static void
+sisfb_search_mode(char *name, BOOLEAN quiet)
 {
-	static struct pci_dev *pdev = NULL;
-	static unsigned char init = 0, valid_pdev = 0;
+	int i = 0;
+	unsigned int j = 0, xres = 0, yres = 0, depth = 0, rate = 0;
+	char strbuf[16], strbuf1[20];
+	char *nameptr = name;
 
-	if (!set)
-		DPRINTK("sisfb: Get VGA offset 0x%lx\n", offset);
-	else
-		DPRINTK("sisfb: Set offset 0x%lx to 0x%lx\n", offset, *value);
+	/* BEWARE: We don't know the hardware specs yet and there is no ivideo */
 
-	if (!init) {
-		init = TRUE;
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,74)
-		pci_for_each_dev(pdev) {
-#else
-		while((pdev = pci_find_device(PCI_VENDOR_ID_SI, PCI_ANY_ID, pdev))) {
-#endif
-			DPRINTK("sisfb: Current: 0x%x, target: 0x%x\n",
-			         pdev->device, ivideo.chip_id);
-			if ((pdev->vendor == PCI_VENDOR_ID_SI)
-			           && (pdev->device == ivideo.chip_id)) {
-				valid_pdev = TRUE;
-				break;
-			}
-		}
+	if(name == NULL) {
+	   if(!quiet) {
+	      printk(KERN_ERR "sisfb: Internal error, using default mode.\n");
+	   }
+	   sisfb_mode_idx = DEFAULT_MODE;
+	   return;
 	}
 
-	if (!valid_pdev) {
-		printk(KERN_DEBUG "sisfb: Can't find SiS %d VGA device.\n",
-				ivideo.chip_id);
-		return FALSE;
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
+        if(!strnicmp(name, sisbios_mode[MODE_INDEX_NONE].name, strlen(name))) {
+	   if(!quiet) {
+	      printk(KERN_ERR "sisfb: Mode 'none' not supported anymore. Using default.\n");
+	   }
+	   sisfb_mode_idx = DEFAULT_MODE;
+	   return;
 	}
+#endif
+	if(strlen(name) <= 19) {
+	   strcpy(strbuf1, name);
+	   for(i=0; i<strlen(strbuf1); i++) {
+	      if(strbuf1[i] < '0' || strbuf1[i] > '9') strbuf1[i] = ' ';
+	   }
 
-	if (set == 0)
-		pci_read_config_dword(pdev, offset, (u32 *)value);
-	else
-		pci_write_config_dword(pdev, offset, (u32)(*value));
+	   /* This does some fuzzy mode naming detection */
+	   if(sscanf(strbuf1, "%u %u %u %u", &xres, &yres, &depth, &rate) == 4) {
+	      if((rate <= 32) || (depth > 32)) {
+	         j = rate; rate = depth; depth = j;
+	      }
+	      sprintf(strbuf, "%ux%ux%u", xres, yres, depth);
+	      nameptr = strbuf;
+	      sisfb_parm_rate = rate;
+	   } else if(sscanf(strbuf1, "%u %u %u", &xres, &yres, &depth) == 3) {
+	      sprintf(strbuf, "%ux%ux%u", xres, yres, depth);
+	      nameptr = strbuf;
+	   } else {
+	      xres = 0;
+	      if((sscanf(strbuf1, "%u %u", &xres, &yres) == 2) && (xres != 0)) {
+	         sprintf(strbuf, "%ux%ux8", xres, yres);
+	         nameptr = strbuf;
+	      } else {
+	         sisfb_search_vesamode(simple_strtoul(name, NULL, 0), quiet);
+	         return;
+	      }
+	   }
+	}
 
-	return TRUE;
+	i = 0; j = 0;
+	while(sisbios_mode[i].mode_no[0] != 0) {
+		if(!strnicmp(nameptr, sisbios_mode[i++].name, strlen(nameptr))) {
+		   	if(sisfb_fstn) {
+		      		if(sisbios_mode[i-1].mode_no[1] == 0x50 ||
+		         	   sisbios_mode[i-1].mode_no[1] == 0x56 ||
+		         	   sisbios_mode[i-1].mode_no[1] == 0x53) continue;
+	           	} else {
+		      		if(sisbios_mode[i-1].mode_no[1] == 0x5a ||
+		         	   sisbios_mode[i-1].mode_no[1] == 0x5b) continue;
+		   	}
+		   	sisfb_mode_idx = i - 1;
+		   	j = 1;
+		   	break;
+		}
+	}
+	if((!j) && !quiet) printk(KERN_ERR "sisfb: Invalid mode '%s'\n", nameptr);
 }
 
-BOOLEAN sisfb_query_north_bridge_space(PSIS_HW_INFO psishw_ext,
-	unsigned long offset, unsigned long set, unsigned long *value)
+#ifndef MODULE
+static void __devinit
+sisfb_get_vga_mode_from_kernel(void)
 {
-	static struct pci_dev *pdev = NULL;
-	static unsigned char init = 0, valid_pdev = 0;
-	u16 nbridge_id = 0;
-
-	if (!init) {
-		init = TRUE;
-		switch (ivideo.chip) {
-#ifdef CONFIG_FB_SIS_300
-		case SIS_540:
-			nbridge_id = PCI_DEVICE_ID_SI_540;
-			break;
-		case SIS_630:
-			nbridge_id = PCI_DEVICE_ID_SI_630;
-			break;
-		case SIS_730:
-			nbridge_id = PCI_DEVICE_ID_SI_730;
-			break;
+#if (defined(__i386__) || defined(__x86_64__)) && defined(CONFIG_VIDEO_SELECT)
+   	char mymode[32];
+	int  mydepth = screen_info.lfb_depth;
+
+	if(screen_info.orig_video_isVGA != VIDEO_TYPE_VLFB) return;
+
+	if( (screen_info.lfb_width >= 320) && (screen_info.lfb_width <= 2048) &&
+	    (screen_info.lfb_height >= 200) && (screen_info.lfb_height <= 1536) &&
+	    (mydepth >= 8) && (mydepth <= 32) ) {
+
+	    if(mydepth == 24) mydepth = 32;
+
+	    sprintf(mymode, "%ux%ux%u", screen_info.lfb_width,
+	    				screen_info.lfb_height,
+					mydepth);
+
+	    printk(KERN_DEBUG "sisfb: Using vga mode %s pre-set by kernel as default\n", mymode);
+
+	    sisfb_search_mode(mymode, TRUE);
+	}
 #endif
-#ifdef CONFIG_FB_SIS_315
-		case SIS_550:
-			nbridge_id = PCI_DEVICE_ID_SI_550;
-			break;
-		case SIS_650:
-			nbridge_id = PCI_DEVICE_ID_SI_650;
-			break;
-		case SIS_740:
-			nbridge_id = PCI_DEVICE_ID_SI_740;
-			break;
-		case SIS_661:
-			nbridge_id = PCI_DEVICE_ID_SI_660;
-			break;
-		case SIS_741:
-			nbridge_id = PCI_DEVICE_ID_SI_741;
-			break;
-		case SIS_660:
-			nbridge_id = PCI_DEVICE_ID_SI_660;
-			break;
-		case SIS_760:
-			nbridge_id = PCI_DEVICE_ID_SI_760;
-			break;
+	return;
+}
 #endif
-		default:
-			nbridge_id = 0;
-			break;
-		}
 
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,74)
-		pci_for_each_dev(pdev) {
-#else
-		while((pdev = pci_find_device(PCI_VENDOR_ID_SI, PCI_ANY_ID, pdev))) {
-#endif
-			DPRINTK("Current: 0x%x, target: 0x%x\n",
-					pdev->device, ivideo.chip_id);
-			if ((pdev->vendor == PCI_VENDOR_ID_SI)
-					&& (pdev->device == nbridge_id)) {
-				valid_pdev = TRUE;
-				break;
-			}
-		}
-	}
+static void __init
+sisfb_search_crt2type(const char *name)
+{
+	int i = 0;
 
-	if (!valid_pdev) {
-		printk(KERN_DEBUG "sisfb: Can't find SiS %d North Bridge device.\n",
-				nbridge_id);
-		return FALSE;
+	/* BEWARE: We don't know the hardware specs yet and there is no ivideo */
+
+	if(name == NULL) return;
+
+	while(sis_crt2type[i].type_no != -1) {
+	   	if(!strnicmp(name, sis_crt2type[i].name, strlen(sis_crt2type[i].name))) {
+	      		sisfb_crt2type = sis_crt2type[i].type_no;
+	      		sisfb_tvplug = sis_crt2type[i].tvplug_no;
+	      		sisfb_crt2flags = sis_crt2type[i].flags;
+	      		break;
+	   	}
+	   	i++;
 	}
 
-	if (set == 0)
-		pci_read_config_dword(pdev, offset, (u32 *)value);
-	else
-		pci_write_config_dword(pdev, offset, (u32)(*value));
+	sisfb_dstn = (sisfb_crt2flags & FL_550_DSTN) ? 1 : 0;
+	sisfb_fstn = (sisfb_crt2flags & FL_550_FSTN) ? 1 : 0;
 
-	return TRUE;
+	if(sisfb_crt2type < 0) {
+		printk(KERN_ERR "sisfb: Invalid CRT2 type: %s\n", name);
+	}
 }
 
-/* ------------------ Internal helper routines ----------------- */
-
-static BOOLEAN sisfb_verify_rate(struct sisfb_monitor *monitor, int mode_idx, int rate_idx, int rate)
+static void __init
+sisfb_search_tvstd(const char *name)
 {
-	int htotal, vtotal;
-	unsigned int dclock, hsync;
-
-	if(!monitor->datavalid) return TRUE;
+	int i = 0;
 
-	if(mode_idx < 0) return FALSE;
+	/* BEWARE: We don't know the hardware specs yet and there is no ivideo */
 
-	if(rate < (monitor->vmin - 1)) return FALSE;
-	if(rate > (monitor->vmax + 1)) return FALSE;
+	if(name == NULL) return;
 
-	if(sisfb_gettotalfrommode(&SiS_Pr, &sishw_ext, sisbios_mode[mode_idx].mode_no,
-	                          &htotal, &vtotal, rate_idx)) {
-		dclock = (htotal * vtotal * rate) / 1000;
-		if(dclock > (monitor->dclockmax + 1000)) return FALSE;
-		hsync = dclock / htotal;
-		if(hsync < (monitor->hmin - 1)) return FALSE;
-		if(hsync > (monitor->hmax + 1)) return FALSE;
-        } else {
-	  	return FALSE;
+	while(sis_tvtype[i].type_no != -1) {
+	   	if(!strnicmp(name, sis_tvtype[i].name, strlen(sis_tvtype[i].name))) {
+	      		sisfb_tvstd = sis_tvtype[i].type_no;
+	      		break;
+	   	}
+	   	i++;
 	}
-	return TRUE;
-};
+}
+
+static void __init
+sisfb_search_specialtiming(const char *name)
+{
+	int i = 0;
+	BOOLEAN found = FALSE;
+
+	/* BEWARE: We don't know the hardware specs yet and there is no ivideo */
+
+	if(name == NULL) return;
+
+	if(!strnicmp(name, "none", 4)) {
+	        sisfb_specialtiming = CUT_FORCENONE;
+		printk(KERN_DEBUG "sisfb: Special timing disabled\n");
+	} else {
+	   while(mycustomttable[i].chipID != 0) {
+	      if(!strnicmp(name,mycustomttable[i].optionName, strlen(mycustomttable[i].optionName))) {
+		 sisfb_specialtiming = mycustomttable[i].SpecialID;
+		 found = TRUE;
+		 printk(KERN_INFO "sisfb: Special timing for %s %s forced (\"%s\")\n",
+		 	mycustomttable[i].vendorName, mycustomttable[i].cardName,
+		 	mycustomttable[i].optionName);
+		 break;
+	      }
+	      i++;
+	   }
+	   if(!found) {
+	      printk(KERN_WARNING "sisfb: Invalid SpecialTiming parameter, valid are:");
+	      printk(KERN_WARNING "\t\"none\" (to disable special timings)\n");
+	      i = 0;
+	      while(mycustomttable[i].chipID != 0) {
+		 printk(KERN_WARNING "\t\"%s\" (for %s %s)\n",
+		     mycustomttable[i].optionName,
+		     mycustomttable[i].vendorName,
+		     mycustomttable[i].cardName);
+		 i++;
+	      }
+           }
+ 	}
+}
 
-static BOOLEAN sisfb_interpret_edid(struct sisfb_monitor *monitor, u8 *buffer)
+static BOOLEAN __devinit
+sisfb_interpret_edid(struct sisfb_monitor *monitor, u8 *buffer)
 {
 	int i, j, xres, yres, refresh, index;
 	u32 emodes;
@@ -385,7 +473,8 @@
  	return(monitor->datavalid);
 }
 
-static void sisfb_handle_ddc(struct sisfb_monitor *monitor, int crtno)
+static void __devinit
+sisfb_handle_ddc(struct sis_video_info *ivideo, struct sisfb_monitor *monitor, int crtno)
 {
 	USHORT  temp, i, realcrtno = crtno;
    	u8      buffer[256];
@@ -393,14 +482,15 @@
 	monitor->datavalid = FALSE;
 
 	if(crtno) {
-       	   if(ivideo.vbflags & CRT2_LCD)      realcrtno = 1;
-      	   else if(ivideo.vbflags & CRT2_VGA) realcrtno = 2;
+       	   if(ivideo->vbflags & CRT2_LCD)      realcrtno = 1;
+      	   else if(ivideo->vbflags & CRT2_VGA) realcrtno = 2;
       	   else return;
    	}
 
-	if((sisfb_crt1off) && (!crtno)) return;
+	if((ivideo->sisfb_crt1off) && (!crtno)) return;
 
-    	temp = SiS_HandleDDC(&SiS_Pr, ivideo.vbflags, sisvga_engine, realcrtno, 0, &buffer[0]);
+    	temp = SiS_HandleDDC(&ivideo->SiS_Pr, ivideo->vbflags, ivideo->sisvga_engine,
+				realcrtno, 0, &buffer[0]);
    	if((!temp) || (temp == 0xffff)) {
       	   printk(KERN_INFO "sisfb: CRT%d DDC probing failed\n", crtno + 1);
 	   return;
@@ -415,7 +505,7 @@
       	   if(temp & 0x02) {
 	      i = 3;  /* Number of retrys */
 	      do {
-	    	 temp = SiS_HandleDDC(&SiS_Pr, ivideo.vbflags, sisvga_engine,
+	    	 temp = SiS_HandleDDC(&ivideo->SiS_Pr, ivideo->vbflags, ivideo->sisvga_engine,
 				     realcrtno, 1, &buffer[0]);
 	      } while((temp) && i--);
               if(!temp) {
@@ -435,194 +525,117 @@
 	}
 }
 
-static void sisfb_search_vesamode(unsigned int vesamode, BOOLEAN quiet)
+static BOOLEAN
+sisfb_verify_rate(struct sis_video_info *ivideo, struct sisfb_monitor *monitor,
+		int mode_idx, int rate_idx, int rate)
 {
-	int i = 0, j = 0;
+	int htotal, vtotal;
+	unsigned int dclock, hsync;
 
-	if(vesamode == 0) {
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
-		sisfb_mode_idx = MODE_INDEX_NONE;
-#else
-		if(!quiet)
-		   printk(KERN_ERR "sisfb: Mode 'none' not supported anymore. Using default.\n");
-		sisfb_mode_idx = DEFAULT_MODE;
+	if(!monitor->datavalid) return TRUE;
+
+	if(mode_idx < 0) return FALSE;
+
+	/* Skip for 320x200, 320x240, 640x400 */
+    	switch(sisbios_mode[mode_idx].mode_no[ivideo->mni]) {
+    	case 0x59:
+    	case 0x41:
+    	case 0x4f:
+    	case 0x50:
+    	case 0x56:
+    	case 0x53:
+    	case 0x2f:
+    	case 0x5d:
+    	case 0x5e:
+    		return TRUE;
+#ifdef CONFIG_FB_SIS_315
+	case 0x5a:
+	case 0x5b:
+		if(ivideo->sisvga_engine == SIS_315_VGA) return TRUE;
 #endif
-		return;
-	}
+    	}
 
-	vesamode &= 0x1dff;  /* Clean VESA mode number from other flags */
+	if(rate < (monitor->vmin - 1)) return FALSE;
+	if(rate > (monitor->vmax + 1)) return FALSE;
 
-	while(sisbios_mode[i++].mode_no != 0) {
-		if( (sisbios_mode[i-1].vesa_mode_no_1 == vesamode) ||
-		    (sisbios_mode[i-1].vesa_mode_no_2 == vesamode) ) {
-		    if(sisfb_fstn) {
-		       if(sisbios_mode[i-1].mode_no == 0x50 ||
-		          sisbios_mode[i-1].mode_no == 0x56 ||
-		          sisbios_mode[i-1].mode_no == 0x53) continue;
-	            } else {
-		       if(sisbios_mode[i-1].mode_no == 0x5a ||
-		          sisbios_mode[i-1].mode_no == 0x5b) continue;
-		    }
-		    sisfb_mode_idx = i - 1;
-		    j = 1;
-		    break;
-		}
+	if(sisfb_gettotalfrommode(&ivideo->SiS_Pr, &ivideo->sishw_ext,
+				  sisbios_mode[mode_idx].mode_no[ivideo->mni],
+	                          &htotal, &vtotal, rate_idx)) {
+		dclock = (htotal * vtotal * rate) / 1000;
+		if(dclock > (monitor->dclockmax + 1000)) return FALSE;
+		hsync = dclock / htotal;
+		if(hsync < (monitor->hmin - 1)) return FALSE;
+		if(hsync > (monitor->hmax + 1)) return FALSE;
+        } else {
+	  	return FALSE;
 	}
-	if((!j) && !quiet) printk(KERN_ERR "sisfb: Invalid VESA mode 0x%x'\n", vesamode);
+	return TRUE;
 }
 
-static void sisfb_search_mode(char *name, BOOLEAN quiet)
+static int
+sisfb_validate_mode(struct sis_video_info *ivideo, int myindex, u32 vbflags)
 {
-	int i = 0;
-	unsigned int j = 0, xres = 0, yres = 0, depth = 0, rate = 0;
-	char strbuf[16], strbuf1[20];
-	char *nameptr = name;
-
-	if(name == NULL) {
-	   if(!quiet)
-	      printk(KERN_ERR "sisfb: Internal error, using default mode.\n");
-	   sisfb_mode_idx = DEFAULT_MODE;
-	   return;
-	}
-
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
-        if (!strnicmp(name, sisbios_mode[MODE_INDEX_NONE].name, strlen(name))) {
-	   if(!quiet)
-	      printk(KERN_ERR "sisfb: Mode 'none' not supported anymore. Using default.\n");
-	   sisfb_mode_idx = DEFAULT_MODE;
-	   return;
-	}
-#endif
-	if(strlen(name) <= 19) {
-	   strcpy(strbuf1, name);
-	   for(i=0; i<strlen(strbuf1); i++) {
-	      if(strbuf1[i] < '0' || strbuf1[i] > '9') strbuf1[i] = ' ';
-	   }
-
-	   /* This does some fuzzy mode naming detection */
-	   if(sscanf(strbuf1, "%u %u %u %u", &xres, &yres, &depth, &rate) == 4) {
-	      if((rate <= 32) || (depth > 32)) {
-	         j = rate; rate = depth; depth = j;
-	      }
-	      sprintf(strbuf, "%ux%ux%u", xres, yres, depth);
-	      nameptr = strbuf;
-	      ivideo.refresh_rate = sisfb_parm_rate = rate;
-	   } else if(sscanf(strbuf1, "%u %u %u", &xres, &yres, &depth) == 3) {
-	      sprintf(strbuf, "%ux%ux%u", xres, yres, depth);
-	      nameptr = strbuf;
-	   } else {
-	      xres = 0;
-	      if((sscanf(strbuf1, "%u %u", &xres, &yres) == 2) && (xres != 0)) {
-	         sprintf(strbuf, "%ux%ux8", xres, yres);
-	         nameptr = strbuf;
-	      } else {
-	         sisfb_search_vesamode(simple_strtoul(name, NULL, 0), quiet);
-	         return;
-	      }
-	   }
-	}
-
-	i = 0; j = 0;
-	while(sisbios_mode[i].mode_no != 0) {
-		if(!strnicmp(nameptr, sisbios_mode[i++].name, strlen(nameptr))) {
-		   if(sisfb_fstn) {
-		      if(sisbios_mode[i-1].mode_no == 0x50 ||
-		         sisbios_mode[i-1].mode_no == 0x56 ||
-		         sisbios_mode[i-1].mode_no == 0x53) continue;
-	           } else {
-		      if(sisbios_mode[i-1].mode_no == 0x5a ||
-		         sisbios_mode[i-1].mode_no == 0x5b) continue;
-		   }
-		   sisfb_mode_idx = i - 1;
-		   j = 1;
-		   break;
-		}
-	}
-	if((!j) && !quiet) printk(KERN_ERR "sisfb: Invalid mode '%s'\n", nameptr);
-
-}
-
-static int sisfb_validate_mode(int myindex, unsigned long vbflags)
-{
-   u16 xres, yres, myres;
+   u16 xres=0, yres, myres;
 
 #ifdef CONFIG_FB_SIS_300
-   if(sisvga_engine == SIS_300_VGA) {
+   if(ivideo->sisvga_engine == SIS_300_VGA) {
       if(!(sisbios_mode[myindex].chipset & MD_SIS300)) return(-1);
    }
 #endif
 #ifdef CONFIG_FB_SIS_315
-   if(sisvga_engine == SIS_315_VGA) {
+   if(ivideo->sisvga_engine == SIS_315_VGA) {
       if(!(sisbios_mode[myindex].chipset & MD_SIS315)) return(-1);
    }
 #endif
 
    myres = sisbios_mode[myindex].yres;
 
-   switch (vbflags & VB_DISPTYPE_DISP2) {
+   switch(vbflags & VB_DISPTYPE_DISP2) {
+
      case CRT2_LCD:
-	switch (sishw_ext.ulCRT2LCDType) {
-	case LCD_640x480:  xres =  640; yres =  480;  break;
-	case LCD_800x600:  xres =  800; yres =  600;  break;
-        case LCD_1024x600: xres = 1024; yres =  600;  break;
-	case LCD_1024x768: xres = 1024; yres =  768;  break;
-	case LCD_1152x768: xres = 1152; yres =  768;  break;
-	case LCD_1280x960: xres = 1280; yres =  960;  break;
-	case LCD_1280x768: xres = 1280; yres =  768;  break;
-	case LCD_1280x1024:xres = 1280; yres = 1024;  break;
-	case LCD_1400x1050:xres = 1400; yres = 1050;  break;
-	case LCD_1600x1200:xres = 1600; yres = 1200;  break;
-	case LCD_320x480:  xres =  320; yres =  480;  break; /* FSTN (old) */
-	case LCD_640x480_2:
-	case LCD_640x480_3:xres =  640; yres =  480;  break; /* FSTN (new) */
-	default:           xres =    0; yres =    0;  break;
-	}
 
-	if(SiS_Pr.SiS_CustomT == CUT_BARCO1366) {
-	   xres = 1360; yres = 1024;
-	}
+        xres = ivideo->lcdxres; yres = ivideo->lcdyres;
 
-	if(SiS_Pr.SiS_CustomT == CUT_PANEL848) {
-	   xres = 848;  yres =  480;
-	} else {
-	   if(sisbios_mode[myindex].xres > xres) return(-1);
-           if(myres > yres) return(-1);
+	if(ivideo->SiS_Pr.SiS_CustomT != CUT_PANEL848) {
+	   	if(sisbios_mode[myindex].xres > xres) return(-1);
+           	if(myres > yres) return(-1);
 	}
 
 	if(vbflags & (VB_LVDS | VB_30xBDH)) {
 	   if(sisbios_mode[myindex].xres == 320) {
 	      if((myres == 240) || (myres == 480)) {
-		 if(!sisfb_fstn) {
-		    if(sisbios_mode[myindex].mode_no == 0x5a ||
-		       sisbios_mode[myindex].mode_no == 0x5b)
+		 if(!ivideo->sisfb_fstn) {
+		    if(sisbios_mode[myindex].mode_no[1] == 0x5a ||
+		       sisbios_mode[myindex].mode_no[1] == 0x5b)
 		       return(-1);
 		 } else {
-		    if(sisbios_mode[myindex].mode_no == 0x50 ||
-		       sisbios_mode[myindex].mode_no == 0x56 ||
-		       sisbios_mode[myindex].mode_no == 0x53)
+		    if(sisbios_mode[myindex].mode_no[1] == 0x50 ||
+		       sisbios_mode[myindex].mode_no[1] == 0x56 ||
+		       sisbios_mode[myindex].mode_no[1] == 0x53)
 		       return(-1);
 		 }
 	      }
 	   }
 	}
 
-	if(SiS_GetModeID_LCD(sisvga_engine, vbflags, sisbios_mode[myindex].xres, sisbios_mode[myindex].yres,
-	                     0, sisfb_fstn, SiS_Pr.SiS_CustomT, xres, yres) < 0x14) {
-	   return(-1);
+	if(SiS_GetModeID_LCD(ivideo->sisvga_engine, vbflags, sisbios_mode[myindex].xres,
+			     sisbios_mode[myindex].yres, 0, ivideo->sisfb_fstn,
+			     ivideo->SiS_Pr.SiS_CustomT, xres, yres) < 0x14) {
+	   	return(-1);
 	}
 	break;
 
      case CRT2_TV:
-	if(SiS_GetModeID_TV(sisvga_engine, vbflags, sisbios_mode[myindex].xres,
+	if(SiS_GetModeID_TV(ivideo->sisvga_engine, vbflags, sisbios_mode[myindex].xres,
 	                    sisbios_mode[myindex].yres, 0) < 0x14) {
-	   return(-1);
+	   	return(-1);
 	}
 	break;
 
      case CRT2_VGA:
-        if(SiS_GetModeID_VGA2(sisvga_engine, vbflags, sisbios_mode[myindex].xres,
-	                    sisbios_mode[myindex].yres, 0) < 0x14) {
-	   return(-1);
+        if(SiS_GetModeID_VGA2(ivideo->sisvga_engine, vbflags, sisbios_mode[myindex].xres,
+	                      sisbios_mode[myindex].yres, 0) < 0x14) {
+	   	return(-1);
 	}
 	break;
      }
@@ -630,49 +643,8 @@
      return(myindex);
 }
 
-static void sisfb_search_crt2type(const char *name)
-{
-	int i = 0;
-
-	if(name == NULL)
-		return;
-
-	while(sis_crt2type[i].type_no != -1) {
-		if (!strnicmp(name, sis_crt2type[i].name, strlen(sis_crt2type[i].name))) {
-			sisfb_crt2type = sis_crt2type[i].type_no;
-			sisfb_tvplug = sis_crt2type[i].tvplug_no;
-			sisfb_dstn = (sis_crt2type[i].flags & FL_550_DSTN) ? 1 : 0;
-			sisfb_fstn = (sis_crt2type[i].flags & FL_550_FSTN) ? 1 : 0;
-			break;
-		}
-		i++;
-	}
-	if(sisfb_crt2type < 0)
-		printk(KERN_ERR "sisfb: Invalid CRT2 type: %s\n", name);
-        if(ivideo.chip != SIS_550) {
-	   sisfb_dstn = sisfb_fstn = 0;
-	}
-}
-
-static void sisfb_search_queuemode(const char *name)
-{
-	int i = 0;
-
-	if(name == NULL)
-		return;
-
-	while (sis_queuemode[i].type_no != -1) {
-		if (!strnicmp(name, sis_queuemode[i].name, strlen(sis_queuemode[i].name))) {
-			sisfb_queuemode = sis_queuemode[i].type_no;
-			break;
-		}
-		i++;
-	}
-	if (sisfb_queuemode < 0)
-		printk(KERN_ERR "sisfb: Invalid queuemode type: %s\n", name);
-}
-
-static u8 sisfb_search_refresh_rate(unsigned int rate, int mode_idx)
+static u8
+sisfb_search_refresh_rate(struct sis_video_info *ivideo, unsigned int rate, int mode_idx)
 {
 	u16 xres, yres;
 	int i = 0;
@@ -680,116 +652,64 @@
 	xres = sisbios_mode[mode_idx].xres;
 	yres = sisbios_mode[mode_idx].yres;
 
-	sisfb_rate_idx = 0;
-	while ((sisfb_vrate[i].idx != 0) && (sisfb_vrate[i].xres <= xres)) {
-		if ((sisfb_vrate[i].xres == xres) && (sisfb_vrate[i].yres == yres)) {
-			if (sisfb_vrate[i].refresh == rate) {
-				sisfb_rate_idx = sisfb_vrate[i].idx;
+	ivideo->rate_idx = 0;
+	while((sisfb_vrate[i].idx != 0) && (sisfb_vrate[i].xres <= xres)) {
+		if((sisfb_vrate[i].xres == xres) && (sisfb_vrate[i].yres == yres)) {
+			if(sisfb_vrate[i].refresh == rate) {
+				ivideo->rate_idx = sisfb_vrate[i].idx;
 				break;
-			} else if (sisfb_vrate[i].refresh > rate) {
-				if ((sisfb_vrate[i].refresh - rate) <= 3) {
+			} else if(sisfb_vrate[i].refresh > rate) {
+				if((sisfb_vrate[i].refresh - rate) <= 3) {
 					DPRINTK("sisfb: Adjusting rate from %d up to %d\n",
 						rate, sisfb_vrate[i].refresh);
-					sisfb_rate_idx = sisfb_vrate[i].idx;
-					ivideo.refresh_rate = sisfb_vrate[i].refresh;
-				} else if (((rate - sisfb_vrate[i-1].refresh) <= 2)
+					ivideo->rate_idx = sisfb_vrate[i].idx;
+					ivideo->refresh_rate = sisfb_vrate[i].refresh;
+				} else if(((rate - sisfb_vrate[i-1].refresh) <= 2)
 						&& (sisfb_vrate[i].idx != 1)) {
 					DPRINTK("sisfb: Adjusting rate from %d down to %d\n",
 						rate, sisfb_vrate[i-1].refresh);
-					sisfb_rate_idx = sisfb_vrate[i-1].idx;
-					ivideo.refresh_rate = sisfb_vrate[i-1].refresh;
+					ivideo->rate_idx = sisfb_vrate[i-1].idx;
+					ivideo->refresh_rate = sisfb_vrate[i-1].refresh;
 				} 
 				break;
 			} else if((rate - sisfb_vrate[i].refresh) <= 2) {
 				DPRINTK("sisfb: Adjusting rate from %d down to %d\n",
 						rate, sisfb_vrate[i].refresh);
-	           		sisfb_rate_idx = sisfb_vrate[i].idx;
+	           		ivideo->rate_idx = sisfb_vrate[i].idx;
 		   		break;
 	       		}
 		}
 		i++;
 	}
-	if (sisfb_rate_idx > 0) {
-		return sisfb_rate_idx;
+	if(ivideo->rate_idx > 0) {
+		return ivideo->rate_idx;
 	} else {
-		printk(KERN_INFO
-			"sisfb: Unsupported rate %d for %dx%d\n", rate, xres, yres);
+		printk(KERN_INFO "sisfb: Unsupported rate %d for %dx%d\n",
+				rate, xres, yres);
 		return 0;
 	}
 }
 
-static void sisfb_search_tvstd(const char *name)
-{
-	int i = 0;
-
-	if(name == NULL)
-		return;
-
-	while (sis_tvtype[i].type_no != -1) {
-		if (!strnicmp(name, sis_tvtype[i].name, strlen(sis_tvtype[i].name))) {
-			ivideo.vbflags |= sis_tvtype[i].type_no;
-			break;
-		}
-		i++;
-	}
-}
-
-static void sisfb_search_specialtiming(const char *name)
-{
-	int i = 0;
-	BOOLEAN found = FALSE;
-
-	if(name == NULL)
-		return;
-
-	if(!strnicmp(name, "none", 4)) {
-	        SiS_Pr.SiS_CustomT = CUT_FORCENONE;
-		printk(KERN_DEBUG "sisfb: Special timing disabled\n");
-	} else {
-	   while(mycustomttable[i].chipID != 0) {
-	      if(!strnicmp(name,mycustomttable[i].optionName, strlen(mycustomttable[i].optionName))) {
-		 SiS_Pr.SiS_CustomT = mycustomttable[i].SpecialID;
-		 found = TRUE;
-		 printk(KERN_INFO "sisfb: Special timing for %s %s forced (\"%s\")\n",
-		 	mycustomttable[i].vendorName, mycustomttable[i].cardName,
-		 	mycustomttable[i].optionName);
-		 break;
-	      }
-	      i++;
-	   }
-	   if(!found) {
-	      printk(KERN_WARNING "sisfb: Invalid SpecialTiming parameter, valid are:");
-	      printk(KERN_WARNING "\t\"none\" (to disable special timings)\n");
-	      i = 0;
-	      while(mycustomttable[i].chipID != 0) {
-		 printk(KERN_WARNING "\t\"%s\" (for %s %s)\n",
-		     mycustomttable[i].optionName,
-		     mycustomttable[i].vendorName,
-		     mycustomttable[i].cardName);
-		 i++;
-	      }
-           }
- 	}
-}
-
-static BOOLEAN sisfb_bridgeisslave(void)
+static BOOLEAN
+sisfb_bridgeisslave(struct sis_video_info *ivideo)
 {
    unsigned char P1_00;
 
-   if(!(ivideo.vbflags & VB_VIDEOBRIDGE)) return FALSE;
+   if(!(ivideo->vbflags & VB_VIDEOBRIDGE)) return FALSE;
 
    inSISIDXREG(SISPART1,0x00,P1_00);
-   if( ((sisvga_engine == SIS_300_VGA) && (P1_00 & 0xa0) == 0x20) ||
-       ((sisvga_engine == SIS_315_VGA) && (P1_00 & 0x50) == 0x10) ) {
+   if( ((ivideo->sisvga_engine == SIS_300_VGA) && (P1_00 & 0xa0) == 0x20) ||
+       ((ivideo->sisvga_engine == SIS_315_VGA) && (P1_00 & 0x50) == 0x10) ) {
 	   return TRUE;
    } else {
            return FALSE;
    }
 }
 
-static BOOLEAN sisfballowretracecrt1(void)
+static BOOLEAN
+sisfballowretracecrt1(struct sis_video_info *ivideo)
 {
-   unsigned char temp;
+   u8 temp;
 
    inSISIDXREG(SISCR,0x17,temp);
    if(!(temp & 0x80)) return FALSE;
@@ -800,20 +720,21 @@
    return TRUE;
 }
 
-static BOOLEAN sisfbcheckvretracecrt1(void)
+static BOOLEAN
+sisfbcheckvretracecrt1(struct sis_video_info *ivideo)
 {
-
-   if(!sisfballowretracecrt1()) return FALSE;
+   if(!sisfballowretracecrt1(ivideo)) return FALSE;
 
    if(inSISREG(SISINPSTAT) & 0x08) return TRUE;
    else 			   return FALSE;
 }
 
-static void sisfbwaitretracecrt1(void)
+static void
+sisfbwaitretracecrt1(struct sis_video_info *ivideo)
 {
    int watchdog;
 
-   if(!sisfballowretracecrt1()) return;
+   if(!sisfballowretracecrt1(ivideo)) return;
 
    watchdog = 65536;
    while((!(inSISREG(SISINPSTAT) & 0x08)) && --watchdog);
@@ -821,19 +742,15 @@
    while((inSISREG(SISINPSTAT) & 0x08) && --watchdog);
 }
 
-static BOOLEAN sisfbcheckvretracecrt2(void)
+static BOOLEAN
+sisfbcheckvretracecrt2(struct sis_video_info *ivideo)
 {
    unsigned char temp, reg;
 
-   switch(sisvga_engine) {
-   case SIS_300_VGA:
-   	reg = 0x25;
-	break;
-   case SIS_315_VGA:
-   	reg = 0x30;
-	break;
-   default:
-        return FALSE;
+   switch(ivideo->sisvga_engine) {
+   case SIS_300_VGA: reg = 0x25; break;
+   case SIS_315_VGA: reg = 0x30; break;
+   default:          return FALSE;
    }
 
    inSISIDXREG(SISPART1, reg, temp);
@@ -841,19 +758,67 @@
    else 	   return TRUE;
 }
 
-static BOOLEAN sisfb_CheckVBRetrace(void)
+static BOOLEAN
+sisfb_CheckVBRetrace(struct sis_video_info *ivideo)
 {
-   if(ivideo.currentvbflags & VB_DISPTYPE_DISP2) {
-      if(sisfb_bridgeisslave()) {
-         return(sisfbcheckvretracecrt1());
+   if(ivideo->currentvbflags & VB_DISPTYPE_DISP2) {
+      if(sisfb_bridgeisslave(ivideo)) {
+         return(sisfbcheckvretracecrt1(ivideo));
       } else {
-         return(sisfbcheckvretracecrt2());
+         return(sisfbcheckvretracecrt2(ivideo));
       }
    } 
-   return(sisfbcheckvretracecrt1());
+   return(sisfbcheckvretracecrt1(ivideo));
+}
+
+static u32
+sisfb_setupvbblankflags(struct sis_video_info *ivideo, u32 *vcount, u32 *hcount)
+{
+   u8 idx, reg1, reg2, reg3, reg4;
+   u32 ret = 0;
+
+   (*vcount) = (*hcount) = 0;
+
+   if((ivideo->currentvbflags & VB_DISPTYPE_DISP2) && (!(sisfb_bridgeisslave(ivideo)))) {
+      ret |= (FB_VBLANK_HAVE_VSYNC  |
+      	      FB_VBLANK_HAVE_HBLANK |
+              FB_VBLANK_HAVE_VBLANK |
+	      FB_VBLANK_HAVE_VCOUNT |
+	      FB_VBLANK_HAVE_HCOUNT);
+      switch(ivideo->sisvga_engine) {
+         case SIS_300_VGA: idx = 0x25; break;
+	 default:
+         case SIS_315_VGA: idx = 0x30; break;
+      }
+      inSISIDXREG(SISPART1,(idx+0),reg1); /* 30 */
+      inSISIDXREG(SISPART1,(idx+1),reg2); /* 31 */
+      inSISIDXREG(SISPART1,(idx+2),reg3); /* 32 */
+      inSISIDXREG(SISPART1,(idx+3),reg4); /* 33 */
+      if(!(reg1 & 0x01)) ret |= FB_VBLANK_VBLANKING;
+      if(!(reg1 & 0x02)) ret |= FB_VBLANK_VSYNCING;
+      if(!(reg4 & 0x80)) ret |= FB_VBLANK_HBLANKING;
+      (*vcount) = reg3 | ((reg4 & 0x70) << 4);
+      (*hcount) = reg2 | ((reg4 & 0x0f) << 8);
+   } else if(sisfballowretracecrt1(ivideo)) {
+      ret |= (FB_VBLANK_HAVE_VSYNC  |
+              FB_VBLANK_HAVE_VBLANK |
+	      FB_VBLANK_HAVE_VCOUNT |
+	      FB_VBLANK_HAVE_HCOUNT);
+      reg1 = inSISREG(SISINPSTAT);
+      if(reg1 & 0x08) ret |= FB_VBLANK_VSYNCING;
+      if(reg1 & 0x01) ret |= FB_VBLANK_VBLANKING;
+      inSISIDXREG(SISCR,0x20,reg1);
+      inSISIDXREG(SISCR,0x1b,reg1);
+      inSISIDXREG(SISCR,0x1c,reg2);
+      inSISIDXREG(SISCR,0x1d,reg3);
+      (*vcount) = reg2 | ((reg3 & 0x07) << 8);
+      (*hcount) = (reg1 | ((reg3 & 0x10) << 4)) << 3;
+   }
+   return ret;
 }
 
-static int sisfb_myblank(int blank)
+static int
+sisfb_myblank(struct sis_video_info *ivideo, int blank)
 {
    u8 sr01, sr11, sr1f, cr63=0, p2_0, p1_13;
    BOOLEAN backlight = TRUE;
@@ -908,63 +873,64 @@
       return 1;
    }
 
-   if(ivideo.currentvbflags & VB_DISPTYPE_CRT1) {
+   if(ivideo->currentvbflags & VB_DISPTYPE_CRT1) {
 
-      setSISIDXREG(SISSR, 0x01, ~0x20, sr01);
+      if( (!ivideo->sisfb_thismonitor.datavalid) ||
+          ((ivideo->sisfb_thismonitor.datavalid) &&
+           (ivideo->sisfb_thismonitor.feature & 0xe0))) {
 
-      if( (!sisfb_thismonitor.datavalid) ||
-          ((sisfb_thismonitor.datavalid) &&
-           (sisfb_thismonitor.feature & 0xe0))) {
-
-	 if(sisvga_engine == SIS_315_VGA) {
-	    setSISIDXREG(SISCR, SiS_Pr.SiS_MyCR63, 0xbf, cr63);
+	 if(ivideo->sisvga_engine == SIS_315_VGA) {
+	    setSISIDXREG(SISCR, ivideo->SiS_Pr.SiS_MyCR63, 0xbf, cr63);
 	 }
 
-	 setSISIDXREG(SISSR, 0x1f, 0x3f, sr1f);
+	 if(!(sisfb_bridgeisslave(ivideo))) {
+	    setSISIDXREG(SISSR, 0x01, ~0x20, sr01);
+	    setSISIDXREG(SISSR, 0x1f, 0x3f, sr1f);
+	 }
       }
 
    }
 
-   if(ivideo.currentvbflags & CRT2_LCD) {
+   if(ivideo->currentvbflags & CRT2_LCD) {
 
-      if(ivideo.vbflags & (VB_301LV|VB_302LV|VB_302ELV)) {
+      if(ivideo->vbflags & (VB_301LV|VB_302LV|VB_302ELV)) {
 	 if(backlight) {
-	    SiS_SiS30xBLOn(&SiS_Pr, &sishw_ext);
+	    SiS_SiS30xBLOn(&ivideo->SiS_Pr, &ivideo->sishw_ext);
 	 } else {
-	    SiS_SiS30xBLOff(&SiS_Pr, &sishw_ext);
+	    SiS_SiS30xBLOff(&ivideo->SiS_Pr, &ivideo->sishw_ext);
 	 }
-      } else if(sisvga_engine == SIS_315_VGA) {
-	 if(ivideo.vbflags & VB_CHRONTEL) {
+      } else if(ivideo->sisvga_engine == SIS_315_VGA) {
+	 if(ivideo->vbflags & VB_CHRONTEL) {
 	    if(backlight) {
-	       SiS_Chrontel701xBLOn(&SiS_Pr,&sishw_ext);
+	       SiS_Chrontel701xBLOn(&ivideo->SiS_Pr,&ivideo->sishw_ext);
 	    } else {
-	       SiS_Chrontel701xBLOff(&SiS_Pr);
+	       SiS_Chrontel701xBLOff(&ivideo->SiS_Pr);
 	    }
 	 }
       }
 
-      if(((sisvga_engine == SIS_300_VGA) &&
-          (ivideo.vbflags & (VB_301|VB_30xBDH|VB_LVDS))) ||
-         ((sisvga_engine == SIS_315_VGA) &&
-          ((ivideo.vbflags & (VB_LVDS | VB_CHRONTEL)) == VB_LVDS))) {
+      if(((ivideo->sisvga_engine == SIS_300_VGA) &&
+          (ivideo->vbflags & (VB_301|VB_30xBDH|VB_LVDS))) ||
+         ((ivideo->sisvga_engine == SIS_315_VGA) &&
+          ((ivideo->vbflags & (VB_LVDS | VB_CHRONTEL)) == VB_LVDS))) {
           setSISIDXREG(SISSR, 0x11, ~0x0c, sr11);
       }
 
-      if(sisvga_engine == SIS_300_VGA) {
-         if((ivideo.vbflags & (VB_301B|VB_301C|VB_302B)) &&
-            (!(ivideo.vbflags & VB_30xBDH))) {
+      if(ivideo->sisvga_engine == SIS_300_VGA) {
+         if((ivideo->vbflags & (VB_301B|VB_301C|VB_302B)) &&
+            (!(ivideo->vbflags & VB_30xBDH))) {
 	    setSISIDXREG(SISPART1, 0x13, 0x3f, p1_13);
 	 }
-      } else if(sisvga_engine == SIS_315_VGA) {
-         if((ivideo.vbflags & (VB_301B|VB_301C|VB_302B)) &&
-            (!(ivideo.vbflags & VB_30xBDH))) {
+      } else if(ivideo->sisvga_engine == SIS_315_VGA) {
+         if((ivideo->vbflags & (VB_301B|VB_301C|VB_302B)) &&
+            (!(ivideo->vbflags & VB_30xBDH))) {
 	    setSISIDXREG(SISPART2, 0x00, 0x1f, p2_0);
 	 }
       }
 
-   } else if(ivideo.currentvbflags & CRT2_VGA) {
+   } else if(ivideo->currentvbflags & CRT2_VGA) {
 
-      if(ivideo.vbflags & (VB_301B|VB_301C|VB_302B)) {
+      if(ivideo->vbflags & (VB_301B|VB_301C|VB_302B)) {
          setSISIDXREG(SISPART2, 0x00, 0x1f, p2_0);
       }
 
@@ -975,35 +941,122 @@
 
 /* ----------- FBDev related routines for all series ----------- */
 
-static void sisfb_set_vparms(void)
+static int
+sisfb_get_cmap_len(const struct fb_var_screeninfo *var)
 {
-   switch(ivideo.video_bpp) {
-   case 8:
-       	ivideo.DstColor = 0x0000;
-	ivideo.SiS310_AccelDepth = 0x00000000;
-	ivideo.video_cmap_len = 256;
-       	break;
-   case 16:
-       	ivideo.DstColor = 0x8000;
-       	ivideo.SiS310_AccelDepth = 0x00010000;
-	ivideo.video_cmap_len = 16;
-       	break;
-   case 32:
-       	ivideo.DstColor = 0xC000;
-	ivideo.SiS310_AccelDepth = 0x00020000;
-	ivideo.video_cmap_len = 16;
-       	break;
-   default:
- 	ivideo.video_cmap_len = 16;
-	printk(KERN_ERR "sisfb: Unsupported depth %d", ivideo.video_bpp);
-	ivideo.accel = 0;
-	break;
-   }
+	return (var->bits_per_pixel == 8) ? 256 : 16;
+}
+
+static void
+sisfb_set_vparms(struct sis_video_info *ivideo)
+{
+   	switch(ivideo->video_bpp) {
+	case 8:
+		ivideo->DstColor = 0x0000;
+		ivideo->SiS310_AccelDepth = 0x00000000;
+		ivideo->video_cmap_len = 256;
+		break;
+	case 16:
+		ivideo->DstColor = 0x8000;
+		ivideo->SiS310_AccelDepth = 0x00010000;
+		ivideo->video_cmap_len = 16;
+		break;
+	case 32:
+		ivideo->DstColor = 0xC000;
+		ivideo->SiS310_AccelDepth = 0x00020000;
+		ivideo->video_cmap_len = 16;
+		break;
+	default:
+		ivideo->video_cmap_len = 16;
+		printk(KERN_ERR "sisfb: Unsupported depth %d", ivideo->video_bpp);
+		ivideo->accel = 0;
+		break;
+   	}
+}
+
+static int
+sisfb_calc_maxyres(struct sis_video_info *ivideo, struct fb_var_screeninfo *var)
+{
+	int maxyres = ivideo->heapstart / (var->xres_virtual * (var->bits_per_pixel >> 3));
+
+	if(maxyres > 32767) maxyres = 32767;
+
+	return maxyres;
+}
+
+static void
+sisfb_calc_pitch(struct sis_video_info *ivideo, struct fb_var_screeninfo *var)
+{
+	ivideo->video_linelength = var->xres_virtual * (var->bits_per_pixel >> 3);
+	ivideo->scrnpitchCRT1 = ivideo->video_linelength;
+	if(!(ivideo->currentvbflags & CRT1_LCDA)) {
+		if((var->vmode & FB_VMODE_MASK) == FB_VMODE_INTERLACED) {
+			ivideo->scrnpitchCRT1 <<= 1;
+		}
+	}
+
+}
+
+static void
+sisfb_set_pitch(struct sis_video_info *ivideo)
+{
+   	BOOLEAN isslavemode = FALSE;
+	unsigned short HDisplay1 = ivideo->scrnpitchCRT1 >> 3;
+	unsigned short HDisplay2 = ivideo->video_linelength >> 3;
+
+   	if(sisfb_bridgeisslave(ivideo)) isslavemode = TRUE;
+
+   	/* We need to set pitch for CRT1 if bridge is in slave mode, too */
+   	if((ivideo->currentvbflags & VB_DISPTYPE_DISP1) || (isslavemode)) {
+   		outSISIDXREG(SISCR,0x13,(HDisplay1 & 0xFF));
+   		setSISIDXREG(SISSR,0x0E,0xF0,(HDisplay1 >> 8));
+	}
+
+   	/* We must not set the pitch for CRT2 if bridge is in slave mode */
+   	if((ivideo->currentvbflags & VB_DISPTYPE_DISP2) && (!isslavemode)) {
+		orSISIDXREG(SISPART1,ivideo->CRT2_write_enable,0x01);
+   		outSISIDXREG(SISPART1,0x07,(HDisplay2 & 0xFF));
+   		setSISIDXREG(SISPART1,0x09,0xF0,(HDisplay2 >> 8));
+   	}
+}
+
+static void
+sisfb_bpp_to_var(struct sis_video_info *ivideo, struct fb_var_screeninfo *var)
+{
+	ivideo->video_cmap_len = sisfb_get_cmap_len(var);
+
+	switch(var->bits_per_pixel) {
+	case 8:
+		var->red.offset = var->green.offset = var->blue.offset = 0;
+		var->red.length = var->green.length = var->blue.length = 6;
+		break;
+	case 16:
+		var->red.offset = 11;
+		var->red.length = 5;
+		var->green.offset = 5;
+		var->green.length = 6;
+		var->blue.offset = 0;
+		var->blue.length = 5;
+		var->transp.offset = 0;
+		var->transp.length = 0;
+		break;
+	case 32:
+		var->red.offset = 16;
+		var->red.length = 8;
+		var->green.offset = 8;
+		var->green.length = 8;
+		var->blue.offset = 0;
+		var->blue.length = 8;
+		var->transp.offset = 24;
+		var->transp.length = 8;
+		break;
+	}
 }
 
-static int sisfb_do_set_var(struct fb_var_screeninfo *var, int isactive,
-		      struct fb_info *info)
+static int
+sisfb_do_set_var(struct fb_var_screeninfo *var, int isactive, struct fb_info *info)
 {
+	struct sis_video_info *ivideo = (struct sis_video_info *)info->par;
 	unsigned int htotal = 0, vtotal = 0;
 	unsigned int drate = 0, hrate = 0;
 	int found_mode = 0;
@@ -1033,52 +1086,51 @@
 	}
 
 	if(pixclock && htotal && vtotal) {
-	   drate = 1000000000 / pixclock;
-	   hrate = (drate * 1000) / htotal;
-	   ivideo.refresh_rate = (unsigned int) (hrate * 2 / vtotal);
-	} else ivideo.refresh_rate = 60;
-
-#if 0
-	printk(KERN_DEBUG "sisfb: Change mode to %dx%dx%d-%dHz\n",
-		var->xres,var->yres,var->bits_per_pixel,ivideo.refresh_rate);
-#endif
+	   	drate = 1000000000 / pixclock;
+	   	hrate = (drate * 1000) / htotal;
+	   	ivideo->refresh_rate = (unsigned int) (hrate * 2 / vtotal);
+	} else {
+	   	ivideo->refresh_rate = 60;
+	}
 
-	old_mode = sisfb_mode_idx;
-	sisfb_mode_idx = 0;
+	old_mode = ivideo->sisfb_mode_idx;
+	ivideo->sisfb_mode_idx = 0;
 
-	while( (sisbios_mode[sisfb_mode_idx].mode_no != 0) &&
-	       (sisbios_mode[sisfb_mode_idx].xres <= var->xres) ) {
-		if( (sisbios_mode[sisfb_mode_idx].xres == var->xres) &&
-		    (sisbios_mode[sisfb_mode_idx].yres == var->yres) &&
-		    (sisbios_mode[sisfb_mode_idx].bpp == var->bits_per_pixel)) {
-			sisfb_mode_no = sisbios_mode[sisfb_mode_idx].mode_no;
+	while( (sisbios_mode[ivideo->sisfb_mode_idx].mode_no[0] != 0) &&
+	       (sisbios_mode[ivideo->sisfb_mode_idx].xres <= var->xres) ) {
+		if( (sisbios_mode[ivideo->sisfb_mode_idx].xres == var->xres) &&
+		    (sisbios_mode[ivideo->sisfb_mode_idx].yres == var->yres) &&
+		    (sisbios_mode[ivideo->sisfb_mode_idx].bpp == var->bits_per_pixel)) {
+			ivideo->mode_no = sisbios_mode[ivideo->sisfb_mode_idx].mode_no[ivideo->mni];
 			found_mode = 1;
 			break;
 		}
-		sisfb_mode_idx++;
+		ivideo->sisfb_mode_idx++;
 	}
 
-	if(found_mode)
-		sisfb_mode_idx = sisfb_validate_mode(sisfb_mode_idx, ivideo.currentvbflags);
-	else
-		sisfb_mode_idx = -1;
+	if(found_mode) {
+		ivideo->sisfb_mode_idx = sisfb_validate_mode(ivideo,
+				ivideo->sisfb_mode_idx, ivideo->currentvbflags);
+	} else {
+		ivideo->sisfb_mode_idx = -1;
+	}
 
-       	if(sisfb_mode_idx < 0) {
+       	if(ivideo->sisfb_mode_idx < 0) {
 		printk(KERN_ERR "sisfb: Mode %dx%dx%d not supported\n", var->xres,
 		       var->yres, var->bits_per_pixel);
-		sisfb_mode_idx = old_mode;
+		ivideo->sisfb_mode_idx = old_mode;
 		return -EINVAL;
 	}
 
-	if(sisfb_search_refresh_rate(ivideo.refresh_rate, sisfb_mode_idx) == 0) {
-		sisfb_rate_idx = sisbios_mode[sisfb_mode_idx].rate_idx;
-		ivideo.refresh_rate = 60;
+	if(sisfb_search_refresh_rate(ivideo, ivideo->refresh_rate, ivideo->sisfb_mode_idx) == 0) {
+		ivideo->rate_idx = sisbios_mode[ivideo->sisfb_mode_idx].rate_idx;
+		ivideo->refresh_rate = 60;
 	}
 
 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
-	if(sisfb_thismonitor.datavalid) {
-	   if(!sisfb_verify_rate(&sisfb_thismonitor, sisfb_mode_idx,
-	                         sisfb_rate_idx, ivideo.refresh_rate)) {
+	if(ivideo->sisfb_thismonitor.datavalid) {
+	   if(!sisfb_verify_rate(ivideo, &ivideo->sisfb_thismonitor, ivideo->sisfb_mode_idx,
+	                         ivideo->rate_idx, ivideo->refresh_rate)) {
 	      printk(KERN_INFO "sisfb: WARNING: Refresh rate exceeds monitor specs!\n");
 	   }
 	}
@@ -1089,64 +1141,77 @@
 #else
 	if(isactive) {
 #endif
-		sisfb_pre_setmode();
+		sisfb_pre_setmode(ivideo);
 
-		if(SiSSetMode(&SiS_Pr, &sishw_ext, sisfb_mode_no) == 0) {
-			printk(KERN_ERR "sisfb: Setting mode[0x%x] failed\n", sisfb_mode_no);
+		if(SiSSetMode(&ivideo->SiS_Pr, &ivideo->sishw_ext, ivideo->mode_no) == 0) {
+			printk(KERN_ERR "sisfb: Setting mode[0x%x] failed\n", ivideo->mode_no);
 			return -EINVAL;
 		}
 
 		outSISIDXREG(SISSR, IND_SIS_PASSWORD, SIS_PASSWORD);
 
-		ivideo.video_bpp = sisbios_mode[sisfb_mode_idx].bpp;
-		ivideo.video_vwidth = ivideo.video_width = sisbios_mode[sisfb_mode_idx].xres;
-		ivideo.video_vheight = ivideo.video_height = sisbios_mode[sisfb_mode_idx].yres;
-		ivideo.org_x = ivideo.org_y = 0;
-		ivideo.video_linelength = ivideo.video_width * (ivideo.video_bpp >> 3);
-		ivideo.accel = 0;
-		if(sisfb_accel) {
-		   ivideo.accel = (var->accel_flags & FB_ACCELF_TEXT) ? -1 : 0;
-		}
-
-		sisfb_set_vparms();
-
-		ivideo.current_width = ivideo.video_width;
-		ivideo.current_height = ivideo.video_height;
-		ivideo.current_bpp = ivideo.video_bpp;
-		ivideo.current_htotal = htotal;
-		ivideo.current_vtotal = vtotal;
-		ivideo.current_pixclock = var->pixclock;
-		ivideo.current_refresh_rate = ivideo.refresh_rate;
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
-                sisfb_lastrates[sisfb_mode_no] = ivideo.refresh_rate;
+		sisfb_post_setmode(ivideo);
+
+		ivideo->video_bpp    = sisbios_mode[ivideo->sisfb_mode_idx].bpp;
+		ivideo->video_width  = sisbios_mode[ivideo->sisfb_mode_idx].xres;
+		ivideo->video_height = sisbios_mode[ivideo->sisfb_mode_idx].yres;
+
+		sisfb_calc_pitch(ivideo, var);
+		sisfb_set_pitch(ivideo);
+
+		ivideo->accel = 0;
+#if defined(FBINFO_HWACCEL_DISABLED) && defined(FBINFO_HWACCEL_XPAN)
+#ifdef STUPID_ACCELF_TEXT_SHIT
+		if(var->accel_flags & FB_ACCELF_TEXT) {
+			info->flags &= ~FBINFO_HWACCEL_DISABLED;
+		} else {
+			info->flags |= FBINFO_HWACCEL_DISABLED;
+		}
+#endif
+		if(!(info->flags & FBINFO_HWACCEL_DISABLED)) ivideo->accel = -1;
+#else
+		if(var->accel_flags & FB_ACCELF_TEXT) ivideo->accel = -1;
 #endif
 
-		sisfb_post_setmode();
+		sisfb_set_vparms(ivideo);
 
+		ivideo->current_width = ivideo->video_width;
+		ivideo->current_height = ivideo->video_height;
+		ivideo->current_bpp = ivideo->video_bpp;
+		ivideo->current_htotal = htotal;
+		ivideo->current_vtotal = vtotal;
+		ivideo->current_linelength = ivideo->video_linelength;
+		ivideo->current_pixclock = var->pixclock;
+		ivideo->current_refresh_rate = ivideo->refresh_rate;
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
+                ivideo->sisfb_lastrates[ivideo->mode_no] = ivideo->refresh_rate;
+#endif
 	}
+
 	return 0;
 }
 
-static int sisfb_pan_var(struct fb_var_screeninfo *var)
+static int
+sisfb_pan_var(struct sis_video_info *ivideo, struct fb_var_screeninfo *var)
 {
 	unsigned int base;
 
-	if (var->xoffset > (var->xres_virtual - var->xres)) {
+	if(var->xoffset > (var->xres_virtual - var->xres)) {
 		return -EINVAL;
 	}
 	if(var->yoffset > (var->yres_virtual - var->yres)) {
 		return -EINVAL;
 	}
 
-	base = var->yoffset * var->xres_virtual + var->xoffset;
+	base = (var->yoffset * var->xres_virtual) + var->xoffset;
 
         /* calculate base bpp dep. */
         switch(var->bits_per_pixel) {
+	case 32:
+            	break;
         case 16:
         	base >>= 1;
         	break;
-	case 32:
-            	break;
 	case 8:
         default:
         	base >>= 2;
@@ -1158,81 +1223,27 @@
         outSISIDXREG(SISCR, 0x0D, base & 0xFF);
 	outSISIDXREG(SISCR, 0x0C, (base >> 8) & 0xFF);
 	outSISIDXREG(SISSR, 0x0D, (base >> 16) & 0xFF);
-	if(sisvga_engine == SIS_315_VGA) {
+	if(ivideo->sisvga_engine == SIS_315_VGA) {
 		setSISIDXREG(SISSR, 0x37, 0xFE, (base >> 24) & 0x01);
 	}
-        if(ivideo.currentvbflags & VB_DISPTYPE_DISP2) {
-		orSISIDXREG(SISPART1, sisfb_CRT2_write_enable, 0x01);
+        if(ivideo->currentvbflags & VB_DISPTYPE_DISP2) {
+		orSISIDXREG(SISPART1, ivideo->CRT2_write_enable, 0x01);
         	outSISIDXREG(SISPART1, 0x06, (base & 0xFF));
         	outSISIDXREG(SISPART1, 0x05, ((base >> 8) & 0xFF));
         	outSISIDXREG(SISPART1, 0x04, ((base >> 16) & 0xFF));
-		if(sisvga_engine == SIS_315_VGA) {
+		if(ivideo->sisvga_engine == SIS_315_VGA) {
 			setSISIDXREG(SISPART1, 0x02, 0x7F, ((base >> 24) & 0x01) << 7);
 		}
         }
 	return 0;
 }
 
-static void sisfb_bpp_to_var(struct fb_var_screeninfo *var)
-{
-	switch(var->bits_per_pixel) {
-	   case 8:
-	   	var->red.offset = var->green.offset = var->blue.offset = 0;
-		var->red.length = var->green.length = var->blue.length = 6;
-		ivideo.video_cmap_len = 256;
-		break;
-	   case 16:
-		var->red.offset = 11;
-		var->red.length = 5;
-		var->green.offset = 5;
-		var->green.length = 6;
-		var->blue.offset = 0;
-		var->blue.length = 5;
-		var->transp.offset = 0;
-		var->transp.length = 0;
-		ivideo.video_cmap_len = 16;
-		break;
-	   case 32:
-		var->red.offset = 16;
-		var->red.length = 8;
-		var->green.offset = 8;
-		var->green.length = 8;
-		var->blue.offset = 0;
-		var->blue.length = 8;
-		var->transp.offset = 24;
-		var->transp.length = 8;
-		ivideo.video_cmap_len = 16;
-		break;
-	}
-}
-
-void sis_dispinfo(struct ap_data *rec)
-{
-	rec->minfo.bpp      = ivideo.video_bpp;
-	rec->minfo.xres     = ivideo.video_width;
-	rec->minfo.yres     = ivideo.video_height;
-	rec->minfo.v_xres   = ivideo.video_vwidth;
-	rec->minfo.v_yres   = ivideo.video_vheight;
-	rec->minfo.org_x    = ivideo.org_x;
-	rec->minfo.org_y    = ivideo.org_y;
-	rec->minfo.vrate    = ivideo.refresh_rate;
-	rec->iobase         = ivideo.vga_base - 0x30;
-	rec->mem_size       = ivideo.video_size;
-	rec->disp_state     = ivideo.disp_state;
-	rec->version        = (VER_MAJOR << 24) | (VER_MINOR << 16) | VER_LEVEL;
-	rec->hasVB          = ivideo.hasVB;
-	rec->TV_type        = ivideo.TV_type;
-	rec->TV_plug        = ivideo.TV_plug;
-	rec->chip           = ivideo.chip;
-	rec->vbflags	    = ivideo.vbflags;
-	rec->currentvbflags = ivideo.currentvbflags;
-}
-
-/* ------------ FBDev related routines for 2.4 series ----------- */
-
-#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,5,0)
-
-static void sisfb_crtc_to_var(struct fb_var_screeninfo *var)
+/* ------------ FBDev related routines for 2.4 series ----------- */
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
+
+static void
+sisfb_crtc_to_var(struct sis_video_info *ivideo, struct fb_var_screeninfo *var)
 {
 	u16 VRE, VBE, VRS, VBS, VDE, VT;
 	u16 HRE, HBE, HRS, HBS, HDE, HT;
@@ -1247,50 +1258,55 @@
 	else
 	   var->vmode = FB_VMODE_NONINTERLACED;
 
-	switch ((sr_data & 0x1C) >> 2) {
-	   case SIS_8BPP_COLOR_MODE:
+	switch((sr_data & 0x1C) >> 2) {
+	case SIS_8BPP_COLOR_MODE:
 		var->bits_per_pixel = 8;
 		break;
-	   case SIS_16BPP_COLOR_MODE:
+	case SIS_16BPP_COLOR_MODE:
 		var->bits_per_pixel = 16;
 		break;
-	   case SIS_32BPP_COLOR_MODE:
+	case SIS_32BPP_COLOR_MODE:
 		var->bits_per_pixel = 32;
 		break;
 	}
 
-	sisfb_bpp_to_var(var);
+	sisfb_bpp_to_var(ivideo, var);
 	
 	inSISIDXREG(SISSR, 0x0A, sr_data);
-
         inSISIDXREG(SISCR, 0x06, cr_data);
-
         inSISIDXREG(SISCR, 0x07, cr_data2);
 
-	VT = (cr_data & 0xFF) | ((u16) (cr_data2 & 0x01) << 8) |
-	     ((u16) (cr_data2 & 0x20) << 4) | ((u16) (sr_data & 0x01) << 10);
+	VT = (cr_data & 0xFF) |
+	     ((u16) (cr_data2 & 0x01) << 8) |
+	     ((u16) (cr_data2 & 0x20) << 4) |
+	     ((u16) (sr_data  & 0x01) << 10);
 	A = VT + 2;
 
 	inSISIDXREG(SISCR, 0x12, cr_data);
 
-	VDE = (cr_data & 0xff) | ((u16) (cr_data2 & 0x02) << 7) |
-	      ((u16) (cr_data2 & 0x40) << 3) | ((u16) (sr_data & 0x02) << 9);
+	VDE = (cr_data & 0xff) |
+	      ((u16) (cr_data2 & 0x02) << 7) |
+	      ((u16) (cr_data2 & 0x40) << 3) |
+	      ((u16) (sr_data  & 0x02) << 9);
 	E = VDE + 1;
 
 	inSISIDXREG(SISCR, 0x10, cr_data);
 
-	VRS = (cr_data & 0xff) | ((u16) (cr_data2 & 0x04) << 6) |
-	      ((u16) (cr_data2 & 0x80) << 2) | ((u16) (sr_data & 0x08) << 7);
+	VRS = (cr_data & 0xff) |
+	      ((u16) (cr_data2 & 0x04) << 6) |
+	      ((u16) (cr_data2 & 0x80) << 2) |
+	      ((u16) (sr_data  & 0x08) << 7);
 	F = VRS + 1 - E;
 
 	inSISIDXREG(SISCR, 0x15, cr_data);
-
 	inSISIDXREG(SISCR, 0x09, cr_data3);
 
 	if(cr_data3 & 0x80) var->vmode = FB_VMODE_DOUBLE;
 
-	VBS = (cr_data & 0xff) | ((u16) (cr_data2 & 0x08) << 5) |
-	      ((u16) (cr_data3 & 0x20) << 4) | ((u16) (sr_data & 0x04) << 8);
+	VBS = (cr_data & 0xff) |
+	      ((u16) (cr_data2 & 0x08) << 5) |
+	      ((u16) (cr_data3 & 0x20) << 4) |
+	      ((u16) (sr_data & 0x04) << 8);
 
 	inSISIDXREG(SISCR, 0x16, cr_data);
 
@@ -1324,7 +1340,6 @@
 	}
 
 	inSISIDXREG(SISSR, 0x0b, sr_data);
-
 	inSISIDXREG(SISCR, 0x00, cr_data);
 
 	HT = (cr_data & 0xff) | ((u16) (sr_data & 0x03) << 8);
@@ -1345,13 +1360,12 @@
 	HBS = (cr_data & 0xff) | ((u16) (sr_data & 0x30) << 4);
 
 	inSISIDXREG(SISSR, 0x0c, sr_data);
-
 	inSISIDXREG(SISCR, 0x03, cr_data);
-
 	inSISIDXREG(SISCR, 0x05, cr_data2);
 
-	HBE = (cr_data & 0x1f) | ((u16) (cr_data2 & 0x80) >> 2) |
-	      ((u16) (sr_data & 0x03) << 6);
+	HBE = (cr_data & 0x1f) |
+	      ((u16) (cr_data2 & 0x80) >> 2) |
+	      ((u16) (sr_data  & 0x03) << 6);
 	HRE = (cr_data2 & 0x1f) | ((sr_data & 0x04) << 3);
 
 	temp = HBE - ((E - 1) & 255);
@@ -1362,7 +1376,10 @@
 
 	D = B - F - C;
 
-	var->xres = var->xres_virtual = E * 8;
+	var->xres = E * 8;
+	if(var->xres_virtual < var->xres) {
+		var->xres_virtual = var->xres;
+	}
 
 	if((var->xres == 320) &&
 	   (var->yres == 200 || var->yres == 240)) {
@@ -1399,14 +1416,13 @@
 	if((var->vmode & FB_VMODE_MASK) == FB_VMODE_INTERLACED) {
 	   VT <<= 1;
 	}
-	hrate = ivideo.refresh_rate * VT / 2;
+	hrate = ivideo->refresh_rate * VT / 2;
 	drate = (hrate * HT) / 1000;
 	var->pixclock = (u32) (1000000000 / drate);
 
-	if(sisfb_ypan) {
-	   maxyres = ivideo.heapstart / (var->xres * (var->bits_per_pixel >> 3));
-	   if(maxyres > 32767) maxyres = 32767;
-	   if(sisfb_max) {
+	if(ivideo->sisfb_ypan) {
+	   maxyres = sisfb_calc_maxyres(ivideo, var);
+	   if(ivideo->sisfb_max) {
 	      var->yres_virtual = maxyres;
 	   } else {
 	      if(var->yres_virtual > maxyres) {
@@ -1416,42 +1432,48 @@
 	   if(var->yres_virtual <= var->yres) {
 	      var->yres_virtual = var->yres;
 	   }
-	} else
+	} else {
 	   var->yres_virtual = var->yres;
+	}
 
 }
 
-static int sis_getcolreg(unsigned regno, unsigned *red, unsigned *green, unsigned *blue,
-			 unsigned *transp, struct fb_info *fb_info)
+static int
+sis_getcolreg(unsigned regno, unsigned *red, unsigned *green, unsigned *blue,
+			 unsigned *transp, struct fb_info *info)
 {
-	if (regno >= ivideo.video_cmap_len)
-		return 1;
+	struct sis_video_info *ivideo = (struct sis_video_info *)info->par;
 
-	*red = sis_palette[regno].red;
-	*green = sis_palette[regno].green;
-	*blue = sis_palette[regno].blue;
+	if(regno >= ivideo->video_cmap_len) return 1;
+
+	*red   = ivideo->sis_palette[regno].red;
+	*green = ivideo->sis_palette[regno].green;
+	*blue  = ivideo->sis_palette[regno].blue;
 	*transp = 0;
+
 	return 0;
 }
 
-static int sisfb_setcolreg(unsigned regno, unsigned red, unsigned green, unsigned blue,
-                           unsigned transp, struct fb_info *fb_info)
+static int
+sisfb_setcolreg(unsigned regno, unsigned red, unsigned green, unsigned blue,
+                           unsigned transp, struct fb_info *info)
 {
-	if (regno >= ivideo.video_cmap_len)
-		return 1;
+	struct sis_video_info *ivideo = (struct sis_video_info *)info->par;
+
+	if(regno >= ivideo->video_cmap_len) return 1;
 
-	sis_palette[regno].red = red;
-	sis_palette[regno].green = green;
-	sis_palette[regno].blue = blue;
+	ivideo->sis_palette[regno].red   = red;
+	ivideo->sis_palette[regno].green = green;
+	ivideo->sis_palette[regno].blue  = blue;
 
-	switch (ivideo.video_bpp) {
+	switch(ivideo->video_bpp) {
 #ifdef FBCON_HAS_CFB8
 	case 8:
 	        outSISREG(SISDACA, regno);
 		outSISREG(SISDACD, (red >> 10));
 		outSISREG(SISDACD, (green >> 10));
 		outSISREG(SISDACD, (blue >> 10));
-		if (ivideo.currentvbflags & VB_DISPTYPE_DISP2) {
+		if(ivideo->currentvbflags & VB_DISPTYPE_DISP2) {
 		        outSISREG(SISDAC2A, regno);
 			outSISREG(SISDAC2D, (red >> 8));
 			outSISREG(SISDAC2D, (green >> 8));
@@ -1461,317 +1483,250 @@
 #endif
 #ifdef FBCON_HAS_CFB16
 	case 16:
-		sis_fbcon_cmap.cfb16[regno] =
+		ivideo->sis_fbcon_cmap.cfb16[regno] =
 		    ((red & 0xf800)) | ((green & 0xfc00) >> 5) | ((blue & 0xf800) >> 11);
 		break;
 #endif
 #ifdef FBCON_HAS_CFB32
 	case 32:
-		red >>= 8;
+		red   >>= 8;
 		green >>= 8;
-		blue >>= 8;
-		sis_fbcon_cmap.cfb32[regno] = (red << 16) | (green << 8) | (blue);
+		blue  >>= 8;
+		ivideo->sis_fbcon_cmap.cfb32[regno] = (red << 16) | (green << 8) | (blue);
 		break;
 #endif
 	}
+
 	return 0;
 }
 
-static void sisfb_set_disp(int con, struct fb_var_screeninfo *var,
-                           struct fb_info *info)
+static void
+sisfb_set_disp(int con, struct fb_var_screeninfo *var, struct fb_info *info)
 {
+	struct sis_video_info    *ivideo = (struct sis_video_info *)info->par;
+	struct display           *display;
+	struct display_switch    *sw;
 	struct fb_fix_screeninfo fix;
 	long   flags;
-	struct display *display;
-	struct display_switch *sw;
 
-	if(con >= 0)
-		display = &fb_display[con];
-	else
-		display = &sis_disp;
+	display = (con >= 0) ? &fb_display[con] : &ivideo->sis_disp;
 
-	sisfb_get_fix(&fix, con, 0);
+	sisfb_get_fix(&fix, con, info);
 
-	display->screen_base = ivideo.video_vbase;
+	display->var = *var;
+	display->screen_base = (char *)ivideo->video_vbase;
 	display->visual = fix.visual;
 	display->type = fix.type;
 	display->type_aux = fix.type_aux;
 	display->ypanstep = fix.ypanstep;
 	display->ywrapstep = fix.ywrapstep;
 	display->line_length = fix.line_length;
-	display->next_line = fix.line_length;
 	display->can_soft_blank = 1;
-	display->inverse = sisfb_inverse;
-	display->var = *var;
+	display->inverse = ivideo->sisfb_inverse;
+	display->next_line = fix.line_length;
 
 	save_flags(flags);
 
-	switch (ivideo.video_bpp) {
+	switch(ivideo->video_bpp) {
 #ifdef FBCON_HAS_CFB8
-	   case 8:
-#ifdef SISFBACCEL
-		sw = ivideo.accel ? &fbcon_sis8 : &fbcon_cfb8;
-#else
-		sw = &fbcon_cfb8;
-#endif
+	case 8:	sw = ivideo->accel ? &fbcon_sis8 : &fbcon_cfb8;
 		break;
 #endif
 #ifdef FBCON_HAS_CFB16
-	   case 16:
-#ifdef SISFBACCEL
-		sw = ivideo.accel ? &fbcon_sis16 : &fbcon_cfb16;
-#else
-		sw = &fbcon_cfb16;
-#endif
-		display->dispsw_data = sis_fbcon_cmap.cfb16;
+	case 16:sw = ivideo->accel ? &fbcon_sis16 : &fbcon_cfb16;
+		display->dispsw_data = &ivideo->sis_fbcon_cmap.cfb16;
 		break;
 #endif
 #ifdef FBCON_HAS_CFB32
-	   case 32:
-#ifdef SISFBACCEL
-		sw = ivideo.accel ? &fbcon_sis32 : &fbcon_cfb32;
-#else
-		sw = &fbcon_cfb32;
-#endif
-		display->dispsw_data = sis_fbcon_cmap.cfb32;
+	case 32:sw = ivideo->accel ? &fbcon_sis32 : &fbcon_cfb32;
+		display->dispsw_data = &ivideo->sis_fbcon_cmap.cfb32;
 		break;
 #endif
-	   default:
-		sw = &fbcon_dummy;
-		return;
+	default:sw = &fbcon_dummy;
+		break;
 	}
-	memcpy(&sisfb_sw, sw, sizeof(*sw));
-	display->dispsw = &sisfb_sw;
+	memcpy(&ivideo->sisfb_sw, sw, sizeof(*sw));
+	display->dispsw = &ivideo->sisfb_sw;
+
 	restore_flags(flags);
 
-        if(sisfb_ypan) {
+        if(ivideo->sisfb_ypan) {
   	    /* display->scrollmode = 0;  */
 	} else {
 	    display->scrollmode = SCROLL_YREDRAW;
-	    sisfb_sw.bmove = fbcon_redraw_bmove;
+	    ivideo->sisfb_sw.bmove = fbcon_redraw_bmove;
 	}
 }
 
-static void sisfb_do_install_cmap(int con, struct fb_info *info)
+static void
+sisfb_do_install_cmap(int con, struct fb_info *info)
 {
-        if (con != currcon)
-		return;
+	struct sis_video_info *ivideo = (struct sis_video_info *)info->par;
 
-        if (fb_display[con].cmap.len)
+        if(con != ivideo->currcon) return;
+
+        if(fb_display[con].cmap.len) {
 		fb_set_cmap(&fb_display[con].cmap, 1, sisfb_setcolreg, info);
-        else
-		fb_set_cmap(fb_default_cmap(ivideo.video_cmap_len), 1,
-			    sisfb_setcolreg, info);
+        } else {
+		int size = sisfb_get_cmap_len(&fb_display[con].var);
+		fb_set_cmap(fb_default_cmap(size), 1, sisfb_setcolreg, info);
+	}
 }
 
-
-static int sisfb_get_var(struct fb_var_screeninfo *var, int con,
-			 struct fb_info *info)
+static int
+sisfb_get_var(struct fb_var_screeninfo *var, int con, struct fb_info *info)
 {
-	if(con == -1)
-		memcpy(var, &default_var, sizeof(struct fb_var_screeninfo));
-	else
+	struct sis_video_info *ivideo = (struct sis_video_info *)info->par;
+
+	if(con == -1) {
+		memcpy(var, &ivideo->default_var, sizeof(struct fb_var_screeninfo));
+	} else {
 		*var = fb_display[con].var;
+	}
 
-	if(sisfb_fstn) {
-	   if (var->xres == 320 && var->yres == 480)
-		var->yres = 240;
+	if(ivideo->sisfb_fstn) {
+	   	if(var->xres == 320 && var->yres == 480) var->yres = 240;
         }
 
 	return 0;
 }
 
-static int sisfb_set_var(struct fb_var_screeninfo *var, int con,
-			 struct fb_info *info)
+static int
+sisfb_set_var(struct fb_var_screeninfo *var, int con, struct fb_info *info)
 {
+	struct sis_video_info *ivideo = (struct sis_video_info *)info->par;
 	int err;
-	unsigned int cols, rows;
 
 	fb_display[con].var.activate = FB_ACTIVATE_NOW;
-        if(sisfb_do_set_var(var, con == currcon, info)) {
-		sisfb_crtc_to_var(var);
+
+        if(sisfb_do_set_var(var, con == ivideo->currcon, info)) {
+		sisfb_crtc_to_var(ivideo, var);
 		return -EINVAL;
 	}
 
-	sisfb_crtc_to_var(var);
+	sisfb_crtc_to_var(ivideo, var);
 
 	sisfb_set_disp(con, var, info);
 
-	if(info->changevar)
-		(*info->changevar) (con);
+	if(info->changevar) {
+		(*info->changevar)(con);
+	}
 
-	if((err = fb_alloc_cmap(&fb_display[con].cmap, 0, 0)))
+	if((err = fb_alloc_cmap(&fb_display[con].cmap, 0, 0))) {
 		return err;
+	}
 
 	sisfb_do_install_cmap(con, info);
 
-	cols = sisbios_mode[sisfb_mode_idx].cols;
-	rows = sisbios_mode[sisfb_mode_idx].rows;
-#if 0
-	/* Why was this called here? */
+#if 0	/* Why was this called here? */
+	unsigned int cols, rows;
+	cols = sisbios_mode[ivideo->sisfb_mode_idx].cols;
+	rows = sisbios_mode[ivideo->sisfb_mode_idx].rows;
  	vc_resize_con(rows, cols, fb_display[con].conp->vc_num);
 #endif
-
 	return 0;
 }
 
-static int sisfb_get_cmap(struct fb_cmap *cmap, int kspc, int con,
-			  struct fb_info *info)
+static int
+sisfb_get_cmap(struct fb_cmap *cmap, int kspc, int con, struct fb_info *info)
 {
-        if (con == currcon)
+	struct sis_video_info *ivideo = (struct sis_video_info *)info->par;
+	struct display *display;
+
+	display = (con >= 0) ? &fb_display[con] : &ivideo->sis_disp;
+
+        if(con == ivideo->currcon) {
+
 		return fb_get_cmap(cmap, kspc, sis_getcolreg, info);
 
-	else if (fb_display[con].cmap.len)
-		fb_copy_cmap(&fb_display[con].cmap, cmap, kspc ? 0 : 2);
-	else
-		fb_copy_cmap(fb_default_cmap(ivideo.video_cmap_len), cmap, kspc ? 0 : 2);
+	} else if(display->cmap.len) {
+
+		fb_copy_cmap(&display->cmap, cmap, kspc ? 0 : 2);
+
+	} else {
+
+		int size = sisfb_get_cmap_len(&display->var);
+		fb_copy_cmap(fb_default_cmap(size), cmap, kspc ? 0 : 2);
+
+	}
 
 	return 0;
 }
 
-static int sisfb_set_cmap(struct fb_cmap *cmap, int kspc, int con,
-			  struct fb_info *info)
+static int
+sisfb_set_cmap(struct fb_cmap *cmap, int kspc, int con, struct fb_info *info)
 {
-	int err;
+	struct sis_video_info *ivideo = (struct sis_video_info *)info->par;
+	struct display *display;
+	int err, size;
 
-	if (!fb_display[con].cmap.len) {
-		err = fb_alloc_cmap(&fb_display[con].cmap, ivideo.video_cmap_len, 0);
-		if (err)
-			return err;
+	display = (con >= 0) ? &fb_display[con] : &ivideo->sis_disp;
+
+	size = sisfb_get_cmap_len(&display->var);
+	if(display->cmap.len != size) {
+		err = fb_alloc_cmap(&display->cmap, size, 0);
+		if(err)	return err;
 	}
         
-	if (con == currcon)
+	if(con == ivideo->currcon) {
 		return fb_set_cmap(cmap, kspc, sisfb_setcolreg, info);
-
-	else
-		fb_copy_cmap(cmap, &fb_display[con].cmap, kspc ? 0 : 1);
+	} else {
+		fb_copy_cmap(cmap, &display->cmap, kspc ? 0 : 1);
+	}
 
 	return 0;
 }
 
-static int sisfb_pan_display(struct fb_var_screeninfo *var, int con,
-			     struct fb_info* info)
+static int
+sisfb_pan_display(struct fb_var_screeninfo *var, int con, struct fb_info* info)
 {
+	struct sis_video_info *ivideo = (struct sis_video_info *)info->par;
 	int err;
 
-	if (var->vmode & FB_VMODE_YWRAP) {
-		if (var->yoffset < 0 || var->yoffset >= fb_display[con].var.yres_virtual || var->xoffset)
-			return -EINVAL;
-	} else {
-		if (var->xoffset+fb_display[con].var.xres > fb_display[con].var.xres_virtual ||
-		    var->yoffset+fb_display[con].var.yres > fb_display[con].var.yres_virtual)
-			return -EINVAL;
+	if(var->vmode & FB_VMODE_YWRAP) return -EINVAL;
+
+	if((var->xoffset+fb_display[con].var.xres > fb_display[con].var.xres_virtual) ||
+	   (var->yoffset+fb_display[con].var.yres > fb_display[con].var.yres_virtual)) {
+		return -EINVAL;
 	}
 
-        if(con == currcon) {
-	   if((err = sisfb_pan_var(var)) < 0) return err;
+        if(con == ivideo->currcon) {
+	   	if((err = sisfb_pan_var(ivideo, var)) < 0) return err;
 	}
 
 	fb_display[con].var.xoffset = var->xoffset;
 	fb_display[con].var.yoffset = var->yoffset;
-	if (var->vmode & FB_VMODE_YWRAP)
-		fb_display[con].var.vmode |= FB_VMODE_YWRAP;
-	else
-		fb_display[con].var.vmode &= ~FB_VMODE_YWRAP;
-
-	return 0;
-}
-
-static int sisfb_mmap(struct fb_info *info, struct file *file,
-		      struct vm_area_struct *vma)
-{
-	struct fb_var_screeninfo var;
-	unsigned long start;
-	unsigned long off;
-	u32 len, mmio_off;
-
-	if(vma->vm_pgoff > (~0UL >> PAGE_SHIFT))  return -EINVAL;
-
-	off = vma->vm_pgoff << PAGE_SHIFT;
-
-	start = (unsigned long) ivideo.video_base;
-	len = PAGE_ALIGN((start & ~PAGE_MASK) + ivideo.video_size);
-#if 0
-	if (off >= len) {
-		off -= len;
-#endif
-	/* By Jake Page: Treat mmap request with offset beyond heapstart
-	 *               as request for mapping the mmio area 
-	 */
-	mmio_off = PAGE_ALIGN((start & ~PAGE_MASK) + ivideo.heapstart);
-	if(off >= mmio_off) {
-		off -= mmio_off;		
-		sisfb_get_var(&var, currcon, info);
-		if(var.accel_flags) return -EINVAL;
-
-		start = (unsigned long) ivideo.mmio_base;
-		len = PAGE_ALIGN((start & ~PAGE_MASK) + sisfb_mmio_size);
-	}
-
-	start &= PAGE_MASK;
-	if((vma->vm_end - vma->vm_start + off) > len)	return -EINVAL;
-
-	off += start;
-	vma->vm_pgoff = off >> PAGE_SHIFT;
-	vma->vm_flags |= VM_IO;   /* by Jake Page; is that really needed? */
-
-#if defined(__i386__) || defined(__x86_64__)
-	if (boot_cpu_data.x86 > 3)
-		pgprot_val(vma->vm_page_prot) |= _PAGE_PCD;
-#endif
-        /* RedHat requires vma as the first paramater to the following call */
-	if (io_remap_page_range(vma->vm_start, off, vma->vm_end - vma->vm_start,
-				vma->vm_page_prot))
-		return -EAGAIN;
 
 	return 0;
 }
 
-static void sis_get_glyph(struct fb_info *info, SIS_GLYINFO *gly)
+static int
+sisfb_update_var(int con, struct fb_info *info)
 {
-	struct display *p = &fb_display[currcon];
-	u16 c;
-	u8 *cdat;
-	int widthb;
-	u8 *gbuf = gly->gmask;
-	int size;
-
-	gly->fontheight = fontheight(p);
-	gly->fontwidth = fontwidth(p);
-	widthb = (fontwidth(p) + 7) / 8;
-
-	c = gly->ch & p->charmask;
-	if (fontwidth(p) <= 8)
-		cdat = p->fontdata + c * fontheight(p);
-	else
-		cdat = p->fontdata + (c * fontheight(p) << 1);
-
-	size = fontheight(p) * widthb;
-	memcpy(gbuf, cdat, size);
-	gly->ngmask = size;
-}
+	struct sis_video_info *ivideo = (struct sis_video_info *)info->par;
 
-static int sisfb_update_var(int con, struct fb_info *info)
-{
-        return(sisfb_pan_var(&fb_display[con].var));
+        return(sisfb_pan_var(ivideo, &fb_display[con].var));
 }
 
-static int sisfb_switch(int con, struct fb_info *info)
+static int
+sisfb_switch(int con, struct fb_info *info)
 {
+	struct sis_video_info *ivideo = (struct sis_video_info *)info->par;
 	int cols, rows;
 
-        if(fb_display[currcon].cmap.len)
-		fb_get_cmap(&fb_display[currcon].cmap, 1, sis_getcolreg, info);
+        if(fb_display[ivideo->currcon].cmap.len) {
+		fb_get_cmap(&fb_display[ivideo->currcon].cmap, 1, sis_getcolreg, info);
+	}
 
 	fb_display[con].var.activate = FB_ACTIVATE_NOW;
 
-	if(!memcmp(&fb_display[con].var, &fb_display[currcon].var,
-	                           sizeof(struct fb_var_screeninfo))) {
-		currcon = con;
+	if(!memcmp(&fb_display[con].var, &fb_display[ivideo->currcon].var,
+	                           	sizeof(struct fb_var_screeninfo))) {
+		ivideo->currcon = con;
 		return 1;
 	}
 
-	currcon = con;
+	ivideo->currcon = con;
 
 	sisfb_do_set_var(&fb_display[con].var, 1, info);
 
@@ -1779,8 +1734,8 @@
 
 	sisfb_do_install_cmap(con, info);
 
-	cols = sisbios_mode[sisfb_mode_idx].cols;
-	rows = sisbios_mode[sisfb_mode_idx].rows;
+	cols = sisbios_mode[ivideo->sisfb_mode_idx].cols;
+	rows = sisbios_mode[ivideo->sisfb_mode_idx].rows;
 	vc_resize_con(rows, cols, fb_display[con].conp->vc_num);
 
 	sisfb_update_var(con, info);
@@ -1788,55 +1743,46 @@
 	return 1;
 }
 
-static void sisfb_blank(int blank, struct fb_info *info)
+static void
+sisfb_blank(int blank, struct fb_info *info)
 {
-	sisfb_myblank(blank);
+	struct sis_video_info *ivideo = (struct sis_video_info *)info->par;
+
+	sisfb_myblank(ivideo, blank);
 }
 #endif
 
-/* ------------ FBDev related routines for 2.5 series ----------- */
+/* ------------ FBDev related routines for 2.6 series ----------- */
 
 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
 
-static int sisfb_open(struct fb_info *info, int user)
+static int
+sisfb_open(struct fb_info *info, int user)
 {
-    return 0;
+    	return 0;
 }
 
-static int sisfb_release(struct fb_info *info, int user)
+static int
+sisfb_release(struct fb_info *info, int user)
 {
-    return 0;
+    	return 0;
 }
 
-static int sisfb_get_cmap_len(const struct fb_var_screeninfo *var)
+static int
+sisfb_setcolreg(unsigned regno, unsigned red, unsigned green, unsigned blue,
+		unsigned transp, struct fb_info *info)
 {
-	int rc = 16;		
+	struct sis_video_info *ivideo = (struct sis_video_info *)info->par;
 
-	switch(var->bits_per_pixel) {
-	case 8:
-		rc = 256;	
-		break;
-	case 16:
-	case 32:
-		rc = 16;
-		break;
-	}
-	return rc;
-}
+	if(regno >= sisfb_get_cmap_len(&info->var)) return 1;
 
-static int sisfb_setcolreg(unsigned regno, unsigned red, unsigned green, unsigned blue,
-                           unsigned transp, struct fb_info *info)
-{
-	if (regno >= sisfb_get_cmap_len(&info->var))
-		return 1;
-
-	switch (info->var.bits_per_pixel) {
+	switch(info->var.bits_per_pixel) {
 	case 8:
 	        outSISREG(SISDACA, regno);
 		outSISREG(SISDACD, (red >> 10));
 		outSISREG(SISDACD, (green >> 10));
 		outSISREG(SISDACD, (blue >> 10));
-		if (ivideo.currentvbflags & VB_DISPTYPE_DISP2) {
+		if(ivideo->currentvbflags & VB_DISPTYPE_DISP2) {
 		        outSISREG(SISDAC2A, regno);
 			outSISREG(SISDAC2D, (red >> 8));
 			outSISREG(SISDAC2D, (green >> 8));
@@ -1851,28 +1797,31 @@
 		red >>= 8;
 		green >>= 8;
 		blue >>= 8;
-		((u32 *) (info->pseudo_palette))[regno] =
-			(red << 16) | (green << 8) | (blue);
+		((u32 *)(info->pseudo_palette))[regno] =
+				(red << 16) | (green << 8) | (blue);
 		break;
 	}
 	return 0;
 }
 
-static int sisfb_set_par(struct fb_info *info)
+static int
+sisfb_set_par(struct fb_info *info)
 {
 	int err;
 
-        if((err = sisfb_do_set_var(&info->var, 1, info)))
+        if((err = sisfb_do_set_var(&info->var, 1, info))) {
 		return err;
+	}
 
 	sisfb_get_fix(&info->fix, info->currcon, info);
 
 	return 0;
 }
 
-static int sisfb_check_var(struct fb_var_screeninfo *var,
-                           struct fb_info *info)
+static int
+sisfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
 {
+	struct sis_video_info *ivideo = (struct sis_video_info *)info->par;
 	unsigned int htotal = 0, vtotal = 0, myrateindex = 0;
 	unsigned int drate = 0, hrate = 0, maxyres;
 	int found_mode = 0;
@@ -1902,12 +1851,12 @@
 	}
 
 	search_idx = 0;
-	while( (sisbios_mode[search_idx].mode_no != 0) &&
+	while( (sisbios_mode[search_idx].mode_no[0] != 0) &&
 	       (sisbios_mode[search_idx].xres <= var->xres) ) {
 		if( (sisbios_mode[search_idx].xres == var->xres) &&
 		    (sisbios_mode[search_idx].yres == var->yres) &&
 		    (sisbios_mode[search_idx].bpp == var->bits_per_pixel)) {
-		        if(sisfb_validate_mode(search_idx, ivideo.currentvbflags) > 0) {
+		        if(sisfb_validate_mode(ivideo, search_idx, ivideo->currentvbflags) > 0) {
 			   found_mode = 1;
 			   break;
 			}
@@ -1916,13 +1865,12 @@
 	}
 
 	if(!found_mode) {
-
                 search_idx = 0;
-		while(sisbios_mode[search_idx].mode_no != 0) {
+		while(sisbios_mode[search_idx].mode_no[0] != 0) {
 		   if( (var->xres <= sisbios_mode[search_idx].xres) &&
 		       (var->yres <= sisbios_mode[search_idx].yres) &&
 		       (var->bits_per_pixel == sisbios_mode[search_idx].bpp) ) {
-		          if(sisfb_validate_mode(search_idx, ivideo.currentvbflags) > 0) {
+		          if(sisfb_validate_mode(ivideo,search_idx, ivideo->currentvbflags) > 0) {
 			     found_mode = 1;
 			     break;
 			  }
@@ -1946,24 +1894,25 @@
 		}
 	}
 
-	if( ((ivideo.vbflags & VB_LVDS) ||			/* Slave modes on LVDS and 301B-DH */
-	     ((ivideo.vbflags & VB_30xBDH) && (ivideo.currentvbflags & CRT2_LCD))) &&
+	if( ((ivideo->vbflags & VB_LVDS) ||			/* Slave modes on LVDS and 301B-DH */
+	     ((ivideo->vbflags & VB_30xBDH) && (ivideo->currentvbflags & CRT2_LCD))) &&
 	    (var->bits_per_pixel == 8) ) {
 	    	refresh_rate = 60;
 		recalc_clock = TRUE;
-	} else if( (ivideo.current_htotal == htotal) &&		/* x=x & y=y & c=c -> assume depth change */
-	    	   (ivideo.current_vtotal == vtotal) &&
-	    	   (ivideo.current_pixclock == pixclock) ) {
+	} else if( (ivideo->current_htotal == htotal) &&	/* x=x & y=y & c=c -> assume depth change */
+	    	   (ivideo->current_vtotal == vtotal) &&
+	    	   (ivideo->current_pixclock == pixclock) ) {
 		drate = 1000000000 / pixclock;
 	        hrate = (drate * 1000) / htotal;
 	        refresh_rate = (unsigned int) (hrate * 2 / vtotal);
-	} else if( ( (ivideo.current_htotal != htotal) ||	/* x!=x | y!=y & c=c -> invalid pixclock */
-	    	     (ivideo.current_vtotal != vtotal) ) &&
-	    	   (ivideo.current_pixclock == var->pixclock) ) {
-		if(sisfb_lastrates[sisbios_mode[search_idx].mode_no]) {
-			refresh_rate = sisfb_lastrates[sisbios_mode[search_idx].mode_no];
-		} else if(sisfb_parm_rate != -1) {
-			refresh_rate = sisfb_parm_rate;
+	} else if( ( (ivideo->current_htotal != htotal) ||	/* x!=x | y!=y & c=c -> invalid pixclock */
+	    	     (ivideo->current_vtotal != vtotal) ) &&
+	    	   (ivideo->current_pixclock == var->pixclock) ) {
+		if(ivideo->sisfb_lastrates[sisbios_mode[search_idx].mode_no[ivideo->mni]]) {
+			refresh_rate = ivideo->sisfb_lastrates[sisbios_mode[search_idx].mode_no[ivideo->mni]];
+		} else if(ivideo->sisfb_parm_rate != -1) {
+			/* Sic, sisfb_parm_rate - want to know originally desired rate here */
+			refresh_rate = ivideo->sisfb_parm_rate;
 		} else {
 			refresh_rate = 60;
 		}
@@ -1972,56 +1921,51 @@
 		drate = 1000000000 / pixclock;
 	   	hrate = (drate * 1000) / htotal;
 	   	refresh_rate = (unsigned int) (hrate * 2 / vtotal);
-	} else if(ivideo.current_refresh_rate) {
-		refresh_rate = ivideo.current_refresh_rate;
+	} else if(ivideo->current_refresh_rate) {
+		refresh_rate = ivideo->current_refresh_rate;
 		recalc_clock = TRUE;
 	} else {
 		refresh_rate = 60;
 		recalc_clock = TRUE;
 	}
 
-	myrateindex = sisfb_search_refresh_rate(refresh_rate, search_idx);
+	myrateindex = sisfb_search_refresh_rate(ivideo, refresh_rate, search_idx);
 
 	/* Eventually recalculate timing and clock */
 	if(recalc_clock) {
 	   if(!myrateindex) myrateindex = sisbios_mode[search_idx].rate_idx;
-	   var->pixclock = (u32) (1000000000 / sisfb_mode_rate_to_dclock(&SiS_Pr, &sishw_ext,
-						sisbios_mode[search_idx].mode_no, myrateindex));
-	   sisfb_mode_rate_to_ddata(&SiS_Pr, &sishw_ext,
-		 			sisbios_mode[search_idx].mode_no, myrateindex,
-		 			&var->left_margin, &var->right_margin,
-		 			&var->upper_margin, &var->lower_margin,
-		 			&var->hsync_len, &var->vsync_len,
-		 			&var->sync, &var->vmode);
+	   var->pixclock = (u32) (1000000000 / sisfb_mode_rate_to_dclock(&ivideo->SiS_Pr,
+	   					&ivideo->sishw_ext,
+						sisbios_mode[search_idx].mode_no[ivideo->mni],
+						myrateindex));
+	   sisfb_mode_rate_to_ddata(&ivideo->SiS_Pr, &ivideo->sishw_ext,
+		 		    sisbios_mode[search_idx].mode_no[ivideo->mni], myrateindex,	var);
 	   if((var->vmode & FB_VMODE_MASK) == FB_VMODE_DOUBLE) {
-		var->pixclock <<= 1;
+	      var->pixclock <<= 1;
 	   }
 	}
 
-	if(sisfb_thismonitor.datavalid) {
-	   if(!sisfb_verify_rate(&sisfb_thismonitor, search_idx,
+	if(ivideo->sisfb_thismonitor.datavalid) {
+	   if(!sisfb_verify_rate(ivideo, &ivideo->sisfb_thismonitor, search_idx,
 	                         myrateindex, refresh_rate)) {
 	      printk(KERN_INFO "sisfb: WARNING: Refresh rate exceeds monitor specs!\n");
 	   }
 	}
 
 	/* Adapt RGB settings */
-	sisfb_bpp_to_var(var);	
+	sisfb_bpp_to_var(ivideo, var);
 	
 	/* Sanity check for offsets */
-	if (var->xoffset < 0)
-		var->xoffset = 0;
-	if (var->yoffset < 0)
-		var->yoffset = 0;
+	if(var->xoffset < 0) var->xoffset = 0;
+	if(var->yoffset < 0) var->yoffset = 0;
 
-	/* Horiz-panning not supported */
-	if(var->xres != var->xres_virtual)
-		var->xres_virtual = var->xres;
+	if(var->xres > var->xres_virtual) {
+	   var->xres_virtual = var->xres;
+	}
 
-	if(sisfb_ypan) {
-	   maxyres = ivideo.heapstart / (var->xres * (var->bits_per_pixel >> 3));
-	   if(maxyres > 32767) maxyres = 32767;
-	   if(sisfb_max) {
+	if(ivideo->sisfb_ypan) {
+	   maxyres = sisfb_calc_maxyres(ivideo, var);
+	   if(ivideo->sisfb_max) {
 	      var->yres_virtual = maxyres;
 	   } else {
 	      if(var->yres_virtual > maxyres) {
@@ -2040,310 +1984,240 @@
 	}
 	
 	/* Truncate offsets to maximum if too high */
-	if(var->xoffset > var->xres_virtual - var->xres)
-		var->xoffset = var->xres_virtual - var->xres - 1;
+	if(var->xoffset > var->xres_virtual - var->xres) {
+	   var->xoffset = var->xres_virtual - var->xres - 1;
+	}
 
-	if(var->yoffset > var->yres_virtual - var->yres)
-		var->yoffset = var->yres_virtual - var->yres - 1;
+	if(var->yoffset > var->yres_virtual - var->yres) {
+	   var->yoffset = var->yres_virtual - var->yres - 1;
+	}
 	
 	/* Set everything else to 0 */
 	var->red.msb_right = 
-	    var->green.msb_right =
-	    var->blue.msb_right =
-	    var->transp.offset = var->transp.length = var->transp.msb_right = 0;		
+	var->green.msb_right =
+	var->blue.msb_right =
+	var->transp.offset =
+	var->transp.length =
+	var->transp.msb_right = 0;
 
 	return 0;
 }
 
-static int sisfb_pan_display(struct fb_var_screeninfo *var,
-			     struct fb_info* info)
+static int
+sisfb_pan_display(struct fb_var_screeninfo *var, struct fb_info* info)
 {
+	struct sis_video_info *ivideo = (struct sis_video_info *)info->par;
 	int err;
 
-	if (var->xoffset > (var->xres_virtual - var->xres))
+	if(var->xoffset > (var->xres_virtual - var->xres)) {
 		return -EINVAL;
-	if (var->yoffset > (var->yres_virtual - var->yres))
+	}
+	if(var->yoffset > (var->yres_virtual - var->yres)) {
 		return -EINVAL;
-
-	if (var->vmode & FB_VMODE_YWRAP) {
-		if (var->yoffset < 0 ||
-		    var->yoffset >= info->var.yres_virtual ||
-		    var->xoffset)
-		    	return -EINVAL;
-	} else {
-		if (var->xoffset + info->var.xres > info->var.xres_virtual ||
-		    var->yoffset + info->var.yres > info->var.yres_virtual)
-			return -EINVAL;
 	}
-    
-	if((err = sisfb_pan_var(var)) < 0) return err;
-
-	info->var.xoffset = var->xoffset;
-	info->var.yoffset = var->yoffset;
-	if (var->vmode & FB_VMODE_YWRAP)
-		info->var.vmode |= FB_VMODE_YWRAP;
-	else
-		info->var.vmode &= ~FB_VMODE_YWRAP;
-
-	return 0;
-}
-
-static int sisfb_mmap(struct fb_info *info, struct file *file,
-		      struct vm_area_struct *vma)
-{
-	unsigned long start;
-	unsigned long off;
-	u32 len, mmio_off;
 
-	if(vma->vm_pgoff > (~0UL >> PAGE_SHIFT))  return -EINVAL;
-
-	off = vma->vm_pgoff << PAGE_SHIFT;
-
-	start = (unsigned long) ivideo.video_base;
-	len = PAGE_ALIGN((start & ~PAGE_MASK) + ivideo.video_size);
-#if 0
-	if (off >= len) {
-		off -= len;
-#endif
-	/* By Jake Page: Treat mmap request with offset beyond heapstart
-	 *               as request for mapping the mmio area 
-	 */
-	mmio_off = PAGE_ALIGN((start & ~PAGE_MASK) + ivideo.heapstart);
-	if(off >= mmio_off) {
-		off -= mmio_off;		
-		if(info->var.accel_flags) return -EINVAL;
+	if(var->vmode & FB_VMODE_YWRAP) return -EINVAL;
 
-		start = (unsigned long) ivideo.mmio_base;
-		len = PAGE_ALIGN((start & ~PAGE_MASK) + sisfb_mmio_size);
+	if(var->xoffset + info->var.xres > info->var.xres_virtual ||
+	   var->yoffset + info->var.yres > info->var.yres_virtual) {
+		return -EINVAL;
 	}
 
-	start &= PAGE_MASK;
-	if((vma->vm_end - vma->vm_start + off) > len)	return -EINVAL;
+	if((err = sisfb_pan_var(ivideo, var)) < 0) return err;
 
-	off += start;
-	vma->vm_pgoff = off >> PAGE_SHIFT;
-	vma->vm_flags |= VM_IO;   /* by Jake Page; is that really needed? */
-
-#if defined(__i386__) || defined(__x86_64__)
-	if (boot_cpu_data.x86 > 3)
-		pgprot_val(vma->vm_page_prot) |= _PAGE_PCD;
-#endif
-	if (io_remap_page_range(vma, vma->vm_start, off, vma->vm_end - vma->vm_start,
-				vma->vm_page_prot))
-		return -EAGAIN;
+	info->var.xoffset = var->xoffset;
+	info->var.yoffset = var->yoffset;
 
 	return 0;
 }
 
-static int sisfb_blank(int blank, struct fb_info *info)
+static int
+sisfb_blank(int blank, struct fb_info *info)
 {
-	return(sisfb_myblank(blank));
+	struct sis_video_info *ivideo = (struct sis_video_info *)info->par;
+
+	return(sisfb_myblank(ivideo, blank));
 }
 
 #endif
 
 /* ----------- FBDev related routines for all series ---------- */
 
-
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
-static int sisfb_ioctl(struct inode *inode, struct file *file,
-		       unsigned int cmd, unsigned long arg,
-		       struct fb_info *info)
-#else
-static int sisfb_ioctl(struct inode *inode, struct file *file,
-		       unsigned int cmd, unsigned long arg, int con,
-		       struct fb_info *info)
-#endif
-{
-	struct sis_memreq sismemreq;
-	struct ap_data sisapdata;
-	unsigned long sismembase = 0;
+static int
+sisfb_ioctl(struct inode *inode, struct file *file,
+            unsigned int cmd, unsigned long arg,
 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
-	SIS_GLYINFO sisglyinfo;
+	    int con,
 #endif
+	    struct fb_info *info)
+{
+	struct sis_video_info 	*ivideo = (struct sis_video_info *)info->par;
+	struct sis_memreq 	sismemreq;
+	struct fb_vblank  	sisvbblank;
+	sisfb_info        	x;
+	u32			gpu32 = 0;
+	static int 		count = 0;
 
 	switch (cmd) {
 	   case FBIO_ALLOC:
-		if(!capable(CAP_SYS_RAWIO))
+		if(!capable(CAP_SYS_RAWIO)) {
 			return -EPERM;
-		if(copy_from_user(&sismemreq, (void *)arg, sizeof(sismemreq)))
+		}
+		if(copy_from_user(&sismemreq, (void *)arg, sizeof(sismemreq))) {
 		   	return -EFAULT;
+		}
         	sis_malloc(&sismemreq);
 		if(copy_to_user((void *)arg, &sismemreq, sizeof(sismemreq))) {
-			sis_free(sismemreq.offset);
+			sis_free((u32)sismemreq.offset);
 		    	return -EFAULT;
 		}
 		break;
+
 	   case FBIO_FREE:
-		if(!capable(CAP_SYS_RAWIO))
+		if(!capable(CAP_SYS_RAWIO)) {
 			return -EPERM;
-		if(get_user(sismembase, (unsigned long *) arg))
+		}
+		if(get_user(gpu32, (u32 *)arg)) {
 			return -EFAULT;
-		sis_free(sismembase);
+		}
+		sis_free(gpu32);
 		break;
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
-	   case FBIOGET_GLYPH:
-	        if(copy_from_user(&sisglyinfo, (void *)arg, sizeof(sisglyinfo)))
+
+	   case FBIOGET_VBLANK:
+		sisvbblank.count = 0;
+		sisvbblank.flags = sisfb_setupvbblankflags(ivideo, &sisvbblank.vcount, &sisvbblank.hcount);
+		if(copy_to_user((void *)arg, &sisvbblank, sizeof(sisvbblank))) {
 			return -EFAULT;
-                sis_get_glyph(info, &sisglyinfo);
+		}
 		break;
-	   case FBIOPUT_MODEINFO:
-		{
-			struct mode_info x;
 
-			if(copy_from_user(&x, (void *)arg, sizeof(x)))
-				return -EFAULT;
+	   case SISFB_GET_INFO_SIZE:
+	        return put_user(sizeof(sisfb_info), (u32 *)arg);
 
-			ivideo.video_bpp        = x.bpp;
-			ivideo.video_width      = x.xres;
-			ivideo.video_height     = x.yres;
-			ivideo.video_vwidth     = x.v_xres;
-			ivideo.video_vheight    = x.v_yres;
-			ivideo.org_x            = x.org_x;
-			ivideo.org_y            = x.org_y;
-			ivideo.refresh_rate     = x.vrate;
-			ivideo.video_linelength = ivideo.video_vwidth * (ivideo.video_bpp >> 3);
-			sisfb_set_vparms();
-			break;
+	   case SISFB_GET_INFO_OLD:
+	        if(++count < 50) {
+	           printk(KERN_INFO "sisfb: Deprecated ioctl call received - update your application!\n");
 		}
-#endif
-	   case FBIOGET_HWCINFO:
-		{
-			unsigned long myhwcoffset = 0;
-
-			if(sisfb_caps & HW_CURSOR_CAP)
-				myhwcoffset = sisfb_hwcursor_vbase -
-				    (unsigned long) ivideo.video_vbase;
-
-			return put_user(myhwcoffset, (unsigned long *)arg);
-
-			break;
+	   case SISFB_GET_INFO:  /* For communication with X driver */
+		x.sisfb_id         = SISFB_ID;
+		x.sisfb_version    = VER_MAJOR;
+		x.sisfb_revision   = VER_MINOR;
+		x.sisfb_patchlevel = VER_LEVEL;
+		x.chip_id = ivideo->chip_id;
+		x.memory = ivideo->video_size / 1024;
+		x.heapstart = ivideo->heapstart / 1024;
+		if(ivideo->modechanged) {
+		   x.fbvidmode = ivideo->mode_no;
+		} else {
+		   x.fbvidmode = ivideo->modeprechange;
 		}
-	   case FBIOGET_DISPINFO:
-	   	sis_dispinfo(&sisapdata);
-		if(copy_to_user((void *)arg, &sisapdata, sizeof(sisapdata)))
+		x.sisfb_caps = ivideo->caps;
+		x.sisfb_tqlen = 512; /* yet fixed */
+		x.sisfb_pcibus = ivideo->pcibus;
+		x.sisfb_pcislot = ivideo->pcislot;
+		x.sisfb_pcifunc = ivideo->pcifunc;
+		x.sisfb_lcdpdc = ivideo->detectedpdc;
+		x.sisfb_lcdpdca = ivideo->detectedpdca;
+		x.sisfb_lcda = ivideo->detectedlcda;
+		x.sisfb_vbflags = ivideo->vbflags;
+		x.sisfb_currentvbflags = ivideo->currentvbflags;
+		x.sisfb_scalelcd = ivideo->SiS_Pr.UsePanelScaler;
+		x.sisfb_specialtiming = ivideo->SiS_Pr.SiS_CustomT;
+		x.sisfb_haveemi = ivideo->SiS_Pr.HaveEMI ? 1 : 0;
+		x.sisfb_haveemilcd = ivideo->SiS_Pr.HaveEMILCD ? 1 : 0;
+		x.sisfb_emi30 = ivideo->SiS_Pr.EMI_30;
+		x.sisfb_emi31 = ivideo->SiS_Pr.EMI_31;
+		x.sisfb_emi32 = ivideo->SiS_Pr.EMI_32;
+		x.sisfb_emi33 = ivideo->SiS_Pr.EMI_33;
+		x.sisfb_tvxpos = (u16)(ivideo->tvxpos + 32);
+		x.sisfb_tvypos = (u16)(ivideo->tvypos + 32);
+
+		if(copy_to_user((void *)arg, &x, sizeof(x))) {
 			return -EFAULT;
-		break;
-	   case SISFB_GET_INFO:  /* For communication with X driver */
-	        {
-			sisfb_info x;
+		}
+	        break;
 
-			x.sisfb_id = SISFB_ID;
-			x.sisfb_version = VER_MAJOR;
-			x.sisfb_revision = VER_MINOR;
-			x.sisfb_patchlevel = VER_LEVEL;
-			x.chip_id = ivideo.chip_id;
-			x.memory = ivideo.video_size / 1024;
-			x.heapstart = ivideo.heapstart / 1024;
-			x.fbvidmode = sisfb_mode_no;
-			x.sisfb_caps = sisfb_caps;
-			x.sisfb_tqlen = 512; /* yet fixed */
-			x.sisfb_pcibus = ivideo.pcibus;
-			x.sisfb_pcislot = ivideo.pcislot;
-			x.sisfb_pcifunc = ivideo.pcifunc;
-			x.sisfb_lcdpdc = sisfb_detectedpdc;
-			x.sisfb_lcda = sisfb_detectedlcda;
-			x.sisfb_vbflags = ivideo.vbflags;
-			x.sisfb_currentvbflags = ivideo.currentvbflags;
-			x.sisfb_scalelcd = SiS_Pr.UsePanelScaler;
-			x.sisfb_specialtiming = SiS_Pr.SiS_CustomT;
-			x.sisfb_haveemi = SiS_Pr.HaveEMI ? 1 : 0;
-			x.sisfb_haveemilcd = SiS_Pr.HaveEMILCD ? 1 : 0;
-			x.sisfb_emi30 = SiS_Pr.EMI_30;
-			x.sisfb_emi31 = SiS_Pr.EMI_31;
-			x.sisfb_emi32 = SiS_Pr.EMI_32;
-			x.sisfb_emi33 = SiS_Pr.EMI_33;
-			if(copy_to_user((void *)arg, &x, sizeof(x)))
-				return -EFAULT;
-	                break;
+	   case SISFB_GET_VBRSTATUS_OLD:
+	   	if(++count < 50) {
+	           printk(KERN_INFO "sisfb: Deprecated ioctl call received - update your application!\n");
 		}
 	   case SISFB_GET_VBRSTATUS:
-	        {
-			if(sisfb_CheckVBRetrace())
-				return put_user(1UL, (unsigned long *) arg);
-			else
-				return put_user(0UL, (unsigned long *) arg);
-			break;
+	        if(sisfb_CheckVBRetrace(ivideo)) {
+			return put_user((u32)1, (u32 *) arg);
+		} else {
+			return put_user((u32)0, (u32 *) arg);
+		}
+
+	   case SISFB_GET_AUTOMAXIMIZE_OLD:
+	   	if(++count < 50) {
+	           printk(KERN_INFO "sisfb: Deprecated ioctl call received - update your application!\n");
 		}
 	   case SISFB_GET_AUTOMAXIMIZE:
-	        {
-			if(sisfb_max)
-				return put_user(1UL, (unsigned long *) arg);
-			else
-				return put_user(0UL, (unsigned long *) arg);
-			break;
+	        if(ivideo->sisfb_max) return put_user((u32)1, (u32 *)arg);
+		else 	              return put_user((u32)0, (u32 *)arg);
+
+	   case SISFB_SET_AUTOMAXIMIZE_OLD:
+	   	if(++count < 50) {
+		   printk(KERN_INFO "sisfb: Deprecated ioctl call received - update your application!\n");
 		}
 	   case SISFB_SET_AUTOMAXIMIZE:
-	        {
-			unsigned long newmax;
+		if(copy_from_user(&gpu32, (u32 *)arg, sizeof(gpu32))) {
+			return -EFAULT;
+		}
+		ivideo->sisfb_max = (gpu32) ? 1 : 0;
+		break;
+
+	   case SISFB_SET_TVPOSOFFSET:
+		if(copy_from_user(&gpu32, (u32 *)arg, sizeof(gpu32))) {
+			return -EFAULT;
+		}
+		sisfb_set_TVxposoffset(ivideo, ((int)(gpu32 >> 16)) - 32);
+		sisfb_set_TVyposoffset(ivideo, ((int)(gpu32 & 0xffff)) - 32);
+		break;
 
-			if(copy_from_user(&newmax, (unsigned long *)arg, sizeof(newmax)))
-				return -EFAULT;
+	   case SISFB_GET_TVPOSOFFSET:
+	        return put_user((u32)(((ivideo->tvxpos+32)<<16)|((ivideo->tvypos+32)&0xffff)), (u32 *)arg);
 
-			if(newmax) sisfb_max = 1;
-			else	   sisfb_max = 0;
-			break;
+	   case SISFB_SET_LOCK:
+		if(copy_from_user(&gpu32, (u32 *)arg, sizeof(gpu32))) {
+			return -EFAULT;
 		}
+		ivideo->sisfblocked = (gpu32) ? 1 : 0;
+		break;
+
 	   default:
 		return -EINVAL;
 	}
 	return 0;
 }
 
-
-static int sisfb_get_fix(struct fb_fix_screeninfo *fix, int con,
-			 struct fb_info *info)
+static int
+sisfb_get_fix(struct fb_fix_screeninfo *fix, int con, struct fb_info *info)
 {
-	memset(fix, 0, sizeof(struct fb_fix_screeninfo));
-
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)	
-	strcpy(fix->id, sis_fb_info->modename);
-#else
-	strcpy(fix->id, myid);
-#endif	
+	struct sis_video_info *ivideo = (struct sis_video_info *)info->par;
 
-	fix->smem_start = ivideo.video_base;
+	memset(fix, 0, sizeof(struct fb_fix_screeninfo));
 
-        if((!sisfb_mem) || (sisfb_mem > (ivideo.video_size/1024))) {
-	    if(sisvga_engine == SIS_300_VGA) {
-	       if(ivideo.video_size > 0x1000000) {
-	          	fix->smem_len = 0xc00000;
-	       } else if(ivideo.video_size > 0x800000)
-		  	fix->smem_len = 0x800000;
-	       else
-		  	fix->smem_len = 0x400000;
-            } else {
-	       	fix->smem_len = ivideo.video_size - 0x100000;
-	    }
-        } else
-		fix->smem_len = sisfb_mem * 1024;
+	strcpy(fix->id, ivideo->myid);
 
+	fix->smem_start  = ivideo->video_base;
+	fix->smem_len    = ivideo->sisfb_mem;
 	fix->type        = FB_TYPE_PACKED_PIXELS;
 	fix->type_aux    = 0;
-	if(ivideo.video_bpp == 8)
-	   fix->visual = FB_VISUAL_PSEUDOCOLOR;
-	else
-	   fix->visual = FB_VISUAL_TRUECOLOR;
-	fix->xpanstep    = 0;
-
-        if(sisfb_ypan) 	 fix->ypanstep = 1;
-
+	fix->visual      = (ivideo->video_bpp == 8) ? FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_TRUECOLOR;
+	fix->xpanstep    = 1;
+	fix->ypanstep 	 = (ivideo->sisfb_ypan) ? 1 : 0;
 	fix->ywrapstep   = 0;
-	fix->line_length = ivideo.video_linelength;
-	fix->mmio_start  = ivideo.mmio_base;
-	fix->mmio_len    = sisfb_mmio_size;
-	if(sisvga_engine == SIS_300_VGA) 
+	fix->line_length = ivideo->video_linelength;
+	fix->mmio_start  = ivideo->mmio_base;
+	fix->mmio_len    = ivideo->mmio_size;
+	if(ivideo->sisvga_engine == SIS_300_VGA) {
 	   fix->accel    = FB_ACCEL_SIS_GLAMOUR;
-	else if((ivideo.chip == SIS_330) || (ivideo.chip == SIS_760))
+	} else if((ivideo->chip == SIS_330) || (ivideo->chip == SIS_760)) {
 	   fix->accel    = FB_ACCEL_SIS_XABRE;
-	else
+	} else {
 	   fix->accel    = FB_ACCEL_SIS_GLAMOUR_2;
-
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
-	fix->reserved[0] = ivideo.video_size & 0xFFFF;
-	fix->reserved[1] = (ivideo.video_size >> 16) & 0xFFFF;
-	fix->reserved[2] = sisfb_caps;
-#endif
+	}
 
 	return 0;
 }
@@ -2359,458 +2233,416 @@
 	.fb_get_cmap	= sisfb_get_cmap,
 	.fb_set_cmap	= sisfb_set_cmap,
         .fb_pan_display = sisfb_pan_display,
-	.fb_ioctl	= sisfb_ioctl,
-	.fb_mmap	= sisfb_mmap,
+	.fb_ioctl	= sisfb_ioctl
 };
 #endif
 
-
 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
 static struct fb_ops sisfb_ops = {
-	.owner        =	THIS_MODULE,
-	.fb_open      = sisfb_open,
-	.fb_release   = sisfb_release,
-	.fb_check_var = sisfb_check_var,
-	.fb_set_par   = sisfb_set_par,
-	.fb_setcolreg = sisfb_setcolreg,
+	.owner          = THIS_MODULE,
+	.fb_open        = sisfb_open,
+	.fb_release     = sisfb_release,
+	.fb_check_var   = sisfb_check_var,
+	.fb_set_par     = sisfb_set_par,
+	.fb_setcolreg   = sisfb_setcolreg,
         .fb_pan_display = sisfb_pan_display,
-        .fb_blank     = sisfb_blank,
-	.fb_fillrect  = fbcon_sis_fillrect,
-	.fb_copyarea  = fbcon_sis_copyarea,
-	.fb_imageblit = cfb_imageblit,
-	.fb_cursor    = soft_cursor,	
-	.fb_sync      = fbcon_sis_sync,
-	.fb_ioctl     =	sisfb_ioctl,
-	.fb_mmap      =	sisfb_mmap,
+        .fb_blank       = sisfb_blank,
+	.fb_fillrect    = fbcon_sis_fillrect,
+	.fb_copyarea    = fbcon_sis_copyarea,
+	.fb_imageblit   = cfb_imageblit,
+	.fb_cursor      = soft_cursor,
+	.fb_sync        = fbcon_sis_sync,
+	.fb_ioctl       = sisfb_ioctl
 };
 #endif
 
-
 /* ---------------- Chip generation dependent routines ---------------- */
 
-#ifdef CONFIG_FB_SIS_300 /* for SiS 300/630/540/730 */
-
-static int sisfb_get_dram_size_300(void)
+static struct pci_dev * sisfb_get_northbridge(int basechipid)
 {
 	struct pci_dev *pdev = NULL;
-	int pdev_valid = 0;
-	u8  pci_data, reg;
-	u16 nbridge_id;
-
-	switch (ivideo.chip) {
-	   case SIS_540:
-		nbridge_id = PCI_DEVICE_ID_SI_540;
-		break;
-	   case SIS_630:
-		nbridge_id = PCI_DEVICE_ID_SI_630;
-		break;
-	   case SIS_730:
-		nbridge_id = PCI_DEVICE_ID_SI_730;
-		break;
-	   default:
-		nbridge_id = 0;
-		break;
-	}
-
-	if (nbridge_id == 0) {  /* 300 */
-
-	        inSISIDXREG(SISSR, IND_SIS_DRAM_SIZE,reg);
-		ivideo.video_size =
-		        ((unsigned int) ((reg & SIS_DRAM_SIZE_MASK) + 1) << 20);
+	int nbridgenum, nbridgeidx, i;
+	const unsigned short nbridgeids[] = {
+		PCI_DEVICE_ID_SI_540,	/* for SiS 540 VGA */
+		PCI_DEVICE_ID_SI_630,	/* for SiS 630/730 VGA */
+		PCI_DEVICE_ID_SI_730,
+		PCI_DEVICE_ID_SI_550,   /* for SiS 550 VGA */
+		PCI_DEVICE_ID_SI_650,   /* for SiS 650/651/740 VGA */
+		PCI_DEVICE_ID_SI_651,
+		PCI_DEVICE_ID_SI_740,
+		PCI_DEVICE_ID_SI_661,	/* for SiS 661/741/660/760 VGA */
+		PCI_DEVICE_ID_SI_741,
+		PCI_DEVICE_ID_SI_660,
+		PCI_DEVICE_ID_SI_760
+	};
 
-	} else {		/* 540, 630, 730 */
-
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,74)
-		pci_for_each_dev(pdev) {
-#else
-		while((pdev = pci_find_device(PCI_VENDOR_ID_SI, PCI_ANY_ID, pdev))) {
+    	switch(basechipid) {
+#ifdef CONFIG_FB_SIS_300
+	case SIS_540:	nbridgeidx = 0; nbridgenum = 1; break;
+	case SIS_630:	nbridgeidx = 1; nbridgenum = 2; break;
 #endif
-			if ((pdev->vendor == PCI_VENDOR_ID_SI)
-				       && (pdev->device == nbridge_id)) {
-				pci_read_config_byte(pdev, IND_BRI_DRAM_STATUS, &pci_data);
-				pci_data = (pci_data & BRI_DRAM_SIZE_MASK) >> 4;
-				ivideo.video_size = (unsigned int)(1 << (pci_data+21));
-				pdev_valid = 1;
-
-				reg = SIS_DATA_BUS_64 << 6;
-				switch (pci_data) {
-				   case BRI_DRAM_SIZE_2MB:
-					reg |= SIS_DRAM_SIZE_2MB;
-					break;
-				   case BRI_DRAM_SIZE_4MB:
-					reg |= SIS_DRAM_SIZE_4MB;
-					break;
-				   case BRI_DRAM_SIZE_8MB:
-					reg |= SIS_DRAM_SIZE_8MB;
-					break;
-				   case BRI_DRAM_SIZE_16MB:
-					reg |= SIS_DRAM_SIZE_16MB;
-					break;
-				   case BRI_DRAM_SIZE_32MB:
-					reg |= SIS_DRAM_SIZE_32MB;
-					break;
-				   case BRI_DRAM_SIZE_64MB:
-					reg |= SIS_DRAM_SIZE_64MB;
-					break;
-				}
-				outSISIDXREG(SISSR, IND_SIS_DRAM_SIZE, reg);
-				break;
-			}  
-		}
-	
-		if (!pdev_valid)  return -1;
+#ifdef CONFIG_FB_SIS_315
+	case SIS_550:   nbridgeidx = 3; nbridgenum = 1; break;
+	case SIS_650:	nbridgeidx = 4; nbridgenum = 3; break;
+	case SIS_660:	nbridgeidx = 7; nbridgenum = 4; break;
+#endif
+	default:	return NULL;
 	}
-	return 0;
+	for(i = 0; i < nbridgenum; i++) {
+		if((pdev = pci_find_device(PCI_VENDOR_ID_SI, nbridgeids[nbridgeidx+i], NULL))) break;
+	}
+	return pdev;
 }
 
-#endif  /* CONFIG_FB_SIS_300 */
-
-
-#ifdef CONFIG_FB_SIS_315    /* for SiS 315/550/650/740/330/661/741/760 */
-
-static int sisfb_get_dram_size_315(void)
+static int __devinit sisfb_get_dram_size(struct sis_video_info *ivideo)
 {
-	u8  reg = 0;
-
-	if(ivideo.chip == SIS_550 ||
-	   ivideo.chip == SIS_650 ||
-	   ivideo.chip == SIS_740) {
-
-                inSISIDXREG(SISSR, IND_SIS_DRAM_SIZE, reg);
-		reg &= 0x3f;
-		reg++;
-		reg <<= 2;
-		ivideo.video_size = reg << 20;
-		return 0;
+#if defined(CONFIG_FB_SIS_300) || defined(CONFIG_FB_SIS_315)
+	u8 reg;
+#endif
 
-	} else if(ivideo.chip == SIS_661 ||
-	          ivideo.chip == SIS_741 ||
-		  ivideo.chip == SIS_660 ||
-		  ivideo.chip == SIS_760) {
+	ivideo->video_size = 0;
 
+	switch(ivideo->chip) {
+#ifdef CONFIG_FB_SIS_300
+	case SIS_300:
+	        inSISIDXREG(SISSR, 0x14, reg);
+		ivideo->video_size = ((reg & 0x3F) + 1) << 20;
+		break;
+	case SIS_540:
+	case SIS_630:
+	case SIS_730:
+	   	if(!ivideo->nbridge) return -1;
+	   	pci_read_config_byte(ivideo->nbridge, 0x63, &reg);
+		ivideo->video_size = 1 << (((reg & 0x70) >> 4) + 21);
+		break;
+#endif
+#ifdef CONFIG_FB_SIS_315
+	case SIS_315H:
+	case SIS_315PRO:
+	case SIS_315:
+	   	inSISIDXREG(SISSR, 0x14, reg);
+		ivideo->video_size = (1 << ((reg & 0xf0) >> 4)) << 20;
+		switch((reg >> 2) & 0x03) {
+		case 0x01:
+		case 0x03:
+		   ivideo->video_size <<= 1;
+		   break;
+		case 0x02:
+		   ivideo->video_size += (ivideo->video_size/2);
+		}
+	   	break;
+	case SIS_330:
+	   	inSISIDXREG(SISSR, 0x14, reg);
+		ivideo->video_size = (1 << ((reg & 0xf0) >> 4)) << 20;
+		if(reg & 0x0c) ivideo->video_size <<= 1;
+	   	break;
+	case SIS_550:
+	case SIS_650:
+	case SIS_740:
+	    	inSISIDXREG(SISSR, 0x14, reg);
+		ivideo->video_size = (((reg & 0x3f) + 1) << 2) << 20;
+		break;
+	case SIS_661:
+	case SIS_741:
+	     	inSISIDXREG(SISCR, 0x79, reg);
+		ivideo->video_size = (1 << ((reg & 0xf0) >> 4)) << 20;
+	   	break;
+	case SIS_660:
+	case SIS_760:
 		inSISIDXREG(SISCR, 0x79, reg);
-		reg &= 0xf0;
-		reg >>= 4;
-		ivideo.video_size = (1 << reg) << 20;
-		return 0;
-
-	} else {	/* 315, 330 */
-
-	        inSISIDXREG(SISSR, IND_SIS_DRAM_SIZE, reg);
-		ivideo.video_size = (1 << ((reg & 0xf0) >> 4)) << 20;
-
-		reg &= SIS315_DUAL_CHANNEL_MASK;
-		reg >>= 2;
-
-		if(ivideo.chip == SIS_330) {
-
-		   if(reg) ivideo.video_size <<= 1;
-		
-		} else {
-		   
-		   switch (reg) {
-		      case SIS315_SINGLE_CHANNEL_2_RANK:
-			   ivideo.video_size <<= 1;
-			   break;
-		      case SIS315_DUAL_CHANNEL_1_RANK:
-			   ivideo.video_size <<= 1;
-			   break;
-		      case SIS315_ASYM_DDR:		/* TW: DDR asymetric */
-			   ivideo.video_size += (ivideo.video_size/2);
-			   break;
-		   }
+		reg = (reg & 0xf0) >> 4;
+		if(reg)	ivideo->video_size = (1 << reg) << 20;
+		inSISIDXREG(SISCR, 0x78, reg);
+		reg &= 0x30;
+		if(reg) {
+		   if(reg == 0x10) ivideo->video_size += (32 << 20);
+		   else		   ivideo->video_size += (64 << 20);
 		}
-
-		return 0;
+	   	break;
+#endif
+	default:
+		return -1;
 	}
-	
-	return -1;
-	
+	return 0;
 }
 
-#endif   /* CONFIG_FB_SIS_315 */
-
-
-/* -------------- video bridge detection --------------- */
+/* -------------- video bridge device detection --------------- */
 
-static void sisfb_detect_VB_connect()
+static void __devinit sisfb_detect_VB_connect(struct sis_video_info *ivideo)
 {
-	u8 sr16, sr17, cr32, temp;
+	u8 cr32, temp;
 
-	if(sisvga_engine == SIS_300_VGA) {
+#ifdef CONFIG_FB_SIS_300
+	if(ivideo->sisvga_engine == SIS_300_VGA) {
+		inSISIDXREG(SISSR, 0x17, temp);
+		if((temp & 0x0F) && (ivideo->chip != SIS_300)) {
+			/* PAL/NTSC is stored on SR16 on such machines */
+			if(!(ivideo->vbflags & (TV_PAL | TV_NTSC | TV_PALM | TV_PALN))) {
+		   		inSISIDXREG(SISSR, 0x16, temp);
+				if(temp & 0x20)
+					ivideo->vbflags |= TV_PAL;
+				else
+					ivideo->vbflags |= TV_NTSC;
+			}
+		}
+	}
+#endif
 
-		inSISIDXREG(SISSR, IND_SIS_SCRATCH_REG_17, sr17);
+	inSISIDXREG(SISCR, 0x32, cr32);
 
-		if ((sr17 & 0x0F) && (ivideo.chip != SIS_300)) {
+	if(cr32 & SIS_CRT1) {
+		ivideo->sisfb_crt1off = 0;
+	} else {
+		ivideo->sisfb_crt1off = (cr32 & 0xDF) ? 1 : 0;
+	}
 
-			/* Old BIOSes store the detected CRT2 type in SR17
-		 	 * instead of CR32. However, since our detection
-			 * routines store their results to CR32, we now copy
-			 * the remaining bits (for LCD and VGA) to CR32 for
-			 * unified usage.
-			 * SR17[0] CRT1    [1] LCD     [2] TV    [3] VGA2
-			 *     [4] AVIDEO  [5] SVIDEO
-			 */
+	ivideo->vbflags &= ~(CRT2_TV | CRT2_LCD | CRT2_VGA);
 
-#if 0
-			if (sr17 & 0x01) orSISIDXREG(SISCR, 0x32, SIS_CRT1);
-			else		 andSISIDXREG(SISCR, 0x32, ~SIS_CRT1);
+	if(cr32 & SIS_VB_TV)   ivideo->vbflags |= CRT2_TV;
+	if(cr32 & SIS_VB_LCD)  ivideo->vbflags |= CRT2_LCD;
+	if(cr32 & SIS_VB_CRT2) ivideo->vbflags |= CRT2_VGA;
 
-			if (sr17 & 0x02) orSISIDXREG(SISCR, 0x32, SIS_VB_LCD);
-			else		 andSISIDXREG(SISCR, 0x32, ~SIS_VB_LCD);
+	/* Check given parms for hardware compatibility.
+	 * (Cannot do this in the search_xx routines since we don't
+	 * know what hardware we are running on then)
+	 */
 
-			/* no HiVision and no DVI connector here */
-			andSISIDXREG(SISCR, 0x32, ~0xc0);
-#endif
+	if(ivideo->chip != SIS_550) {
+	   ivideo->sisfb_dstn = ivideo->sisfb_fstn = 0;
+	}
 
-			/* PAL/NTSC is stored on SR16 on such machines */
-			if (!(ivideo.vbflags & (TV_PAL | TV_NTSC))) {
-		   		inSISIDXREG(SISSR, IND_SIS_SCRATCH_REG_16, sr16);
-				if (sr16 & 0x20)
-					ivideo.vbflags |= TV_PAL;
-				else
-					ivideo.vbflags |= TV_NTSC;
-			}
+	if(ivideo->sisfb_tvplug != -1) {
+	   if( (ivideo->sisvga_engine != SIS_315_VGA) ||
+	       (!(ivideo->vbflags & (VB_301C|VB_301LV|VB_302LV))) ) {
+	      if(ivideo->sisfb_tvplug & TV_YPBPR) {
+	         ivideo->sisfb_tvplug = -1;
+		 printk(KERN_ERR "sisfb: YPbPr not supported\n");
+	      }
+	   }
+	}
+	if(ivideo->sisfb_tvplug != -1) {
+	   if( (ivideo->sisvga_engine != SIS_315_VGA) ||
+	       (!(ivideo->vbflags & (VB_301|VB_301B|VB_302B))) ) {
+	      if(ivideo->sisfb_tvplug & TV_HIVISION) {
+	         ivideo->sisfb_tvplug = -1;
+		 printk(KERN_ERR "sisfb: HiVision not supported\n");
+	      }
+	   }
+	}
+	if(ivideo->sisfb_tvstd != -1) {
+	   if( (!(ivideo->vbflags & VB_SISBRIDGE)) &&
+	       (!((ivideo->sisvga_engine == SIS_315_VGA) && (ivideo->vbflags & VB_CHRONTEL))) ) {
+	      if(ivideo->sisfb_tvstd & (TV_PALN | TV_PALN | TV_NTSCJ)) {
+	         ivideo->sisfb_tvstd = -1;
+	         printk(KERN_ERR "sisfb: PALM/PALN/NTSCJ not supported\n");
+	      }
+	   }
+	}
 
+	/* Detect/set TV plug & type */
+	if(ivideo->sisfb_tvplug != -1) {
+		ivideo->vbflags |= ivideo->sisfb_tvplug;
+	} else {
+		if(cr32 & SIS_VB_YPBPR)     	 ivideo->vbflags |= (TV_YPBPR|TV_YPBPR525I); /* default: 480i */
+		else if(cr32 & SIS_VB_HIVISION)  ivideo->vbflags |= TV_HIVISION;
+		else if(cr32 & SIS_VB_SCART)     ivideo->vbflags |= TV_SCART;
+	 	else {
+			if(cr32 & SIS_VB_SVIDEO)    ivideo->vbflags |= TV_SVIDEO;
+			if(cr32 & SIS_VB_COMPOSITE) ivideo->vbflags |= TV_AVIDEO;
 		}
-
 	}
 
-	inSISIDXREG(SISCR, IND_SIS_SCRATCH_REG_CR32, cr32);
-
-	if (cr32 & SIS_CRT1)
-		sisfb_crt1off = 0;
-	else {
-		if (cr32 & 0x5F)
-			sisfb_crt1off = 1;
-		else
-			sisfb_crt1off = 0;
-	}
-
-	ivideo.vbflags &= ~(CRT2_TV | CRT2_LCD | CRT2_VGA);
-
-	if (cr32 & SIS_VB_TV)
-		ivideo.vbflags |= CRT2_TV;
-	if (cr32 & SIS_VB_LCD)
-		ivideo.vbflags |= CRT2_LCD;
-	if (cr32 & SIS_VB_CRT2)
-		ivideo.vbflags |= CRT2_VGA;
-
-	/* TW: Detect/set TV plug & type */
-	if(sisfb_tvplug != -1)
-	        ivideo.vbflags |= sisfb_tvplug;
-
-	if (cr32 & SIS_VB_SVIDEO)
-		ivideo.vbflags |= TV_SVIDEO;
-	else if (cr32 & SIS_VB_COMPOSITE)
-		ivideo.vbflags |= TV_AVIDEO;
-	else if (cr32 & SIS_VB_SCART)
-		ivideo.vbflags |= TV_SCART;
-
-	if (!(ivideo.vbflags & (TV_PAL | TV_NTSC))) {
-		if(sisvga_engine == SIS_300_VGA) {
-	        	inSISIDXREG(SISSR, IND_SIS_POWER_ON_TRAP, temp);
-			if (temp & 0x01)
-				ivideo.vbflags |= TV_PAL;
-			else
-				ivideo.vbflags |= TV_NTSC;
-		} else if((ivideo.chip <= SIS_315PRO) || (ivideo.chip >= SIS_330)) {
-
+	if(!(ivideo->vbflags & (TV_YPBPR | TV_HIVISION))) {
+	    if(ivideo->sisfb_tvstd != -1) {
+	       ivideo->vbflags &= ~(TV_NTSC | TV_PAL | TV_PALM | TV_PALN | TV_NTSCJ);
+	       ivideo->vbflags |= ivideo->sisfb_tvstd;
+	    }
+	    if(ivideo->vbflags & TV_SCART) {
+	       ivideo->vbflags &= ~(TV_NTSC | TV_PALM | TV_PALN | TV_NTSCJ);
+	       ivideo->vbflags |= TV_PAL;
+	    }
+	    if(!(ivideo->vbflags & (TV_PAL | TV_NTSC | TV_PALM | TV_PALN | TV_NTSCJ))) {
+		if(ivideo->sisvga_engine == SIS_300_VGA) {
+	        	inSISIDXREG(SISSR, 0x38, temp);
+			if(temp & 0x01) ivideo->vbflags |= TV_PAL;
+			else		ivideo->vbflags |= TV_NTSC;
+		} else if((ivideo->chip <= SIS_315PRO) || (ivideo->chip >= SIS_330)) {
                 	inSISIDXREG(SISSR, 0x38, temp);
-			if(temp & 0x01)
-				ivideo.vbflags |= TV_PAL;
-			else
-				ivideo.vbflags |= TV_NTSC;
-
+			if(temp & 0x01) ivideo->vbflags |= TV_PAL;
+			else		ivideo->vbflags |= TV_NTSC;
 	    	} else {
-
 	        	inSISIDXREG(SISCR, 0x79, temp);
-			if(temp & 0x20)
-				ivideo.vbflags |= TV_PAL;
-			else
-				ivideo.vbflags |= TV_NTSC;
+			if(temp & 0x20)	ivideo->vbflags |= TV_PAL;
+			else		ivideo->vbflags |= TV_NTSC;
 	    	}
+	    }
 	}
 
-	/* TW: Copy forceCRT1 option to CRT1off if option is given */
-    	if (sisfb_forcecrt1 != -1) {
-    		if(sisfb_forcecrt1) sisfb_crt1off = 0;
-		else                sisfb_crt1off = 1;
+	/* Copy forceCRT1 option to CRT1off if option is given */
+    	if(ivideo->sisfb_forcecrt1 != -1) {
+    	   ivideo->sisfb_crt1off = (ivideo->sisfb_forcecrt1) ? 0 : 1;
     	}
-
 }
 
-static void sisfb_get_VB_type(void)
+static void __devinit sisfb_get_VB_type(struct sis_video_info *ivideo)
 {
-	u8 vb_chipid;
-	u8 reg;
 	char stdstr[]    = "sisfb: Detected";
 	char bridgestr[] = "video bridge";
-	char lvdsstr[]   = "LVDS transmitter";
-  	char chrstr[]    = "Chrontel TV encoder";
-
-	ivideo.hasVB = HASVB_NONE;
-	sishw_ext.ujVBChipID = VB_CHIP_UNKNOWN;
-	sishw_ext.Is301BDH = FALSE;
-	sishw_ext.usExternalChip = 0;
+	u8 vb_chipid;
+	u8 reg;
 
 	inSISIDXREG(SISPART4, 0x00, vb_chipid);
-	switch (vb_chipid) {
-	   case 0x01:
-		ivideo.hasVB = HASVB_301;
+	switch(vb_chipid) {
+	case 0x01:
 		inSISIDXREG(SISPART4, 0x01, reg);
 		if(reg < 0xb0) {
-			ivideo.vbflags |= VB_301;
-			sishw_ext.ujVBChipID = VB_CHIP_301;
+			ivideo->vbflags |= VB_301;
 			printk(KERN_INFO "%s SiS301 %s\n", stdstr, bridgestr);
 		} else if(reg < 0xc0) {
-		 	ivideo.vbflags |= VB_301B;
-			sishw_ext.ujVBChipID = VB_CHIP_301B;
+		 	ivideo->vbflags |= VB_301B;
 			inSISIDXREG(SISPART4,0x23,reg);
 			if(!(reg & 0x02)) {
-			   sishw_ext.Is301BDH = TRUE;
-			   ivideo.vbflags |= VB_30xBDH;
+			   ivideo->vbflags |= VB_30xBDH;
 			   printk(KERN_INFO "%s SiS301B-DH %s\n", stdstr, bridgestr);
 			} else {
 			   printk(KERN_INFO "%s SiS301B %s\n", stdstr, bridgestr);
 			}
 		} else if(reg < 0xd0) {
-		 	ivideo.vbflags |= VB_301C;
-			sishw_ext.ujVBChipID = VB_CHIP_301C;
+		 	ivideo->vbflags |= VB_301C;
 			printk(KERN_INFO "%s SiS301C %s\n", stdstr, bridgestr);
 		} else if(reg < 0xe0) {
-			ivideo.vbflags |= VB_301LV;
-			sishw_ext.ujVBChipID = VB_CHIP_301LV;
+			ivideo->vbflags |= VB_301LV;
 			printk(KERN_INFO "%s SiS301LV %s\n", stdstr, bridgestr);
 		} else if(reg <= 0xe1) {
 		        inSISIDXREG(SISPART4,0x39,reg);
 			if(reg == 0xff) {
-			   ivideo.vbflags |= VB_302LV;
-			   sishw_ext.ujVBChipID = VB_CHIP_302LV;
+			   ivideo->vbflags |= VB_302LV;
 			   printk(KERN_INFO "%s SiS302LV %s\n", stdstr, bridgestr);
 			} else {
-			   ivideo.vbflags |= VB_302ELV;
-			   sishw_ext.ujVBChipID = VB_CHIP_302ELV;
+			   ivideo->vbflags |= VB_301C;
+			   printk(KERN_INFO "%s SiS301C(P4) %s\n", stdstr, bridgestr);
+#if 0
+			   ivideo->vbflags |= VB_302ELV;
 			   printk(KERN_INFO "%s SiS302ELV %s\n", stdstr, bridgestr);
+#endif
 			}
 		}
 		break;
-	   case 0x02:
-		ivideo.hasVB = HASVB_302;
-		inSISIDXREG(SISPART4, 0x01, reg);
-		if(reg < 0xd0) {
-			ivideo.vbflags |= VB_302B;
-			sishw_ext.ujVBChipID = VB_CHIP_302B;
-			inSISIDXREG(SISPART4,0x23,reg);
-		  	if(!(reg & 0x02)) {
-			   sishw_ext.Is301BDH = TRUE;
-			   ivideo.vbflags |= VB_30xBDH;
-			   printk(KERN_INFO "%s SiS302B-DH %s\n", stdstr, bridgestr);
-			} else {
-			   printk(KERN_INFO "%s SiS302B %s\n", stdstr, bridgestr);
-			}
-		} else if(reg < 0xe0) {
-		 	ivideo.vbflags |= VB_301LV;
-			sishw_ext.ujVBChipID = VB_CHIP_301LV;
-			printk(KERN_INFO "%s SiS301LV %s\n", stdstr, bridgestr);
-		} else if(reg <= 0xe1) {
-			ivideo.vbflags |= VB_302LV;
-			sishw_ext.ujVBChipID = VB_CHIP_302LV;
-			printk(KERN_INFO "%s SiS302LV %s\n", stdstr, bridgestr);
-		}
+	case 0x02:
+		ivideo->vbflags |= VB_302B;
+		printk(KERN_INFO "%s SiS302B %s\n", stdstr, bridgestr);
 		break;
 	}
 
-	if((!(ivideo.vbflags & VB_VIDEOBRIDGE)) && (ivideo.chip != SIS_300)) {
-		inSISIDXREG(SISCR, IND_SIS_SCRATCH_REG_CR37, reg);
+	if((!(ivideo->vbflags & VB_VIDEOBRIDGE)) && (ivideo->chip != SIS_300)) {
+		inSISIDXREG(SISCR, 0x37, reg);
 		reg &= SIS_EXTERNAL_CHIP_MASK;
 		reg >>= 1;
-		if(sisvga_engine == SIS_300_VGA) {
-			switch (reg) {
+		if(ivideo->sisvga_engine == SIS_300_VGA) {
+#ifdef CONFIG_FB_SIS_300
+			switch(reg) {
 			   case SIS_EXTERNAL_CHIP_LVDS:
-				ivideo.hasVB = HASVB_LVDS;
-				ivideo.vbflags |= VB_LVDS;
-				sishw_ext.usExternalChip = 0x01;
-				printk(KERN_INFO "%s %s\n", stdstr, lvdsstr);
+				ivideo->vbflags |= VB_LVDS;
 				break;
 			   case SIS_EXTERNAL_CHIP_TRUMPION:
-				ivideo.hasVB = HASVB_TRUMPION;
-				sishw_ext.usExternalChip = 0x02;
-				printk(KERN_INFO "%s Trumpion LCD scaler\n", stdstr);
+				ivideo->vbflags |= VB_TRUMPION;
 				break;
 			   case SIS_EXTERNAL_CHIP_CHRONTEL:
-				ivideo.hasVB = HASVB_CHRONTEL;
-				ivideo.vbflags |= VB_CHRONTEL;
-				sishw_ext.usExternalChip = 0x04;
-				printk(KERN_INFO "%s %s\n", stdstr, chrstr);
+				ivideo->vbflags |= VB_CHRONTEL;
 				break;
 			   case SIS_EXTERNAL_CHIP_LVDS_CHRONTEL:
-				ivideo.hasVB = HASVB_LVDS_CHRONTEL;
-				ivideo.vbflags |= (VB_LVDS | VB_CHRONTEL);
-				sishw_ext.usExternalChip = 0x05;
-				printk(KERN_INFO "%s %s and %s\n", stdstr, lvdsstr, chrstr);
+				ivideo->vbflags |= (VB_LVDS | VB_CHRONTEL);
 				break;
 			}
-		} else if(ivideo.chip < SIS_661) {
+			if(ivideo->vbflags & VB_CHRONTEL) ivideo->chronteltype = 1;
+#endif
+		} else if(ivideo->chip < SIS_661) {
+#ifdef CONFIG_FB_SIS_315
 			switch (reg) {
 	 	   	   case SIS310_EXTERNAL_CHIP_LVDS:
-				ivideo.hasVB = HASVB_LVDS;
-				ivideo.vbflags |= VB_LVDS;
-				sishw_ext.usExternalChip = 0x01;
-				printk(KERN_INFO "%s %s\n", stdstr, lvdsstr);
+				ivideo->vbflags |= VB_LVDS;
 				break;
 		   	   case SIS310_EXTERNAL_CHIP_LVDS_CHRONTEL:
-				ivideo.hasVB = HASVB_LVDS_CHRONTEL;
-				ivideo.vbflags |= (VB_LVDS | VB_CHRONTEL);
-				sishw_ext.usExternalChip = 0x05;
-				printk(KERN_INFO "%s %s and %s\n", stdstr, lvdsstr, chrstr);
+				ivideo->vbflags |= (VB_LVDS | VB_CHRONTEL);
 				break;
 			}
+			if(ivideo->vbflags & VB_CHRONTEL) ivideo->chronteltype = 2;
+#endif
+		} else if(ivideo->chip >= SIS_661) {
+#ifdef CONFIG_FB_SIS_315
+			inSISIDXREG(SISCR, 0x38, reg);
+			reg >>= 5;
+			switch(reg) {
+			   case 0x02:
+				ivideo->vbflags |= VB_LVDS;
+				break;
+			   case 0x03:
+				ivideo->vbflags |= (VB_LVDS | VB_CHRONTEL);
+				break;
+			   case 0x04:
+				ivideo->vbflags |= (VB_LVDS | VB_CONEXANT);
+				break;
+			}
+			if(ivideo->vbflags & VB_CHRONTEL) ivideo->chronteltype = 2;
+#endif
+		}
+		if(ivideo->vbflags & VB_LVDS) {
+		   printk(KERN_INFO "%s LVDS transmitter\n", stdstr);
+		}
+		if(ivideo->vbflags & VB_TRUMPION) {
+		   printk(KERN_INFO "%s Trumpion Zurac LCD scaler\n", stdstr);
+		}
+		if(ivideo->vbflags & VB_CHRONTEL) {
+		   printk(KERN_INFO "%s Chrontel TV encoder\n", stdstr);
+		}
+		if(ivideo->vbflags & VB_CONEXANT) {
+		   printk(KERN_INFO "%s Conexant external device\n", stdstr);
 		}
-
 	}
 
-	if(ivideo.vbflags & VB_SISBRIDGE) {
-		SiS_Sense30x();
-	} else if(ivideo.vbflags & VB_CHRONTEL) {
-		SiS_SenseCh();
+	if(ivideo->vbflags & VB_SISBRIDGE) {
+		SiS_Sense30x(ivideo);
+	} else if(ivideo->vbflags & VB_CHRONTEL) {
+		SiS_SenseCh(ivideo);
 	}
-
 }
 
 /* ------------------ Sensing routines ------------------ */
 
-static BOOLEAN
-sisfb_test_DDC1(void)
+static BOOLEAN __devinit sisfb_test_DDC1(struct sis_video_info *ivideo)
 {
     unsigned short old;
     int count = 48;
 
-    old = SiS_ReadDDC1Bit(&SiS_Pr);
+    old = SiS_ReadDDC1Bit(&ivideo->SiS_Pr);
     do {
-       if(old != SiS_ReadDDC1Bit(&SiS_Pr)) break;
+       	if(old != SiS_ReadDDC1Bit(&ivideo->SiS_Pr)) break;
     } while(count--);
     return (count == -1) ? FALSE : TRUE;
 }
 
-static void
-sisfb_sense_crt1(void)
+static void __devinit sisfb_sense_crt1(struct sis_video_info *ivideo)
 {
-    unsigned char SR1F, CR63=0, CR17;
-    unsigned short temp = 0xffff;
-    int i;
     BOOLEAN mustwait = FALSE;
+    u8  SR1F, CR17;
+#ifdef CONFIG_FB_SIS_315
+    u8  CR63=0;
+#endif
+    u16 temp = 0xffff;
+    int i;
 
     inSISIDXREG(SISSR,0x1F,SR1F);
     orSISIDXREG(SISSR,0x1F,0x04);
     andSISIDXREG(SISSR,0x1F,0x3F);
     if(SR1F & 0xc0) mustwait = TRUE;
 
-    if(sisvga_engine == SIS_315_VGA) {
-       inSISIDXREG(SISCR,SiS_Pr.SiS_MyCR63,CR63);
+#ifdef CONFIG_FB_SIS_315
+    if(ivideo->sisvga_engine == SIS_315_VGA) {
+       inSISIDXREG(SISCR,ivideo->SiS_Pr.SiS_MyCR63,CR63);
        CR63 &= 0x40;
-       andSISIDXREG(SISCR,SiS_Pr.SiS_MyCR63,0xBF);
+       andSISIDXREG(SISCR,ivideo->SiS_Pr.SiS_MyCR63,0xBF);
     }
+#endif
 
     inSISIDXREG(SISCR,0x17,CR17);
     CR17 &= 0x80;
@@ -2822,25 +2654,46 @@
     }
 
     if(mustwait) {
-       for(i=0; i < 10; i++) sisfbwaitretracecrt1();
+       for(i=0; i < 10; i++) sisfbwaitretracecrt1(ivideo);
     }
 
-    i = 3;
-    do {
-       temp = SiS_HandleDDC(&SiS_Pr, ivideo.vbflags, sisvga_engine, 0, 0, NULL);
-    } while(((temp == 0) || (temp == 0xffff)) && i--);
+#ifdef CONFIG_FB_SIS_315
+    if(ivideo->chip >= SIS_330) {
+       andSISIDXREG(SISCR,0x32,~0x20);
+       if(ivideo->chip >= SIS_340) {
+          outSISIDXREG(SISCR, 0x57, 0x4a);
+       } else {
+          outSISIDXREG(SISCR, 0x57, 0x5f);
+       }
+       orSISIDXREG(SISCR, 0x53, 0x02);
+       while((inSISREG(SISINPSTAT)) & 0x01)    break;
+       while(!((inSISREG(SISINPSTAT)) & 0x01)) break;
+       if((inSISREG(SISMISCW)) & 0x10) temp = 1;
+       andSISIDXREG(SISCR, 0x53, 0xfd);
+       andSISIDXREG(SISCR, 0x57, 0x00);
+    }
+#endif
+
+    if(temp == 0xffff) {
+       i = 3;
+       do {
+          temp = SiS_HandleDDC(&ivideo->SiS_Pr, ivideo->vbflags, ivideo->sisvga_engine, 0, 0, NULL);
+       } while(((temp == 0) || (temp == 0xffff)) && i--);
 
-    if((temp == 0) || (temp == 0xffff)) {
-       if(sisfb_test_DDC1()) temp = 1;
+       if((temp == 0) || (temp == 0xffff)) {
+          if(sisfb_test_DDC1(ivideo)) temp = 1;
+       }
     }
 
     if((temp) && (temp != 0xffff)) {
        orSISIDXREG(SISCR,0x32,0x20);
     }
 
-    if(sisvga_engine == SIS_315_VGA) {
-       setSISIDXREG(SISCR,SiS_Pr.SiS_MyCR63,0xBF,CR63);
+#ifdef CONFIG_FB_SIS_315
+    if(ivideo->sisvga_engine == SIS_315_VGA) {
+       setSISIDXREG(SISCR,ivideo->SiS_Pr.SiS_MyCR63,0xBF,CR63);
     }
+#endif
 
     setSISIDXREG(SISCR,0x17,0x7F,CR17);
 
@@ -2848,225 +2701,207 @@
 }
 
 /* Determine and detect attached devices on SiS30x */
-static int
-SISDoSense(int tempbl, int tempbh, int tempcl, int tempch)
+static int __devinit SISDoSense(struct sis_video_info *ivideo, u16 type, u16 test)
 {
-    int temp;
+    int temp, mytest, result, i, j;
 
-    outSISIDXREG(SISPART4,0x11,tempbl);
-    temp = tempbh | tempcl;
-    setSISIDXREG(SISPART4,0x10,0xe0,temp);
-    SiS_DDC2Delay(&SiS_Pr, 0x1000);
-    tempch &= 0x7f;
-    inSISIDXREG(SISPART4,0x03,temp);
-    temp ^= 0x0e;
-    temp &= tempch;
-    return((temp == tempch));
+    for(j = 0; j < 10; j++) {
+       result = 0;
+       for(i = 0; i < 3; i++) {
+          mytest = test;
+          outSISIDXREG(SISPART4,0x11,(type & 0x00ff));
+          temp = (type >> 8) | (mytest & 0x00ff);
+          setSISIDXREG(SISPART4,0x10,0xe0,temp);
+          SiS_DDC2Delay(&ivideo->SiS_Pr, 0x1500);
+          mytest >>= 8;
+          mytest &= 0x7f;
+          inSISIDXREG(SISPART4,0x03,temp);
+          temp ^= 0x0e;
+          temp &= mytest;
+          if(temp == mytest) result++;
+#if 1
+	  outSISIDXREG(SISPART4,0x11,0x00);
+	  andSISIDXREG(SISPART4,0x10,0xe0);
+	  SiS_DDC2Delay(&ivideo->SiS_Pr, 0x1000);
+#endif
+       }
+       if((result == 0) || (result >= 2)) break;
+    }
+    return(result);
 }
 
-static void
-SiS_Sense30x(void)
+static void __devinit SiS_Sense30x(struct sis_video_info *ivideo)
 {
-  u8 backupP4_0d,backupP2_00;
-  u8 svhs_bl, svhs_bh;
-  u8 svhs_cl, svhs_ch;
-  u8 cvbs_bl, cvbs_bh;
-  u8 cvbs_cl, cvbs_ch;
-  u8 vga2_bl, vga2_bh;
-  u8 vga2_cl, vga2_ch;
-  int myflag, result, haveresult, i, j;
-  char stdstr[] = "sisfb: Detected";
-  char tvstr[]  = "TV connected to";
-
-  inSISIDXREG(SISPART4,0x0d,backupP4_0d);
-  if(!(ivideo.vbflags & (VB_301C|VB_302ELV))) {
-     outSISIDXREG(SISPART4,0x0d,(backupP4_0d | 0x04));
-  }
-
-  inSISIDXREG(SISPART2,0x00,backupP2_00);
-  outSISIDXREG(SISPART2,0x00,(backupP2_00 | 0x1c));
-
-  if(sisvga_engine == SIS_300_VGA) {
-
-	if(ivideo.vbflags & (VB_301B|VB_301C|VB_302B|VB_301LV|VB_302LV)) {
-	   	vga2_bh = 0x01; vga2_bl = 0x90;
-	   	svhs_bh = 0x01; svhs_bl = 0x6b;
-	   	cvbs_bh = 0x01; cvbs_bl = 0x74;
-	} else {
-		vga2_bh = 0x00; vga2_bl = 0xd1;
-        	svhs_bh = 0x00; svhs_bl = 0xb9;
-		cvbs_bh = 0x00; cvbs_bl = 0xb3;
-	}
-	inSISIDXREG(SISPART4,0x01,myflag);
-	if(myflag & 0x04) {
-	   vga2_bh = 0x00; vga2_bl = 0xfd;
-	   svhs_bh = 0x00; svhs_bl = 0xdd;
-	   cvbs_bh = 0x00; cvbs_bl = 0xee;
-	}
-	vga2_ch = 0x0e;	vga2_cl = 0x08;
-	svhs_ch = 0x04;	svhs_cl = 0x04;
-	cvbs_ch = 0x08; cvbs_cl = 0x04;
-	if(ivideo.vbflags & (VB_301LV|VB_302LV)) {
-	   	vga2_bh = 0x00; vga2_bl = 0x00;
-	   	vga2_ch = 0x00; vga2_cl = 0x00;
-	 }
-	if(ivideo.chip == SIS_300) {
-	   inSISIDXREG(SISSR,0x3b,myflag);
-	   if(!(myflag & 0x01)) {
-	      	vga2_bh = 0x00; vga2_bl = 0x00;
-	      	vga2_ch = 0x00; vga2_cl = 0x00;
-	   }
-	}
+    u8  backupP4_0d,backupP2_00,backupP2_4d,backupSR_1e,biosflag=0;
+    u16 svhs=0, svhs_c=0;
+    u16 cvbs=0, cvbs_c=0;
+    u16 vga2=0, vga2_c=0;
+    int myflag, result;
+    char stdstr[] = "sisfb: Detected";
+    char tvstr[]  = "TV connected to";
+
+    if(ivideo->vbflags & VB_301) {
+       svhs = 0x00b9; cvbs = 0x00b3; vga2 = 0x00d1;
+       inSISIDXREG(SISPART4,0x01,myflag);
+       if(myflag & 0x04) {
+	  svhs = 0x00dd; cvbs = 0x00ee; vga2 = 0x00fd;
+       }
+    } else if(ivideo->vbflags & (VB_301B | VB_302B)) {
+       svhs = 0x016b; cvbs = 0x0174; vga2 = 0x0190;
+    } else if(ivideo->vbflags & (VB_301LV | VB_302LV)) {
+       svhs = 0x0200; cvbs = 0x0100;
+    } else if(ivideo->vbflags & (VB_301C | VB_302ELV)) {
+       svhs = 0x016b; cvbs = 0x0110; vga2 = 0x0190;
+    } else return;
+
+    vga2_c = 0x0e08; svhs_c = 0x0404; cvbs_c = 0x0804;
+    if(ivideo->vbflags & (VB_301LV|VB_302LV|VB_302ELV)) {
+       svhs_c = 0x0408; cvbs_c = 0x0808;
+    }
+    biosflag = 2;
 
-  } else {
-
-	if(ivideo.vbflags & (VB_301B|VB_302B)) {
-		vga2_bh = 0x01; vga2_bl = 0x90;
-		svhs_bh = 0x01; svhs_bl = 0x6b;
-		cvbs_bh = 0x01; cvbs_bl = 0x74;
-	} else if(ivideo.vbflags & (VB_301C|VB_302ELV)) {
-	      	vga2_bh = 0x01; vga2_bl = 0x90;
-	      	svhs_bh = 0x01; svhs_bl = 0x6b;
-	      	cvbs_bh = 0x01; cvbs_bl = 0x10;
-	} else if(ivideo.vbflags & (VB_301LV|VB_302LV)) {
-	      	vga2_bh = 0x00; vga2_bl = 0x00;
-	      	svhs_bh = 0x02; svhs_bl = 0x00;
-	      	cvbs_bh = 0x01; cvbs_bl = 0x00;
-	} else {
-		vga2_bh = 0x00; vga2_bl = 0xd1;
-        	svhs_bh = 0x00; svhs_bl = 0xb9;
-		cvbs_bh = 0x00; cvbs_bl = 0xb3;
-		inSISIDXREG(SISPART4,0x01,myflag);
-	        if(myflag & 0x04) {
-	           vga2_bh = 0x00; vga2_bl = 0xfd;
-	           svhs_bh = 0x00; svhs_bl = 0xdd;
-	           cvbs_bh = 0x00; cvbs_bl = 0xee;
-	        }
-	}
+    if(ivideo->chip == SIS_300) {
+       inSISIDXREG(SISSR,0x3b,myflag);
+       if(!(myflag & 0x01)) vga2 = vga2_c = 0;
+    }
 
-	if(ivideo.vbflags & (VB_301LV|VB_302LV|VB_302ELV)) {
-	   vga2_bh = 0x00; vga2_bl = 0x00;
-	   vga2_ch = 0x00; vga2_cl = 0x00;
-	   svhs_ch = 0x04; svhs_cl = 0x08;
-	   cvbs_ch = 0x08; cvbs_cl = 0x08;
-	} else {
-	   vga2_ch = 0x0e; vga2_cl = 0x08;
-	   svhs_ch = 0x04; svhs_cl = 0x04;
-	   cvbs_ch = 0x08; cvbs_cl = 0x04;
-	}
-    } 
-
-    if(vga2_ch || vga2_cl || vga2_bh || vga2_bl) {
-       haveresult = 0;
-       for(j = 0; j < 10; j++) {
-          result = 0;
-          for(i = 0; i < 3; i++) {
-             if(SISDoSense(vga2_bl, vga2_bh, vga2_cl, vga2_ch))
-	        result++;
-          }
-	  if((result == 0) || (result >= 2)) break;
-       }
-       if(result) {
-          printk(KERN_INFO "%s secondary VGA connection\n", stdstr);
-	  orSISIDXREG(SISCR, 0x32, 0x10);
-       } else {
-	  andSISIDXREG(SISCR, 0x32, ~0x10);
+    inSISIDXREG(SISSR,0x1e,backupSR_1e);
+    orSISIDXREG(SISSR,0x1e,0x20);
+
+    inSISIDXREG(SISPART4,0x0d,backupP4_0d);
+    if(ivideo->vbflags & VB_301C) {
+       setSISIDXREG(SISPART4,0x0d,~0x07,0x01);
+    } else {
+       orSISIDXREG(SISPART4,0x0d,0x04);
+    }
+    SiS_DDC2Delay(&ivideo->SiS_Pr, 0x2000);
+
+    inSISIDXREG(SISPART2,0x00,backupP2_00);
+    outSISIDXREG(SISPART2,0x00,((backupP2_00 | 0x1c) & 0xfc));
+
+    inSISIDXREG(SISPART2,0x4d,backupP2_4d);
+    if(ivideo->vbflags & (VB_301C|VB_301LV|VB_302LV|VB_302ELV)) {
+       outSISIDXREG(SISPART2,0x4d,(backupP2_4d & ~0x10));
+    }
+
+    if(!(ivideo->vbflags & VB_301C)) {
+       SISDoSense(ivideo, 0, 0);
+    }
+
+    andSISIDXREG(SISCR, 0x32, ~0x14);
+
+    if(vga2_c || vga2) {
+       if(SISDoSense(ivideo, vga2, vga2_c)) {
+          if(biosflag & 0x01) {
+	     printk(KERN_INFO "%s %s SCART output\n", stdstr, tvstr);
+	     orSISIDXREG(SISCR, 0x32, 0x04);
+	  } else {
+	     printk(KERN_INFO "%s secondary VGA connection\n", stdstr);
+	     orSISIDXREG(SISCR, 0x32, 0x10);
+	  }
        }
     }
 
-    if(ivideo.vbflags & (VB_301C|VB_302ELV)) {
+    andSISIDXREG(SISCR, 0x32, 0x3f);
+
+    if(ivideo->vbflags & VB_301C) {
        orSISIDXREG(SISPART4,0x0d,0x04);
     }
 
-    haveresult = 0;
-    for(j = 0; j < 10; j++) {
-       result = 0;
-       for(i = 0; i < 3; i++) {
-          if(SISDoSense(svhs_bl, svhs_bh, svhs_cl, svhs_ch))
-	        result++;
+    if((ivideo->sisvga_engine == SIS_315_VGA) &&
+       (ivideo->vbflags & (VB_301C|VB_301LV|VB_302LV|VB_302ELV))) {
+       outSISIDXREG(SISPART2,0x4d,(backupP2_4d | 0x10));
+       SiS_DDC2Delay(&ivideo->SiS_Pr, 0x2000);
+       if((result = SISDoSense(ivideo, svhs, 0x0604))) {
+          if((result = SISDoSense(ivideo, cvbs, 0x0804))) {
+	     printk(KERN_INFO "%s %s YPbPr component output\n", stdstr, tvstr);
+	     orSISIDXREG(SISCR,0x32,0x80);
+	  }
        }
-       if((result == 0) || (result >= 2)) break;
-    }
-    if(result) {
-        printk(KERN_INFO "%s %s SVIDEO output\n", stdstr, tvstr);
-	ivideo.vbflags |= TV_SVIDEO;
-	orSISIDXREG(SISCR, 0x32, 0x02);
-	andSISIDXREG(SISCR, 0x32, ~0x05);
+       outSISIDXREG(SISPART2,0x4d,backupP2_4d);
     }
 
-    if(!result) {
+    andSISIDXREG(SISCR, 0x32, ~0x03);
 
-	haveresult = 0;
-       	for(j = 0; j < 10; j++) {
-           result = 0;
-           for(i = 0; i < 3; i++) {
-              if(SISDoSense(cvbs_bl, cvbs_bh, cvbs_cl, cvbs_ch))
-	        result++;
-           }
-           if((result == 0) || (result >= 2)) break;
-        }
-	if(result) {
-	    printk(KERN_INFO "%s %s COMPOSITE output\n", stdstr, tvstr);
-	    ivideo.vbflags |= TV_AVIDEO;
-	    orSISIDXREG(SISCR, 0x32, 0x01);
-	    andSISIDXREG(SISCR, 0x32, ~0x06);
-	} else {
-	    andSISIDXREG(SISCR, 0x32, ~0x07);
-	}
+    if(!(ivideo->vbflags & TV_YPBPR)) {
+       if((result = SISDoSense(ivideo, svhs, svhs_c))) {
+          printk(KERN_INFO "%s %s SVIDEO output\n", stdstr, tvstr);
+          orSISIDXREG(SISCR, 0x32, 0x02);
+       }
+       if((biosflag & 0x02) || (!result)) {
+          if(SISDoSense(ivideo, cvbs, cvbs_c)) {
+	     printk(KERN_INFO "%s %s COMPOSITE output\n", stdstr, tvstr);
+	     orSISIDXREG(SISCR, 0x32, 0x01);
+          }
+       }
     }
-    SISDoSense(0, 0, 0, 0);
+
+    SISDoSense(ivideo, 0, 0);
 
     outSISIDXREG(SISPART2,0x00,backupP2_00);
     outSISIDXREG(SISPART4,0x0d,backupP4_0d);
+    outSISIDXREG(SISSR,0x1e,backupSR_1e);
+
+    if(ivideo->vbflags & VB_301C) {
+       inSISIDXREG(SISPART2,0x00,biosflag);
+       if(biosflag & 0x20) {
+          for(myflag = 2; myflag > 0; myflag--) {
+	     biosflag ^= 0x20;
+	     outSISIDXREG(SISPART2,0x00,biosflag);
+	  }
+       }
+    }
+
+    outSISIDXREG(SISPART2,0x00,backupP2_00);
 }
 
 /* Determine and detect attached TV's on Chrontel */
-static void
-SiS_SenseCh(void)
+static void __devinit SiS_SenseCh(struct sis_video_info *ivideo)
 {
-
-   u8 temp1, temp2;
+#if defined(CONFIG_FB_SIS_300) || defined(CONFIG_FB_SIS_315)
+    u8 temp1, temp2;
+    char stdstr[] = "sisfb: Chrontel: Detected TV connected to";
+#endif
 #ifdef CONFIG_FB_SIS_300
-   unsigned char test[3];
-   int i;
+    unsigned char test[3];
+    int i;
 #endif
-   char stdstr[] = "sisfb: Chrontel: Detected TV connected to";
 
-   if(ivideo.chip < SIS_315H) {
+    if(ivideo->chip < SIS_315H) {
 
 #ifdef CONFIG_FB_SIS_300
-       SiS_Pr.SiS_IF_DEF_CH70xx = 1;		/* Chrontel 700x */
-       SiS_SetChrontelGPIO(&SiS_Pr, 0x9c);	/* Set general purpose IO for Chrontel communication */
-       SiS_DDC2Delay(&SiS_Pr, 1000);
-       temp1 = SiS_GetCH700x(&SiS_Pr, 0x25);
+       ivideo->SiS_Pr.SiS_IF_DEF_CH70xx = 1;		/* Chrontel 700x */
+       SiS_SetChrontelGPIO(&ivideo->SiS_Pr, 0x9c);	/* Set general purpose IO for Chrontel communication */
+       SiS_DDC2Delay(&ivideo->SiS_Pr, 1000);
+       temp1 = SiS_GetCH700x(&ivideo->SiS_Pr, 0x25);
        /* See Chrontel TB31 for explanation */
-       temp2 = SiS_GetCH700x(&SiS_Pr, 0x0e);
+       temp2 = SiS_GetCH700x(&ivideo->SiS_Pr, 0x0e);
        if(((temp2 & 0x07) == 0x01) || (temp2 & 0x04)) {
-	  SiS_SetCH700x(&SiS_Pr, 0x0b0e);
-	  SiS_DDC2Delay(&SiS_Pr, 300);
+	  SiS_SetCH700x(&ivideo->SiS_Pr, 0x0b0e);
+	  SiS_DDC2Delay(&ivideo->SiS_Pr, 300);
        }
-       temp2 = SiS_GetCH700x(&SiS_Pr, 0x25);
+       temp2 = SiS_GetCH700x(&ivideo->SiS_Pr, 0x25);
        if(temp2 != temp1) temp1 = temp2;
 
        if((temp1 >= 0x22) && (temp1 <= 0x50)) {
 	   /* Read power status */
-	   temp1 = SiS_GetCH700x(&SiS_Pr, 0x0e);
+	   temp1 = SiS_GetCH700x(&ivideo->SiS_Pr, 0x0e);
 	   if((temp1 & 0x03) != 0x03) {
      	        /* Power all outputs */
-		SiS_SetCH700x(&SiS_Pr, 0x0B0E);
-		SiS_DDC2Delay(&SiS_Pr, 300);
+		SiS_SetCH700x(&ivideo->SiS_Pr, 0x0B0E);
+		SiS_DDC2Delay(&ivideo->SiS_Pr, 300);
 	   }
 	   /* Sense connected TV devices */
 	   for(i = 0; i < 3; i++) {
-	       SiS_SetCH700x(&SiS_Pr, 0x0110);
-	       SiS_DDC2Delay(&SiS_Pr, 0x96);
-	       SiS_SetCH700x(&SiS_Pr, 0x0010);
-	       SiS_DDC2Delay(&SiS_Pr, 0x96);
-	       temp1 = SiS_GetCH700x(&SiS_Pr, 0x10);
+	       SiS_SetCH700x(&ivideo->SiS_Pr, 0x0110);
+	       SiS_DDC2Delay(&ivideo->SiS_Pr, 0x96);
+	       SiS_SetCH700x(&ivideo->SiS_Pr, 0x0010);
+	       SiS_DDC2Delay(&ivideo->SiS_Pr, 0x96);
+	       temp1 = SiS_GetCH700x(&ivideo->SiS_Pr, 0x10);
 	       if(!(temp1 & 0x08))       test[i] = 0x02;
 	       else if(!(temp1 & 0x02))  test[i] = 0x01;
 	       else                      test[i] = 0;
-	       SiS_DDC2Delay(&SiS_Pr, 0x96);
+	       SiS_DDC2Delay(&ivideo->SiS_Pr, 0x96);
 	   }
 
 	   if(test[0] == test[1])      temp1 = test[0];
@@ -3079,42 +2914,42 @@
 	   }
 	   if(temp1 == 0x02) {
 		printk(KERN_INFO "%s SVIDEO output\n", stdstr);
-		ivideo.vbflags |= TV_SVIDEO;
+		ivideo->vbflags |= TV_SVIDEO;
 		orSISIDXREG(SISCR, 0x32, 0x02);
 		andSISIDXREG(SISCR, 0x32, ~0x05);
 	   } else if (temp1 == 0x01) {
 		printk(KERN_INFO "%s CVBS output\n", stdstr);
-		ivideo.vbflags |= TV_AVIDEO;
+		ivideo->vbflags |= TV_AVIDEO;
 		orSISIDXREG(SISCR, 0x32, 0x01);
 		andSISIDXREG(SISCR, 0x32, ~0x06);
 	   } else {
- 		SiS_SetCH70xxANDOR(&SiS_Pr, 0x010E,0xF8);
+ 		SiS_SetCH70xxANDOR(&ivideo->SiS_Pr, 0x010E,0xF8);
 		andSISIDXREG(SISCR, 0x32, ~0x07);
 	   }
        } else if(temp1 == 0) {
-	  SiS_SetCH70xxANDOR(&SiS_Pr, 0x010E,0xF8);
+	  SiS_SetCH70xxANDOR(&ivideo->SiS_Pr, 0x010E,0xF8);
 	  andSISIDXREG(SISCR, 0x32, ~0x07);
        }
        /* Set general purpose IO for Chrontel communication */
-       SiS_SetChrontelGPIO(&SiS_Pr, 0x00);
+       SiS_SetChrontelGPIO(&ivideo->SiS_Pr, 0x00);
 #endif
 
-   } else {
+    } else {
 
 #ifdef CONFIG_FB_SIS_315
-	SiS_Pr.SiS_IF_DEF_CH70xx = 2;		/* Chrontel 7019 */
-        temp1 = SiS_GetCH701x(&SiS_Pr, 0x49);
-	SiS_SetCH701x(&SiS_Pr, 0x2049);
-	SiS_DDC2Delay(&SiS_Pr, 0x96);
-	temp2 = SiS_GetCH701x(&SiS_Pr, 0x20);
+	ivideo->SiS_Pr.SiS_IF_DEF_CH70xx = 2;		/* Chrontel 7019 */
+        temp1 = SiS_GetCH701x(&ivideo->SiS_Pr, 0x49);
+	SiS_SetCH701x(&ivideo->SiS_Pr, 0x2049);
+	SiS_DDC2Delay(&ivideo->SiS_Pr, 0x96);
+	temp2 = SiS_GetCH701x(&ivideo->SiS_Pr, 0x20);
 	temp2 |= 0x01;
-	SiS_SetCH701x(&SiS_Pr, (temp2 << 8) | 0x20);
-	SiS_DDC2Delay(&SiS_Pr, 0x96);
+	SiS_SetCH701x(&ivideo->SiS_Pr, (temp2 << 8) | 0x20);
+	SiS_DDC2Delay(&ivideo->SiS_Pr, 0x96);
 	temp2 ^= 0x01;
-	SiS_SetCH701x(&SiS_Pr, (temp2 << 8) | 0x20);
-	SiS_DDC2Delay(&SiS_Pr, 0x96);
-	temp2 = SiS_GetCH701x(&SiS_Pr, 0x20);
-	SiS_SetCH701x(&SiS_Pr, (temp1 << 8) | 0x49);
+	SiS_SetCH701x(&ivideo->SiS_Pr, (temp2 << 8) | 0x20);
+	SiS_DDC2Delay(&ivideo->SiS_Pr, 0x96);
+	temp2 = SiS_GetCH701x(&ivideo->SiS_Pr, 0x20);
+	SiS_SetCH701x(&ivideo->SiS_Pr, (temp1 << 8) | 0x49);
         temp1 = 0;
 	if(temp2 & 0x02) temp1 |= 0x01;
 	if(temp2 & 0x10) temp1 |= 0x01;
@@ -3123,13 +2958,13 @@
 	switch(temp1) {
 	case 0x01:
 	     printk(KERN_INFO "%s CVBS output\n", stdstr);
-	     ivideo.vbflags |= TV_AVIDEO;
+	     ivideo->vbflags |= TV_AVIDEO;
 	     orSISIDXREG(SISCR, 0x32, 0x01);
 	     andSISIDXREG(SISCR, 0x32, ~0x06);
              break;
 	case 0x02:
 	     printk(KERN_INFO "%s SVIDEO output\n", stdstr);
-	     ivideo.vbflags |= TV_SVIDEO;
+	     ivideo->vbflags |= TV_SVIDEO;
 	     orSISIDXREG(SISCR, 0x32, 0x02);
 	     andSISIDXREG(SISCR, 0x32, ~0x05);
              break;
@@ -3142,336 +2977,171 @@
 	     andSISIDXREG(SISCR, 0x32, ~0x07);
 	}
 #endif
-
-   }
+    }
 }
 
-
 /* ------------------------ Heap routines -------------------------- */
 
-static int sisfb_heap_init(void)
+static u32 __devinit
+sisfb_getheapstart(struct sis_video_info *ivideo)
 {
-	SIS_OH *poh;
-	u8 temp=0;
-#ifdef CONFIG_FB_SIS_315
-	int            agp_enabled = 1;
-	u32            agp_size;
-	unsigned long *cmdq_baseport = 0;
-	unsigned long *read_port = 0;
-	unsigned long *write_port = 0;
-	SIS_CMDTYPE    cmd_type;
-#ifndef AGPOFF
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
-	struct agp_kern_info  *agp_info;
-	struct agp_memory     *agp;
-#else
-	agp_kern_info  *agp_info;
-	agp_memory     *agp;
-#endif
-	u32            agp_phys;
-#endif
-#endif
-/*     The heap start is either set manually using the "mem" parameter, or
- *     defaults as follows:
- *     -) If more than 16MB videoRAM available, let our heap start at 12MB.
- *     -) If more than  8MB videoRAM available, let our heap start at  8MB.
- *     -) If 4MB or less is available, let it start at 4MB.
- *     This is for avoiding a clash with X driver which uses the beginning
- *     of the videoRAM. To limit size of X framebuffer, use Option MaxXFBMem
- *     in XF86Config-4.
- *     The heap start can also be specified by parameter "mem" when starting the sisfb
- *     driver. sisfb mem=1024 lets heap starts at 1MB, etc.
- *
- *     On the 315 and Xabre series, the default is a 1MB heap since DRI is not
- *     supported there.
- */
-     if ((!sisfb_mem) || (sisfb_mem > (ivideo.video_size/1024))) {
-        if(sisvga_engine == SIS_300_VGA) {
-           if (ivideo.video_size > 0x1000000) {
-	        ivideo.heapstart = 0xc00000;
-	   } else if (ivideo.video_size > 0x800000) {
-	        ivideo.heapstart = 0x800000;
+	u32 ret = ivideo->sisfb_parm_mem * 1024;
+	u32 max = ivideo->video_size - ivideo->hwcursor_size;
+	u32 def;
+
+	/* Calculate heap start = end of memory for console
+	 *
+	 * CCCCCCCCDDDDDDDDDDDDDDDDDDDDDDDDDDDDHHHHQQQQQQQQQQ
+	 * C = console, D = heap, H = HWCursor, Q = cmd-queue
+	 *
+	 * Basically given by "mem" parameter
+	 *
+	 * maximum = videosize - cmd_queue - hwcursor
+	 *           (results in a heap of size 0)
+	 * default = SiS 300: depends on videosize
+	 *           SiS 315/330: 32k below max
+	 */
+
+	if(ivideo->sisvga_engine == SIS_300_VGA) {
+	   max -= TURBO_QUEUE_AREA_SIZE;
+	   if(ivideo->video_size > 0x1000000) {
+	      def = 0xc00000;
+	   } else if(ivideo->video_size > 0x800000) {
+	      def = 0x800000;
 	   } else {
-		ivideo.heapstart = 0x400000;
+	      def = 0x400000;
 	   }
 	} else {
-	   ivideo.heapstart = ivideo.video_size - 0x100000;
+	   max -= COMMAND_QUEUE_AREA_SIZE;
+	   def = max - 0x8000;
 	}
-     } else {
-           ivideo.heapstart = sisfb_mem * 1024;
-     }
-     sisfb_heap_start = (unsigned long) (ivideo.video_vbase + ivideo.heapstart);
-     printk(KERN_INFO "sisfb: Memory heap starting at %dK\n",
-     					(int)(ivideo.heapstart / 1024));
 
-     sisfb_heap_end = (unsigned long) ivideo.video_vbase + ivideo.video_size;
-     sisfb_heap_size = sisfb_heap_end - sisfb_heap_start;
+        if((!ret) || (ret > max) || (ivideo->cardnumber != 0)) {
+	   ret = def;
+        }
 
-#ifdef CONFIG_FB_SIS_315
-     if (sisvga_engine == SIS_315_VGA) {
-        /* Now initialize the 315/330 series' command queue mode.
-	 * On 315, there are three queue modes available which
-	 * are chosen by setting bits 7:5 in SR26:
-	 * 1. MMIO queue mode (bit 5, 0x20). The hardware will keep
-	 *    track of the queue, the FIFO, command parsing and so
-	 *    on. This is the one comparable to the 300 series.
-	 * 2. VRAM queue mode (bit 6, 0x40). In this case, one will
-	 *    have to do queue management himself. Register 0x85c4 will
-	 *    hold the location of the next free queue slot, 0x85c8
-	 *    is the "queue read pointer" whose way of working is
-	 *    unknown to me. Anyway, this mode would require a
-	 *    translation of the MMIO commands to some kind of
-	 *    accelerator assembly and writing these commands
-	 *    to the memory location pointed to by 0x85c4.
-	 *    We will not use this, as nobody knows how this
-	 *    "assembly" works, and as it would require a complete
-	 *    re-write of the accelerator code.
-	 * 3. AGP queue mode (bit 7, 0x80). Works as 2., but keeps the
-	 *    queue in AGP memory space.
-	 *
-	 * SR26 bit 4 is called "Bypass H/W queue".
-	 * SR26 bit 1 is called "Enable Command Queue Auto Correction"
-	 * SR26 bit 0 resets the queue
-	 * Size of queue memory is encoded in bits 3:2 like this:
-	 *    00  (0x00)  512K
-	 *    01  (0x04)  1M
-	 *    10  (0x08)  2M
-	 *    11  (0x0C)  4M
-	 * The queue location is to be written to 0x85C0.
-	 *
-         */
-	cmdq_baseport = (unsigned long *)(ivideo.mmio_vbase + MMIO_QUEUE_PHYBASE);
-	write_port    = (unsigned long *)(ivideo.mmio_vbase + MMIO_QUEUE_WRITEPORT);
-	read_port     = (unsigned long *)(ivideo.mmio_vbase + MMIO_QUEUE_READPORT);
-
-	DPRINTK("AGP base: 0x%p, read: 0x%p, write: 0x%p\n", cmdq_baseport, read_port, write_port);
-
-	agp_size  = COMMAND_QUEUE_AREA_SIZE;
-
-#ifndef AGPOFF
-	if (sisfb_queuemode == AGP_CMD_QUEUE) {
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
-		agp_info = vmalloc(sizeof(*agp_info));
-		memset((void*)agp_info, 0x00, sizeof(*agp_info));
-#else
-		agp_info = vmalloc(sizeof(agp_kern_info));
-		memset((void*)agp_info, 0x00, sizeof(agp_kern_info));
-#endif
-		agp_copy_info(agp_info);
+	return ret;
+}
 
-		agp_backend_acquire();
+static int __devinit
+sisfb_heap_init(struct sis_video_info *ivideo)
+{
+     SIS_OH *poh;
 
-		agp = agp_allocate_memory(COMMAND_QUEUE_AREA_SIZE/PAGE_SIZE,
-					  AGP_NORMAL_MEMORY);
-		if (agp == NULL) {
-			DPRINTK("sisfb: Allocating AGP buffer failed.\n");
-			agp_enabled = 0;
-		} else {
-			if (agp_bind_memory(agp, agp->pg_start) != 0) {
-				DPRINTK("sisfb: AGP: Failed to bind memory\n");
-				/* TODO: Free AGP memory here */
-				agp_enabled = 0;
-			} else {
-				agp_enable(0);
-			}
-		}
-	}
-#else
-	agp_enabled = 0;
-#endif
+     ivideo->heapstart = ivideo->sisfb_mem = sisfb_getheapstart(ivideo);
 
-	/* Now select the queue mode */
+     ivideo->sisfb_heap_start = ivideo->video_vbase + ivideo->heapstart;
+     ivideo->sisfb_heap_end   = ivideo->video_vbase + ivideo->video_size;
 
-	if ((agp_enabled) && (sisfb_queuemode == AGP_CMD_QUEUE)) {
-		cmd_type = AGP_CMD_QUEUE;
-		printk(KERN_INFO "sisfb: Using AGP queue mode\n");
-/*	} else if (sisfb_heap_size >= COMMAND_QUEUE_AREA_SIZE)  */
-        } else if (sisfb_queuemode == VM_CMD_QUEUE) {
-		cmd_type = VM_CMD_QUEUE;
-		printk(KERN_INFO "sisfb: Using VRAM queue mode\n");
-	} else {
-		printk(KERN_INFO "sisfb: Using MMIO queue mode\n");
-		cmd_type = MMIO_CMD;
-	}
+     /* Initialize command queue (We use MMIO only) */
 
-	switch (agp_size) {
-	   case 0x80000:
-		temp = SIS_CMD_QUEUE_SIZE_512k;
-		break;
-	   case 0x100000:
-		temp = SIS_CMD_QUEUE_SIZE_1M;
-		break;
-	   case 0x200000:
-		temp = SIS_CMD_QUEUE_SIZE_2M;
-		break;
-	   case 0x400000:
-		temp = SIS_CMD_QUEUE_SIZE_4M;
-		break;
-	}
+#ifdef CONFIG_FB_SIS_315
+     if(ivideo->sisvga_engine == SIS_315_VGA) {
+        u32 tempq = 0;
+	u8  temp = 0;
 
-	switch (cmd_type) {
-	   case AGP_CMD_QUEUE:
-#ifndef AGPOFF
-		DPRINTK("sisfb: AGP buffer base = 0x%lx, offset = 0x%x, size = %dK\n",
-			agp_info->aper_base, agp->physical, agp_size/1024);
+        ivideo->sisfb_heap_end -= COMMAND_QUEUE_AREA_SIZE;
 
-		agp_phys = agp_info->aper_base + agp->physical;
+	outSISIDXREG(SISSR, IND_SIS_CMDQUEUE_THRESHOLD, COMMAND_QUEUE_THRESHOLD);
+	outSISIDXREG(SISSR, IND_SIS_CMDQUEUE_SET, SIS_CMD_QUEUE_RESET);
 
-		outSISIDXREG(SISCR,  IND_SIS_AGP_IO_PAD, 0);
-		outSISIDXREG(SISCR,  IND_SIS_AGP_IO_PAD, SIS_AGP_2X);
+	tempq = MMIO_IN32(ivideo->mmio_vbase, MMIO_QUEUE_READPORT);
+	MMIO_OUT32(ivideo->mmio_vbase, MMIO_QUEUE_WRITEPORT, tempq);
 
-                outSISIDXREG(SISSR, IND_SIS_CMDQUEUE_THRESHOLD, COMMAND_QUEUE_THRESHOLD);
+	temp = SIS_CMD_QUEUE_SIZE_512k;
+	temp |= (SIS_MMIO_CMD_ENABLE | SIS_CMD_AUTO_CORR);
+	outSISIDXREG(SISSR, IND_SIS_CMDQUEUE_SET, temp);
 
-		outSISIDXREG(SISSR, IND_SIS_CMDQUEUE_SET, SIS_CMD_QUEUE_RESET);
+	tempq = (u32)(ivideo->video_size - COMMAND_QUEUE_AREA_SIZE);
+	MMIO_OUT32(ivideo->mmio_vbase, MMIO_QUEUE_PHYBASE, tempq);
 
-		*write_port = *read_port;
+	ivideo->caps |= MMIO_CMD_QUEUE_CAP;
+     }
+#endif
 
-		temp |= SIS_AGP_CMDQUEUE_ENABLE;
-		outSISIDXREG(SISSR, IND_SIS_CMDQUEUE_SET, temp);
+#ifdef CONFIG_FB_SIS_300
+     if(ivideo->sisvga_engine == SIS_300_VGA) {
+     	unsigned long tqueue_pos;
+	u8 tq_state;
 
-		*cmdq_baseport = agp_phys;
+	ivideo->sisfb_heap_end -= TURBO_QUEUE_AREA_SIZE;
 
-		sisfb_caps |= AGP_CMD_QUEUE_CAP;
-#endif
-		break;
+	tqueue_pos = (ivideo->video_size - TURBO_QUEUE_AREA_SIZE) / (64 * 1024);
 
-	   case VM_CMD_QUEUE:
-		sisfb_heap_end -= COMMAND_QUEUE_AREA_SIZE;
-		sisfb_heap_size -= COMMAND_QUEUE_AREA_SIZE;
+	inSISIDXREG(SISSR, IND_SIS_TURBOQUEUE_SET, tq_state);
+	tq_state |= 0xf0;
+	tq_state &= 0xfc;
+	tq_state |= (u8)(tqueue_pos >> 8);
+	outSISIDXREG(SISSR, IND_SIS_TURBOQUEUE_SET, tq_state);
 
-		outSISIDXREG(SISSR, IND_SIS_CMDQUEUE_THRESHOLD, COMMAND_QUEUE_THRESHOLD);
+	outSISIDXREG(SISSR, IND_SIS_TURBOQUEUE_ADR, (u8)(tqueue_pos & 0xff));
 
-		outSISIDXREG(SISSR, IND_SIS_CMDQUEUE_SET, SIS_CMD_QUEUE_RESET);
+	ivideo->caps |= TURBO_QUEUE_CAP;
+     }
+#endif
 
-		*write_port = *read_port;
+     /* Reserve memory for the HWCursor */
+     ivideo->sisfb_heap_end -= ivideo->hwcursor_size;
+     ivideo->hwcursor_vbase = ivideo->sisfb_heap_end;
+     ivideo->caps |= HW_CURSOR_CAP;
 
-		temp |= SIS_VRAM_CMDQUEUE_ENABLE;
-		outSISIDXREG(SISSR, IND_SIS_CMDQUEUE_SET, temp);
+     ivideo->sisfb_heap_size = ivideo->sisfb_heap_end - ivideo->sisfb_heap_start;
 
-		*cmdq_baseport = ivideo.video_size - COMMAND_QUEUE_AREA_SIZE;
+     if(ivideo->cardnumber == 0) {
 
-		sisfb_caps |= VM_CMD_QUEUE_CAP;
+     	printk(KERN_INFO "sisfb: Memory heap starting at %dK, size %dK\n",
+     		(int)(ivideo->heapstart / 1024), (int)(ivideo->sisfb_heap_size / 1024));
 
-		DPRINTK("sisfb: VM Cmd Queue offset = 0x%lx, size is %dK\n",
-			*cmdq_baseport, COMMAND_QUEUE_AREA_SIZE/1024);
-		break;
+	sisfb_heap.vinfo = ivideo;
 
-	   default:  /* MMIO */
-	   	sisfb_heap_end -= COMMAND_QUEUE_AREA_SIZE;
-		sisfb_heap_size -= COMMAND_QUEUE_AREA_SIZE;
+     	sisfb_heap.poha_chain = NULL;
+     	sisfb_heap.poh_freelist = NULL;
 
-		outSISIDXREG(SISSR, IND_SIS_CMDQUEUE_THRESHOLD, COMMAND_QUEUE_THRESHOLD);
-		outSISIDXREG(SISSR, IND_SIS_CMDQUEUE_SET, SIS_CMD_QUEUE_RESET);
+     	poh = sisfb_poh_new_node();
+     	if(poh == NULL) return 1;
 
-		*write_port = *read_port;
+     	poh->poh_next = &sisfb_heap.oh_free;
+     	poh->poh_prev = &sisfb_heap.oh_free;
+     	poh->size = ivideo->sisfb_heap_size;
+     	poh->offset = ivideo->heapstart;
 
-		/* Set Auto_Correction bit */
-		temp |= (SIS_MMIO_CMD_ENABLE | SIS_CMD_AUTO_CORR);
-		outSISIDXREG(SISSR, IND_SIS_CMDQUEUE_SET, temp);
+     	sisfb_heap.oh_free.poh_next = poh;
+     	sisfb_heap.oh_free.poh_prev = poh;
+     	sisfb_heap.oh_free.size = 0;
+     	sisfb_heap.max_freesize = poh->size;
 
-		*cmdq_baseport = ivideo.video_size - COMMAND_QUEUE_AREA_SIZE;
+     	sisfb_heap.oh_used.poh_next = &sisfb_heap.oh_used;
+     	sisfb_heap.oh_used.poh_prev = &sisfb_heap.oh_used;
+     	sisfb_heap.oh_used.size = SENTINEL;
 
-		sisfb_caps |= MMIO_CMD_QUEUE_CAP;
+     } else {
 
-		DPRINTK("sisfb: MMIO Cmd Queue offset = 0x%lx, size is %dK\n",
-			*cmdq_baseport, COMMAND_QUEUE_AREA_SIZE/1024);
-		break;
-	}
-     } /* sisvga_engine = 315 */
-#endif
+        printk(KERN_INFO "Skipped heap initialization for secondary cards\n");
 
-#ifdef CONFIG_FB_SIS_300
-     if (sisvga_engine == SIS_300_VGA) {
-  	    /* Now initialize TurboQueue. TB is always located at the very
-	     * top of the video RAM. */
-	    if (sisfb_heap_size >= TURBO_QUEUE_AREA_SIZE) {
-		unsigned int  tqueue_pos;
-		u8 tq_state;
-
-		tqueue_pos = (ivideo.video_size -
-		       TURBO_QUEUE_AREA_SIZE) / (64 * 1024);
-
-		temp = (u8) (tqueue_pos & 0xff);
-
-		inSISIDXREG(SISSR, IND_SIS_TURBOQUEUE_SET, tq_state);
-		tq_state |= 0xf0;
-		tq_state &= 0xfc;
-		tq_state |= (u8) (tqueue_pos >> 8);
-		outSISIDXREG(SISSR, IND_SIS_TURBOQUEUE_SET, tq_state);
-
-		outSISIDXREG(SISSR, IND_SIS_TURBOQUEUE_ADR, temp);
-
-		sisfb_caps |= TURBO_QUEUE_CAP;
-
-		sisfb_heap_end -= TURBO_QUEUE_AREA_SIZE;
-		sisfb_heap_size -= TURBO_QUEUE_AREA_SIZE;
-		DPRINTK("sisfb: TurboQueue start at 0x%lx, size is %dK\n",
-			sisfb_heap_end, TURBO_QUEUE_AREA_SIZE/1024);
-	    }
      }
-#endif
-     /* Now reserve memory for the HWCursor. It is always located at the very
-        top of the videoRAM, right below the TB memory area (if used). */
-     if (sisfb_heap_size >= sisfb_hwcursor_size) {
-		sisfb_heap_end -= sisfb_hwcursor_size;
-		sisfb_heap_size -= sisfb_hwcursor_size;
-		sisfb_hwcursor_vbase = sisfb_heap_end;
 
-		sisfb_caps |= HW_CURSOR_CAP;
-
-		DPRINTK("sisfb: Hardware Cursor start at 0x%lx, size is %dK\n",
-			sisfb_heap_end, sisfb_hwcursor_size/1024);
-     }
+     return 0;
+}
 
-     sisfb_heap.poha_chain = NULL;
-     sisfb_heap.poh_freelist = NULL;
-
-     poh = sisfb_poh_new_node();
-
-     if(poh == NULL)  return 1;
-	
-     poh->poh_next = &sisfb_heap.oh_free;
-     poh->poh_prev = &sisfb_heap.oh_free;
-     poh->size = sisfb_heap_end - sisfb_heap_start + 1;
-     poh->offset = sisfb_heap_start - (unsigned long) ivideo.video_vbase;
-
-     DPRINTK("sisfb: Heap start:0x%p, end:0x%p, len=%dk\n",
-		(char *) sisfb_heap_start, (char *) sisfb_heap_end,
-		(unsigned int) poh->size / 1024);
-
-     DPRINTK("sisfb: First Node offset:0x%x, size:%dk\n",
-		(unsigned int) poh->offset, (unsigned int) poh->size / 1024);
-
-     sisfb_heap.oh_free.poh_next = poh;
-     sisfb_heap.oh_free.poh_prev = poh;
-     sisfb_heap.oh_free.size = 0;
-     sisfb_heap.max_freesize = poh->size;
-
-     sisfb_heap.oh_used.poh_next = &sisfb_heap.oh_used;
-     sisfb_heap.oh_used.poh_prev = &sisfb_heap.oh_used;
-     sisfb_heap.oh_used.size = SENTINEL;
-
-     return 0;
-}
-
-static SIS_OH *sisfb_poh_new_node(void)
+static SIS_OH *
+sisfb_poh_new_node(void)
 {
 	int           i;
 	unsigned long cOhs;
 	SIS_OHALLOC   *poha;
 	SIS_OH        *poh;
 
-	if (sisfb_heap.poh_freelist == NULL) {
-		poha = kmalloc(OH_ALLOC_SIZE, GFP_KERNEL);
+	if(sisfb_heap.poh_freelist == NULL) {
+		poha = kmalloc(SIS_OH_ALLOC_SIZE, GFP_KERNEL);
 		if(!poha) return NULL;
 
 		poha->poha_next = sisfb_heap.poha_chain;
 		sisfb_heap.poha_chain = poha;
 
-		cOhs = (OH_ALLOC_SIZE - sizeof(SIS_OHALLOC)) / sizeof(SIS_OH) + 1;
+		cOhs = (SIS_OH_ALLOC_SIZE - sizeof(SIS_OHALLOC)) / sizeof(SIS_OH) + 1;
 
 		poh = &poha->aoh[0];
-		for (i = cOhs - 1; i != 0; i--) {
+		for(i = cOhs - 1; i != 0; i--) {
 			poh->poh_next = poh + 1;
 			poh = poh + 1;
 		}
@@ -3486,21 +3156,22 @@
 	return (poh);
 }
 
-static SIS_OH *sisfb_poh_allocate(unsigned long size)
+static SIS_OH *
+sisfb_poh_allocate(u32 size)
 {
 	SIS_OH *pohThis;
 	SIS_OH *pohRoot;
 	int     bAllocated = 0;
 
-	if (size > sisfb_heap.max_freesize) {
-		DPRINTK("sisfb: Can't allocate %dk size on offscreen\n",
+	if(size > sisfb_heap.max_freesize) {
+		DPRINTK("sisfb: Can't allocate %dk video memory\n",
 			(unsigned int) size / 1024);
 		return (NULL);
 	}
 
 	pohThis = sisfb_heap.oh_free.poh_next;
 
-	while (pohThis != &sisfb_heap.oh_free) {
+	while(pohThis != &sisfb_heap.oh_free) {
 		if (size <= pohThis->size) {
 			bAllocated = 1;
 			break;
@@ -3508,19 +3179,19 @@
 		pohThis = pohThis->poh_next;
 	}
 
-	if (!bAllocated) {
-		DPRINTK("sisfb: Can't allocate %dk size on offscreen\n",
+	if(!bAllocated) {
+		DPRINTK("sisfb: Can't allocate %dk video memory\n",
 			(unsigned int) size / 1024);
 		return (NULL);
 	}
 
-	if (size == pohThis->size) {
+	if(size == pohThis->size) {
 		pohRoot = pohThis;
 		sisfb_delete_node(pohThis);
 	} else {
 		pohRoot = sisfb_poh_new_node();
 
-		if (pohRoot == NULL) {
+		if(pohRoot == NULL) {
 			return (NULL);
 		}
 
@@ -3539,7 +3210,8 @@
 	return (pohRoot);
 }
 
-static void sisfb_delete_node(SIS_OH *poh)
+static void
+sisfb_delete_node(SIS_OH *poh)
 {
 	SIS_OH *poh_prev;
 	SIS_OH *poh_next;
@@ -3549,10 +3221,10 @@
 
 	poh_prev->poh_next = poh_next;
 	poh_next->poh_prev = poh_prev;
-
 }
 
-static void sisfb_insert_node(SIS_OH *pohList, SIS_OH *poh)
+static void
+sisfb_insert_node(SIS_OH *pohList, SIS_OH *poh)
 {
 	SIS_OH *pohTemp;
 
@@ -3565,15 +3237,16 @@
 	poh->poh_next = pohTemp;
 }
 
-static SIS_OH *sisfb_poh_free(unsigned long base)
+static SIS_OH *
+sisfb_poh_free(u32 base)
 {
 	SIS_OH *pohThis;
 	SIS_OH *poh_freed;
 	SIS_OH *poh_prev;
 	SIS_OH *poh_next;
-	unsigned long ulUpper;
-	unsigned long ulLower;
-	int foundNode = 0;
+	u32     ulUpper;
+	u32     ulLower;
+	int     foundNode = 0;
 
 	poh_freed = sisfb_heap.oh_used.poh_next;
 
@@ -3586,7 +3259,7 @@
 		poh_freed = poh_freed->poh_next;
 	}
 
-	if (!foundNode)  return (NULL);
+	if(!foundNode) return(NULL);
 
 	sisfb_heap.max_freesize += poh_freed->size;
 
@@ -3596,12 +3269,10 @@
 
 	pohThis = sisfb_heap.oh_free.poh_next;
 
-	while (pohThis != &sisfb_heap.oh_free) {
-		if (pohThis->offset == ulUpper) {
+	while(pohThis != &sisfb_heap.oh_free) {
+		if(pohThis->offset == ulUpper) {
 			poh_next = pohThis;
-		}
-			else if ((pohThis->offset + pohThis->size) ==
-				 ulLower) {
+		} else if((pohThis->offset + pohThis->size) == ulLower) {
 			poh_prev = pohThis;
 		}
 		pohThis = pohThis->poh_next;
@@ -3609,65 +3280,73 @@
 
 	sisfb_delete_node(poh_freed);
 
-	if (poh_prev && poh_next) {
+	if(poh_prev && poh_next) {
 		poh_prev->size += (poh_freed->size + poh_next->size);
 		sisfb_delete_node(poh_next);
 		sisfb_free_node(poh_freed);
 		sisfb_free_node(poh_next);
-		return (poh_prev);
+		return(poh_prev);
 	}
 
-	if (poh_prev) {
+	if(poh_prev) {
 		poh_prev->size += poh_freed->size;
 		sisfb_free_node(poh_freed);
-		return (poh_prev);
+		return(poh_prev);
 	}
 
-	if (poh_next) {
+	if(poh_next) {
 		poh_next->size += poh_freed->size;
 		poh_next->offset = poh_freed->offset;
 		sisfb_free_node(poh_freed);
-		return (poh_next);
+		return(poh_next);
 	}
 
 	sisfb_insert_node(&sisfb_heap.oh_free, poh_freed);
 
-	return (poh_freed);
+	return(poh_freed);
 }
 
-static void sisfb_free_node(SIS_OH *poh)
+static void
+sisfb_free_node(SIS_OH *poh)
 {
 	if(poh == NULL) return;
 
 	poh->poh_next = sisfb_heap.poh_freelist;
 	sisfb_heap.poh_freelist = poh;
-
 }
 
-void sis_malloc(struct sis_memreq *req)
+void
+sis_malloc(struct sis_memreq *req)
 {
-	SIS_OH *poh;
+	struct sis_video_info *ivideo = sisfb_heap.vinfo;
+	SIS_OH *poh = NULL;
 
-	poh = sisfb_poh_allocate(req->size);
+	if((ivideo) && (!ivideo->havenoheap)) {
+	   poh = sisfb_poh_allocate((u32)req->size);
+	}
 
 	if(poh == NULL) {
-		req->offset = 0;
-		req->size = 0;
-		DPRINTK("sisfb: Video RAM allocation failed\n");
+	   req->offset = req->size = 0;
+	   DPRINTK("sisfb: Video RAM allocation failed\n");
 	} else {
-		DPRINTK("sisfb: Video RAM allocation succeeded: 0x%p\n",
-			(char *) (poh->offset + (unsigned long) ivideo.video_vbase));
-
-		req->offset = poh->offset;
-		req->size = poh->size;
+	   req->offset = poh->offset;
+	   req->size = poh->size;
+	   DPRINTK("sisfb: Video RAM allocation succeeded: 0x%lx\n",
+	   	    (poh->offset + ivideo->video_vbase));
 	}
 }
 
-void sis_free(unsigned long base)
+/* sis_free: u32 because "base" is offset inside video ram, can never be >4GB */
+
+void
+sis_free(u32 base)
 {
+	struct sis_video_info *ivideo = sisfb_heap.vinfo;
 	SIS_OH *poh;
 
-	poh = sisfb_poh_free(base);
+	if((!ivideo) || (ivideo->havenoheap)) return;
+
+	poh = sisfb_poh_free((u32)base);
 
 	if(poh == NULL) {
 		DPRINTK("sisfb: sisfb_poh_free() failed at base 0x%x\n",
@@ -3677,125 +3356,313 @@
 
 /* --------------------- SetMode routines ------------------------- */
 
-static void sisfb_pre_setmode(void)
+static void
+sisfb_pre_setmode(struct sis_video_info *ivideo)
 {
-	u8 cr30 = 0, cr31 = 0, cr33 = 0, cr35 = 0;
+	u8 cr30 = 0, cr31 = 0, cr33 = 0, cr35 = 0, cr38 = 0;
+	int tvregnum = 0;
 
-	ivideo.currentvbflags &= (VB_VIDEOBRIDGE | VB_DISPTYPE_DISP2);
+	ivideo->currentvbflags &= (VB_VIDEOBRIDGE | VB_DISPTYPE_DISP2);
 
 	inSISIDXREG(SISCR, 0x31, cr31);
 	cr31 &= ~0x60;
 	cr31 |= 0x04;
 
-	cr33 = sisfb_rate_idx & 0x0F;
+	cr33 = ivideo->rate_idx & 0x0F;
+
+#ifdef CONFIG_FB_SIS_315
+	if(ivideo->sisvga_engine == SIS_315_VGA) {
+	   if(ivideo->chip >= SIS_661) {
+	      inSISIDXREG(SISCR, 0x38, cr38);
+	      cr38 &= ~0x07;  /* Clear LCDA/DualEdge and YPbPr bits */
+	   } else {
+	      tvregnum = 0x38;
+	      inSISIDXREG(SISCR, tvregnum, cr38);
+	      cr38 &= ~0x3b;  /* Clear LCDA/DualEdge and YPbPr bits */
+	   }
+	}
+#endif
+#ifdef CONFIG_FB_SIS_300
+	if(ivideo->sisvga_engine == SIS_300_VGA) {
+	   tvregnum = 0x35;
+	   inSISIDXREG(SISCR, tvregnum, cr38);
+	}
+#endif
+
+	SiS_SetEnableDstn(&ivideo->SiS_Pr, FALSE);
+	SiS_SetEnableFstn(&ivideo->SiS_Pr, FALSE);
 
-	SiS_SetEnableDstn(&SiS_Pr, FALSE);
-	SiS_SetEnableFstn(&SiS_Pr, FALSE);
+	switch(ivideo->currentvbflags & VB_DISPTYPE_DISP2) {
 
-	switch (ivideo.currentvbflags & VB_DISPTYPE_DISP2) {
 	   case CRT2_TV:
-		ivideo.disp_state = DISPTYPE_TV;
-		if (ivideo.vbflags & TV_SVIDEO) {
-			cr30 = (SIS_VB_OUTPUT_SVIDEO | SIS_SIMULTANEOUS_VIEW_ENABLE);
-			ivideo.currentvbflags |= TV_SVIDEO;
-			ivideo.TV_plug = TVPLUG_SVIDEO;
-		} else if (ivideo.vbflags & TV_AVIDEO) {
-			cr30 = (SIS_VB_OUTPUT_COMPOSITE | SIS_SIMULTANEOUS_VIEW_ENABLE);
-			ivideo.currentvbflags |= TV_AVIDEO;
-			ivideo.TV_plug = TVPLUG_COMPOSITE;
-		} else if (ivideo.vbflags & TV_SCART) {
-			cr30 = (SIS_VB_OUTPUT_SCART | SIS_SIMULTANEOUS_VIEW_ENABLE);
-			ivideo.currentvbflags |= TV_SCART;
-			ivideo.TV_plug = TVPLUG_SCART;
-		}
-		cr31 |= SIS_DRIVER_MODE;
-
-		if(!(ivideo.vbflags & TV_HIVISION)) {
-	        	if (ivideo.vbflags & TV_PAL) {
-		 		cr31 |= 0x01;
-				cr35 |= 0x01;
-				ivideo.currentvbflags |= TV_PAL;
-				ivideo.TV_type = TVMODE_PAL;
-                	} else {
-		       		cr31 &= ~0x01;
-				cr35 &= ~0x01;
-				ivideo.currentvbflags |= TV_NTSC;
-				ivideo.TV_type = TVMODE_NTSC;
-			}
-		}
-		break;
+	      cr38 &= ~0xc0;   /* Clear PAL-M / PAL-N bits */
+	      if((ivideo->vbflags & TV_YPBPR) && (ivideo->vbflags & (VB_301C|VB_301LV|VB_302LV))) {
+#ifdef CONFIG_FB_SIS_315
+	         if(ivideo->chip >= SIS_661) {
+	            cr38 |= 0x04;
+	            if(ivideo->vbflags & TV_YPBPR525P)       cr35 |= 0x20;
+		    else if(ivideo->vbflags & TV_YPBPR750P)  cr35 |= 0x40;
+		    else if(ivideo->vbflags & TV_YPBPR1080I) cr35 |= 0x60;
+		    cr30 |= SIS_SIMULTANEOUS_VIEW_ENABLE;
+		    cr35 &= ~0x01;
+		    ivideo->currentvbflags |= (TV_YPBPR | (ivideo->vbflags & TV_YPBPRALL));
+	         } else if(ivideo->sisvga_engine == SIS_315_VGA) {
+	            cr30 |= (0x80 | SIS_SIMULTANEOUS_VIEW_ENABLE);
+		    cr38 |= 0x08;
+	            if(ivideo->vbflags & TV_YPBPR525P)       cr38 |= 0x10;
+		    else if(ivideo->vbflags & TV_YPBPR750P)  cr38 |= 0x20;
+		    else if(ivideo->vbflags & TV_YPBPR1080I) cr38 |= 0x30;
+		    cr31 &= ~0x01;
+		    ivideo->currentvbflags |= (TV_YPBPR | (ivideo->vbflags & TV_YPBPRALL));
+	         }
+#endif
+	      } else if((ivideo->vbflags & TV_HIVISION) && (ivideo->vbflags & (VB_301|VB_301B|VB_302B))) {
+	         if(ivideo->chip >= SIS_661) {
+	            cr38 |= 0x04;
+	            cr35 |= 0x60;
+	         } else {
+	            cr30 |= 0x80;
+	         }
+		 cr30 |= SIS_SIMULTANEOUS_VIEW_ENABLE;
+	         cr31 |= 0x01;
+	         cr35 |= 0x01;
+		 ivideo->currentvbflags |= TV_HIVISION;
+	      } else if(ivideo->vbflags & TV_SCART) {
+		 cr30 = (SIS_VB_OUTPUT_SCART | SIS_SIMULTANEOUS_VIEW_ENABLE);
+		 cr31 |= 0x01;
+		 cr35 |= 0x01;
+		 ivideo->currentvbflags |= TV_SCART;
+	      } else {
+		 if(ivideo->vbflags & TV_SVIDEO) {
+		    cr30 = (SIS_VB_OUTPUT_SVIDEO | SIS_SIMULTANEOUS_VIEW_ENABLE);
+		    ivideo->currentvbflags |= TV_SVIDEO;
+		 }
+		 if(ivideo->vbflags & TV_AVIDEO) {
+		    cr30 = (SIS_VB_OUTPUT_COMPOSITE | SIS_SIMULTANEOUS_VIEW_ENABLE);
+		    ivideo->currentvbflags |= TV_AVIDEO;
+		 }
+	      }
+	      cr31 |= SIS_DRIVER_MODE;
+
+	      if(ivideo->vbflags & (TV_AVIDEO|TV_SVIDEO)) {
+	         if(ivideo->vbflags & TV_PAL) {
+		    cr31 |= 0x01; cr35 |= 0x01;
+		    ivideo->currentvbflags |= TV_PAL;
+		    if(ivideo->vbflags & TV_PALM) {
+		       cr38 |= 0x40; cr35 |= 0x04;
+		       ivideo->currentvbflags |= TV_PALM;
+		    } else if(ivideo->vbflags & TV_PALN) {
+		       cr38 |= 0x80; cr35 |= 0x08;
+		       ivideo->currentvbflags |= TV_PALN;
+	  	    }
+                 } else {
+		    cr31 &= ~0x01; cr35 &= ~0x01;
+		    ivideo->currentvbflags |= TV_NTSC;
+		    if(ivideo->vbflags & TV_NTSCJ) {
+		       cr38 |= 0x40; cr35 |= 0x02;
+		       ivideo->currentvbflags |= TV_NTSCJ;
+	 	    }
+		 }
+	      }
+	      break;
+
 	   case CRT2_LCD:
-		ivideo.disp_state = DISPTYPE_LCD;
-		cr30  = (SIS_VB_OUTPUT_LCD | SIS_SIMULTANEOUS_VIEW_ENABLE);
-		cr31 |= SIS_DRIVER_MODE;
-		SiS_SetEnableDstn(&SiS_Pr, sisfb_dstn);
-	        SiS_SetEnableFstn(&SiS_Pr, sisfb_fstn);
-		break;
+	      cr30  = (SIS_VB_OUTPUT_LCD | SIS_SIMULTANEOUS_VIEW_ENABLE);
+	      cr31 |= SIS_DRIVER_MODE;
+	      SiS_SetEnableDstn(&ivideo->SiS_Pr, ivideo->sisfb_dstn);
+	      SiS_SetEnableFstn(&ivideo->SiS_Pr, ivideo->sisfb_fstn);
+	      break;
+
 	   case CRT2_VGA:
-		ivideo.disp_state = DISPTYPE_CRT2;
-		cr30 = (SIS_VB_OUTPUT_CRT2 | SIS_SIMULTANEOUS_VIEW_ENABLE);
-		cr31 |= SIS_DRIVER_MODE;
-		if(sisfb_nocrt2rate) {
-			cr33 |= (sisbios_mode[sisfb_mode_idx].rate_idx << 4);
-		} else {
-			cr33 |= ((sisfb_rate_idx & 0x0F) << 4);
-		}
-		break;
+	      cr30 = (SIS_VB_OUTPUT_CRT2 | SIS_SIMULTANEOUS_VIEW_ENABLE);
+	      cr31 |= SIS_DRIVER_MODE;
+	      if(ivideo->sisfb_nocrt2rate) {
+		 cr33 |= (sisbios_mode[ivideo->sisfb_mode_idx].rate_idx << 4);
+	      } else {
+		 cr33 |= ((ivideo->rate_idx & 0x0F) << 4);
+	      }
+	      break;
+
 	   default:	/* disable CRT2 */
-		cr30 = 0x00;
-		cr31 |= (SIS_DRIVER_MODE | SIS_VB_OUTPUT_DISABLE);
+	      cr30 = 0x00;
+	      cr31 |= (SIS_DRIVER_MODE | SIS_VB_OUTPUT_DISABLE);
 	}
 
-	if(ivideo.chip >= SIS_661) {
-	   cr31 &= ~0x01;
-	   /* Leave overscan bit alone */
-	   setSISIDXREG(SISCR, 0x35, ~0x10, cr35);
-	}
-	outSISIDXREG(SISCR, IND_SIS_SCRATCH_REG_CR30, cr30);
-	outSISIDXREG(SISCR, IND_SIS_SCRATCH_REG_CR31, cr31);
-	outSISIDXREG(SISCR, IND_SIS_SCRATCH_REG_CR33, cr33);
+	outSISIDXREG(SISCR, 0x30, cr30);
+	outSISIDXREG(SISCR, 0x33, cr33);
 
+	if(ivideo->chip >= SIS_661) {
 #ifdef CONFIG_FB_SIS_315
-        if(sisvga_engine == SIS_315_VGA) {
-	   /* Clear LCDA and PAL-N/M bits */
-	   andSISIDXREG(SISCR,0x38,~0x03);
-	   if(ivideo.chip < SIS_661) {
-	      andSISIDXREG(SISCR,0x38,~0xc0);
-	   }
+	   cr31 &= ~0x01;                          /* Clear PAL flag (now in CR35) */
+	   setSISIDXREG(SISCR, 0x35, ~0x10, cr35); /* Leave overscan bit alone */
+	   cr38 &= 0x07;                           /* Use only LCDA and HiVision/YPbPr bits */
+	   setSISIDXREG(SISCR, 0x38, 0xf8, cr38);
+#endif
+	} else if(ivideo->chip != SIS_300) {
+	   outSISIDXREG(SISCR, tvregnum, cr38);
 	}
+	outSISIDXREG(SISCR, 0x31, cr31);
+
+	if(ivideo->accel) sisfb_syncaccel(ivideo);
+
+	ivideo->SiS_Pr.SiS_UseOEM = ivideo->sisfb_useoem;
+}
+
+/* Fix SR11 for 661 and later */
+#ifdef CONFIG_FB_SIS_315
+static void
+sisfb_fixup_SR11(struct sis_video_info *ivideo)
+{
+    u8  tmpreg;
+
+    if(ivideo->chip >= SIS_661) {
+       inSISIDXREG(SISSR,0x11,tmpreg);
+       if(tmpreg & 0x20) {
+          inSISIDXREG(SISSR,0x3e,tmpreg);
+	  tmpreg = (tmpreg + 1) & 0xff;
+	  outSISIDXREG(SISSR,0x3e,tmpreg);
+	  inSISIDXREG(SISSR,0x11,tmpreg);
+       }
+       if(tmpreg & 0xf0) {
+          andSISIDXREG(SISSR,0x11,0x0f);
+       }
+    }
+}
 #endif
 
-	if(ivideo.accel) sisfb_syncaccel();
+static void sisfb_set_TVxposoffset(struct sis_video_info *ivideo, int val)
+{
+   if(val > 32) val = 32;
+   if(val < -32) val = -32;
+   ivideo->tvxpos = val;
+
+   if(ivideo->sisfblocked) return;
+   if(!ivideo->modechanged) return;
+
+   if(ivideo->currentvbflags & CRT2_TV) {
+
+      if(ivideo->vbflags & VB_CHRONTEL) {
+
+	 int x = ivideo->tvx;
+
+	 switch(ivideo->chronteltype) {
+	 case 1:
+	     x += val;
+	     if(x < 0) x = 0;
+	     outSISIDXREG(SISSR,0x05,0x86);
+	     SiS_SetCH700x(&ivideo->SiS_Pr, (((x & 0xff) << 8) | 0x0a));
+	     SiS_SetCH70xxANDOR(&ivideo->SiS_Pr, (((x & 0x0100) << 1) | 0x08),0xFD);
+	     break;
+	 case 2:
+	     /* Not supported by hardware */
+	     break;
+	 }
+
+      } else if(ivideo->vbflags & VB_SISBRIDGE) {
+
+	 u8 p2_1f,p2_20,p2_2b,p2_42,p2_43;
+	 unsigned short temp;
 
-	SiS_Pr.SiS_UseOEM = sisfb_useoem;
+	 p2_1f = ivideo->p2_1f;
+	 p2_20 = ivideo->p2_20;
+	 p2_2b = ivideo->p2_2b;
+	 p2_42 = ivideo->p2_42;
+	 p2_43 = ivideo->p2_43;
+
+	 temp = p2_1f | ((p2_20 & 0xf0) << 4);
+	 temp += (val * 2);
+	 p2_1f = temp & 0xff;
+	 p2_20 = (temp & 0xf00) >> 4;
+	 p2_2b = ((p2_2b & 0x0f) + (val * 2)) & 0x0f;
+	 temp = p2_43 | ((p2_42 & 0xf0) << 4);
+	 temp += (val * 2);
+	 p2_43 = temp & 0xff;
+	 p2_42 = (temp & 0xf00) >> 4;
+	 outSISIDXREG(SISPART2,0x1f,p2_1f);
+	 setSISIDXREG(SISPART2,0x20,0x0F,p2_20);
+	 setSISIDXREG(SISPART2,0x2b,0xF0,p2_2b);
+	 setSISIDXREG(SISPART2,0x42,0x0F,p2_42);
+	 outSISIDXREG(SISPART2,0x43,p2_43);
+      }
+   }
 }
 
-static void sisfb_post_setmode(void)
+static void sisfb_set_TVyposoffset(struct sis_video_info *ivideo, int val)
+{
+   if(val > 32) val = 32;
+   if(val < -32) val = -32;
+   ivideo->tvypos = val;
+
+   if(ivideo->sisfblocked) return;
+   if(!ivideo->modechanged) return;
+
+   if(ivideo->currentvbflags & CRT2_TV) {
+
+      if(ivideo->vbflags & VB_CHRONTEL) {
+
+	 int y = ivideo->tvy;
+
+	 switch(ivideo->chronteltype) {
+	 case 1:
+	    y -= val;
+	    if(y < 0) y = 0;
+	    outSISIDXREG(SISSR,0x05,0x86);
+	    SiS_SetCH700x(&ivideo->SiS_Pr, (((y & 0xff) << 8) | 0x0b));
+	    SiS_SetCH70xxANDOR(&ivideo->SiS_Pr, ((y & 0x0100) | 0x08),0xFE);
+	    break;
+	 case 2:
+	    /* Not supported by hardware */
+	    break;
+	 }
+
+      } else if(ivideo->vbflags & VB_SISBRIDGE) {
+
+	 char p2_01, p2_02;
+	 val /= 2;
+	 p2_01 = ivideo->p2_01;
+	 p2_02 = ivideo->p2_02;
+
+	 p2_01 += val;
+	 p2_02 += val;
+	 while((p2_01 <= 0) || (p2_02 <= 0)) {
+	    p2_01 += 2;
+	    p2_02 += 2;
+	 }
+	 outSISIDXREG(SISPART2,0x01,p2_01);
+	 outSISIDXREG(SISPART2,0x02,p2_02);
+      }
+   }
+}
+
+static void
+sisfb_post_setmode(struct sis_video_info *ivideo)
 {
-	u8 reg;
 	BOOLEAN crt1isoff = FALSE;
+	BOOLEAN doit = TRUE;
+#if defined(CONFIG_FB_SIS_300) || defined(CONFIG_FB_SIS_315)
+	u8 reg;
+#endif
 #ifdef CONFIG_FB_SIS_315
 	u8 reg1;
 #endif
-#ifdef CONFIG_FB_SIS_300
-	BOOLEAN doit = TRUE;
-#endif
-	/* We can't switch off CRT1 if bridge is in slave mode */
-	if(ivideo.vbflags & VB_VIDEOBRIDGE) {
-#ifdef CONFIG_FB_SIS_300
-		if(sisvga_engine == SIS_300_VGA) {
-			inSISIDXREG(SISPART1, 0x00, reg);
-			if((reg & 0xa0) == 0x20) {
-				doit = FALSE;
-			}
-		}
+
+	outSISIDXREG(SISSR,0x05,0x86);
+
+#ifdef CONFIG_FB_SIS_315
+	sisfb_fixup_SR11(ivideo);
 #endif
-	} else sisfb_crt1off = 0;
 
-	if(sisvga_engine == SIS_300_VGA) {
+	/* Now we actually HAVE changed the display mode */
+        ivideo->modechanged = 1;
+
+	/* We can't switch off CRT1 if bridge is in slave mode */
+	if(ivideo->vbflags & VB_VIDEOBRIDGE) {
+		if(sisfb_bridgeisslave(ivideo)) doit = FALSE;
+	} else ivideo->sisfb_crt1off = 0;
 
 #ifdef CONFIG_FB_SIS_300
-	   if((sisfb_crt1off) && (doit)) {
+	if(ivideo->sisvga_engine == SIS_300_VGA) {
+	   if((ivideo->sisfb_crt1off) && (doit)) {
 	        crt1isoff = TRUE;
 		reg = 0x00;
 	   } else {
@@ -3803,12 +3670,11 @@
 		reg = 0x80;
 	   }
 	   setSISIDXREG(SISCR, 0x17, 0x7f, reg);
+	}
 #endif
-
-	} else {
-
 #ifdef CONFIG_FB_SIS_315
-	   if(sisfb_crt1off) {
+	if(ivideo->sisvga_engine == SIS_315_VGA) {
+	   if((ivideo->sisfb_crt1off) && (doit)) {
 	        crt1isoff = TRUE;
 		reg  = 0x40;
 		reg1 = 0xc0;
@@ -3818,66 +3684,89 @@
 		reg1 = 0x00;
 
 	   }
-	   setSISIDXREG(SISCR, SiS_Pr.SiS_MyCR63, ~0x40, reg);
+	   setSISIDXREG(SISCR, ivideo->SiS_Pr.SiS_MyCR63, ~0x40, reg);
 	   setSISIDXREG(SISSR, 0x1f, ~0xc0, reg1);
-#endif
-
 	}
+#endif
 
 	if(crt1isoff) {
-	   ivideo.currentvbflags &= ~VB_DISPTYPE_CRT1;
-	   ivideo.currentvbflags |= VB_SINGLE_MODE;
-	   ivideo.disp_state |= DISPMODE_SINGLE;
+	   ivideo->currentvbflags &= ~VB_DISPTYPE_CRT1;
+	   ivideo->currentvbflags |= VB_SINGLE_MODE;
 	} else {
-	   ivideo.currentvbflags |= VB_DISPTYPE_CRT1;
-	   ivideo.disp_state |= DISPTYPE_CRT1;
-	   if(ivideo.currentvbflags & VB_DISPTYPE_CRT2) {
-	  	ivideo.currentvbflags |= VB_MIRROR_MODE;
-		ivideo.disp_state |= DISPMODE_MIRROR;
+	   ivideo->currentvbflags |= VB_DISPTYPE_CRT1;
+	   if(ivideo->currentvbflags & VB_DISPTYPE_CRT2) {
+	  	ivideo->currentvbflags |= VB_MIRROR_MODE;
 	   } else {
-	 	ivideo.currentvbflags |= VB_SINGLE_MODE;
-		ivideo.disp_state |= DISPMODE_SINGLE;
+	 	ivideo->currentvbflags |= VB_SINGLE_MODE;
 	   }
 	}
 
         andSISIDXREG(SISSR, IND_SIS_RAMDAC_CONTROL, ~0x04);
 
-	if((ivideo.currentvbflags & CRT2_TV) && (ivideo.vbflags & VB_301)) {  /* Set filter for SiS301 */
+	if(ivideo->currentvbflags & CRT2_TV) {
+	   if(ivideo->vbflags & VB_SISBRIDGE) {
+	      inSISIDXREG(SISPART2,0x1f,ivideo->p2_1f);
+	      inSISIDXREG(SISPART2,0x20,ivideo->p2_20);
+	      inSISIDXREG(SISPART2,0x2b,ivideo->p2_2b);
+	      inSISIDXREG(SISPART2,0x42,ivideo->p2_42);
+	      inSISIDXREG(SISPART2,0x43,ivideo->p2_43);
+	      inSISIDXREG(SISPART2,0x01,ivideo->p2_01);
+	      inSISIDXREG(SISPART2,0x02,ivideo->p2_02);
+	   } else if(ivideo->vbflags & VB_CHRONTEL) {
+	      if(ivideo->chronteltype == 1) {
+	         ivideo->tvx = SiS_GetCH700x(&ivideo->SiS_Pr, 0x0a);
+	         ivideo->tvx |= (((SiS_GetCH700x(&ivideo->SiS_Pr, 0x08) & 0x02) >> 1) << 8);
+	         ivideo->tvy = SiS_GetCH700x(&ivideo->SiS_Pr, 0x0b);
+	         ivideo->tvy |= ((SiS_GetCH700x(&ivideo->SiS_Pr, 0x08) & 0x01) << 8);
+ 	      }
+	   }
+	}
+
+	if(ivideo->tvxpos) {
+   	   sisfb_set_TVxposoffset(ivideo, ivideo->tvxpos);
+	}
+	if(ivideo->tvypos) {
+   	   sisfb_set_TVyposoffset(ivideo, ivideo->tvypos);
+	}
+
+	if((ivideo->currentvbflags & CRT2_TV) && (ivideo->vbflags & VB_301)) {  /* Set filter for SiS301 */
+
+	   	unsigned char filter_tb = 0;
 
-		switch (ivideo.video_width) {
+		switch (ivideo->video_width) {
 		   case 320:
-			filter_tb = (ivideo.vbflags & TV_NTSC) ? 4 : 12;
+			filter_tb = (ivideo->vbflags & TV_NTSC) ? 4 : 12;
 			break;
 		   case 640:
-			filter_tb = (ivideo.vbflags & TV_NTSC) ? 5 : 13;
+			filter_tb = (ivideo->vbflags & TV_NTSC) ? 5 : 13;
 			break;
 		   case 720:
-			filter_tb = (ivideo.vbflags & TV_NTSC) ? 6 : 14;
+			filter_tb = (ivideo->vbflags & TV_NTSC) ? 6 : 14;
 			break;
 		   case 400:
 		   case 800:
-			filter_tb = (ivideo.vbflags & TV_NTSC) ? 7 : 15;
+			filter_tb = (ivideo->vbflags & TV_NTSC) ? 7 : 15;
 			break;
 		   default:
-			filter = -1;
+			ivideo->sisfb_filter = -1;
 			break;
 		}
 
-		orSISIDXREG(SISPART1, sisfb_CRT2_write_enable, 0x01);
+		orSISIDXREG(SISPART1, ivideo->CRT2_write_enable, 0x01);
 
-		if(ivideo.vbflags & TV_NTSC) {
+		if(ivideo->vbflags & TV_NTSC) {
 
 		        andSISIDXREG(SISPART2, 0x3a, 0x1f);
 
-			if (ivideo.vbflags & TV_SVIDEO) {
+			if (ivideo->vbflags & TV_SVIDEO) {
 
 			        andSISIDXREG(SISPART2, 0x30, 0xdf);
 
-			} else if (ivideo.vbflags & TV_AVIDEO) {
+			} else if (ivideo->vbflags & TV_AVIDEO) {
 
 			        orSISIDXREG(SISPART2, 0x30, 0x20);
 
-				switch (ivideo.video_width) {
+				switch (ivideo->video_width) {
 				case 640:
 				        outSISIDXREG(SISPART2, 0x35, 0xEB);
 					outSISIDXREG(SISPART2, 0x36, 0x04);
@@ -3900,19 +3789,19 @@
 				}
 			}
 
-		} else if(ivideo.vbflags & TV_PAL) {
+		} else if(ivideo->vbflags & TV_PAL) {
 
 			andSISIDXREG(SISPART2, 0x3A, 0x1F);
 
-			if (ivideo.vbflags & TV_SVIDEO) {
+			if (ivideo->vbflags & TV_SVIDEO) {
 
 			        andSISIDXREG(SISPART2, 0x30, 0xDF);
 
-			} else if (ivideo.vbflags & TV_AVIDEO) {
+			} else if (ivideo->vbflags & TV_AVIDEO) {
 
 			        orSISIDXREG(SISPART2, 0x30, 0x20);
 
-				switch (ivideo.video_width) {
+				switch (ivideo->video_width) {
 				case 640:
 					outSISIDXREG(SISPART2, 0x35, 0xF1);
 					outSISIDXREG(SISPART2, 0x36, 0xF7);
@@ -3936,129 +3825,137 @@
 			}
 		}
 
-		if ((filter >= 0) && (filter <= 7)) {
-			DPRINTK("FilterTable[%d]-%d: %02x %02x %02x %02x\n", filter_tb, filter,
-				sis_TV_filter[filter_tb].filter[filter][0],
-				sis_TV_filter[filter_tb].filter[filter][1],
-				sis_TV_filter[filter_tb].filter[filter][2],
-				sis_TV_filter[filter_tb].filter[filter][3]
-			);
-			outSISIDXREG(SISPART2, 0x35, (sis_TV_filter[filter_tb].filter[filter][0]));
-			outSISIDXREG(SISPART2, 0x36, (sis_TV_filter[filter_tb].filter[filter][1]));
-			outSISIDXREG(SISPART2, 0x37, (sis_TV_filter[filter_tb].filter[filter][2]));
-			outSISIDXREG(SISPART2, 0x38, (sis_TV_filter[filter_tb].filter[filter][3]));
+		if((ivideo->sisfb_filter >= 0) && (ivideo->sisfb_filter <= 7)) {
+		   outSISIDXREG(SISPART2,0x35,(sis_TV_filter[filter_tb].filter[ivideo->sisfb_filter][0]));
+		   outSISIDXREG(SISPART2,0x36,(sis_TV_filter[filter_tb].filter[ivideo->sisfb_filter][1]));
+		   outSISIDXREG(SISPART2,0x37,(sis_TV_filter[filter_tb].filter[ivideo->sisfb_filter][2]));
+		   outSISIDXREG(SISPART2,0x38,(sis_TV_filter[filter_tb].filter[ivideo->sisfb_filter][3]));
 		}
 	  
 	}
-
 }
 
 #ifndef MODULE
-int sisfb_setup(char *options)
+int __init sisfb_setup(char *options)
 {
 	char *this_opt;
 	
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
-	sisfb_fontname[0] = '\0';
-#endif
-
-	ivideo.refresh_rate = 0;
-	SiS_Pr.SiS_CustomT = CUT_NONE;
-	SiS_Pr.UsePanelScaler = -1;
-	SiS_Pr.LVDSHL = -1;
+	sisfb_setdefaultparms();
 
         printk(KERN_DEBUG "sisfb: Options %s\n", options);
 
-	if (!options || !*options)
+	if(!options || !(*options)) {
 		return 0;
+	}
 
 	while((this_opt = strsep(&options, ",")) != NULL) {
 
-		if (!*this_opt)	continue;
+		if(!(*this_opt)) continue;
 
-		if (!strnicmp(this_opt, "mode:", 5)) {
+		if(!strnicmp(this_opt, "off", 3)) {
+			sisfb_off = 1;
+		} else if(!strnicmp(this_opt, "forcecrt2type:", 14)) {
+			/* Need to check crt2 type first for fstn/dstn */
+			sisfb_search_crt2type(this_opt + 14);
+		} else if(!strnicmp(this_opt, "tvmode:",7)) {
+		        sisfb_search_tvstd(this_opt + 7);
+                } else if(!strnicmp(this_opt, "tvstandard:",11)) {
+			sisfb_search_tvstd(this_opt + 7);
+		} else if(!strnicmp(this_opt, "mode:", 5)) {
 			sisfb_search_mode(this_opt + 5, FALSE);
-		} else if (!strnicmp(this_opt, "vesa:", 5)) {
+		} else if(!strnicmp(this_opt, "vesa:", 5)) {
 			sisfb_search_vesamode(simple_strtoul(this_opt + 5, NULL, 0), FALSE);
 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
-		} else if (!strnicmp(this_opt, "inverse", 7)) {
+		} else if(!strnicmp(this_opt, "inverse", 7)) {
 			sisfb_inverse = 1;
 			/* fb_invert_cmaps(); */
-		} else if (!strnicmp(this_opt, "font:", 5)) {
-			strncpy(sisfb_fontname, this_opt + 5, sizeof(sisfb_fontname) - 1);
-			sisfb_fontname[sizeof(sisfb_fontname) - 1] = '\0';
-#endif
-		} else if (!strnicmp(this_opt, "vrate:", 6)) {
-			ivideo.refresh_rate = simple_strtoul(this_opt + 6, NULL, 0);
-			sisfb_parm_rate = ivideo.refresh_rate;
-		} else if (!strnicmp(this_opt, "rate:", 5)) {
-			ivideo.refresh_rate = simple_strtoul(this_opt + 5, NULL, 0);
-			sisfb_parm_rate = ivideo.refresh_rate;
-		} else if (!strnicmp(this_opt, "off", 3)) {
-			sisfb_off = 1;
-		} else if (!strnicmp(this_opt, "crt1off", 7)) {
-			sisfb_crt1off = 1;
-		} else if (!strnicmp(this_opt, "filter:", 7)) {
-			filter = (int)simple_strtoul(this_opt + 7, NULL, 0);
-		} else if (!strnicmp(this_opt, "forcecrt2type:", 14)) {
-			sisfb_search_crt2type(this_opt + 14);
-		} else if (!strnicmp(this_opt, "forcecrt1:", 10)) {
+		} else if(!strnicmp(this_opt, "font:", 5)) {
+		        if(strlen(this_opt + 5) < 40) {
+			   strncpy(sisfb_fontname, this_opt + 5, sizeof(sisfb_fontname) - 1);
+			   sisfb_fontname[sizeof(sisfb_fontname) - 1] = '\0';
+			}
+#endif
+		} else if(!strnicmp(this_opt, "rate:", 5)) {
+			sisfb_parm_rate = simple_strtoul(this_opt + 5, NULL, 0);
+		} else if(!strnicmp(this_opt, "filter:", 7)) {
+			sisfb_filter = (int)simple_strtoul(this_opt + 7, NULL, 0);
+		} else if(!strnicmp(this_opt, "forcecrt1:", 10)) {
 			sisfb_forcecrt1 = (int)simple_strtoul(this_opt + 10, NULL, 0);
-                } else if (!strnicmp(this_opt, "tvmode:",7)) {
-		        sisfb_search_tvstd(this_opt + 7);
-                } else if (!strnicmp(this_opt, "tvstandard:",11)) {
-			sisfb_search_tvstd(this_opt + 7);
-                } else if (!strnicmp(this_opt, "mem:",4)) {
-		        sisfb_mem = simple_strtoul(this_opt + 4, NULL, 0);
-		} else if (!strnicmp(this_opt, "queuemode:", 10)) {
-			sisfb_search_queuemode(this_opt + 10);
-		} else if (!strnicmp(this_opt, "pdc:", 4)) {
+                } else if(!strnicmp(this_opt, "mem:",4)) {
+		        sisfb_parm_mem = simple_strtoul(this_opt + 4, NULL, 0);
+		} else if(!strnicmp(this_opt, "pdc:", 4)) {
 		        sisfb_pdc = simple_strtoul(this_opt + 4, NULL, 0);
-		} else if (!strnicmp(this_opt, "noaccel", 7)) {
+		} else if(!strnicmp(this_opt, "pdc1:", 5)) {
+		        sisfb_pdca = simple_strtoul(this_opt + 5, NULL, 0);
+		} else if(!strnicmp(this_opt, "noaccel", 7)) {
 			sisfb_accel = 0;
-		} else if (!strnicmp(this_opt, "noypan", 6)) {
+		} else if(!strnicmp(this_opt, "accel", 5)) {
+			sisfb_accel = -1;
+		} else if(!strnicmp(this_opt, "noypan", 6)) {
 		        sisfb_ypan = 0;
-		} else if (!strnicmp(this_opt, "nomax", 5)) {
+		} else if(!strnicmp(this_opt, "ypan", 4)) {
+		        sisfb_ypan = -1;
+		} else if(!strnicmp(this_opt, "nomax", 5)) {
 		        sisfb_max = 0;
-		} else if (!strnicmp(this_opt, "userom:", 7)) {
+		} else if(!strnicmp(this_opt, "max", 3)) {
+		        sisfb_max = -1;
+		} else if(!strnicmp(this_opt, "userom:", 7)) {
 			sisfb_userom = (int)simple_strtoul(this_opt + 7, NULL, 0);
-		} else if (!strnicmp(this_opt, "useoem:", 7)) {
+		} else if(!strnicmp(this_opt, "useoem:", 7)) {
 			sisfb_useoem = (int)simple_strtoul(this_opt + 7, NULL, 0);
-		} else if (!strnicmp(this_opt, "nocrt2rate", 10)) {
+		} else if(!strnicmp(this_opt, "nocrt2rate", 10)) {
 			sisfb_nocrt2rate = 1;
-	 	} else if (!strnicmp(this_opt, "scalelcd:", 9)) {
+	 	} else if(!strnicmp(this_opt, "scalelcd:", 9)) {
 		        unsigned long temp = 2;
 		        temp = simple_strtoul(this_opt + 9, NULL, 0);
 		        if((temp == 0) || (temp == 1)) {
-			   SiS_Pr.UsePanelScaler = temp ^ 1;
+			   sisfb_scalelcd = temp ^ 1;
+		        }
+		} else if(!strnicmp(this_opt, "tvxposoffset:", 13)) {
+		        int temp = 0;
+		        temp = (int)simple_strtol(this_opt + 13, NULL, 0);
+		        if((temp >= -32) && (temp <= 32)) {
+			   sisfb_tvxposoffset = temp;
 		        }
-		} else if (!strnicmp(this_opt, "specialtiming:", 14)) {
+		} else if(!strnicmp(this_opt, "tvyposoffset:", 13)) {
+		        int temp = 0;
+		        temp = (int)simple_strtol(this_opt + 13, NULL, 0);
+		        if((temp >= -32) && (temp <= 32)) {
+			   sisfb_tvyposoffset = temp;
+		        }
+		} else if(!strnicmp(this_opt, "specialtiming:", 14)) {
 			sisfb_search_specialtiming(this_opt + 14);
-		} else if (!strnicmp(this_opt, "lvdshl:", 7)) {
-		        unsigned long temp = 4;
+		} else if(!strnicmp(this_opt, "lvdshl:", 7)) {
+		        int temp = 4;
 		        temp = simple_strtoul(this_opt + 7, NULL, 0);
 		        if((temp >= 0) && (temp <= 3)) {
-			   SiS_Pr.LVDSHL = temp;
+			   sisfb_lvdshl = temp;
 		        }
 		} else if(this_opt[0] >= '0' && this_opt[0] <= '9') {
 			sisfb_search_mode(this_opt, TRUE);
+#if !defined(__i386__) && !defined(__x86_64__)
+	        } else if(!strnicmp(this_opt, "resetcard", 9)) {
+		  	sisfb_resetcard = 1;
+	        } else if(!strnicmp(this_opt, "videoram:", 9)) {
+		  	sisfb_videoram = simple_strtoul(this_opt + 9, NULL, 0);
+#endif
 		} else {
 			printk(KERN_INFO "sisfb: Invalid option %s\n", this_opt);
 		}
 
-		/* TW: Acceleration only with MMIO mode */
-		if((sisfb_queuemode != -1) && (sisfb_queuemode != MMIO_CMD)) {
-			sisfb_accel = 0;
-		}
-
 	}
+
+
+
 	return 0;
 }
 #endif
 
-static char *sis_find_rom(void)
+static char * __devinit sis_find_rom(struct pci_dev *pdev)
 {
-#if defined(__i386__)
+	struct sis_video_info *ivideo = pci_get_drvdata(pdev);
+
+#if defined(__i386__) || defined(__x86_64__)
         u32  segstart;
         unsigned char *rom_base, *rom;
         int  romptr;
@@ -4066,292 +3963,972 @@
 
         for(segstart=0x000c0000; segstart<0x000f0000; segstart+=0x00001000) {
 
-                rom_base = (char *)ioremap(segstart, 0x10000);
-		if(!rom_base) continue;
+            rom_base = (unsigned char *)ioremap(segstart, 0x10000);
+	    if(!rom_base) continue;
 
-                if((*rom_base != 0x55) || (*(rom_base + 1) != 0xaa)) {
-                   iounmap(rom_base);
-                   continue;
-                }
+	    if((readb(rom_base) != 0x55) || (readb(rom_base + 1) != 0xaa)) {
+	       iounmap(rom_base);
+               continue;
+	    }
 
-		romptr = (unsigned short)(*(rom_base + 0x18) | (*(rom_base + 0x19) << 8));
-		if(romptr > (0x10000 - 8)) {
-		   iounmap(rom_base);
-		   continue;
-		}
+	    romptr = (unsigned short)(readb(rom_base + 0x18) | (readb(rom_base + 0x19) << 8));
+	    if(romptr > (0x10000 - 8)) {
+	       iounmap(rom_base);
+	       continue;
+	    }
 
-		rom = rom_base + romptr;
+	    rom = rom_base + romptr;
 
-		if((*rom != 'P') || (*(rom + 1) != 'C') || (*(rom + 2) != 'I') || (*(rom + 3) != 'R')) {
-		   iounmap(rom_base);
-		   continue;
-		}
+	    if((readb(rom)     != 'P') || (readb(rom + 1) != 'C') ||
+	       (readb(rom + 2) != 'I') || (readb(rom + 3) != 'R')) {
+	       iounmap(rom_base);
+	       continue;
+	    }
 
-		pciid = (*(rom + 4)) | ((*(rom + 5)) << 8);
-		if(pciid != 0x1039) {
-		   iounmap(rom_base);
-		   continue;
-		}
+	    pciid = readb(rom + 4) | (readb(rom + 5) << 8);
+	    if(pciid != 0x1039) {
+	       iounmap(rom_base);
+	       continue;
+	    }
 
-		pciid = (*(rom + 6)) | ((*(rom + 7)) << 8);
-		if(pciid == ivideo.chip_id) return rom_base;
+	    pciid = readb(rom + 6) | (readb(rom + 7) << 8);
+	    if(pciid == ivideo->chip_id) return rom_base;
 
-		iounmap(rom_base);
+	    iounmap(rom_base);
         }
+#else
+	unsigned char *rom_base, *rom, *myrombase = NULL;
+        int  romptr;
+	unsigned short pciid;
+	u32 backup;
+
+	pci_read_config_dword(pdev, PCI_ROM_ADDRESS, &backup);
+	pci_write_config_dword(pdev, PCI_ROM_ADDRESS,
+			(ivideo->video_base & PCI_ROM_ADDRESS_MASK) | PCI_ROM_ADDRESS_ENABLE);
+
+	rom_base = ioremap(ivideo->video_base, 65536);
+	if(rom_base) {
+	   if((readb(rom_base) == 0x55) && (readb(rom_base + 1) == 0xaa)) {
+	      romptr = (u16)(readb(rom_base + 0x18) | (readb(rom_base + 0x19) << 8));
+	      if(romptr <= (0x10000 - 8)) {
+	         rom = rom_base + romptr;
+		 if((readb(rom)     == 'P') && (readb(rom + 1) == 'C') &&
+		    (readb(rom + 2) == 'I') && (readb(rom + 3) == 'R')) {
+		    pciid = readb(rom + 4) | (readb(rom + 5) << 8);
+		    if(pciid == 0x1039) {
+		       pciid = readb(rom + 6) | (readb(rom + 7) << 8);
+		       if(pciid == ivideo->chip_id) {
+		          if((myrombase = vmalloc(65536))) {
+			     memcpy_fromio(myrombase, rom_base, 65536);
+			  }
+		       }
+		    }
+		 }
+	      }
+	   }
+	   iounmap(rom_base);
+	}
+        pci_write_config_dword(pdev, PCI_ROM_ADDRESS, backup);
+	if(myrombase) return myrombase;
 #endif
         return NULL;
 }
 
+#ifdef CONFIG_FB_SIS_300
+static int __devinit
+sisfb_chkbuswidth300(struct pci_dev *pdev, ULONG FBAddress)
+{
+	struct sis_video_info *ivideo = pci_get_drvdata(pdev);
+	int i, j;
+	USHORT temp;
+	UCHAR reg;
+
+	andSISIDXREG(SISSR,0x15,0xFB);
+	orSISIDXREG(SISSR,0x15,0x04);
+   	outSISIDXREG(SISSR,0x13,0x00);
+   	outSISIDXREG(SISSR,0x14,0xBF);
+
+	for(i=0; i<2; i++) {
+	   temp = 0x1234;
+	   for(j=0; j<4; j++) {
+	      writew(temp, FBAddress);
+	      if(readw(FBAddress) == temp) break;
+	      orSISIDXREG(SISSR,0x3c,0x01);
+	      inSISIDXREG(SISSR,0x05,reg);
+	      inSISIDXREG(SISSR,0x05,reg);
+	      andSISIDXREG(SISSR,0x3c,0xfe);
+	      inSISIDXREG(SISSR,0x05,reg);
+	      inSISIDXREG(SISSR,0x05,reg);
+	      temp++;
+	   }
+	}
+
+	writel(0x01234567L, FBAddress);
+	writel(0x456789ABL, (FBAddress+4));
+	writel(0x89ABCDEFL, (FBAddress+8));
+	writel(0xCDEF0123L, (FBAddress+12));
+	inSISIDXREG(SISSR,0x3b,reg);
+	if(reg & 0x01) {
+	   if(readl((FBAddress+12)) == 0xCDEF0123L) return(4);  /* Channel A 128bit */
+	}
+	if(readl((FBAddress+4)) == 0x456789ABL)     return(2);  /* Channel B 64bit */
+	return(1);						/* 32bit */
+}
+
+static void __devinit
+sisfb_setramsize300(struct pci_dev *pdev)
+{
+	struct  sis_video_info *ivideo = pci_get_drvdata(pdev);
+  	ULONG 	FBAddr = (ULONG)ivideo->sishw_ext.pjVideoMemoryAddress, Addr;
+	USHORT 	SR13, SR14=0, buswidth, Done, data, TotalCapacity, PhysicalAdrOtherPage=0;
+	int     PseudoRankCapacity, PseudoTotalCapacity, PseudoAdrPinCount;
+   	int     RankCapacity, AdrPinCount, BankNumHigh, BankNumMid, MB2Bank;
+   	int     PageCapacity, PhysicalAdrHigh, PhysicalAdrHalfPage, i, j, k;
+	const 	USHORT SiS_DRAMType[17][5] = {
+			{0x0C,0x0A,0x02,0x40,0x39},
+			{0x0D,0x0A,0x01,0x40,0x48},
+			{0x0C,0x09,0x02,0x20,0x35},
+			{0x0D,0x09,0x01,0x20,0x44},
+			{0x0C,0x08,0x02,0x10,0x31},
+			{0x0D,0x08,0x01,0x10,0x40},
+			{0x0C,0x0A,0x01,0x20,0x34},
+			{0x0C,0x09,0x01,0x08,0x32},
+			{0x0B,0x08,0x02,0x08,0x21},
+			{0x0C,0x08,0x01,0x08,0x30},
+			{0x0A,0x08,0x02,0x04,0x11},
+			{0x0B,0x0A,0x01,0x10,0x28},
+			{0x09,0x08,0x02,0x02,0x01},
+			{0x0B,0x09,0x01,0x08,0x24},
+			{0x0B,0x08,0x01,0x04,0x20},
+			{0x0A,0x08,0x01,0x02,0x10},
+			{0x09,0x08,0x01,0x01,0x00}
+		};
+
+        buswidth = sisfb_chkbuswidth300(pdev, FBAddr);
+
+   	MB2Bank = 16;
+   	Done = 0;
+   	for(i = 6; i >= 0; i--) {
+      	   if(Done) break;
+      	   PseudoRankCapacity = 1 << i;
+      	   for(j = 4; j >= 1; j--) {
+              if(Done) break;
+              PseudoTotalCapacity = PseudoRankCapacity * j;
+              PseudoAdrPinCount = 15 - j;
+              if(PseudoTotalCapacity <= 64) {
+                 for(k = 0; k <= 16; k++) {
+                    if(Done) break;
+                    RankCapacity = buswidth * SiS_DRAMType[k][3];
+                    AdrPinCount = SiS_DRAMType[k][2] + SiS_DRAMType[k][0];
+                    if(RankCapacity == PseudoRankCapacity)
+                       if(AdrPinCount <= PseudoAdrPinCount) {
+                          if(j == 3) {             /* Rank No */
+                             BankNumHigh = RankCapacity * MB2Bank * 3 - 1;
+                             BankNumMid  = RankCapacity * MB2Bank * 1 - 1;
+                          } else {
+                             BankNumHigh = RankCapacity * MB2Bank * j - 1;
+                             BankNumMid  = RankCapacity * MB2Bank * j / 2 - 1;
+                          }
+                          PageCapacity = (1 << SiS_DRAMType[k][1]) * buswidth * 4;
+                          PhysicalAdrHigh = BankNumHigh;
+                          PhysicalAdrHalfPage = (PageCapacity / 2 + PhysicalAdrHigh) % PageCapacity;
+                          PhysicalAdrOtherPage = PageCapacity * SiS_DRAMType[k][2] + PhysicalAdrHigh;
+                          /* Write data */
+                          andSISIDXREG(SISSR,0x15,0xFB); /* Test */
+                          orSISIDXREG(SISSR,0x15,0x04);  /* Test */
+                          TotalCapacity = SiS_DRAMType[k][3] * buswidth;
+                          SR13 = SiS_DRAMType[k][4];
+                          if(buswidth == 4) SR14 = (TotalCapacity - 1) | 0x80;
+                          if(buswidth == 2) SR14 = (TotalCapacity - 1) | 0x40;
+                          if(buswidth == 1) SR14 = (TotalCapacity - 1) | 0x00;
+                          outSISIDXREG(SISSR,0x13,SR13);
+                          outSISIDXREG(SISSR,0x14,SR14);
+                          Addr = FBAddr + BankNumHigh * 64 * 1024 + PhysicalAdrHigh;
+                          /* *((USHORT *)(Addr)) = (USHORT)PhysicalAdrHigh; */
+			  writew(((USHORT)PhysicalAdrHigh), Addr);
+                          Addr = FBAddr + BankNumMid * 64 * 1024 + PhysicalAdrHigh;
+                          /* *((USHORT *)(Addr)) = (USHORT)BankNumMid; */
+			  writew(((USHORT)BankNumMid), Addr);
+                          Addr = FBAddr + BankNumHigh * 64 * 1024 + PhysicalAdrHalfPage;
+                          /* *((USHORT *)(Addr)) = (USHORT)PhysicalAdrHalfPage; */
+			  writew(((USHORT)PhysicalAdrHalfPage), Addr);
+                          Addr = FBAddr + BankNumHigh * 64 * 1024 + PhysicalAdrOtherPage;
+                          /* *((USHORT *)(Addr)) = PhysicalAdrOtherPage; */
+			  writew(((USHORT)PhysicalAdrOtherPage), Addr);
+                          /* Read data */
+                          Addr = FBAddr + BankNumHigh * 64 * 1024 + PhysicalAdrHigh;
+                          data = readw(Addr); /* *((USHORT *)(Addr)); */
+                          if(data == PhysicalAdrHigh) Done = 1;
+                       }  /* if */
+                 }  /* for k */
+              }  /* if */
+      	   }  /* for j */
+   	}  /* for i */
+}
+
+static void __devinit sisfb_post_sis300(struct pci_dev *pdev)
+{
+	struct sis_video_info *ivideo = pci_get_drvdata(pdev);
+	u8  reg, v1, v2, v3, v4, v5, v6, v7, v8;
+	u16 index, rindex, memtype = 0;
+
+	outSISIDXREG(SISSR,0x05,0x86);
+
+	if(ivideo->sishw_ext.UseROM) {
+	   if(ivideo->sishw_ext.pjVirtualRomBase[0x52] & 0x80) {
+	      memtype = ivideo->sishw_ext.pjVirtualRomBase[0x52];
+ 	   } else {
+	      inSISIDXREG(SISSR,0x3a,memtype);
+	   }
+	   memtype &= 0x07;
+	}
 
+	if(ivideo->revision_id <= 0x13) {
+	   v1 = 0x44; v2 = 0x42; v3 = 0x80;
+	   v4 = 0x44; v5 = 0x42; v6 = 0x80;
+	} else {
+	   v1 = 0x68; v2 = 0x43; v3 = 0x80;  /* Assume 125Mhz MCLK */
+	   v4 = 0x68; v5 = 0x43; v6 = 0x80;  /* Assume 125Mhz ECLK */
+	   if(ivideo->sishw_ext.UseROM) {
+	      index = memtype * 5;
+	      rindex = index + 0x54;
+	      v1 = ivideo->sishw_ext.pjVirtualRomBase[rindex++];
+	      v2 = ivideo->sishw_ext.pjVirtualRomBase[rindex++];
+	      v3 = ivideo->sishw_ext.pjVirtualRomBase[rindex++];
+	      rindex = index + 0x7c;
+	      v4 = ivideo->sishw_ext.pjVirtualRomBase[rindex++];
+	      v5 = ivideo->sishw_ext.pjVirtualRomBase[rindex++];
+	      v6 = ivideo->sishw_ext.pjVirtualRomBase[rindex++];
+	   }
+	}
+	outSISIDXREG(SISSR,0x28,v1);
+	outSISIDXREG(SISSR,0x29,v2);
+	outSISIDXREG(SISSR,0x2a,v3);
+	outSISIDXREG(SISSR,0x2e,v4);
+	outSISIDXREG(SISSR,0x2f,v5);
+	outSISIDXREG(SISSR,0x30,v6);
+	v1 = 0x10;
+	if(ivideo->sishw_ext.UseROM) v1 = ivideo->sishw_ext.pjVirtualRomBase[0xa4];
+	outSISIDXREG(SISSR,0x07,v1);       /* DAC speed */
+	outSISIDXREG(SISSR,0x11,0x0f);     /* DDC, power save */
+	v1 = 0x01; v2 = 0x43; v3 = 0x1e; v4 = 0x2a;
+	v5 = 0x06; v6 = 0x00; v7 = 0x00; v8 = 0x00;
+	if(ivideo->sishw_ext.UseROM) {
+	   memtype += 0xa5;
+	   v1 = ivideo->sishw_ext.pjVirtualRomBase[memtype];
+	   v2 = ivideo->sishw_ext.pjVirtualRomBase[memtype + 8];
+	   v3 = ivideo->sishw_ext.pjVirtualRomBase[memtype + 16];
+	   v4 = ivideo->sishw_ext.pjVirtualRomBase[memtype + 24];
+	   v5 = ivideo->sishw_ext.pjVirtualRomBase[memtype + 32];
+	   v6 = ivideo->sishw_ext.pjVirtualRomBase[memtype + 40];
+	   v7 = ivideo->sishw_ext.pjVirtualRomBase[memtype + 48];
+	   v8 = ivideo->sishw_ext.pjVirtualRomBase[memtype + 56];
+	}
+	if(ivideo->revision_id >= 0x80) v3 &= 0xfd;
+	outSISIDXREG(SISSR,0x15,v1);       /* Ram type (assuming 0, BIOS 0xa5 step 8) */
+	outSISIDXREG(SISSR,0x16,v2);
+	outSISIDXREG(SISSR,0x17,v3);
+	outSISIDXREG(SISSR,0x18,v4);
+	outSISIDXREG(SISSR,0x19,v5);
+	outSISIDXREG(SISSR,0x1a,v6);
+	outSISIDXREG(SISSR,0x1b,v7);
+	outSISIDXREG(SISSR,0x1c,v8);	   /* ---- */
+	andSISIDXREG(SISSR,0x15,0xfb);
+	orSISIDXREG(SISSR,0x15,0x04);
+	if(ivideo->sishw_ext.UseROM) {
+	   if(ivideo->sishw_ext.pjVirtualRomBase[0x53] & 0x02) {
+	      orSISIDXREG(SISSR,0x19,0x20);
+	   }
+	}
+	v1 = 0x04;			   /* DAC pedestal (BIOS 0xe5) */
+	if(ivideo->revision_id >= 0x80) v1 |= 0x01;
+	outSISIDXREG(SISSR,0x1f,v1);
+	outSISIDXREG(SISSR,0x20,0xa0);     /* linear & relocated io */
+	v1 = 0xf6; v2 = 0x0d; v3 = 0x00;
+	if(ivideo->sishw_ext.UseROM) {
+	   v1 = ivideo->sishw_ext.pjVirtualRomBase[0xe8];
+	   v2 = ivideo->sishw_ext.pjVirtualRomBase[0xe9];
+	   v3 = ivideo->sishw_ext.pjVirtualRomBase[0xea];
+	}
+	outSISIDXREG(SISSR,0x23,v1);
+	outSISIDXREG(SISSR,0x24,v2);
+	outSISIDXREG(SISSR,0x25,v3);
+	outSISIDXREG(SISSR,0x21,0x84);
+	outSISIDXREG(SISSR,0x22,0x00);
+	outSISIDXREG(SISCR,0x37,0x00);
+	orSISIDXREG(SISPART1,0x24,0x01);   /* unlock crt2 */
+	outSISIDXREG(SISPART1,0x00,0x00);
+	v1 = 0x40; v2 = 0x11;
+	if(ivideo->sishw_ext.UseROM) {
+	   v1 = ivideo->sishw_ext.pjVirtualRomBase[0xec];
+	   v2 = ivideo->sishw_ext.pjVirtualRomBase[0xeb];
+	}
+	outSISIDXREG(SISPART1,0x02,v1);
+	if(ivideo->revision_id >= 0x80) v2 &= ~0x01;
+	inSISIDXREG(SISPART4,0x00,reg);
+	if((reg == 1) || (reg == 2)) {
+	   outSISIDXREG(SISCR,0x37,0x02);
+	   outSISIDXREG(SISPART2,0x00,0x1c);
+	   v4 = 0x00; v5 = 0x00; v6 = 0x10;
+	   if(ivideo->sishw_ext.UseROM) {
+	      v4 = ivideo->sishw_ext.pjVirtualRomBase[0xf5];
+	      v5 = ivideo->sishw_ext.pjVirtualRomBase[0xf6];
+	      v6 = ivideo->sishw_ext.pjVirtualRomBase[0xf7];
+	   }
+	   outSISIDXREG(SISPART4,0x0d,v4);
+	   outSISIDXREG(SISPART4,0x0e,v5);
+	   outSISIDXREG(SISPART4,0x10,v6);
+	   outSISIDXREG(SISPART4,0x0f,0x3f);
+	   inSISIDXREG(SISPART4,0x01,reg);
+	   if(reg >= 0xb0) {
+	      inSISIDXREG(SISPART4,0x23,reg);
+	      reg &= 0x20;
+	      reg <<= 1;
+	      outSISIDXREG(SISPART4,0x23,reg);
+	   }
+	} else {
+	   v2 &= ~0x10;
+	}
+	outSISIDXREG(SISSR,0x32,v2);
+	andSISIDXREG(SISPART1,0x24,0xfe);  /* Lock CRT2 */
+	inSISIDXREG(SISSR,0x16,reg);
+	reg &= 0xc3;
+	outSISIDXREG(SISCR,0x35,reg);
+	outSISIDXREG(SISCR,0x83,0x00);
+#if !defined(__i386__) && !defined(__x86_64__)
+	if(sisfb_videoram) {
+	   outSISIDXREG(SISSR,0x13,0x28);  /* ? */
+	   reg = ((sisfb_videoram >> 10) - 1) | 0x40;
+	   outSISIDXREG(SISSR,0x14,reg);
+	} else {
+#endif
+	   /* Need to map max FB size for finding out about RAM size */
+	   ivideo->sishw_ext.pjVideoMemoryAddress = ioremap(ivideo->video_base, 0x4000000);
+	   if(ivideo->sishw_ext.pjVideoMemoryAddress) {
+	      sisfb_setramsize300(pdev);
+	      iounmap(ivideo->sishw_ext.pjVideoMemoryAddress);
+	   } else {
+	      printk(KERN_DEBUG "sisfb: Failed to map memory for size detection, assuming 8MB\n");
+	      outSISIDXREG(SISSR,0x13,0x28);  /* ? */
+	      outSISIDXREG(SISSR,0x14,0x47);  /* 8MB, 64bit default */
+	   }
+#if !defined(__i386__) && !defined(__x86_64__)
+	}
+#endif
+	if(ivideo->sishw_ext.UseROM) {
+	   v1 = ivideo->sishw_ext.pjVirtualRomBase[0xe6];
+	   v2 = ivideo->sishw_ext.pjVirtualRomBase[0xe7];
+	} else {
+	   inSISIDXREG(SISSR,0x3a,reg);
+	   if((reg & 0x30) == 0x30) {
+	      v1 = 0x04; /* PCI */
+	      v2 = 0x92;
+	   } else {
+	      v1 = 0x14; /* AGP */
+	      v2 = 0xb2;
+	   }
+	}
+	outSISIDXREG(SISSR,0x21,v1);
+	outSISIDXREG(SISSR,0x22,v2);
+}
+#endif
 
-int __init sisfb_init(void)
+#ifdef CONFIG_FB_SIS_315
+static void __devinit sisfb_post_sis315330(struct pci_dev *pdev)
 {
-	struct pci_dev *pdev = NULL;
-	struct board *b;
-	int pdev_valid = 0;
-	u32 reg32;
-	u16 reg16;
-	u8  reg;
+#ifdef YET_TO_BE_DONE
+	struct sis_video_info *ivideo = pci_get_drvdata(pdev);
+	u8  reg, v1, v2, v3, v4, v5, v6, v7, v8;
+	u16 index, rindex, memtype = 0;
+	u32 reg1_32, reg2_32, reg3_32;
+	int i;
+
+	/* Unlock */
+	/* outSISIDXREG(0x3c4,0x05,0x86); */
+	outSISIDXREG(SISSR,0x05,0x86);
+
+	/* Enable relocated i/o ports */
+	/* setSISIDXREG(0x3c4,0x20,~0x10,0x20); */
+	setSISIDXREG(SISSR,0x20,~0x10,0x20);
+
+	/* Clear regs */
+	for(i = 0; i < 0x22; i++) {
+	   outSISIDXREG(SISSR,(0x06 + i),0x00);
+	}
+	v1 = 0x0d;
+	if( is 330) v1 = 0x0b;
+	for(i = 0; i < v1; i++) {
+	   outSISIDXREG(SISSR,(0x31 + i),0x00);
+	}
+	for(i = 0; i < 0x10; i++) {
+	   outSISIDXREG(SISCR,(0x30 + i),0x00);
+	}
+
+	/* Reset clocks */
+	reg = inSISREG(SISMISCR);
+	outSISIDXREG(SISSR,0x28,0x81);
+	outSISIDXREG(SISSR,0x2A,0x00);
+	outSISIDXREG(SISSR,0x29,0xE1);
+	outSISREG(SISMISCW,(reg | 0x0c));
+	outSISIDXREG(SISSR,0x2B,0x81);
+	outSISIDXREG(SISSR,0x2D,0x00);
+	outSISIDXREG(SISSR,0x2C,0xE1);
+	outSISIDXREG(SISSR,0x2E,0x81);
+	outSISIDXREG(SISSR,0x30,0x00);
+	outSISIDXREG(SISSR,0x2F,0xE1);
+	SiS_DDC2Delay(....);
+	outSISREG(SISMISCW,reg);
+
+	/* Get memory type */
+	if(ivideo->sishw_ext.UseROM) {
+	   if(ivideo->sishw_ext.pjVirtualRomBase[0x52] & 0x80)) {
+	      memtype = ivideo->sishw_ext.pjVirtualRomBase[0x52];
+ 	   } else {
+	      inSISIDXREG(SISSR,0x3a,memtype);
+	   }
+	   memtype &= 0x03;
+	   if( is 330 ) {
+	      if(memtype <= 1) memtype = 0;
+	      else {
+	         inSISIDXREG(SISCR,0x5F,reg);
+		 reg &= 0x30;
+		 switch(reg) {
+		 case 0x00: memtype = 1; break;
+		 case 0x10: memtype = 3; break;
+		 case 0x20: memtype = 3; break;
+		 default:   memtype = 2;
+		 }
+	      }
+	   }
+	}
 
-#if 0
-	/* for DOC VB */
-	sisfb_set_reg4(0xcf8,0x800000e0);
-	reg32 = sisfb_get_reg3(0xcfc);
-	reg32 = reg32 | 0x00001000;
-	sisfb_set_reg4(0xcfc,reg32);
+	/* Set clocks */
+	v1 = 0x3b; v2 = 0x22; v3 = 0x01;  /* Assume 143Mhz MCLK */
+	v4 = 0x5c; v5 = 0x23; v6 = 0x01;  /* Assume 166Mhz ECLK */
+	if(ivideo->sishw_ext.UseROM) {
+	   index = memtype * 5;
+	   rindex = index + 0x54;
+	   v1 = ivideo->sishw_ext.pjVirtualRomBase[rindex++];
+	   v2 = ivideo->sishw_ext.pjVirtualRomBase[rindex++];
+	   v3 = ivideo->sishw_ext.pjVirtualRomBase[rindex++];
+	   rindex = index + 0x68;
+	   v4 = ivideo->sishw_ext.pjVirtualRomBase[rindex++];
+	   v5 = ivideo->sishw_ext.pjVirtualRomBase[rindex++];
+	   v6 = ivideo->sishw_ext.pjVirtualRomBase[rindex++];
+	}
+	outSISIDXREG(SISSR,0x28,v1);
+	outSISIDXREG(SISSR,0x29,v2);
+	outSISIDXREG(SISSR,0x2a,v3);
+	if( is 330 ) {
+	   inSISIDXREG(SISSR,0x3a,reg);
+	   reg &= 0x03;
+	   if(reg >= 2) {
+	      ...
+	   }
 	}
-#endif
+	outSISIDXREG(SISSR,0x2e,v4);
+	outSISIDXREG(SISSR,0x2f,v5);
+	outSISIDXREG(SISSR,0x30,v6);
+
+	/* End of comp with 330 */
+
+	v1 = 0x18;
+	if(ivideo->sishw_ext.UseROM) v1 = ivideo->sishw_ext.pjVirtualRomBase[0x7c];
+	outSISIDXREG(SISSR,0x07,v1);
+	outSISIDXREG(SISSR,0x11,0x0f);
+
+	v1 = 0x00; v2 = 0x0f; v3 = 0xba; v4 = 0xa9;
+	v5 = 0xa0; v6 = 0x00; v7 = 0x30;
+	if(ivideo->sishw_ext.UseROM) {
+	   index = memtype + 0x7d;
+	   v1 = ivideo->sishw_ext.pjVirtualRomBase[index];
+	   v2 = ivideo->sishw_ext.pjVirtualRomBase[index + 4];
+	   v3 = ivideo->sishw_ext.pjVirtualRomBase[index + 8];
+	   v4 = ivideo->sishw_ext.pjVirtualRomBase[index + 12];
+	   v5 = ivideo->sishw_ext.pjVirtualRomBase[index + 16];
+	   v6 = ivideo->sishw_ext.pjVirtualRomBase[index + 20];
+	   v7 = ivideo->sishw_ext.pjVirtualRomBase[index + 24];
+	}
+	outSISIDXREG(SISSR,0x15,v1);       /* Ram type (assuming 0, BIOS 0x7d step 4) */
+	outSISIDXREG(SISSR,0x16,v2);
+	outSISIDXREG(SISSR,0x17,v3);
+	outSISIDXREG(SISSR,0x18,v4);
+	outSISIDXREG(SISSR,0x19,v5);
+	outSISIDXREG(SISSR,0x1a,v6);
+	outSISIDXREG(SISSR,0x1b,v7);
+	outSISIDXREG(SISSR,0x1c,v8);	   /* ---- */
+
+	v1 = 0x77; v2 = 0x77; v3 = 0x00; v4 = 0x5b; v5 = 0x00;
+	if(ivideo->sishw_ext.UseROM) {
+	   index = memtype + 0xa2;
+	   v1 = ivideo->sishw_ext.pjVirtualRomBase[index];
+	   v2 = ivideo->sishw_ext.pjVirtualRomBase[index + 4];
+	   v3 = ivideo->sishw_ext.pjVirtualRomBase[index + 8];
+	   v4 = ivideo->sishw_ext.pjVirtualRomBase[index + 12];
+	   v5 = ivideo->sishw_ext.pjVirtualRomBase[index + 16];
+	}
+	outSISIDXREG(SISCR,0x40,v1);
+	outSISIDXREG(SISCR,0x41,v2);
+	outSISIDXREG(SISCR,0x42,v3);
+	outSISIDXREG(SISCR,0x43,v4);
+	outSISIDXREG(SISCR,0x44,v5);
+
+	if( is 330 ) {
+
+	   v1 = 0x;
+	   if(ivideo->sishw_ext.UseROM) {
+	      v1 = ivideo->sishw_ext.pjVirtualRomBase[0xBA];
+	   }
+	   outSISIDXREG(SISCR,0x59,v1);
+
+	   v1 = 0x; v2 = 0x; v3 = 0x; v4 = 0x;
+	   v5 = 0x; v6 = 0x; v7 = 0x; v8 = 0x;
+	   if(ivideo->sishw_ext.UseROM) {
+	      index = memtype + 0xbe;
+	      v1 = ivideo->sishw_ext.pjVirtualRomBase[index];
+	      v2 = ivideo->sishw_ext.pjVirtualRomBase[index + 4];
+	      v3 = ivideo->sishw_ext.pjVirtualRomBase[index + 8];
+	      v4 = ivideo->sishw_ext.pjVirtualRomBase[index + 12];
+	      v5 = ivideo->sishw_ext.pjVirtualRomBase[index + 16];
+	      v6 = ivideo->sishw_ext.pjVirtualRomBase[index + 20];
+	      v7 = ivideo->sishw_ext.pjVirtualRomBase[index + 24];
+	      v8 = ivideo->sishw_ext.pjVirtualRomBase[index + 28];
+	   }
+	   outSISIDXREG(SISCR,0x68,v1);
+	   outSISIDXREG(SISCR,0x69,v2);
+	   outSISIDXREG(SISCR,0x6a,v3);
+	   outSISIDXREG(SISCR,0x6b,v4);
+	   outSISIDXREG(SISCR,0x6c,v5);
+	   outSISIDXREG(SISCR,0x6d,v6);
+	   outSISIDXREG(SISCR,0x6e,v7);
+	   outSISIDXREG(SISCR,0x6f,v8);
+
+	   v1 = 0x20;
+	   inSISIDXREG(SISSR,0x3b,reg);
+
+	   if(!(reg & 0x04)) {
+	      inSISIDXREG(SISCR,0x5F,reg);
+	      reg &= 0x30;
+	      if(reg) v1 = 0x23;
+	   }
+	   outSISIDXREG(SISCR,0x48,v1);
+	   outSISIDXREG(SISCR,0x4c,0x20);
 
-	if (sisfb_off)
-		return -ENXIO;
+	   xx= xxx();
+	   if(xx >= 1) {
+	      v1 = 0x;
+	      if(ivideo->sishw_ext.UseROM) {
+	         v1 = ivideo->sishw_ext.pjVirtualRomBase[0xBA];
+	      }
+	      outSISIDXREG(SISCR,0x59,v1);
+	   }
 
-	sisfb_registered = 0;
-	sisfb_thismonitor.datavalid = FALSE;
 
-	memset(&sishw_ext, 0, sizeof(sishw_ext));
 
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
-        memset(&sisfb_lastrates[0], 0, 128);
+	} else {
+
+	   outSISIDXREG(SISCR,0x48,0x23);
+
+	   andSISIDXREG(SISSR,0x16,0x0f);
+	   if(memtype <= 1) {
+	      orSISIDXREG(SISSR,0x16,0x80);
+	   } else {
+	      v1 = 0x0f;
+	      if(ivideo->sishw_ext.UseROM) {
+	         v1 = ivideo->sishw_ext.pjVirtualRomBase[0x81 + memtype];
+	      }
+	      if(!(v1 & 0x10)) v2 = 0xc0;
+	      else             v2 = 0xd0;
+	      orSISIDXREG(SISSR,0x16,v2);
+	      andSISIDXREG(SISSR,0x16,0x0f);
+	      if(!(v1 & 0x10)) v2 = 0x80;
+	      else             v2 = 0xA0;
+	      orSISIDXREG(SISSR,0x16,v2);
+ 	   }
+
+	   if(memtype >= 2) {
+	      const u8 sr3cseq1[] = { 0xc0,0xe0,0xf0,0xe0,0xf0,0xa0,0xb0,0xa0,0xb0,0x90,0xd0 };
+	      const u8 sr3cseq2[] = { 0xc0,0xa0,0xb0,0xa0,0xb0,0xe0,0xf0,0xa0,0xb0,0x90,0xd0 };
+	      for(i = 0; i < 11; i++) {
+	         outSISIDXREG(SISSR,0x3c,sr3cseq1[i]);
+	      }
+	      outSISIDXREG(SISSR,0x3d,0x00);
+	      outSISIDXREG(SISSR,0x3d,0x04);
+	      SiS_DDC2Delay(0x200);
+	      v1 = inSISIDXREG(SISCR,0xEC);
+	      v2 = inSISIDXREG(SISCR,0xED);
+	      reg1_32 = (v2 << 8) | v1;
+	      outSISIDXREG(SISSR,0x3D,0x00);
+	      for(i = 0; i < 11; i++) {
+	         outSISIDXREG(SISSR,0x3c,sr3cseq2[i]);
+	      }
+	      outSISIDXREG(SISSR,0x3d,0x00);
+	      outSISIDXREG(SISSR,0x3d,0x04);
+	      SiS_DDC2Delay(0x200);
+	      v1 = inSISIDXREG(SISCR,0xEC);
+	      v2 = inSISIDXREG(SISCR,0xED);
+	      reg2_32 = (v2 << 8) | v1;
+	      outSISIDXREG(SISSR,0x3D,0x00);
+	      reg3_32 = reg2_32 << 1;
+	      reg2_32 >>= 1;
+	      reg3_32 += reg2_32;
+	      v1 = 0x40;
+	      if(reg3_32 > reg1_32) v1 = 0x10;
+	         outSISIDXREG(SISCR,0x59,v1);
+	   }
+
+	}
+
+	v1 = 0x00;
+	if(ivideo->sishw_ext.UseROM) {
+	   v1 = ivideo->sishw_ext.pjVirtualRomBase[0x99];
+	}
+	outSISIDXREG(SISSR,0x1f,v1);
+
+	outSISIDXREG(SISSR,0x20,0x20);
+
+	v1 = 0xf6; v2 = 0x0d; v3 = 0x33;
+	if(ivideo->sishw_ext.UseROM) {
+	   v1 = ivideo->sishw_ext.pjVirtualRomBase[0x9c];
+	   v2 = ivideo->sishw_ext.pjVirtualRomBase[0x9d];
+	   v3 = ivideo->sishw_ext.pjVirtualRomBase[0x9e];
+	}
+	outSISIDXREG(SISSR,0x23,v1);
+	outSISIDXREG(SISSR,0x24,v2);
+	outSISIDXREG(SISSR,0x25,v3);
+
+	outSISIDXREG(SISSR,0x21,0x84);
+	outSISIDXREG(SISSR,0x22,0x00);
+	outSISIDXREG(SISSR,0x27,0x1f);
+
+	v1 = 0x00; v2 = 0x00;
+	if(ivideo->sishw_ext.UseROM) {
+	   v1 = ivideo->sishw_ext.pjVirtualRomBase[0x9F];
+	   v2 = ivideo->sishw_ext.pjVirtualRomBase[0xA1];
+	}
+	outSISIDXREG(SISSR,0x31,v1);
+	outSISIDXREG(SISSR,0x33,v2);
+
+	v1 = 0x11;
+	if(ivideo->sishw_ext.UseROM) {
+	   v1 = ivideo->sishw_ext.pjVirtualRomBase[0xA0];
+	}
+	v2 = inSISIDXREG(SISPART4,0x00);
+	if((v2 != 1) && (v2 != 2)) v1 &= 0xef;
+	outSISIDXREG(SISSR,0x32,v1);
+
+	/* AGP */
+	pci_read_config_long(pdev, 0x50, &reg1_32);
+	reg1_32 >>= 20;
+	reg1_32 &= 0x0f;
+	if(reg1_32 == 1) {
+	   v1 = 0xAA; v2 = 0x33;
+	   if(ivideo->sishw_ext.UseROM) {
+	      v1 = ivideo->sishw_ext.pjVirtualRomBase[0xF7];
+	      v2 = ivideo->sishw_ext.pjVirtualRomBase[0x9E];
+	   }
+	} else {
+	   v1 = 0x88; v2 = 0x03;
+	   if(ivideo->sishw_ext.UseROM) {
+	      v1 = ivideo->sishw_ext.pjVirtualRomBase[0xF8];
+	      v2 = ivideo->sishw_ext.pjVirtualRomBase[0xF6];
+	   }
+	}
+	outSISIDXREG(SISCR,0x49,v1);
+	outSISIDXREG(SISSR,0x25,v2);
+
+	v1 = inSISIDXREG(SISPART4,0x00);
+	if((v1 == 1) || (v1 == 2)) {
+	   orSISIDXREG(SISPART1,0x2F,0x01);  /* Unlock CRT2 */
+	   outSISIDXREG(SISPART1,0x00,0x00);
+	   v1 = 0x00;
+	   if(ivideo->sishw_ext.UseROM) {
+	      v1 = ivideo->sishw_ext.pjVirtualRomBase[0xb6];
+	   }
+	   outSISIDXREG(SISPART1,0x02,v1);
+	   outSISIDXREG(SISPART1,0x2E,0x08);
+	   outSISIDXREG(SISPART2,0x00,0x1c);
+	   v1 = 0x40; v2 = 0x00; v3 = 0x80;
+	   if(ivideo->sishw_ext.UseROM) {
+	      v1 = ivideo->sishw_ext.pjVirtualRomBase[0xb7];
+	      v2 = ivideo->sishw_ext.pjVirtualRomBase[0xb8];
+	      v3 = ivideo->sishw_ext.pjVirtualRomBase[0xbb];
+	   }
+	   outSISIDXREG(SISPART4,0x0d,v1);
+	   outSISIDXREG(SISPART4,0x0e,v2);
+	   outSISIDXREG(SISPART4,0x10,v3);
+	   outSISIDXREG(SISPART4,0x0F,0x3F);
+
+	   inSISIDXREG(SISPART4,0x01,reg);
+	   if(reg >= 0xb0) {
+	      inSISIDXREG(SISPART4,0x23,reg);
+	      reg &= 0x20;
+	      reg <<= 1;
+	      outSISIDXREG(SISPART4,0x23,reg);
+	   }
+	}
+	outSISIDXREG(SISCR,0x37,0x02); /* Why? */
+
+	outSISIDXREG(SISCR,0x83,0x00);
+	outSISIDXREG(SISCR,0x90,0x00);
+	andSISIDXREG(SISSR,0x5B,0xDF);
+	outSISIDXREG(SISVID,0x00,0x86);
+	outSISIDXREG(SISVID,0x32,0x00);
+	outSISIDXREG(SISVID,0x30,0x00);
+	outSISIDXREG(SISVID,0x32,0x01);
+	outSISIDXREG(SISVID,0x30,0x00);
+	orSISIDXREG(SISCR,0x63,0x80);
+	/* End of Init1 */
+
+	/* Set Mode 0x2e */
+
+	/* Ramsize */
+	orSISIDXREG(SISSR,0x16,0x0f);
+	orSISIDXREG(SISSR,0x18,0xA9);
+	orSISIDXREG(SISSR,0x19,0xA0);
+	orSISIDXREG(SISSR,0x1B,0x30);
+	andSISIDXREG(SISSR,0x17,0xF8);
+	orSISIDXREG(SISSR,0x19,0x03);
+	andSIDIDXREG(SISSR,0x13,0x00);
+
+	/* Need to map max FB size for finding out about RAM size */
+	ivideo->sishw_ext.pjVideoMemoryAddress = ioremap(ivideo->video_base, 0x4000000);
+	if(ivideo->sishw_ext.pjVideoMemoryAddress) {
+	   /* Find out about bus width */
+	   if(memtype <= 1) {
+	      outSISIDXREG(SISSR,0x14,0x02);
+	      andSISIDXREG(SISSR,0x16,0x0F);
+	      orSISIDXREG(SISSR,0x16,0x80);
+
+	      ...
+
+	   } else {
+
+	      ...
+
+	   }
+
+	   /* Find out about size */
+
+
+	   iounmap(ivideo->sishw_ext.pjVideoMemoryAddress);
+	} else {
+	   printk(KERN_DEBUG "sisfb: Failed to map memory for size detection, assuming 8MB\n");
+	   outSISIDXREG(SISSR,0x14,0x??);  /* 8MB, 64bit default */
+	}
+
+	/* AGP (Missing: Checks for VIA and AMD hosts) */
+	v1 = 0xA5; v2 = 0xFB;
+	if(ivideo->sishw_ext.UseROM) {
+	   v1 = ivideo->sishw_ext.pjVirtualRomBase[0x9A];
+	   v2 = ivideo->sishw_ext.pjVirtualRomBase[0x9B];
+	}
+	outSISIDXREG(SISSR,0x21,v1);
+	outSISIDXREG(SISSR,0x22,v2);
+
 #endif
-	
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)	
-	memset(&sis_disp, 0, sizeof(sis_disp));
+	return;
+}
 #endif
 
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,74)
-	pci_for_each_dev(pdev) {
+
+int __devinit sisfb_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
+{
+	struct sisfb_chip_info 	*chipinfo = &sisfb_chip_info[ent->driver_data];
+	struct sis_video_info 	*ivideo = NULL;
+	struct fb_info 		*sis_fb_info = NULL;
+	u16 reg16;
+	u8  reg;
+	int sisvga_enabled = 0, i;
+
+	if(sisfb_off) return -ENXIO;
+
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,3))
+	sis_fb_info = framebuffer_alloc(sizeof(*ivideo), &pdev->dev);
+	if(!sis_fb_info) return -ENOMEM;
 #else
-	while((pdev = pci_find_device(PCI_VENDOR_ID_SI, PCI_ANY_ID, pdev))) {
+	sis_fb_info = kmalloc(sizeof(*sis_fb_info) + sizeof(*ivideo), GFP_KERNEL);
+	if(!sis_fb_info) return -ENOMEM;
+	memset(sis_fb_info, 0, sizeof(*sis_fb_info) + sizeof(*ivideo));
+	sis_fb_info->par = ((char *)sis_fb_info + sizeof(*sis_fb_info));
 #endif
-		for (b = sisdev_list; b->vendor; b++) {
-			if ((b->vendor == pdev->vendor)
-			    && (b->device == pdev->device)) {
-				pdev_valid = 1;
-#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)) && defined(NEWFBDEV)
-				sis_fb_info = framebuffer_alloc(0, &pdev->dev);
-#else
-				sis_fb_info = kmalloc(sizeof(*sis_fb_info), GFP_KERNEL);
+
+	ivideo = (struct sis_video_info *)sis_fb_info->par;
+	ivideo->memyselfandi = sis_fb_info;
+	
+	if(card_list == NULL) {
+	   ivideo->cardnumber = 0;
+	} else {
+	   struct sis_video_info *countvideo = card_list;
+	   ivideo->cardnumber = 1;
+	   while((countvideo = countvideo->next)) ivideo->cardnumber++;
+	}
+
+	strncpy(ivideo->myid, chipinfo->chip_name, 30);
+
+	ivideo->chip_id = pdev->device;
+	pci_read_config_byte(pdev, PCI_REVISION_ID, &ivideo->revision_id);
+	ivideo->sishw_ext.jChipRevision = ivideo->revision_id;
+	pci_read_config_word(pdev, PCI_COMMAND, &reg16);
+	sisvga_enabled = reg16 & 0x01;
+	ivideo->pcibus = pdev->bus->number;
+	ivideo->pcislot = PCI_SLOT(pdev->devfn);
+	ivideo->pcifunc = PCI_FUNC(pdev->devfn);
+	ivideo->subsysvendor = pdev->subsystem_vendor;
+	ivideo->subsysdevice = pdev->subsystem_device;
+#ifdef SIS_CONFIG_COMPAT
+	ivideo->ioctl32registered = 0;
+	ivideo->ioctl32vblankregistered = 0;
 #endif
-				if(!sis_fb_info) return -ENOMEM;
-#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)) || (!(defined(NEWFBDEV)))
-				memset(sis_fb_info, 0, sizeof(*sis_fb_info));
+
+#ifndef MODULE
+	if(sisfb_mode_idx == -1) {
+		sisfb_get_vga_mode_from_kernel();
+	}
 #endif
+
+	ivideo->chip = chipinfo->chip;
+	ivideo->sisvga_engine = chipinfo->vgaengine;
+	ivideo->hwcursor_size = chipinfo->hwcursor_size;
+	ivideo->CRT2_write_enable = chipinfo->CRT2_write_enable;
+	ivideo->mni = chipinfo->mni;
+
+	ivideo->detectedpdc  = 0xff;
+	ivideo->detectedpdca = 0xff;
+	ivideo->detectedlcda = 0xff;
+
+	ivideo->sisfb_thismonitor.datavalid = FALSE;
+
+	ivideo->sisfb_parm_mem = sisfb_parm_mem;
+	ivideo->sisfb_accel = sisfb_accel;
+	ivideo->sisfb_ypan = sisfb_ypan;
+	ivideo->sisfb_max = sisfb_max;
+	ivideo->sisfb_userom = sisfb_userom;
+	ivideo->sisfb_useoem = sisfb_useoem;
+	ivideo->sisfb_mode_idx = sisfb_mode_idx;
+	ivideo->sisfb_parm_rate = sisfb_parm_rate;
+	ivideo->sisfb_crt1off = sisfb_crt1off;
+	ivideo->sisfb_forcecrt1 = sisfb_forcecrt1;
+	ivideo->sisfb_crt2type = sisfb_crt2type;
+	ivideo->sisfb_crt2flags = sisfb_crt2flags;
+	/* pdc(a), scalelcd, special timing, lvdshl handled below */
+	ivideo->sisfb_dstn = sisfb_dstn;
+	ivideo->sisfb_fstn = sisfb_fstn;
+	ivideo->sisfb_tvplug = sisfb_tvplug;
+	ivideo->sisfb_tvstd = sisfb_tvstd;
+	ivideo->tvxpos = sisfb_tvxposoffset;
+	ivideo->tvypos = sisfb_tvyposoffset;
+	ivideo->sisfb_filter = sisfb_filter;
+	ivideo->sisfb_nocrt2rate = sisfb_nocrt2rate;
 #if LINUX_VERSION_CODE <= KERNEL_VERSION(2,5,0)
-				strcpy(sis_fb_info->modename, b->name);
-#else				
-				strcpy(myid, b->name);
-#endif				
-				ivideo.chip_id = pdev->device;
-				pci_read_config_byte(pdev, PCI_REVISION_ID,
-				                     &ivideo.revision_id);
-				pci_read_config_word(pdev, PCI_COMMAND, &reg16);
-				sishw_ext.jChipRevision = ivideo.revision_id;
-				sisvga_enabled = reg16 & 0x01;
-				ivideo.pcibus = pdev->bus->number;
-				ivideo.pcislot = PCI_SLOT(pdev->devfn);
-				ivideo.pcifunc = PCI_FUNC(pdev->devfn);
-				ivideo.subsysvendor = pdev->subsystem_vendor;
-				ivideo.subsysdevice = pdev->subsystem_device;
-				break;
-			}
-		}
+	ivideo->sisfb_inverse = sisfb_inverse;
+#endif
 
-		if (pdev_valid)
-			break;
+	ivideo->refresh_rate = 0;
+	if(ivideo->sisfb_parm_rate != -1) {
+	   ivideo->refresh_rate = ivideo->sisfb_parm_rate;
+	}
+
+	ivideo->SiS_Pr.UsePanelScaler = sisfb_scalelcd;
+	ivideo->SiS_Pr.CenterScreen = -1;
+	ivideo->SiS_Pr.SiS_CustomT = sisfb_specialtiming;
+	ivideo->SiS_Pr.LVDSHL = sisfb_lvdshl;
+
+	ivideo->SiS_Pr.SiS_Backup70xx = 0xff;
+        ivideo->SiS_Pr.SiS_CHOverScan = -1;
+        ivideo->SiS_Pr.SiS_ChSW = FALSE;
+	ivideo->SiS_Pr.SiS_UseLCDA = FALSE;
+	ivideo->SiS_Pr.HaveEMI = FALSE;
+	ivideo->SiS_Pr.HaveEMILCD = FALSE;
+	ivideo->SiS_Pr.OverruleEMI = FALSE;
+	ivideo->SiS_Pr.SiS_SensibleSR11 = FALSE;
+	ivideo->SiS_Pr.SiS_MyCR63 = 0x63;
+	ivideo->SiS_Pr.PDC  = -1;
+	ivideo->SiS_Pr.PDCA = -1;
+#ifdef CONFIG_FB_SIS_315
+	if(ivideo->chip >= SIS_330) {
+	   ivideo->SiS_Pr.SiS_MyCR63 = 0x53;
+	   if(ivideo->chip >= SIS_661) {
+	      ivideo->SiS_Pr.SiS_SensibleSR11 = TRUE;
+	   }
 	}
+#endif
 
-	if (!pdev_valid)
-		return -ENODEV;
+	memcpy(&ivideo->default_var, &my_default_var, sizeof(my_default_var));
 
-	switch (ivideo.chip_id) {
+	pci_set_drvdata(pdev, ivideo);
+
+	/* Patch special cases */
+	if((ivideo->nbridge = sisfb_get_northbridge(ivideo->chip))) {
+		switch(ivideo->nbridge->device) {
 #ifdef CONFIG_FB_SIS_300
-	   case PCI_DEVICE_ID_SI_300:
-		ivideo.chip = SIS_300;
-		sisvga_engine = SIS_300_VGA;
-		sisfb_hwcursor_size = HW_CURSOR_AREA_SIZE_300 * 2;  /* New X driver uses 2 buffers */
-		sisfb_CRT2_write_enable = IND_SIS_CRT2_WRITE_ENABLE_300;
-		break;
-	   case PCI_DEVICE_ID_SI_630_VGA:
-		{
-			ivideo.chip = SIS_630;
-			sisfb_set_reg4(0xCF8, 0x80000000);
-			reg32 = sisfb_get_reg3(0xCFC);
-			if(reg32 == 0x07301039) {
-				ivideo.chip = SIS_730;
-#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,5,0)
-				strcpy(sis_fb_info->modename, "SIS 730");
-#else
-				strcpy(myid, "SIS 730");
-#endif
-			}
-			sisvga_engine = SIS_300_VGA;
-			sisfb_hwcursor_size = HW_CURSOR_AREA_SIZE_300 * 2;
-			sisfb_CRT2_write_enable = IND_SIS_CRT2_WRITE_ENABLE_300;
-			break;
-		}
-	   case PCI_DEVICE_ID_SI_540_VGA:
-		ivideo.chip = SIS_540;
-		sisvga_engine = SIS_300_VGA;
-		sisfb_hwcursor_size = HW_CURSOR_AREA_SIZE_300 * 2;
-		sisfb_CRT2_write_enable = IND_SIS_CRT2_WRITE_ENABLE_300;
-		break;
+		case PCI_DEVICE_ID_SI_730:
+		   	ivideo->chip = SIS_730;
+			strcpy(ivideo->myid, "SiS 730");
+		   	break;
 #endif
 #ifdef CONFIG_FB_SIS_315
-	   case PCI_DEVICE_ID_SI_315H:
-		ivideo.chip = SIS_315H;
-		sisvga_engine = SIS_315_VGA;
-		sisfb_hwcursor_size = HW_CURSOR_AREA_SIZE_315 * 2;
-		sisfb_CRT2_write_enable = IND_SIS_CRT2_WRITE_ENABLE_315;
-		break;
-	   case PCI_DEVICE_ID_SI_315:
-		ivideo.chip = SIS_315;
-		sisvga_engine = SIS_315_VGA;
-		sisfb_hwcursor_size = HW_CURSOR_AREA_SIZE_315 * 2;
-		sisfb_CRT2_write_enable = IND_SIS_CRT2_WRITE_ENABLE_315;
-		break;
-	   case PCI_DEVICE_ID_SI_315PRO:
-		ivideo.chip = SIS_315PRO;
-		sisvga_engine = SIS_315_VGA;
-		sisfb_hwcursor_size = HW_CURSOR_AREA_SIZE_315 * 2;
-		sisfb_CRT2_write_enable = IND_SIS_CRT2_WRITE_ENABLE_315;
-		break;
-	   case PCI_DEVICE_ID_SI_550_VGA:
-		ivideo.chip = SIS_550;
-		sisvga_engine = SIS_315_VGA;
-		sisfb_hwcursor_size = HW_CURSOR_AREA_SIZE_315 * 2;
-		sisfb_CRT2_write_enable = IND_SIS_CRT2_WRITE_ENABLE_315;
-		break;
-	   case PCI_DEVICE_ID_SI_650_VGA:
-	   	{
-			ivideo.chip = SIS_650;  
-			sisfb_set_reg4(0xCF8, 0x80000000);
-			reg32 = sisfb_get_reg3(0xCFC);
-			if(reg32 == 0x07401039) {
-				ivideo.chip = SIS_740;
-#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,5,0)
-				strcpy(sis_fb_info->modename, "SIS 740");
-#else
-				strcpy(myid, "SIS 740");
-#endif
-			}
-			sisvga_engine = SIS_315_VGA;
-			sisfb_hwcursor_size = HW_CURSOR_AREA_SIZE_315 * 2;
-			sisfb_CRT2_write_enable = IND_SIS_CRT2_WRITE_ENABLE_315;
+		case PCI_DEVICE_ID_SI_651:
+			/* ivideo->chip is ok */
+			strcpy(ivideo->myid, "SiS 651");
 			break;
-		}
-	   case PCI_DEVICE_ID_SI_330:
-		ivideo.chip = SIS_330;
-		sisvga_engine = SIS_315_VGA;
-		sisfb_hwcursor_size = HW_CURSOR_AREA_SIZE_315 * 2;
-		sisfb_CRT2_write_enable = IND_SIS_CRT2_WRITE_ENABLE_315;
-		break;
-	   case PCI_DEVICE_ID_SI_660_VGA:
-	   	{
-			sisfb_set_reg4(0xCF8, 0x80000000);
-			reg32 = sisfb_get_reg3(0xCFC);
-			if(reg32 == 0x07601039) {
-				ivideo.chip = SIS_760;
-#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,5,0)
-				strcpy(sis_fb_info->modename, "SIS 760");
-#else
-				strcpy(myid, "SIS 760");
-#endif
-			} else if(reg32 == 0x06601039) {
-				ivideo.chip = SIS_660;
-#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,5,0)
-				strcpy(sis_fb_info->modename, "SIS 660");
-#else
-				strcpy(myid, "SIS 660");
-#endif
-			} else if(reg32 == 0x07411039) {
-				ivideo.chip = SIS_741;
-#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,5,0)
-				strcpy(sis_fb_info->modename, "SIS 741");
-#else
-				strcpy(myid, "SIS 741");
-#endif
-			} else {
-				ivideo.chip = SIS_661;
-#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,5,0)
-				strcpy(sis_fb_info->modename, "SIS 661");
-#else
-				strcpy(myid, "SIS 661");
-#endif
-			}
-			sisvga_engine = SIS_315_VGA;
-			sisfb_hwcursor_size = HW_CURSOR_AREA_SIZE_315 * 2;
-			sisfb_CRT2_write_enable = IND_SIS_CRT2_WRITE_ENABLE_315;
+		case PCI_DEVICE_ID_SI_740:
+		   	ivideo->chip = SIS_740;
+			strcpy(ivideo->myid, "SiS 740");
+			break;
+		case PCI_DEVICE_ID_SI_661:
+		   	ivideo->chip = SIS_661;
+			strcpy(ivideo->myid, "SiS 661");
+			break;
+		case PCI_DEVICE_ID_SI_741:
+		   	ivideo->chip = SIS_741;
+			strcpy(ivideo->myid, "SiS 741");
+			break;
+		case PCI_DEVICE_ID_SI_760:
+		   	ivideo->chip = SIS_760;
+			strcpy(ivideo->myid, "SiS 760");
 			break;
-		}
 #endif
-           default:
-	   	kfree(sis_fb_info);
-	        return -ENODEV;
+		}
 	}
-	sishw_ext.jChipType = ivideo.chip;
 
-	/* for Debug */
-	if( (sishw_ext.jChipType == SIS_315PRO) ||
-	    (sishw_ext.jChipType == SIS_315) )
-		sishw_ext.jChipType = SIS_315H;
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
+	strcpy(sis_fb_info->modename, ivideo->myid);
+#endif
+
+	ivideo->sishw_ext.jChipType = ivideo->chip;
 
-	ivideo.video_base = pci_resource_start(pdev, 0);
-	ivideo.mmio_base = pci_resource_start(pdev, 1);
-	sishw_ext.ulIOAddress = SiS_Pr.RelIO = pci_resource_start(pdev, 2) + 0x30;
-	ivideo.vga_base = (unsigned short) sishw_ext.ulIOAddress;
+#ifdef CONFIG_FB_SIS_315
+	if((ivideo->sishw_ext.jChipType == SIS_315PRO) ||
+	   (ivideo->sishw_ext.jChipType == SIS_315)) {
+		ivideo->sishw_ext.jChipType = SIS_315H;
+	}
+#endif
 
-	sisfb_mmio_size =  pci_resource_len(pdev, 1);
+	ivideo->video_base = pci_resource_start(pdev, 0);
+	ivideo->mmio_base  = pci_resource_start(pdev, 1);
+	ivideo->mmio_size  = pci_resource_len(pdev, 1);
+	ivideo->SiS_Pr.RelIO = pci_resource_start(pdev, 2) + 0x30;
+	ivideo->sishw_ext.ulIOAddress = ivideo->vga_base = ivideo->SiS_Pr.RelIO;
 
 	if(!sisvga_enabled) {
-	   if(pci_enable_device(pdev)) {
-	      kfree(sis_fb_info);
-	      return -EIO;
-	   }
+	   	if(pci_enable_device(pdev)) {
+	      		pci_set_drvdata(pdev, NULL);
+	      		kfree(sis_fb_info);
+	      		return -EIO;
+	   	}
 	}
 
-	SiS_Pr.SiS_Backup70xx = 0xff;
-        SiS_Pr.SiS_CHOverScan = -1;
-        SiS_Pr.SiS_ChSW = FALSE;
-	SiS_Pr.SiS_UseLCDA = FALSE;
-	SiS_Pr.HaveEMI = FALSE;
-	SiS_Pr.HaveEMILCD = FALSE;
-	SiS_Pr.OverruleEMI = FALSE;
-	SiS_Pr.SiS_SensibleSR11 = FALSE;
-	SiS_Pr.SiS_MyCR63 = 0x63;
-	if(ivideo.chip >= SIS_661) {
-	   SiS_Pr.SiS_SensibleSR11 = TRUE;
-	   SiS_Pr.SiS_MyCR63 = 0x53;
-	}
-	SiSRegInit(&SiS_Pr, sishw_ext.ulIOAddress);
+	SiSRegInit(&ivideo->SiS_Pr, ivideo->sishw_ext.ulIOAddress);
 
 #ifdef CONFIG_FB_SIS_300
-	/* TW: Find PCI systems for Chrontel/GPIO communication setup */
-	if(ivideo.chip == SIS_630) {
-	   int i=0;
+	/* Find PCI systems for Chrontel/GPIO communication setup */
+	if(ivideo->chip == SIS_630) {
+	   i=0;
            do {
-	      if(mychswtable[i].subsysVendor == ivideo.subsysvendor &&
-	         mychswtable[i].subsysCard   == ivideo.subsysdevice) {
-		 SiS_Pr.SiS_ChSW = TRUE;
+	      if(mychswtable[i].subsysVendor == ivideo->subsysvendor &&
+	         mychswtable[i].subsysCard   == ivideo->subsysdevice) {
+		 ivideo->SiS_Pr.SiS_ChSW = TRUE;
 		 printk(KERN_DEBUG "sisfb: Identified [%s %s] requiring Chrontel/GPIO setup\n",
 		        mychswtable[i].vendorName, mychswtable[i].cardName);
 		 break;
@@ -4361,14 +4938,41 @@
 	}
 #endif
 
-        outSISIDXREG(SISSR, IND_SIS_PASSWORD, SIS_PASSWORD);
+        outSISIDXREG(SISSR, 0x05, 0x86);
 
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)		
-#ifdef MODULE
+	if( (!sisvga_enabled)
+#if !defined(__i386__) && !defined(__x86_64__)
+		  	      || (sisfb_resetcard)
+#endif
+			      			   ) {
+	   	for(i = 0x30; i <= 0x3f; i++) {
+	      		outSISIDXREG(SISCR,i,0x00);
+	   	}
+	}
+
+	/* Find out about current video mode */
 	inSISIDXREG(SISCR,0x34,reg);
+	if(reg & 0x7f) {
+		ivideo->modeprechange = reg & 0x7f;
+	} else {
+		ivideo->modeprechange = 0x03;
+#if defined(__i386__) || defined(__x86_64__)
+		{
+			unsigned char *tt = ioremap(0, 0x1000);
+			if(tt) {
+			   	ivideo->modeprechange = tt[0x449];
+			   	iounmap(tt);
+			}
+		}
+#endif
+	}
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
+#ifdef MODULE
 	if((reg & 0x80) && (reg != 0xff)) {
-	   if((sisbios_mode[sisfb_mode_idx].mode_no) != 0xFF) {
+	   if((sisbios_mode[ivideo->sisfb_mode_idx].mode_no[ivideo->mni]) != 0xFF) {
 	      printk(KERN_INFO "sisfb: Cannot initialize display mode, X server is active\n");
+	      pci_set_drvdata(pdev, NULL);
 	      kfree(sis_fb_info);
 	      return -EBUSY;
 	   }
@@ -4376,96 +4980,82 @@
 #endif	
 #endif
 
-	if (sisvga_engine == SIS_315_VGA) {
-		switch (ivideo.chip) {
-		   case SIS_315H:
-		   case SIS_315:
-		   case SIS_330:
-			sishw_ext.bIntegratedMMEnabled = TRUE;
-			break;
-		   case SIS_550:
-		   case SIS_650:
-		   case SIS_740:
-		   case SIS_661:
-		   case SIS_741:
-		   case SIS_660:
-		   case SIS_760:
-			sishw_ext.bIntegratedMMEnabled = TRUE;
-			break;
-		   default:
-			break;
-		}
-	} else if (sisvga_engine == SIS_300_VGA) {
-		if (ivideo.chip == SIS_300) {
-			sishw_ext.bIntegratedMMEnabled = TRUE;
-		} else {
-		        inSISIDXREG(SISSR, IND_SIS_SCRATCH_REG_1A, reg);
-			if (reg & SIS_SCRATCH_REG_1A_MASK)
-				sishw_ext.bIntegratedMMEnabled = TRUE;
-			else
-				sishw_ext.bIntegratedMMEnabled = FALSE;
-		}
+	ivideo->sishw_ext.bIntegratedMMEnabled = TRUE;
+#ifdef CONFIG_FB_SIS_300
+	if(ivideo->sisvga_engine == SIS_300_VGA) {
+	   if(ivideo->chip != SIS_300) {
+	      inSISIDXREG(SISSR, 0x1a, reg);
+	      if(!(reg & 0x10)) {
+		 ivideo->sishw_ext.bIntegratedMMEnabled = FALSE;
+	      }
+	   }
 	}
+#endif
 
-	if(sisfb_userom) {
-	    sishw_ext.pjVirtualRomBase = sis_find_rom();
-	    if(sishw_ext.pjVirtualRomBase) {
-		printk(KERN_INFO "sisfb: Video ROM found and mapped to %p\n",
-		        sishw_ext.pjVirtualRomBase);
-		sishw_ext.UseROM = TRUE;
+	ivideo->bios_vbase = ivideo->bios_abase = NULL;
+	if(ivideo->sisfb_userom) {
+	    ivideo->sishw_ext.pjVirtualRomBase = sis_find_rom(pdev);
+#if defined(__i386__) || defined(__x86_64__)
+	    ivideo->bios_vbase = ivideo->sishw_ext.pjVirtualRomBase;	/* mapped */
+#else
+	    ivideo->bios_abase = ivideo->sishw_ext.pjVirtualRomBase;	/* allocated */
+#endif
+	    if(ivideo->sishw_ext.pjVirtualRomBase) {
+		printk(KERN_INFO "sisfb: Video ROM found and %s to 0x%p\n",
+			ivideo->bios_vbase ? "mapped" : "copied",
+		        ivideo->sishw_ext.pjVirtualRomBase);
+		ivideo->sishw_ext.UseROM = TRUE;
 	    } else {
-	        sishw_ext.UseROM = FALSE;
+	        ivideo->sishw_ext.UseROM = FALSE;
 	        printk(KERN_INFO "sisfb: Video ROM not found\n");
 	    }
 	} else {
-	    sishw_ext.pjVirtualRomBase = NULL;
-	    sishw_ext.UseROM = FALSE;
+	    ivideo->sishw_ext.pjVirtualRomBase = NULL;
+	    ivideo->sishw_ext.UseROM = FALSE;
 	    printk(KERN_INFO "sisfb: Video ROM usage disabled\n");
 	}
-	sishw_ext.bSkipDramSizing = 0;
-	sishw_ext.pQueryVGAConfigSpace = &sisfb_query_VGA_config_space;
-	sishw_ext.pQueryNorthBridgeSpace = &sisfb_query_north_bridge_space;
 
         /* Find systems for special custom timing */
-	if(SiS_Pr.SiS_CustomT == CUT_NONE) {
-	   int i=0, j;
+	if(ivideo->SiS_Pr.SiS_CustomT == CUT_NONE) {
+	   int j;
 	   unsigned char *biosver = NULL;
            unsigned char *biosdate = NULL;
 	   BOOLEAN footprint;
-	   unsigned long chksum = 0;
+	   u32 chksum = 0;
 
-	   if(sishw_ext.UseROM) {
-	      biosver = sishw_ext.pjVirtualRomBase + 0x06;
-	      biosdate = sishw_ext.pjVirtualRomBase + 0x2c;
-              for(i=0; i<32768; i++) chksum += sishw_ext.pjVirtualRomBase[i];
+	   if(ivideo->sishw_ext.UseROM) {
+	      biosver = ivideo->sishw_ext.pjVirtualRomBase + 0x06;
+	      biosdate = ivideo->sishw_ext.pjVirtualRomBase + 0x2c;
+              for(i=0; i<32768; i++) chksum += ivideo->sishw_ext.pjVirtualRomBase[i];
 	   }
 
 	   i=0;
            do {
-	      if( (mycustomttable[i].chipID == ivideo.chip) &&
+	      if( (mycustomttable[i].chipID == ivideo->chip) &&
 	          ((!strlen(mycustomttable[i].biosversion)) ||
-		   (sishw_ext.UseROM &&
+		   (ivideo->sishw_ext.UseROM &&
 		   (!strncmp(mycustomttable[i].biosversion, biosver, strlen(mycustomttable[i].biosversion))))) &&
 	          ((!strlen(mycustomttable[i].biosdate)) ||
-		   (sishw_ext.UseROM &&
+		   (ivideo->sishw_ext.UseROM &&
 		   (!strncmp(mycustomttable[i].biosdate, biosdate, strlen(mycustomttable[i].biosdate))))) &&
 		  ((!mycustomttable[i].bioschksum) ||
-		   (sishw_ext.UseROM &&
+		   (ivideo->sishw_ext.UseROM &&
 	           (mycustomttable[i].bioschksum == chksum)))	&&
-		  (mycustomttable[i].pcisubsysvendor == ivideo.subsysvendor) &&
-		  (mycustomttable[i].pcisubsyscard == ivideo.subsysdevice) ) {
+		  (mycustomttable[i].pcisubsysvendor == ivideo->subsysvendor) &&
+		  (mycustomttable[i].pcisubsyscard == ivideo->subsysdevice) ) {
 		 footprint = TRUE;
-	         for(j=0; j<5; j++) {
+	         for(j = 0; j < 5; j++) {
 	            if(mycustomttable[i].biosFootprintAddr[j]) {
-		       if(sishw_ext.UseROM) {
-	                  if(sishw_ext.pjVirtualRomBase[mycustomttable[i].biosFootprintAddr[j]] !=
-		      		mycustomttable[i].biosFootprintData[j])
-		          footprint = FALSE;
+		       if(ivideo->sishw_ext.UseROM) {
+	                  if(ivideo->sishw_ext.pjVirtualRomBase[mycustomttable[i].biosFootprintAddr[j]] !=
+		      		mycustomttable[i].biosFootprintData[j]) {
+		             footprint = FALSE;
+			  }
 		       } else footprint = FALSE;
 		    }
 	         }
 	         if(footprint) {
-	 	    SiS_Pr.SiS_CustomT = mycustomttable[i].SpecialID;
+	 	    ivideo->SiS_Pr.SiS_CustomT = mycustomttable[i].SpecialID;
 		    printk(KERN_DEBUG "sisfb: Identified [%s %s], special timing applies\n",
 		        mycustomttable[i].vendorName,
 			mycustomttable[i].cardName);
@@ -4479,466 +5069,502 @@
 	}
 
 #ifdef CONFIG_FB_SIS_300
-	/* Mode numbers for 1280x768 are different for 300 and 315 series */
-	if(sisvga_engine == SIS_300_VGA) {
-		sisbios_mode[MODEINDEX_1280x768].mode_no = 0x55;
-		sisbios_mode[MODEINDEX_1280x768+1].mode_no = 0x5a;
-		sisbios_mode[MODEINDEX_1280x768+2].mode_no = 0x5b;
-		sisbios_mode[MODEINDEX_1280x768+3].mode_no = 0x5b;
-	}
-#endif
-
-	sishw_ext.pSR = vmalloc(sizeof(SIS_DSReg) * SR_BUFFER_SIZE);
-	if (sishw_ext.pSR == NULL) {
-		printk(KERN_ERR "sisfb: Fatal error: Allocating SRReg space failed.\n");
-		kfree(sis_fb_info);
-		return -ENODEV;
-	}
-	sishw_ext.pSR[0].jIdx = sishw_ext.pSR[0].jVal = 0xFF;
-
-	sishw_ext.pCR = vmalloc(sizeof(SIS_DSReg) * CR_BUFFER_SIZE);
-	if (sishw_ext.pCR == NULL) {
-	        vfree(sishw_ext.pSR);
-		printk(KERN_ERR "sisfb: Fatal error: Allocating CRReg space failed.\n");
-		kfree(sis_fb_info);
-		return -ENODEV;
-	}
-	sishw_ext.pCR[0].jIdx = sishw_ext.pCR[0].jVal = 0xFF;
-
-#ifdef CONFIG_FB_SIS_300
-	if(sisvga_engine == SIS_300_VGA) {
-		if(!sisvga_enabled) {
-		        /* Mapping Max FB Size for 300 Init */
-			sishw_ext.pjVideoMemoryAddress = ioremap(ivideo.video_base, 0x4000000);
-			if((sisfb_mode_idx < 0) || ((sisbios_mode[sisfb_mode_idx].mode_no) != 0xFF)) {
-				outSISIDXREG(SISSR, IND_SIS_PASSWORD, SIS_PASSWORD);
+	if(ivideo->sisvga_engine == SIS_300_VGA) {
+		if( (!sisvga_enabled)
+#if !defined(__i386__) && !defined(__x86_64__)
+		    		      || (sisfb_resetcard)
+#endif
+		  					   ) {
+			if(ivideo->chip == SIS_300) {
+				sisfb_post_sis300(pdev);
 			}
 		}
-		if(sisfb_get_dram_size_300()) {
-		        vfree(sishw_ext.pSR);
-			vfree(sishw_ext.pCR);
-			printk(KERN_ERR "sisfb: Fatal error: Unable to determine RAM size\n");
-			kfree(sis_fb_info);
-			return -ENODEV;
-		}
 	}
 #endif
 
 #ifdef CONFIG_FB_SIS_315
-	if (sisvga_engine == SIS_315_VGA) {
-		if (!sisvga_enabled) {
-			/* Mapping Max FB Size for 315 Init */
-			sishw_ext.pjVideoMemoryAddress = ioremap(ivideo.video_base, 0x8000000);
-			if((sisfb_mode_idx < 0) || ((sisbios_mode[sisfb_mode_idx].mode_no) != 0xFF)) {
-				outSISIDXREG(SISSR, IND_SIS_PASSWORD, SIS_PASSWORD);
-				sishw_ext.bSkipDramSizing = TRUE;
-				sishw_ext.pSR[0].jIdx = 0x13;
-				sishw_ext.pSR[1].jIdx = 0x14;
-				sishw_ext.pSR[2].jIdx = 0xFF;
-				inSISIDXREG(SISSR, 0x13, sishw_ext.pSR[0].jVal);
-				inSISIDXREG(SISSR, 0x14, sishw_ext.pSR[1].jVal);
-				sishw_ext.pSR[2].jVal = 0xFF;
+	if(ivideo->sisvga_engine == SIS_315_VGA) {
+		if( (!sisvga_enabled)
+#if !defined(__i386__) && !defined(__x86_64__)
+		    		     || (sisfb_resetcard)
+#endif
+		  					  ) {
+			if((ivideo->chip == SIS_315H)   ||
+			   (ivideo->chip == SIS_315)    ||
+			   (ivideo->chip == SIS_315PRO) ||
+			   (ivideo->chip == SIS_330)) {
+				sisfb_post_sis315330(pdev);
 			}
 		}
-		if(sisfb_get_dram_size_315()) {
-			vfree(sishw_ext.pSR);
-			vfree(sishw_ext.pCR);
-			printk(KERN_INFO "sisfb: Fatal error: Unable to determine RAM size.\n");
-			kfree(sis_fb_info);
-			return -ENODEV;
-		}
 	}
 #endif
 
-	if((sisfb_mode_idx < 0) || ((sisbios_mode[sisfb_mode_idx].mode_no) != 0xFF)) { 
+	if(sisfb_get_dram_size(ivideo)) {
+		printk(KERN_INFO "sisfb: Fatal error: Unable to determine RAM size.\n");
+		if(ivideo->bios_abase) vfree(ivideo->bios_abase);
+		pci_set_drvdata(pdev, NULL);
+		kfree(sis_fb_info);
+		return -ENODEV;
+	}
 
+	if((ivideo->sisfb_mode_idx < 0) ||
+	   ((sisbios_mode[ivideo->sisfb_mode_idx].mode_no[ivideo->mni]) != 0xFF)) {
 	        /* Enable PCI_LINEAR_ADDRESSING and MMIO_ENABLE  */
 	        orSISIDXREG(SISSR, IND_SIS_PCI_ADDRESS_SET, (SIS_PCI_ADDR_ENABLE | SIS_MEM_MAP_IO_ENABLE));
-
                 /* Enable 2D accelerator engine */
 	        orSISIDXREG(SISSR, IND_SIS_MODULE_ENABLE, SIS_ENABLE_2D);
-
 	}
 
-	sishw_ext.ulVideoMemorySize = ivideo.video_size;
-
-	if(sisvga_engine == SIS_300_VGA) sisfb_pdc &= 0x3c;
-	if(sisfb_pdc) {
-	    SiS_Pr.PDC = sisfb_pdc;
-	} else {
-	    SiS_Pr.PDC = 0;
+	if(sisfb_pdc != 0xff) {
+	   if(ivideo->sisvga_engine == SIS_300_VGA) sisfb_pdc &= 0x3c;
+	   else				            sisfb_pdc &= 0x1f;
+	   ivideo->SiS_Pr.PDC = sisfb_pdc;
 	}
+#ifdef CONFIG_FB_SIS_315
+	if(ivideo->sisvga_engine == SIS_315_VGA) {
+	   if(sisfb_pdca != 0xff) ivideo->SiS_Pr.PDCA = sisfb_pdca & 0x1f;
+	}
+#endif
 
-	if(!request_mem_region(ivideo.video_base, ivideo.video_size, "sisfb FB")) {
+	if(!request_mem_region(ivideo->video_base, ivideo->video_size, "sisfb FB")) {
 		printk(KERN_ERR "sisfb: Fatal error: Unable to reserve frame buffer memory\n");
 		printk(KERN_ERR "sisfb: Is there another framebuffer driver active?\n");
-		vfree(sishw_ext.pSR);
-		vfree(sishw_ext.pCR);
+		if(ivideo->bios_abase) vfree(ivideo->bios_abase);
+		if(ivideo->bios_vbase) iounmap(ivideo->bios_vbase);
+		pci_set_drvdata(pdev, NULL);
 		kfree(sis_fb_info);
 		return -ENODEV;
 	}
 
-	if(!request_mem_region(ivideo.mmio_base, sisfb_mmio_size, "sisfb MMIO")) {
+	if(!request_mem_region(ivideo->mmio_base, ivideo->mmio_size, "sisfb MMIO")) {
 		printk(KERN_ERR "sisfb: Fatal error: Unable to reserve MMIO region\n");
-		release_mem_region(ivideo.video_base, ivideo.video_size);
-		vfree(sishw_ext.pSR);
-		vfree(sishw_ext.pCR);
+		release_mem_region(ivideo->video_base, ivideo->video_size);
+		if(ivideo->bios_abase) vfree(ivideo->bios_abase);
+		if(ivideo->bios_vbase) iounmap(ivideo->bios_vbase);
+		pci_set_drvdata(pdev, NULL);
 		kfree(sis_fb_info);
 		return -ENODEV;
 	}
 
-	ivideo.video_vbase = sishw_ext.pjVideoMemoryAddress = ioremap(ivideo.video_base, ivideo.video_size);
-	if(!ivideo.video_vbase) {
+	ivideo->video_vbase = (unsigned long)ioremap(ivideo->video_base, ivideo->video_size);
+	ivideo->sishw_ext.pjVideoMemoryAddress = (unsigned char *)ivideo->video_vbase;
+	if(!ivideo->video_vbase) {
 	   	printk(KERN_ERR "sisfb: Fatal error: Unable to map frame buffer memory\n");
-	   	release_mem_region(ivideo.video_base, ivideo.video_size);
-	   	release_mem_region(ivideo.mmio_base, sisfb_mmio_size);
-	   	vfree(sishw_ext.pSR);
-	   	vfree(sishw_ext.pCR);
+	   	release_mem_region(ivideo->video_base, ivideo->video_size);
+	   	release_mem_region(ivideo->mmio_base, ivideo->mmio_size);
+		if(ivideo->bios_abase) vfree(ivideo->bios_abase);
+		if(ivideo->bios_vbase) iounmap(ivideo->bios_vbase);
+		pci_set_drvdata(pdev, NULL);
 	   	kfree(sis_fb_info);
 	   	return -ENODEV;
 	}
 
-	ivideo.mmio_vbase = ioremap(ivideo.mmio_base, sisfb_mmio_size);
-	if(!ivideo.mmio_vbase) {
+	ivideo->mmio_vbase = (unsigned long)ioremap(ivideo->mmio_base, ivideo->mmio_size);
+	if(!ivideo->mmio_vbase) {
 	   	printk(KERN_ERR "sisfb: Fatal error: Unable to map MMIO region\n");
-	   	iounmap(ivideo.video_vbase);
-	   	release_mem_region(ivideo.video_base, ivideo.video_size);
-	   	release_mem_region(ivideo.mmio_base, sisfb_mmio_size);
-	   	vfree(sishw_ext.pSR);
-	   	vfree(sishw_ext.pCR);
+	   	iounmap((void *)ivideo->video_vbase);
+	   	release_mem_region(ivideo->video_base, ivideo->video_size);
+	   	release_mem_region(ivideo->mmio_base, ivideo->mmio_size);
+		if(ivideo->bios_abase) vfree(ivideo->bios_abase);
+		if(ivideo->bios_vbase) iounmap(ivideo->bios_vbase);
+		pci_set_drvdata(pdev, NULL);
 	   	kfree(sis_fb_info);
 	   	return -ENODEV;
 	}
 
-	printk(KERN_INFO "sisfb: Framebuffer at 0x%lx, mapped to 0x%p, size %dk\n",
-	       	ivideo.video_base, ivideo.video_vbase, ivideo.video_size / 1024);
+	printk(KERN_INFO "sisfb: Framebuffer at 0x%lx, mapped to 0x%lx, size %ldk\n",
+	       	ivideo->video_base, ivideo->video_vbase, ivideo->video_size / 1024);
 
-	printk(KERN_INFO "sisfb: MMIO at 0x%lx, mapped to 0x%p, size %ldk\n",
-	       	ivideo.mmio_base, ivideo.mmio_vbase, sisfb_mmio_size / 1024);
+	printk(KERN_INFO "sisfb: MMIO at 0x%lx, mapped to 0x%lx, size %ldk\n",
+	       	ivideo->mmio_base, ivideo->mmio_vbase, ivideo->mmio_size / 1024);
 
-	if(sisfb_heap_init()) {
+	if((ivideo->havenoheap = sisfb_heap_init(ivideo))) {
 		printk(KERN_WARNING "sisfb: Failed to initialize offscreen memory heap\n");
 	}
 
-	ivideo.mtrr = (unsigned int) 0;
+	/* Used for clearing the screen only, therefore respect our mem limit */
+	ivideo->sishw_ext.ulVideoMemorySize = ivideo->sisfb_mem;
 
-	ivideo.vbflags = 0;
+	ivideo->mtrr = 0;
 
-	if((sisfb_mode_idx < 0) || ((sisbios_mode[sisfb_mode_idx].mode_no) != 0xFF)) {
+	ivideo->vbflags = 0;
+	ivideo->lcddefmodeidx = DEFAULT_LCDMODE;
+	ivideo->tvdefmodeidx  = DEFAULT_TVMODE;
+	ivideo->defmodeidx    = DEFAULT_MODE;
 
-		sishw_ext.ujVBChipID = VB_CHIP_UNKNOWN;
-		sishw_ext.Is301BDH = FALSE;
-		sishw_ext.usExternalChip = 0;
+	ivideo->newrom = SiSDetermineROMLayout661(&ivideo->SiS_Pr, &ivideo->sishw_ext);
 
-		sisfb_sense_crt1();
+	if((ivideo->sisfb_mode_idx < 0) ||
+	   ((sisbios_mode[ivideo->sisfb_mode_idx].mode_no[ivideo->mni]) != 0xFF)) {
 
-		sisfb_get_VB_type();
+		sisfb_sense_crt1(ivideo);
 
-		if(ivideo.vbflags & VB_VIDEOBRIDGE) {
-			sisfb_detect_VB_connect();
+		sisfb_get_VB_type(ivideo);
+
+		if(ivideo->vbflags & VB_VIDEOBRIDGE) {
+			sisfb_detect_VB_connect(ivideo);
 		}
 
-		ivideo.currentvbflags = ivideo.vbflags & VB_VIDEOBRIDGE;
+		ivideo->currentvbflags = ivideo->vbflags & (VB_VIDEOBRIDGE | TV_STANDARD);
 
-		if(ivideo.vbflags & VB_VIDEOBRIDGE) {
-		   if(sisfb_crt2type != -1) {
-		      if((sisfb_crt2type == CRT2_LCD) && (ivideo.vbflags & CRT2_LCD)) {
-		         ivideo.currentvbflags |= CRT2_LCD;
-		      } else if(sisfb_crt2type != CRT2_LCD) {
-		         ivideo.currentvbflags |= sisfb_crt2type;
+		if(ivideo->vbflags & VB_VIDEOBRIDGE) {
+		   if(ivideo->sisfb_crt2type != -1) {
+		      if((ivideo->sisfb_crt2type == CRT2_LCD) && (ivideo->vbflags & CRT2_LCD)) {
+		         ivideo->currentvbflags |= CRT2_LCD;
+		      } else if(ivideo->sisfb_crt2type != CRT2_LCD) {
+		         ivideo->currentvbflags |= ivideo->sisfb_crt2type;
 		      }
 		   } else {
 		      /* Chrontel 700x TV detection often unreliable, therefore use a
 		       * different default order on such machines
 		       */
-		      if((sisvga_engine == SIS_300_VGA) && (ivideo.vbflags & VB_CHRONTEL)) {
-		         if(ivideo.vbflags & CRT2_LCD)      ivideo.currentvbflags |= CRT2_LCD;
-		         else if(ivideo.vbflags & CRT2_TV)  ivideo.currentvbflags |= CRT2_TV;
-		         else if(ivideo.vbflags & CRT2_VGA) ivideo.currentvbflags |= CRT2_VGA;
+		      if((ivideo->sisvga_engine == SIS_300_VGA) && (ivideo->vbflags & VB_CHRONTEL)) {
+		         if(ivideo->vbflags & CRT2_LCD)      ivideo->currentvbflags |= CRT2_LCD;
+		         else if(ivideo->vbflags & CRT2_TV)  ivideo->currentvbflags |= CRT2_TV;
+		         else if(ivideo->vbflags & CRT2_VGA) ivideo->currentvbflags |= CRT2_VGA;
 		      } else {
-		         if(ivideo.vbflags & CRT2_TV)       ivideo.currentvbflags |= CRT2_TV;
-		         else if(ivideo.vbflags & CRT2_LCD) ivideo.currentvbflags |= CRT2_LCD;
-		         else if(ivideo.vbflags & CRT2_VGA) ivideo.currentvbflags |= CRT2_VGA;
+		         if(ivideo->vbflags & CRT2_TV)       ivideo->currentvbflags |= CRT2_TV;
+		         else if(ivideo->vbflags & CRT2_LCD) ivideo->currentvbflags |= CRT2_LCD;
+		         else if(ivideo->vbflags & CRT2_VGA) ivideo->currentvbflags |= CRT2_VGA;
 		      }
 		   }
 		}
 
-		if(ivideo.vbflags & CRT2_LCD) {
-		   inSISIDXREG(SISCR, IND_SIS_LCD_PANEL, reg);
+		if(ivideo->vbflags & CRT2_LCD) {
+		   inSISIDXREG(SISCR, 0x36, reg);
 		   reg &= 0x0f;
-		   if(sisvga_engine == SIS_300_VGA) {
-		      sishw_ext.ulCRT2LCDType = sis300paneltype[reg];
+		   if(ivideo->sisvga_engine == SIS_300_VGA) {
+		      ivideo->sishw_ext.ulCRT2LCDType = sis300paneltype[reg];
+		   } else if(ivideo->chip >= SIS_661) {
+		      ivideo->sishw_ext.ulCRT2LCDType = sis661paneltype[reg];
 		   } else {
-		      sishw_ext.ulCRT2LCDType = sis310paneltype[reg];
+		      ivideo->sishw_ext.ulCRT2LCDType = sis310paneltype[reg];
+		      if((ivideo->chip == SIS_550) && (sisfb_fstn)) {
+		         if((ivideo->sishw_ext.ulCRT2LCDType != LCD_640x480_2) &&
+			    (ivideo->sishw_ext.ulCRT2LCDType != LCD_640x480_3)) {
+		      	    ivideo->sishw_ext.ulCRT2LCDType = LCD_320x480;
+			 }
+		      }
+		   }
+		   if(ivideo->sishw_ext.ulCRT2LCDType == LCD_UNKNOWN) {
+		      ivideo->sishw_ext.ulCRT2LCDType = LCD_1024x768;
+		      printk(KERN_DEBUG "sisfb: Illegal panel ID (%02x), assuming 1024x768\n", reg);
+		   }
+		   for(i = 0; i < SIS_LCD_NUMBER; i++) {
+		      if(ivideo->sishw_ext.ulCRT2LCDType == sis_lcd_data[i].lcdtype) {
+		         ivideo->lcdxres = sis_lcd_data[i].xres;
+			 ivideo->lcdyres = sis_lcd_data[i].yres;
+			 ivideo->lcddefmodeidx = sis_lcd_data[i].default_mode_idx;
+			 break;
+		      }
 		   }
+		   if(ivideo->SiS_Pr.SiS_CustomT == CUT_BARCO1366) {
+	   		ivideo->lcdxres = 1360; ivideo->lcdyres = 1024; ivideo->lcddefmodeidx = 99;
+		   } else if(ivideo->SiS_Pr.SiS_CustomT == CUT_PANEL848) {
+	   		ivideo->lcdxres =  848; ivideo->lcdyres =  480; ivideo->lcddefmodeidx = 47;
+		   }
+		   printk(KERN_DEBUG "sisfb: Detected %dx%d flat panel\n",
+		   		ivideo->lcdxres, ivideo->lcdyres);
 		}
-		
-		sisfb_detectedpdc = 0;
 
 #ifdef CONFIG_FB_SIS_300
                 /* Save the current PanelDelayCompensation if the LCD is currently used */
-		if(sisvga_engine == SIS_300_VGA) {
-	           if(ivideo.vbflags & (VB_LVDS | VB_30xBDH)) {
+		if(ivideo->sisvga_engine == SIS_300_VGA) {
+	           if(ivideo->vbflags & (VB_LVDS | VB_30xBDH)) {
 		       int tmp;
 		       inSISIDXREG(SISCR,0x30,tmp);
 		       if(tmp & 0x20) {
 		          /* Currently on LCD? If yes, read current pdc */
-		          inSISIDXREG(SISPART1,0x13,sisfb_detectedpdc);
-			  sisfb_detectedpdc &= 0x3c;
-			  if(SiS_Pr.PDC == 0) {
+		          inSISIDXREG(SISPART1,0x13,ivideo->detectedpdc);
+			  ivideo->detectedpdc &= 0x3c;
+			  if(ivideo->SiS_Pr.PDC == -1) {
 			     /* Let option override detection */
-			     SiS_Pr.PDC = sisfb_detectedpdc;
+			     ivideo->SiS_Pr.PDC = ivideo->detectedpdc;
 			  }
-			  printk(KERN_INFO
-			         "sisfb: Detected LCD PanelDelayCompensation %d\n",
-  			         sisfb_detectedpdc);
+			  printk(KERN_INFO "sisfb: Detected LCD PDC 0x%02x\n",
+  			         ivideo->detectedpdc);
 		       }
-		       if((SiS_Pr.PDC) && (SiS_Pr.PDC != sisfb_detectedpdc)) {
-		          printk(KERN_INFO
-			         "sisfb: Using LCD PanelDelayCompensation %d\n",
-				 SiS_Pr.PDC);
+		       if((ivideo->SiS_Pr.PDC != -1) && (ivideo->SiS_Pr.PDC != ivideo->detectedpdc)) {
+		          printk(KERN_INFO "sisfb: Using LCD PDC 0x%02x\n",
+				 ivideo->SiS_Pr.PDC);
 		       }
 	           }
 		}
 #endif
 
-	        sisfb_detectedlcda = 0xff;
-
 #ifdef CONFIG_FB_SIS_315
+		if(ivideo->sisvga_engine == SIS_315_VGA) {
+
+		   /* Try to find about LCDA */
+		   if(ivideo->vbflags & (VB_301C | VB_302B | VB_301LV | VB_302LV | VB_302ELV)) {
+		      int tmp;
+		      inSISIDXREG(SISPART1,0x13,tmp);
+		      if(tmp & 0x04) {
+		         ivideo->SiS_Pr.SiS_UseLCDA = TRUE;
+		         ivideo->detectedlcda = 0x03;
+		      }
+	           }
 
-		if(sisvga_engine == SIS_315_VGA) {
 		   /* Save PDC */
-		   if(ivideo.vbflags & (VB_301LV | VB_302LV | VB_302ELV)) {
+		   if(ivideo->vbflags & (VB_301LV | VB_302LV | VB_302ELV)) {
 		      int tmp;
 		      inSISIDXREG(SISCR,0x30,tmp);
-		      if(tmp & 0x20) {
+		      if((tmp & 0x20) || (ivideo->detectedlcda != 0xff)) {
 		         /* Currently on LCD? If yes, read current pdc */
-		         inSISIDXREG(SISPART1,0x2D,sisfb_detectedpdc);
-			 if(SiS_Pr.PDC == 0) {
-			    /* Let option override detection */
-			    SiS_Pr.PDC = sisfb_detectedpdc;
+			 u8 pdc;
+		         inSISIDXREG(SISPART1,0x2D,pdc);
+			 ivideo->detectedpdc  = (pdc & 0x0f) << 1;
+			 ivideo->detectedpdca = (pdc & 0xf0) >> 3;
+			 inSISIDXREG(SISPART1,0x35,pdc);
+			 ivideo->detectedpdc |= ((pdc >> 7) & 0x01);
+			 inSISIDXREG(SISPART1,0x20,pdc);
+			 ivideo->detectedpdca |= ((pdc >> 6) & 0x01);
+			 if(ivideo->newrom) {
+			    /* New ROM invalidates other PDC resp. */
+			    if(ivideo->detectedlcda != 0xff) {
+			       ivideo->detectedpdc = 0xff;
+			    } else {
+			       ivideo->detectedpdca = 0xff;
+			    }
+			 }
+			 if(ivideo->SiS_Pr.PDC == -1) {
+			    if(ivideo->detectedpdc != 0xff) {
+			       ivideo->SiS_Pr.PDC = ivideo->detectedpdc;
+			    }
+			 }
+			 if(ivideo->SiS_Pr.PDCA == -1) {
+			    if(ivideo->detectedpdca != 0xff) {
+			       ivideo->SiS_Pr.PDCA = ivideo->detectedpdca;
+			    }
+			 }
+			 if(ivideo->detectedpdc != 0xff) {
+			    printk(KERN_INFO
+			         "sisfb: Detected LCD PDC 0x%02x (for LCD=CRT2)\n",
+  			          ivideo->detectedpdc);
+			 }
+			 if(ivideo->detectedpdca != 0xff) {
+			    printk(KERN_INFO
+			         "sisfb: Detected LCD PDC1 0x%02x (for LCD=CRT1)\n",
+  			          ivideo->detectedpdca);
 			 }
-			 printk(KERN_INFO
-			        "sisfb: Detected LCD PanelDelayCompensation %d\n",
-  			         sisfb_detectedpdc);
-		      }
-		      if((SiS_Pr.PDC) && (SiS_Pr.PDC != sisfb_detectedpdc)) {
-		         printk(KERN_INFO
-			         "sisfb: Using LCD PanelDelayCompensation %d\n",
-				 SiS_Pr.PDC);
 		      }
+
 		      /* Save EMI */
-		      if(ivideo.vbflags & (VB_302LV | VB_302ELV)) {
-		         inSISIDXREG(SISPART4,0x30,SiS_Pr.EMI_30);
-			 inSISIDXREG(SISPART4,0x31,SiS_Pr.EMI_31);
-			 inSISIDXREG(SISPART4,0x32,SiS_Pr.EMI_32);
-			 inSISIDXREG(SISPART4,0x33,SiS_Pr.EMI_33);
-			 SiS_Pr.HaveEMI = TRUE;
-			 if(tmp & 0x20) SiS_Pr.HaveEMILCD = TRUE;
+		      if(ivideo->vbflags & (VB_302LV | VB_302ELV)) {
+		         inSISIDXREG(SISPART4,0x30,ivideo->SiS_Pr.EMI_30);
+			 inSISIDXREG(SISPART4,0x31,ivideo->SiS_Pr.EMI_31);
+			 inSISIDXREG(SISPART4,0x32,ivideo->SiS_Pr.EMI_32);
+			 inSISIDXREG(SISPART4,0x33,ivideo->SiS_Pr.EMI_33);
+			 ivideo->SiS_Pr.HaveEMI = TRUE;
+			 if((tmp & 0x20) || (ivideo->detectedlcda != 0xff)) {
+			  	ivideo->SiS_Pr.HaveEMILCD = TRUE;
+			 }
 		      }
 		   }
 
-		   /* Try to find about LCDA */
-		   if(ivideo.vbflags & (VB_301C | VB_302B | VB_301LV | VB_302LV | VB_302ELV)) {
-		      int tmp;
-		      inSISIDXREG(SISCR,0x34,tmp);
-		      if((tmp <= 0x13) || (tmp == 0xff)) {
-		         /* Currently on LCDA? (Some BIOSes leave CR38) */
-		         inSISIDXREG(SISCR,0x38,tmp);
-			 if((tmp & 0x03) == 0x03)  SiS_Pr.SiS_UseLCDA = TRUE;
-			 else {
-			    /* Currently on LCDA? (Some newer BIOSes set D0 in CR35) */
-			    inSISIDXREG(SISCR,0x35,tmp);
-			    if(tmp & 0x01) SiS_Pr.SiS_UseLCDA = TRUE;
-			    else {
-			       /* Currently on LCD? If so, we can find out
-			        * by peeking the mode register
-				*/
-			       inSISIDXREG(SISCR,0x30,tmp);
-			       if(tmp & 0x20) {
-			          inSISIDXREG(SISPART1,0x13,tmp);
-				  if(tmp & 0x04) SiS_Pr.SiS_UseLCDA = TRUE;
-			       }
-			    }
-			 }
+		   /* Let user override detected PDCs (all bridges) */
+		   if(ivideo->vbflags & (VB_301B | VB_301C | VB_301LV | VB_302LV | VB_302ELV)) {
+		      if((ivideo->SiS_Pr.PDC != -1) && (ivideo->SiS_Pr.PDC != ivideo->detectedpdc)) {
+		         printk(KERN_INFO "sisfb: Using LCD PDC 0x%02x (for LCD=CRT2)\n",
+				 ivideo->SiS_Pr.PDC);
 		      }
-		      if(SiS_Pr.SiS_UseLCDA) {
-		         sisfb_detectedlcda = 0x03;
-		         printk(KERN_DEBUG
-			        "sisfb: Bridge uses LCDA for low resolution and text modes\n");
+		      if((ivideo->SiS_Pr.PDCA != -1) && (ivideo->SiS_Pr.PDCA != ivideo->detectedpdca)) {
+		         printk(KERN_INFO "sisfb: Using LCD PDC1 0x%02x (for LCD=CRT1)\n",
+				 ivideo->SiS_Pr.PDCA);
 		      }
-	          }
+		   }
+
 		}
 #endif
 
-		if (!sisfb_crt1off) {
-		   	sisfb_handle_ddc(&sisfb_thismonitor, 0);
+		if(!ivideo->sisfb_crt1off) {
+		   	sisfb_handle_ddc(ivideo, &ivideo->sisfb_thismonitor, 0);
 		} else {
-		   	if ((ivideo.vbflags & (VB_301|VB_301B|VB_301C|VB_302B)) &&
-		      	    (ivideo.vbflags & (CRT2_VGA | CRT2_LCD))) {
-		      		sisfb_handle_ddc(&sisfb_thismonitor, 1);
+		   	if((ivideo->vbflags & (VB_301|VB_301B|VB_301C|VB_302B)) &&
+		      	   (ivideo->vbflags & (CRT2_VGA | CRT2_LCD))) {
+		      		sisfb_handle_ddc(ivideo, &ivideo->sisfb_thismonitor, 1);
 		   	}
 		}
 
-		if (sisfb_mode_idx >= 0)
-			sisfb_mode_idx = sisfb_validate_mode(sisfb_mode_idx, ivideo.currentvbflags);
+		if(ivideo->sisfb_mode_idx >= 0) {
+			int bu = ivideo->sisfb_mode_idx;
+			ivideo->sisfb_mode_idx = sisfb_validate_mode(ivideo,
+					ivideo->sisfb_mode_idx, ivideo->currentvbflags);
+			if(bu != ivideo->sisfb_mode_idx) {
+				printk(KERN_ERR "Mode %dx%dx%d failed validation\n",
+					sisbios_mode[bu].xres,
+					sisbios_mode[bu].yres,
+					sisbios_mode[bu].bpp);
+			}
+		}
 
-		if (sisfb_mode_idx < 0) {
-			switch (ivideo.currentvbflags & VB_DISPTYPE_DISP2) {
+		if(ivideo->sisfb_mode_idx < 0) {
+			switch(ivideo->currentvbflags & VB_DISPTYPE_DISP2) {
 			   case CRT2_LCD:
-				sisfb_mode_idx = DEFAULT_LCDMODE;
+				ivideo->sisfb_mode_idx = ivideo->lcddefmodeidx;
 				break;
 			   case CRT2_TV:
-				sisfb_mode_idx = DEFAULT_TVMODE;
+				ivideo->sisfb_mode_idx = ivideo->tvdefmodeidx;
 				break;
 			   default:
-				sisfb_mode_idx = DEFAULT_MODE;
+				ivideo->sisfb_mode_idx = ivideo->defmodeidx;
 				break;
 			}
 		}
 
-		sisfb_mode_no = sisbios_mode[sisfb_mode_idx].mode_no;
+		ivideo->mode_no = sisbios_mode[ivideo->sisfb_mode_idx].mode_no[ivideo->mni];
 
-		if (ivideo.refresh_rate != 0)
-			sisfb_search_refresh_rate(ivideo.refresh_rate, sisfb_mode_idx);
+		if(ivideo->refresh_rate != 0) {
+			sisfb_search_refresh_rate(ivideo, ivideo->refresh_rate, ivideo->sisfb_mode_idx);
+		}
 
-		if (sisfb_rate_idx == 0) {
-			sisfb_rate_idx = sisbios_mode[sisfb_mode_idx].rate_idx;
-			ivideo.refresh_rate = 60;
+		if(ivideo->rate_idx == 0) {
+			ivideo->rate_idx = sisbios_mode[ivideo->sisfb_mode_idx].rate_idx;
+			ivideo->refresh_rate = 60;
 		}
 
-		if (sisfb_thismonitor.datavalid) {
-			if(!sisfb_verify_rate(&sisfb_thismonitor, sisfb_mode_idx,
-			                      sisfb_rate_idx, ivideo.refresh_rate)) {
+		if(ivideo->sisfb_thismonitor.datavalid) {
+			if(!sisfb_verify_rate(ivideo, &ivideo->sisfb_thismonitor, ivideo->sisfb_mode_idx,
+			                      ivideo->rate_idx, ivideo->refresh_rate)) {
 				printk(KERN_INFO "sisfb: WARNING: Refresh rate exceeds monitor specs!\n");
 			}
 		}
 
-		ivideo.video_bpp = sisbios_mode[sisfb_mode_idx].bpp;
-		ivideo.video_vwidth = ivideo.video_width = sisbios_mode[sisfb_mode_idx].xres;
-		ivideo.video_vheight = ivideo.video_height = sisbios_mode[sisfb_mode_idx].yres;
-		ivideo.org_x = ivideo.org_y = 0;
-		ivideo.video_linelength = ivideo.video_width * (ivideo.video_bpp >> 3);
+		ivideo->video_bpp = sisbios_mode[ivideo->sisfb_mode_idx].bpp;
+		ivideo->video_width = sisbios_mode[ivideo->sisfb_mode_idx].xres;
+		ivideo->video_height = sisbios_mode[ivideo->sisfb_mode_idx].yres;
 
-		sisfb_set_vparms();
+		sisfb_set_vparms(ivideo);
 		
 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)	
 
 		/* ---------------- For 2.4: Now switch the mode ------------------ */		
 		
 		printk(KERN_INFO "sisfb: Mode is %dx%dx%d (%dHz)\n",
-	       		ivideo.video_width, ivideo.video_height, ivideo.video_bpp,
-			ivideo.refresh_rate);
+	       		ivideo->video_width, ivideo->video_height, ivideo->video_bpp,
+			ivideo->refresh_rate);
 
-		sisfb_pre_setmode();
+		sisfb_pre_setmode(ivideo);
 
-		if (SiSSetMode(&SiS_Pr, &sishw_ext, sisfb_mode_no) == 0) {
+		if(SiSSetMode(&ivideo->SiS_Pr, &ivideo->sishw_ext, ivideo->mode_no) == 0) {
 			printk(KERN_ERR "sisfb: Fatal error: Setting mode[0x%x] failed\n",
-				sisfb_mode_no);
-			vfree(sishw_ext.pSR);
-			vfree(sishw_ext.pCR);
-			release_mem_region(ivideo.video_base, ivideo.video_size);
-			release_mem_region(ivideo.mmio_base, sisfb_mmio_size);
+									ivideo->mode_no);
+			iounmap((void *)ivideo->video_vbase);
+			iounmap((void *)ivideo->mmio_vbase);
+			release_mem_region(ivideo->video_base, ivideo->video_size);
+			release_mem_region(ivideo->mmio_base, ivideo->mmio_size);
+			if(ivideo->bios_abase) vfree(ivideo->bios_abase);
+			if(ivideo->bios_vbase) iounmap(ivideo->bios_vbase);
+			pci_set_drvdata(pdev, NULL);
 			kfree(sis_fb_info);
 			return -EINVAL;
 		}
 
 		outSISIDXREG(SISSR, IND_SIS_PASSWORD, SIS_PASSWORD);
 
-		sisfb_post_setmode();
-
-		ivideo.accel = 0;
-		if(sisfb_accel) {
-		   ivideo.accel = -1;
-		   default_var.accel_flags |= FB_ACCELF_TEXT;
-		   sisfb_initaccel();
-		}
+		sisfb_post_setmode(ivideo);
 
 		/* Maximize regardless of sisfb_max at startup */
-		default_var.yres_virtual = 32767;
-		sisfb_crtc_to_var(&default_var);
+		ivideo->default_var.yres_virtual = 32767;
+
+		/* Force reset of x virtual in crtc_to_var */
+		ivideo->default_var.xres_virtual = 0;
+
+		sisfb_crtc_to_var(ivideo, &ivideo->default_var);
+
+		sisfb_calc_pitch(ivideo, &ivideo->default_var);
+		sisfb_set_pitch(ivideo);
+
+		ivideo->accel = 0;
+		if(ivideo->sisfb_accel) {
+		   ivideo->accel = -1;
+		   ivideo->default_var.accel_flags |= FB_ACCELF_TEXT;
+		}
+		sisfb_initaccel(ivideo);
 		
-		sis_fb_info->node = -1;
+		sis_fb_info->node  = -1;
 		sis_fb_info->flags = FBINFO_FLAG_DEFAULT;
-		sis_fb_info->blank = &sisfb_blank;
 		sis_fb_info->fbops = &sisfb_ops;
+		sis_fb_info->disp  = &ivideo->sis_disp;
+		sis_fb_info->blank = &sisfb_blank;
 		sis_fb_info->switch_con = &sisfb_switch;
-		sis_fb_info->updatevar = &sisfb_update_var;
-		sis_fb_info->changevar = NULL;
-		sis_fb_info->disp = &sis_disp;
+		sis_fb_info->updatevar  = &sisfb_update_var;
+		sis_fb_info->changevar  = NULL;
 		strcpy(sis_fb_info->fontname, sisfb_fontname);
 
-		sisfb_set_disp(-1, &default_var, sis_fb_info);
+		sisfb_set_disp(-1, &ivideo->default_var, sis_fb_info);
 
-#else		/* --------- For 2.5: Setup a somewhat sane default var ------------ */
+#else		/* --------- For 2.6: Setup a somewhat sane default var ------------ */
 
 		printk(KERN_INFO "sisfb: Default mode is %dx%dx%d (%dHz)\n",
-	       		ivideo.video_width, ivideo.video_height, ivideo.video_bpp,
-			ivideo.refresh_rate);
+	       		ivideo->video_width, ivideo->video_height, ivideo->video_bpp,
+			ivideo->refresh_rate);
 
-		default_var.xres = default_var.xres_virtual = ivideo.video_width;
-		default_var.yres = default_var.yres_virtual = ivideo.video_height;
-		default_var.bits_per_pixel = ivideo.video_bpp;
+		ivideo->default_var.xres = ivideo->default_var.xres_virtual = ivideo->video_width;
+		ivideo->default_var.yres = ivideo->default_var.yres_virtual = ivideo->video_height;
+		ivideo->default_var.bits_per_pixel = ivideo->video_bpp;
 
-		sisfb_bpp_to_var(&default_var);
+		sisfb_bpp_to_var(ivideo, &ivideo->default_var);
 		
-		default_var.pixclock = (u32) (1000000000 /
-				sisfb_mode_rate_to_dclock(&SiS_Pr, &sishw_ext,
-						sisfb_mode_no, sisfb_rate_idx));
+		ivideo->default_var.pixclock = (u32) (1000000000 /
+				sisfb_mode_rate_to_dclock(&ivideo->SiS_Pr, &ivideo->sishw_ext,
+						ivideo->mode_no, ivideo->rate_idx));
 						
-		if(sisfb_mode_rate_to_ddata(&SiS_Pr, &sishw_ext,
-			 sisfb_mode_no, sisfb_rate_idx,
-			 &default_var.left_margin, &default_var.right_margin, 
-			 &default_var.upper_margin, &default_var.lower_margin,
-			 &default_var.hsync_len, &default_var.vsync_len,
-			 &default_var.sync, &default_var.vmode)) {
-		   if((default_var.vmode & FB_VMODE_MASK) == FB_VMODE_DOUBLE) {
-		      default_var.pixclock <<= 1;
+		if(sisfb_mode_rate_to_ddata(&ivideo->SiS_Pr, &ivideo->sishw_ext,
+			 	ivideo->mode_no, ivideo->rate_idx, &ivideo->default_var)) {
+		   if((ivideo->default_var.vmode & FB_VMODE_MASK) == FB_VMODE_DOUBLE) {
+		      ivideo->default_var.pixclock <<= 1;
 	   	   }
 	        }
 
-		ivideo.accel = 0;
-		if(sisfb_accel) {
-		   ivideo.accel = -1;
-		   default_var.accel_flags |= FB_ACCELF_TEXT;
-		   sisfb_initaccel();
-		}
-
-		if(sisfb_ypan) {
+		if(ivideo->sisfb_ypan) {
 		   /* Maximize regardless of sisfb_max at startup */
-	    	   default_var.yres_virtual =
-				ivideo.heapstart / (default_var.xres * (default_var.bits_per_pixel >> 3));
-		   if(default_var.yres_virtual > 32767) default_var.yres_virtual = 32767;
-	    	   if(default_var.yres_virtual <= default_var.yres) {
-	              default_var.yres_virtual = default_var.yres;
+	    	   ivideo->default_var.yres_virtual = sisfb_calc_maxyres(ivideo, &ivideo->default_var);
+	    	   if(ivideo->default_var.yres_virtual < ivideo->default_var.yres) {
+	              ivideo->default_var.yres_virtual = ivideo->default_var.yres;
 	    	   }
 		}
 
+		sisfb_calc_pitch(ivideo, &ivideo->default_var);
+
+		ivideo->accel = 0;
+		if(ivideo->sisfb_accel) {
+		   ivideo->accel = -1;
+#ifdef STUPID_ACCELF_TEXT_SHIT
+		   ivideo->default_var.accel_flags |= FB_ACCELF_TEXT;
+#endif
+		}
+		sisfb_initaccel(ivideo);
+
+#if defined(FBINFO_HWACCEL_DISABLED) && defined(FBINFO_HWACCEL_XPAN)
+		sis_fb_info->flags = FBINFO_DEFAULT 		|
+				     FBINFO_HWACCEL_YPAN 	|
+				     FBINFO_HWACCEL_XPAN 	|
+				     FBINFO_HWACCEL_COPYAREA 	|
+				     FBINFO_HWACCEL_FILLRECT 	|
+				     ((ivideo->accel) ? 0 : FBINFO_HWACCEL_DISABLED);
+#else
 		sis_fb_info->flags = FBINFO_FLAG_DEFAULT;
-		sis_fb_info->var = default_var;
-		sis_fb_info->fix = sisfb_fix;
-		sis_fb_info->par = &ivideo;
-		sis_fb_info->screen_base = ivideo.video_vbase;
-		sis_fb_info->fbops = &sisfb_ops;
-#ifdef NEWFBDEV
-		sis_fb_info->class_dev.dev = &pdev->dev;
 #endif
+		sis_fb_info->var = ivideo->default_var;
+		sis_fb_info->fix = ivideo->sisfb_fix;
+		sis_fb_info->screen_base = (char *)ivideo->video_vbase;
+		sis_fb_info->fbops = &sisfb_ops;
+
 		sisfb_get_fix(&sis_fb_info->fix, -1, sis_fb_info);
-		sis_fb_info->pseudo_palette = pseudo_palette;
+		sis_fb_info->pseudo_palette = ivideo->pseudo_palette;
 		
 		fb_alloc_cmap(&sis_fb_info->cmap, 256 , 0);
-#endif
+#endif		/* 2.6 */
 
-		printk(KERN_INFO "sisfb: Initial vbflags 0x%lx\n", ivideo.vbflags);
+		printk(KERN_DEBUG "sisfb: Initial vbflags 0x%lx\n", (unsigned long)ivideo->vbflags);
 
 #ifdef CONFIG_MTRR
-		ivideo.mtrr = mtrr_add((unsigned int) ivideo.video_base,
-				(unsigned int) ivideo.video_size,
-				MTRR_TYPE_WRCOMB, 1);
-		if(ivideo.mtrr) {
-			printk(KERN_INFO "sisfb: Added MTRRs\n");
+		ivideo->mtrr = mtrr_add(ivideo->video_base, ivideo->video_size,
+					MTRR_TYPE_WRCOMB, 1);
+		if(!ivideo->mtrr) {
+			printk(KERN_DEBUG "sisfb: Failed to add MTRRs\n");
 		}
-
 #endif
 
 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
@@ -4946,39 +5572,157 @@
 #endif
 
 		if(register_framebuffer(sis_fb_info) < 0) {
-			vfree(sishw_ext.pSR);
-			vfree(sishw_ext.pCR);
-			release_mem_region(ivideo.video_base, ivideo.video_size);
-			release_mem_region(ivideo.mmio_base, sisfb_mmio_size);
 			printk(KERN_ERR "sisfb: Fatal error: Failed to register framebuffer\n");
+			iounmap((void *)ivideo->video_vbase);
+			iounmap((void *)ivideo->mmio_vbase);
+			release_mem_region(ivideo->video_base, ivideo->video_size);
+			release_mem_region(ivideo->mmio_base, ivideo->mmio_size);
+			if(ivideo->bios_abase) vfree(ivideo->bios_abase);
+			if(ivideo->bios_vbase) iounmap(ivideo->bios_vbase);
+			pci_set_drvdata(pdev, NULL);
 			kfree(sis_fb_info);
 			return -EINVAL;
 		}
 
-		sisfb_registered = 1;			
+		ivideo->registered = 1;
 
-		printk(KERN_DEBUG "sisfb: Installed SISFB_GET_INFO ioctl (%x)\n", SISFB_GET_INFO);
-		printk(KERN_DEBUG "sisfb: Installed SISFB_GET_VBRSTATUS ioctl (%x)\n", SISFB_GET_VBRSTATUS);
-		
-		printk(KERN_INFO "sisfb: 2D acceleration is %s, scrolling mode %s\n",
-		     sisfb_accel ? "enabled" : "disabled",
-		     sisfb_ypan  ? (sisfb_max ? "ypan (auto-max)" : "ypan (no auto-max)") : "redraw");
+		/* Enlist us */
+		ivideo->next = card_list;
+		card_list = ivideo;
 
+#ifdef SIS_CONFIG_COMPAT
+		{
+		int ret;
+		/* Our ioctls are all "32/64bit compatible" */
+		if(register_ioctl32_conversion(FBIOGET_VBLANK, NULL)) {
+		   printk(KERN_ERR "sisfb: Error registering FBIOGET_VBLANK ioctl32 translation\n");
+		} else {
+		   ivideo->ioctl32vblankregistered = 1;
+		}
+		ret =  register_ioctl32_conversion(FBIO_ALLOC,             NULL);
+		ret |= register_ioctl32_conversion(FBIO_FREE,              NULL);
+		ret |= register_ioctl32_conversion(SISFB_GET_INFO_SIZE,    NULL);
+		ret |= register_ioctl32_conversion(SISFB_GET_INFO,         NULL);
+		ret |= register_ioctl32_conversion(SISFB_GET_TVPOSOFFSET,  NULL);
+		ret |= register_ioctl32_conversion(SISFB_SET_TVPOSOFFSET,  NULL);
+		ret |= register_ioctl32_conversion(SISFB_SET_LOCK,         NULL);
+		ret |= register_ioctl32_conversion(SISFB_GET_VBRSTATUS,    NULL);
+		ret |= register_ioctl32_conversion(SISFB_GET_AUTOMAXIMIZE, NULL);
+		ret |= register_ioctl32_conversion(SISFB_SET_AUTOMAXIMIZE, NULL);
+		if(ret)	printk(KERN_ERR "sisfb: Error registering ioctl32 translations\n");
+		else    ivideo->ioctl32registered = 1;
+		}
+#endif
+
+		printk(KERN_INFO "sisfb: 2D acceleration is %s, y-panning %s\n",
+		     ivideo->sisfb_accel ? "enabled" : "disabled",
+		     ivideo->sisfb_ypan  ?
+		     	(ivideo->sisfb_max ? "enabled (auto-max)" : "enabled (no auto-max)") : "disabled");
+
+
+		printk(KERN_INFO "fb%d: %s frame buffer device, Version %d.%d.%d\n",
 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
-		printk(KERN_INFO "fb%d: %s frame buffer device, Version %d.%d.%02d\n",
-	       		GET_FB_IDX(sis_fb_info->node), sis_fb_info->modename, VER_MAJOR, VER_MINOR,
-	       		VER_LEVEL);		     
+	       		GET_FB_IDX(sis_fb_info->node),
 #else
-		printk(KERN_INFO "fb%d: %s frame buffer device, Version %d.%d.%02d\n",
-	       		sis_fb_info->node, myid, VER_MAJOR, VER_MINOR, VER_LEVEL);
+	       		sis_fb_info->node,
 #endif
+			ivideo->myid, VER_MAJOR, VER_MINOR, VER_LEVEL);
 
 		printk(KERN_INFO "sisfb: (C) 2001-2004 Thomas Winischhofer.\n");
 
 	}	/* if mode = "none" */
+
 	return 0;
 }
 
+/*****************************************************/
+/*                PCI DEVICE HANDLING                */
+/*****************************************************/
+
+static void __devexit sisfb_remove(struct pci_dev *pdev)
+{
+	struct sis_video_info *ivideo = pci_get_drvdata(pdev);
+	struct fb_info        *sis_fb_info = ivideo->memyselfandi;
+	int                   registered = ivideo->registered;
+
+#ifdef SIS_CONFIG_COMPAT
+	if(ivideo->ioctl32vblankregistered) {
+		if(unregister_ioctl32_conversion(FBIOGET_VBLANK)) {
+			printk(KERN_ERR "sisfb: Error unregistering FBIOGET_VBLANK ioctl32 translation\n");
+		}
+	}
+	if(ivideo->ioctl32registered) {
+		int ret;
+		ret =  unregister_ioctl32_conversion(FBIO_ALLOC);
+		ret |= unregister_ioctl32_conversion(FBIO_FREE);
+		ret |= unregister_ioctl32_conversion(SISFB_GET_INFO_SIZE);
+		ret |= unregister_ioctl32_conversion(SISFB_GET_INFO);
+		ret |= unregister_ioctl32_conversion(SISFB_GET_TVPOSOFFSET);
+		ret |= unregister_ioctl32_conversion(SISFB_SET_TVPOSOFFSET);
+		ret |= unregister_ioctl32_conversion(SISFB_SET_LOCK);
+		ret |= unregister_ioctl32_conversion(SISFB_GET_VBRSTATUS);
+		ret |= unregister_ioctl32_conversion(SISFB_GET_AUTOMAXIMIZE);
+		ret |= unregister_ioctl32_conversion(SISFB_SET_AUTOMAXIMIZE);
+		if(ret)	printk(KERN_ERR "sisfb: Error unregistering ioctl32 translations\n");
+	}
+#endif
+
+	/* Unmap */
+	iounmap((void *)ivideo->video_vbase);
+	iounmap((void *)ivideo->mmio_vbase);
+	if(ivideo->bios_vbase) iounmap(ivideo->bios_vbase);
+	if(ivideo->bios_abase)    vfree(ivideo->bios_abase);
+
+	/* Release mem regions */
+	release_mem_region(ivideo->video_base, ivideo->video_size);
+	release_mem_region(ivideo->mmio_base, ivideo->mmio_size);
+
+#ifdef CONFIG_MTRR
+	/* Release MTRR region */
+	if(ivideo->mtrr) {
+		mtrr_del(ivideo->mtrr, ivideo->video_base, ivideo->video_size);
+	}
+#endif
+
+	/* Unregister the framebuffer */
+	if(ivideo->registered) {
+		unregister_framebuffer(sis_fb_info);
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,3))
+		framebuffer_release(sis_fb_info);
+#else
+		kfree(sis_fb_info);
+#endif
+	}
+
+	pci_set_drvdata(pdev, NULL);
+
+	/* TODO: Restore the initial mode
+	 * This sounds easy but is as good as impossible
+	 * on many machines with SiS chip and video bridge
+	 * since text modes are always set up differently
+	 * from machine to machine. Depends on the type
+	 * of integration between chipset and bridge.
+	 */
+	if(registered) {
+	   printk(KERN_INFO "sisfb: Restoring of text mode not supported yet\n");
+	}
+};
+
+static struct pci_driver sisfb_driver = {
+	.name		= "sisfb",
+	.id_table 	= sisfb_pci_table,
+	.probe 		= sisfb_probe,
+	.remove 	= __devexit_p(sisfb_remove)
+};
+
+int __init sisfb_init(void)
+{
+	return(pci_module_init(&sisfb_driver));
+}
+
+/*****************************************************/
+/*                      MODULE                       */
+/*****************************************************/
 
 #ifdef MODULE
 
@@ -4989,202 +5733,240 @@
 static unsigned int mem = 0;
 static char         *forcecrt2type = NULL;
 static int          forcecrt1 = -1;
-static char         *queuemode = NULL;
-static int          pdc = 0;
+static int          pdc = -1;
+static int          pdc1 = -1;
 static int          noaccel = -1;
 static int          noypan  = -1;
 static int	    nomax = -1;
 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
 static int          inverse = 0;
 #endif
-static int          userom = 1;
+static int          userom = -1;
 static int          useoem = -1;
 static char         *tvstandard = NULL;
 static int	    nocrt2rate = 0;
 static int          scalelcd = -1;
 static char	    *specialtiming = NULL;
 static int	    lvdshl = -1;
+static int	    tvxposoffset = 0, tvyposoffset = 0;
+static int	    filter = -1;
+#if !defined(__i386__) && !defined(__x86_64__)
+static int	    resetcard = 0;
+static int	    videoram = 0;
+#endif
 
-MODULE_DESCRIPTION("SiS 300/540/630/730/315/550/650/651/661/740/741/330/760 framebuffer driver");
+MODULE_DESCRIPTION("SiS 300/540/630/730/315/550/65x/661/74x/330/760 framebuffer device driver");
 MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Thomas Winischhofer <thomas@winischhofer.net>; SiS; Various others");
+MODULE_AUTHOR("Thomas Winischhofer <thomas@winischhofer.net>, Others");
 
 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
+MODULE_PARM(mem, "i");
+MODULE_PARM(noaccel, "i");
+MODULE_PARM(noypan, "i");
+MODULE_PARM(nomax, "i");
+MODULE_PARM(userom, "i");
+MODULE_PARM(useoem, "i");
 MODULE_PARM(mode, "s");
-MODULE_PARM_DESC(mode,
-       "\nSelects the desired display mode in the format [X]x[Y]x[Depth], eg.\n"
-         "1024x768x16. Other formats supported include XxY-Depth and\n"
-	 "XxY-Depth@Rate. If the parameter is only one (decimal or hexadecimal)\n"
-	 "number, it will be interpreted as a VESA mode number. (default: none if\n"
-	 "sisfb is a module; this leaves the console untouched and the driver will\n"
-	 "only do the video memory management for eg. DRM/DRI; 800x600x8 if sisfb\n"
-	 "is in the kernel)");
+MODULE_PARM(vesa, "i");
+MODULE_PARM(rate, "i");
+MODULE_PARM(forcecrt1, "i");
+MODULE_PARM(forcecrt2type, "s");
+MODULE_PARM(scalelcd, "i");
+MODULE_PARM(pdc, "i");
+MODULE_PARM(pdc1, "i");
+MODULE_PARM(specialtiming, "s");
+MODULE_PARM(lvdshl, "i");
+MODULE_PARM(tvstandard, "s");
+MODULE_PARM(tvxposoffset, "i");
+MODULE_PARM(tvyposoffset, "i");
+MODULE_PARM(filter, "i");
+MODULE_PARM(nocrt2rate, "i");
+MODULE_PARM(inverse, "i");
+#if !defined(__i386__) && !defined(__x86_64__)
+MODULE_PARM(resetcard, "i");
+MODULE_PARM(videoram, "i");
+#endif
+#endif
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
+module_param(mem, int, 0);
+module_param(noaccel, int, 0);
+module_param(noypan, int, 0);
+module_param(nomax, int, 0);
+module_param(userom, int, 0);
+module_param(useoem, int, 0);
+module_param(mode, charp, 0);
+module_param(vesa, int, 0);
+module_param(rate, int, 0);
+module_param(forcecrt1, int, 0);
+module_param(forcecrt2type, charp, 0);
+module_param(scalelcd, int, 0);
+module_param(pdc, int, 0);
+module_param(pdc1, int, 0);
+module_param(specialtiming, charp, 0);
+module_param(lvdshl, int, 0);
+module_param(tvstandard, charp, 0);
+module_param(tvxposoffset, int, 0);
+module_param(tvyposoffset, int, 0);
+module_param(filter, int, 0);
+module_param(nocrt2rate, int, 0);
+#if !defined(__i386__) && !defined(__x86_64__)
+module_param(resetcard, int, 0);
+module_param(videoram, int, 0);
 #endif
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)	 
-MODULE_PARM(mode, "s");
-MODULE_PARM_DESC(mode,
-       "\nSelects the desired default display mode in the format XxYxDepth,\n"
-         "eg. 1024x768x16. Other formats supported include XxY-Depth and\n"
-	 "XxY-Depth@Rate. If the parameter is only one (decimal or hexadecimal)\n"
-	 "number, it will be interpreted as a VESA mode number. (default: 800x600x8)");
 #endif
 
+MODULE_PARM_DESC(mem,
+	"\nDetermines the beginning of the video memory heap in KB. This heap is used\n"
+	  "for video RAM management for eg. DRM/DRI. On 300 series, the default depends\n"
+	  "on the amount of video RAM available. If 8MB of video RAM or less is available,\n"
+	  "the heap starts at 4096KB, if between 8 and 16MB are available at 8192KB,\n"
+	  "otherwise at 12288KB. On 315 and Xabre series, the heap size is 32KB by default.\n"
+	  "The value is to be specified without 'KB' and must match the MaxXFBMem setting\n"
+	  "for XFree86 4.x/X.org 6.7 and later.\n");
+
+MODULE_PARM_DESC(noaccel,
+        "\nIf set to anything other than 0, 2D acceleration will be disabled.\n"
+	  "(default: 0)\n");
+
+MODULE_PARM_DESC(noypan,
+        "\nIf set to anything other than 0, y-panning will be disabled and scrolling\n"
+ 	  "will be performed by redrawing the screen. (default: 0)\n");
+
+MODULE_PARM_DESC(nomax,
+        "\nIf y-panning is enabled, sisfb will by default use the entire available video\n"
+	  "memory for the virtual screen in order to optimize scrolling performance. If\n"
+	  "this is set to anything other than 0, sisfb will not do this and thereby \n"
+	  "enable the user to positively specify a virtual Y size of the screen using\n"
+	  "fbset. (default: 0)\n");
+
 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
-MODULE_PARM(vesa, "i");
+MODULE_PARM_DESC(mode,
+        "\nSelects the desired display mode in the format [X]x[Y]x[Depth], eg.\n"
+          "1024x768x16. Other formats supported include XxY-Depth and\n"
+ 	  "XxY-Depth@Rate. If the parameter is only one (decimal or hexadecimal)\n"
+	  "number, it will be interpreted as a VESA mode number. (default: none if\n"
+	  "sisfb is a module; this leaves the console untouched and the driver will\n"
+	  "only do the video memory management for eg. DRM/DRI; 800x600x8 if sisfb\n"
+	  "is in the kernel)\n");
 MODULE_PARM_DESC(vesa,
-       "\nSelects the desired display mode by VESA defined mode number, eg. 0x117\n"
-         "(default: 0x0000 if sisfb is a module; this leaves the console untouched\n"
-	 "and the driver will only do the video memory management for eg. DRM/DRI;\n"
-	 "0x0103 if sisfb is in the kernel)");
+        "\nSelects the desired display mode by VESA defined mode number, eg. 0x117\n"
+          "(default: 0x0000 if sisfb is a module; this leaves the console untouched\n"
+	  "and the driver will only do the video memory management for eg. DRM/DRI;\n"
+	  "0x0103 if sisfb is in the kernel)\n");
 #endif
+
 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
-MODULE_PARM(vesa, "i");
+MODULE_PARM_DESC(mode,
+       "\nSelects the desired default display mode in the format XxYxDepth,\n"
+         "eg. 1024x768x16. Other formats supported include XxY-Depth and\n"
+	 "XxY-Depth@Rate. If the parameter is only one (decimal or hexadecimal)\n"
+	 "number, it will be interpreted as a VESA mode number. (default: 800x600x8)\n");
+
 MODULE_PARM_DESC(vesa,
        "\nSelects the desired default display mode by VESA defined mode number, eg.\n"
-         "0x117 (default: 0x0103)");
+         "0x117 (default: 0x0103)\n");
 #endif
 
-MODULE_PARM(rate, "i");
 MODULE_PARM_DESC(rate,
 	"\nSelects the desired vertical refresh rate for CRT1 (external VGA) in Hz.\n"
 	  "If the mode is specified in the format XxY-Depth@Rate, this parameter\n"
-	  "will be ignored (default: 60)");
-
-MODULE_PARM(crt1off,   "i");
-MODULE_PARM_DESC(crt1off,
-	"(Deprecated, please use forcecrt1)");
-
-MODULE_PARM(filter, "i");
-MODULE_PARM_DESC(filter,
-	"\nSelects TV flicker filter type (only for systems with a SiS301 video bridge).\n"
-	  "(Possible values 0-7, default: [no filter])");
-
-MODULE_PARM(queuemode,   "s");
-MODULE_PARM_DESC(queuemode,
-	"\nSelects the queue mode on 315/550/65x/74x/330/760. Possible choices are AGP, VRAM,\n"
-  	  "MMIO. AGP is only available if the kernel has AGP support. The queue mode is\n"
-	  "important to programs using the 2D/3D accelerator of the SiS chip. The modes\n"
-	  "require a totally different way of programming the engines. If any mode than\n"
-	  "MMIO is selected, sisfb will disable its own 2D acceleration. On\n"
-	  "300/540/630/730, this option is ignored. (default: MMIO)");
+	  "will be ignored (default: 60)\n");
 
-/* TW: "Import" the options from the X driver */
-MODULE_PARM(mem,    "i");
-MODULE_PARM_DESC(mem,
-	"\nDetermines the beginning of the video memory heap in KB. This heap is used\n"
-	  "for video RAM management for eg. DRM/DRI. On 300 series, the default depends\n"
-	  "on the amount of video RAM available. If 8MB of video RAM or less is available,\n"
-	  "the heap starts at 4096KB, if between 8 and 16MB are available at 8192KB,\n"
-	  "otherwise at 12288KB. On 315 and Xabre series, the heap is 1MB by default. The\n"
-	  "value is to be specified without 'KB' and should match the MaxXFBMem setting for\n"
-	  "XFree 4.x (x>=2).");
+MODULE_PARM_DESC(forcecrt1,
+	"\nNormally, the driver autodetects whether or not CRT1 (external VGA) is \n"
+	  "connected. With this option, the detection can be overridden (1=CRT1 ON,\n"
+	  "0=CRT1 OFF) (default: [autodetected])\n");
 
-MODULE_PARM(forcecrt2type, "s");
 MODULE_PARM_DESC(forcecrt2type,
 	"\nIf this option is omitted, the driver autodetects CRT2 output devices, such as\n"
 	  "LCD, TV or secondary VGA. With this option, this autodetection can be\n"
 	  "overridden. Possible parameters are LCD, TV, VGA or NONE. NONE disables CRT2.\n"
-	  "On systems with a 301(B/LV) bridge, parameters SVIDEO, COMPOSITE or SCART can be\n"
-	  "used instead of TV to override the TV detection. (default: [autodetected])");
+	  "On systems with a SiS video bridge, parameters SVIDEO, COMPOSITE or SCART can\n"
+	  "be used instead of TV to override the TV detection. Furthermore, on systems\n"
+	  "with a SiS video bridge, SVIDEO+COMPOSITE, HIVISION, YPBPR480I, YPBPR480P,\n"
+	  "YPBPR720P and YPBPR1080I are understood. However, whether or not these work\n"
+	  "depends on the very hardware in use. (default: [autodetected])\n");
 
-MODULE_PARM(forcecrt1, "i");
-MODULE_PARM_DESC(forcecrt1,
-	"\nNormally, the driver autodetects whether or not CRT1 (external VGA) is \n"
-	  "connected. With this option, the detection can be overridden (1=CRT1 ON,\n"
-	  " 0=CRT1 off) (default: [autodetected])");
+MODULE_PARM_DESC(scalelcd,
+	"\nSetting this to 1 will force the driver to scale the LCD image to the panel's\n"
+	  "native resolution. Setting it to 0 will disable scaling; LVDS panels will\n"
+	  "show black bars around the image, TMDS panels will probably do the scaling\n"
+	  "themselves. Default: 1 on LVDS panels, 0 on TMDS panels\n");
 
-MODULE_PARM(pdc, "i");
 MODULE_PARM_DESC(pdc,
         "\nThis is for manually selecting the LCD panel delay compensation. The driver\n"
 	  "should detect this correctly in most cases; however, sometimes this is not\n"
 	  "possible. If you see 'small waves' on the LCD, try setting this to 4, 32 or 24\n"
-	  "on a 300 series chipset; 3 or 51 on a 315 series chipset. If the problem persists,\n"
+	  "on a 300 series chipset; 6 on a 315 series chipset. If the problem persists,\n"
 	  "try other values (on 300 series: between 4 and 60 in steps of 4; on 315 series:\n"
-	  "and value from 0 to 255). (default: [autodetected])");
-
-MODULE_PARM(noaccel, "i");
-MODULE_PARM_DESC(noaccel,
-        "\nIf set to anything other than 0, 2D acceleration will be disabled.\n"
-	  "(default: 0)");
-
-MODULE_PARM(noypan, "i");
-MODULE_PARM_DESC(noypan,
-        "\nIf set to anything other than 0, y-panning will be disabled and scrolling\n"
- 	  "will be performed by redrawing the screen. (default: 0)");
-
-MODULE_PARM(nomax, "i");
-MODULE_PARM_DESC(nomax,
-        "\nIf y-panning is enabled, sisfb will by default use the entire available video\n"
-	  "memory for the virtual screen in order to optimize scrolling performance. If this\n"
-	  "is set to anything other than 0, sisfb will not do this and thereby enable the user\n"
-	  "to positively specify a virtual Y size of the screen using fbset. (default: 0)\n");
+	  "any value from 0 to 31). (default: autodetected, if LCD is active during start)\n");
 
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)	
-MODULE_PARM(inverse, "i");
-MODULE_PARM_DESC(inverse,
-        "\nSetting this to anything but 0 should invert the display colors, but this\n"
-	  "does not seem to work. (default: 0)");
-#endif	
+#ifdef CONFIG_FB_SIS_315
+MODULE_PARM_DESC(pdc1,
+        "\nThis is same as pdc, but for LCD-via CRT1. Hence, this is for the 315/330\n"
+	  "series only. (default: autodetected if LCD is in LCD-via-CRT1 mode during\n"
+	  "startup) - Note: currently, this has no effect because LCD-via-CRT1 is not\n"
+	  "implemented yet.\n");
+#endif
 
-MODULE_PARM(userom, "i");
-MODULE_PARM_DESC(userom,
-        "\nSetting this to 0 keeps sisfb from using the video BIOS data which is needed\n"
-	  "for some LCD and TV setup. (default: 1)");
+MODULE_PARM_DESC(specialtiming,
+	"\nPlease refer to documentation for more information on this option.\n");
 
-MODULE_PARM(useoem, "i");
-MODULE_PARM_DESC(useoem,
-        "\nSetting this to 0 keeps sisfb from using its internel OEM data for some LCD\n"
-	  "panels and TV connector types. (default: [auto])");
+MODULE_PARM_DESC(lvdshl,
+	"\nPlease refer to documentation for more information on this option.\n");
 
-MODULE_PARM(tvstandard, "s");
 MODULE_PARM_DESC(tvstandard,
 	"\nThis allows overriding the BIOS default for the TV standard. Valid choices are\n"
-	  "pal and ntsc. (default: [auto])");
+	  "pal, ntsc, palm and paln. (default: [auto; pal or ntsc only])\n");
+
+MODULE_PARM_DESC(tvxposoffset,
+	"\nRelocate TV output horizontally. Possible parameters: -32 through 32.\n"
+	  "Default: 0\n");
+
+MODULE_PARM_DESC(tvyposoffset,
+	"\nRelocate TV output vertically. Possible parameters: -32 through 32.\n"
+	  "Default: 0\n");
+
+MODULE_PARM_DESC(filter,
+	"\nSelects TV flicker filter type (only for systems with a SiS301 video bridge).\n"
+	  "(Possible values 0-7, default: [no filter])\n");
 
-MODULE_PARM(nocrt2rate, "i");
 MODULE_PARM_DESC(nocrt2rate,
 	"\nSetting this to 1 will force the driver to use the default refresh rate for\n"
-	  "CRT2 if CRT2 type is VGA. (default: 0, use same rate as CRT1)");
-
-MODULE_PARM(scalelcd, "i");
-MODULE_PARM_DESC(scalelcd,
-	"\nSetting this to 1 will force the driver to scale the LCD image to the panel's\n"
-	  "native resolution. Setting it to 0 will disable scaling; if the panel can scale\n"
-	  "by itself, it will probably do this, otherwise you will see a black bar around\n"
-	  "the screen image. Default: [autodetect if panel can scale]");
+	  "CRT2 if CRT2 type is VGA. (default: 0, use same rate as CRT1)\n");
 
-MODULE_PARM(specialtiming, "s");
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
+MODULE_PARM_DESC(inverse,
+        "\nSetting this to anything but 0 should invert the display colors, but this\n"
+	  "does not seem to work. (default: 0)\n");
+#endif
 
-MODULE_PARM(lvdshl, "i");
+#if !defined(__i386__) && !defined(__x86_64__)
+#ifdef CONFIG_FB_SIS_300
+MODULE_PARM_DESC(resetcard,
+	"\nSet this to 1 in order to reset (POST) the card on non-x86 machines where\n"
+	  "the BIOS did not POST the card (only supported for SiS 300/305 currently).\n"
+	  "Default: 0\n");
 
+MODULE_PARM_DESC(videoram,
+	"\nSet this to the amount of video RAM (in kilobyte) the card has. Required on\n"
+	  "some non-x86 architectures where the memory auto detection fails. Only\n"
+	  "relevant if resetcard is set, too. Default: [auto-detect]\n");
+#endif
+#endif
 
-int init_module(void)
+int __init sisfb_init_module(void)
 {
-	int err;
+	sisfb_setdefaultparms();
 
-	SiS_Pr.UsePanelScaler = -1;
-	SiS_Pr.SiS_CustomT = CUT_NONE;
-	SiS_Pr.LVDSHL = -1;
-
-	ivideo.refresh_rate = sisfb_parm_rate = rate;
+	if(rate) sisfb_parm_rate = rate;
 
 	if((scalelcd == 0) || (scalelcd == 1)) {
-	   SiS_Pr.UsePanelScaler = scalelcd ^ 1;
+	   sisfb_scalelcd = scalelcd ^ 1;
 	}
 
-	if(mode)
-		sisfb_search_mode(mode, FALSE);
-	else if(vesa != -1)
-		sisfb_search_vesamode(vesa, FALSE);
-	else
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
-		/* For 2.4, set mode=none if no mode is given  */
-		sisfb_mode_idx = MODE_INDEX_NONE;
-#endif
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
-		/* For 2.5, we don't need this "mode=none" stuff anymore */
-		sisfb_mode_idx = DEFAULT_MODE;
-#endif
+	/* Need to check crt2 type first for fstn/dstn */
 
 	if(forcecrt2type)
 		sisfb_search_crt2type(forcecrt2type);
@@ -5192,16 +5974,16 @@
 	if(tvstandard)
 		sisfb_search_tvstd(tvstandard);
 
-	if(crt1off == 0)
-		sisfb_crt1off = 1;
-	else
-		sisfb_crt1off = 0;
+	if(mode)
+		sisfb_search_mode(mode, FALSE);
+	else if(vesa != -1)
+		sisfb_search_vesamode(vesa, FALSE);
+
+	sisfb_crt1off = (crt1off == 0) ? 1 : 0;
 
 	sisfb_forcecrt1 = forcecrt1;
-	if(forcecrt1 == 1)
-		sisfb_crt1off = 0;
-	else if(forcecrt1 == 0)
-		sisfb_crt1off = 1;
+	if(forcecrt1 == 1)      sisfb_crt1off = 0;
+	else if(forcecrt1 == 0) sisfb_crt1off = 1;
 
 	if(noaccel == 1)      sisfb_accel = 0;
 	else if(noaccel == 0) sisfb_accel = 1;
@@ -5214,84 +5996,48 @@
 	
 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
 	if(inverse)           sisfb_inverse = 1;
-	sisfb_fontname[0] = '\0';
 #endif
 
-	if(mem)		      sisfb_mem = mem;
+	if(mem)		      sisfb_parm_mem = mem;
 
-	sisfb_userom = userom;
+	if(userom != -1)      sisfb_userom = userom;
+	if(useoem != -1)      sisfb_useoem = useoem;
 
-	sisfb_useoem = useoem;
-
-	if (queuemode)        sisfb_search_queuemode(queuemode);
-	
-	/* If other queuemode than MMIO, disable 2D accel and ypan */
-	if((sisfb_queuemode != -1) && (sisfb_queuemode != MMIO_CMD)) {
-	        sisfb_accel = 0;
-	}
-
-        if(pdc) sisfb_pdc = pdc & 0x3c;
+        if(pdc != -1)  sisfb_pdc  = (pdc  & 0x7f);
+	if(pdc1 != -1) sisfb_pdca = (pdc1 & 0x1f);
 
 	sisfb_nocrt2rate = nocrt2rate;
 
 	if(specialtiming)
 		sisfb_search_specialtiming(specialtiming);
 
-	if((lvdshl >= 0) && (lvdshl <= 3)) SiS_Pr.LVDSHL = lvdshl;
-
-	if((err = sisfb_init()) < 0) return err;
-
-	return 0;
-}
+	if((lvdshl >= 0) && (lvdshl <= 3))  sisfb_lvdshl = lvdshl;
 
-void cleanup_module(void)
-{
-	/* Unmap */
-	iounmap(ivideo.video_vbase);
-	iounmap(ivideo.mmio_vbase);
+	if(filter != -1) sisfb_filter = filter;
 
-	/* Release mem regions */
-	release_mem_region(ivideo.video_base, ivideo.video_size);
-	release_mem_region(ivideo.mmio_base, sisfb_mmio_size);
+	sisfb_tvxposoffset = tvxposoffset;
+	sisfb_tvyposoffset = tvyposoffset;
 
-#ifdef CONFIG_MTRR
-	/* Release MTRR region */
-	if(ivideo.mtrr) {
-		mtrr_del(ivideo.mtrr,
-		      (unsigned int)ivideo.video_base,
-	              (unsigned int)ivideo.video_size);
-	}
+#if !defined(__i386__) && !defined(__x86_64__)
+ 	sisfb_resetcard = (resetcard) ? 1 : 0;
+	if(videoram)    sisfb_videoram = videoram;
 #endif
 
-	/* Unregister the framebuffer */
-	if(sisfb_registered) {
-		unregister_framebuffer(sis_fb_info);
-#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)) && (defined(NEWFBDEV))
-		framebuffer_release(sis_fb_info);
-#else
-		kfree(sis_fb_info);
-#endif
-	}
+        return(sisfb_init());
+}
 
-	if(sishw_ext.pSR) vfree(sishw_ext.pSR);
-	if(sishw_ext.pCR) vfree(sishw_ext.pCR);
-	
-	/* TODO: Restore the initial mode
-	 * This sounds easy but is as good as impossible
-	 * on many machines with SiS chip and video bridge
-	 * since text modes are always set up differently
-	 * from machine to machine. Depends on the type
-	 * of integration between chipset and bridge.
-	 */
-	
-	printk(KERN_INFO "sisfb: Module unloaded\n");
+static void __exit sisfb_remove_module(void)
+{
+	pci_unregister_driver(&sisfb_driver);
+	printk(KERN_DEBUG "sisfb: Module unloaded\n");
 }
 
-#endif
+module_init(sisfb_init_module);
+module_exit(sisfb_remove_module);
+
+#endif 	   /*  /MODULE  */
 
 EXPORT_SYMBOL(sis_malloc);
 EXPORT_SYMBOL(sis_free);
-EXPORT_SYMBOL(sis_dispinfo);
 
-EXPORT_SYMBOL(ivideo);
-                                                                                           
+
--- diff/drivers/video/sis/sis_main.h	2004-05-19 22:12:23.000000000 +0100
+++ source/drivers/video/sis/sis_main.h	2004-06-11 19:22:05.000000000 +0100
@@ -1,6 +1,7 @@
 /*
- * SiS 300/630/730/540/315/550/650/651/M650/661FX/M661FX/740/741/330/760
- * frame buffer driver for Linux kernels 2.4.x and 2.5.x
+ * SiS 300/305/540/630(S)/730(S)
+ * SiS 315(H/PRO)/55x/(M)65x/(M)661(F/M)X/740/741(GX)/330/(M)760
+ * frame buffer driver for Linux kernels >=2.4.14 and >=2.6.3
  *
  * Copyright (C) 2001-2004 Thomas Winischhofer, Vienna, Austria.
  *
@@ -22,304 +23,15 @@
 #ifndef _SISFB_MAIN
 #define _SISFB_MAIN
 
-#include "vstruct.h"
-
-/* ------------------- Constant Definitions ------------------------- */
-
-#define AGPOFF     /* default is turn off AGP */
-
-#define SISFAIL(x) do { printk(x "\n"); return -EINVAL; } while(0)
-
-#define VER_MAJOR                 1
-#define VER_MINOR                 6
-#define VER_LEVEL                 25
+#include <linux/spinlock.h>
 
+#include "vstruct.h"
 #include "sis.h"
 
-/* To be included in pci_ids.h */
-#ifndef PCI_DEVICE_ID_SI_650_VGA
-#define PCI_DEVICE_ID_SI_650_VGA  0x6325
-#endif
-#ifndef PCI_DEVICE_ID_SI_650
-#define PCI_DEVICE_ID_SI_650      0x0650
-#endif
-#ifndef PCI_DEVICE_ID_SI_740
-#define PCI_DEVICE_ID_SI_740      0x0740
-#endif
-#ifndef PCI_DEVICE_ID_SI_330
-#define PCI_DEVICE_ID_SI_330      0x0330
-#endif
-#ifndef PCI_DEVICE_ID_SI_660_VGA
-#define PCI_DEVICE_ID_SI_660_VGA  0x6330
-#endif
-#ifndef PCI_DEVICE_ID_SI_660
-#define PCI_DEVICE_ID_SI_660      0x0661
-#endif
-#ifndef PCI_DEVICE_ID_SI_741
-#define PCI_DEVICE_ID_SI_741      0x0741
-#endif
-#ifndef PCI_DEVICE_ID_SI_660
-#define PCI_DEVICE_ID_SI_660      0x0660
-#endif
-#ifndef PCI_DEVICE_ID_SI_760
-#define PCI_DEVICE_ID_SI_760      0x0760
-#endif
-
-/* To be included in fb.h */
-#ifndef FB_ACCEL_SIS_GLAMOUR_2
-#define FB_ACCEL_SIS_GLAMOUR_2  40	/* SiS 315, 65x, 740, 661, 741  */
-#endif
-#ifndef FB_ACCEL_SIS_XABRE
-#define FB_ACCEL_SIS_XABRE      41	/* SiS 330 ("Xabre"), 760 	*/
-#endif
-
-#define MAX_ROM_SCAN              0x10000
-
-#define HW_CURSOR_CAP             0x80
-#define TURBO_QUEUE_CAP           0x40
-#define AGP_CMD_QUEUE_CAP         0x20
-#define VM_CMD_QUEUE_CAP          0x10
-#define MMIO_CMD_QUEUE_CAP        0x08
-
-/* For 300 series */
-#ifdef CONFIG_FB_SIS_300
-#define TURBO_QUEUE_AREA_SIZE     0x80000 /* 512K */
-#endif
-
-/* For 315/Xabre series */
-#ifdef CONFIG_FB_SIS_315
-#define COMMAND_QUEUE_AREA_SIZE   0x80000 /* 512K */
-#define COMMAND_QUEUE_THRESHOLD   0x1F
-#endif
-
-#define HW_CURSOR_AREA_SIZE_315   0x4000  /* 16K */
-#define HW_CURSOR_AREA_SIZE_300   0x1000  /* 4K */
-
-#define OH_ALLOC_SIZE             4000
-#define SENTINEL                  0x7fffffff
-
-#define SEQ_ADR                   0x14
-#define SEQ_DATA                  0x15
-#define DAC_ADR                   0x18
-#define DAC_DATA                  0x19
-#define CRTC_ADR                  0x24
-#define CRTC_DATA                 0x25
-#define DAC2_ADR                  (0x16-0x30)
-#define DAC2_DATA                 (0x17-0x30)
-#define VB_PART1_ADR              (0x04-0x30)
-#define VB_PART1_DATA             (0x05-0x30)
-#define VB_PART2_ADR              (0x10-0x30)
-#define VB_PART2_DATA             (0x11-0x30)
-#define VB_PART3_ADR              (0x12-0x30)
-#define VB_PART3_DATA             (0x13-0x30)
-#define VB_PART4_ADR              (0x14-0x30)
-#define VB_PART4_DATA             (0x15-0x30)
-
-#define SISSR			  SiS_Pr.SiS_P3c4
-#define SISCR                     SiS_Pr.SiS_P3d4
-#define SISDACA                   SiS_Pr.SiS_P3c8
-#define SISDACD                   SiS_Pr.SiS_P3c9
-#define SISPART1                  SiS_Pr.SiS_Part1Port
-#define SISPART2                  SiS_Pr.SiS_Part2Port
-#define SISPART3                  SiS_Pr.SiS_Part3Port
-#define SISPART4                  SiS_Pr.SiS_Part4Port
-#define SISPART5                  SiS_Pr.SiS_Part5Port
-#define SISDAC2A                  SISPART5
-#define SISDAC2D                  (SISPART5 + 1)
-#define SISMISCR                  (SiS_Pr.RelIO + 0x1c)
-#define SISMISCW                  SiS_Pr.SiS_P3c2
-#define SISINPSTAT		  (SiS_Pr.RelIO + 0x2a)
-#define SISPEL			  SiS_Pr.SiS_P3c6
-
-#define IND_SIS_PASSWORD          0x05  /* SRs */
-#define IND_SIS_COLOR_MODE        0x06
-#define IND_SIS_RAMDAC_CONTROL    0x07
-#define IND_SIS_DRAM_SIZE         0x14
-#define IND_SIS_SCRATCH_REG_16    0x16
-#define IND_SIS_SCRATCH_REG_17    0x17
-#define IND_SIS_SCRATCH_REG_1A    0x1A
-#define IND_SIS_MODULE_ENABLE     0x1E
-#define IND_SIS_PCI_ADDRESS_SET   0x20
-#define IND_SIS_TURBOQUEUE_ADR    0x26
-#define IND_SIS_TURBOQUEUE_SET    0x27
-#define IND_SIS_POWER_ON_TRAP     0x38
-#define IND_SIS_POWER_ON_TRAP2    0x39
-#define IND_SIS_CMDQUEUE_SET      0x26
-#define IND_SIS_CMDQUEUE_THRESHOLD  0x27
-
-#define IND_SIS_SCRATCH_REG_CR30  0x30  /* CRs */
-#define IND_SIS_SCRATCH_REG_CR31  0x31
-#define IND_SIS_SCRATCH_REG_CR32  0x32
-#define IND_SIS_SCRATCH_REG_CR33  0x33
-#define IND_SIS_LCD_PANEL         0x36
-#define IND_SIS_SCRATCH_REG_CR37  0x37
-#define IND_SIS_AGP_IO_PAD        0x48
-
-#define IND_BRI_DRAM_STATUS       0x63 /* PCI config memory size offset */
-
-#define MMIO_QUEUE_PHYBASE        0x85C0
-#define MMIO_QUEUE_WRITEPORT      0x85C4
-#define MMIO_QUEUE_READPORT       0x85C8
-
-#define IND_SIS_CRT2_WRITE_ENABLE_300 0x24
-#define IND_SIS_CRT2_WRITE_ENABLE_315 0x2F
-
-#define SIS_PASSWORD              0x86  /* SR05 */
-#define SIS_INTERLACED_MODE       0x20  /* SR06 */
-#define SIS_8BPP_COLOR_MODE       0x0 
-#define SIS_15BPP_COLOR_MODE      0x1 
-#define SIS_16BPP_COLOR_MODE      0x2 
-#define SIS_32BPP_COLOR_MODE      0x4 
-#define SIS_DRAM_SIZE_MASK        0x3F  /* 300/630/730 SR14 */
-#define SIS_DRAM_SIZE_1MB         0x00
-#define SIS_DRAM_SIZE_2MB         0x01
-#define SIS_DRAM_SIZE_4MB         0x03
-#define SIS_DRAM_SIZE_8MB         0x07
-#define SIS_DRAM_SIZE_16MB        0x0F
-#define SIS_DRAM_SIZE_32MB        0x1F
-#define SIS_DRAM_SIZE_64MB        0x3F
-#define SIS_DATA_BUS_MASK         0xC0
-#define SIS_DATA_BUS_32           0x00
-#define SIS_DATA_BUS_64           0x01
-#define SIS_DATA_BUS_128          0x02
-
-#define SIS315_DATA_BUS_MASK      0x02
-#define SIS315_DATA_BUS_64        0x00
-#define SIS315_DATA_BUS_128       0x01
-#define SIS315_DUAL_CHANNEL_MASK  0x0C
-#define SIS315_SINGLE_CHANNEL_1_RANK  	0x0
-#define SIS315_SINGLE_CHANNEL_2_RANK  	0x1
-#define SIS315_ASYM_DDR		  	0x02
-#define SIS315_DUAL_CHANNEL_1_RANK    	0x3
-
-#define SIS_SCRATCH_REG_1A_MASK   0x10
-
-#define SIS_ENABLE_2D             0x40  /* SR1E */
-
-#define SIS_MEM_MAP_IO_ENABLE     0x01  /* SR20 */
-#define SIS_PCI_ADDR_ENABLE       0x80
-
-#define SIS_AGP_CMDQUEUE_ENABLE   0x80  /* 315/650/740 SR26 */
-#define SIS_VRAM_CMDQUEUE_ENABLE  0x40
-#define SIS_MMIO_CMD_ENABLE       0x20
-#define SIS_CMD_QUEUE_SIZE_512k   0x00
-#define SIS_CMD_QUEUE_SIZE_1M     0x04
-#define SIS_CMD_QUEUE_SIZE_2M     0x08
-#define SIS_CMD_QUEUE_SIZE_4M     0x0C
-#define SIS_CMD_QUEUE_RESET       0x01
-#define SIS_CMD_AUTO_CORR	  0x02
-
-#define SIS_SIMULTANEOUS_VIEW_ENABLE  0x01  /* CR30 */
-#define SIS_MODE_SELECT_CRT2      0x02
-#define SIS_VB_OUTPUT_COMPOSITE   0x04
-#define SIS_VB_OUTPUT_SVIDEO      0x08
-#define SIS_VB_OUTPUT_SCART       0x10
-#define SIS_VB_OUTPUT_LCD         0x20
-#define SIS_VB_OUTPUT_CRT2        0x40
-#define SIS_VB_OUTPUT_HIVISION    0x80
-
-#define SIS_VB_OUTPUT_DISABLE     0x20  /* CR31 */
-#define SIS_DRIVER_MODE           0x40
-
-#define SIS_VB_COMPOSITE          0x01  /* CR32 */
-#define SIS_VB_SVIDEO             0x02
-#define SIS_VB_SCART              0x04
-#define SIS_VB_LCD                0x08
-#define SIS_VB_CRT2               0x10
-#define SIS_CRT1                  0x20
-#define SIS_VB_HIVISION           0x40
-#define SIS_VB_DVI                0x80
-#define SIS_VB_TV                 (SIS_VB_COMPOSITE | SIS_VB_SVIDEO | \
-                                   SIS_VB_SCART | SIS_VB_HIVISION)
-
-#define SIS_EXTERNAL_CHIP_MASK    	   0x0E  /* CR37 (< SiS 660) */
-#define SIS_EXTERNAL_CHIP_SIS301           0x01  /* in CR37 << 1 ! */
-#define SIS_EXTERNAL_CHIP_LVDS             0x02  /* in CR37 << 1 ! */
-#define SIS_EXTERNAL_CHIP_TRUMPION         0x03  /* in CR37 << 1 ! */
-#define SIS_EXTERNAL_CHIP_LVDS_CHRONTEL    0x04  /* in CR37 << 1 ! */
-#define SIS_EXTERNAL_CHIP_CHRONTEL         0x05  /* in CR37 << 1 ! */
-#define SIS310_EXTERNAL_CHIP_LVDS          0x02  /* in CR37 << 1 ! */
-#define SIS310_EXTERNAL_CHIP_LVDS_CHRONTEL 0x03  /* in CR37 << 1 ! */
-
-#define SIS_AGP_2X                0x20  /* CR48 */
-
-#define BRI_DRAM_SIZE_MASK        0x70  /* PCI bridge config data */
-#define BRI_DRAM_SIZE_2MB         0x00
-#define BRI_DRAM_SIZE_4MB         0x01
-#define BRI_DRAM_SIZE_8MB         0x02
-#define BRI_DRAM_SIZE_16MB        0x03
-#define BRI_DRAM_SIZE_32MB        0x04
-#define BRI_DRAM_SIZE_64MB        0x05
-
-#define HW_DEVICE_EXTENSION	  SIS_HW_INFO
-#define PHW_DEVICE_EXTENSION      PSIS_HW_INFO
-
-#define SR_BUFFER_SIZE            5
-#define CR_BUFFER_SIZE            5
-
-/* entries for disp_state - deprecated as of 1.6.02 */
-#define DISPTYPE_CRT1       0x00000008L
-#define DISPTYPE_CRT2       0x00000004L
-#define DISPTYPE_LCD        0x00000002L
-#define DISPTYPE_TV         0x00000001L
-#define DISPTYPE_DISP1      DISPTYPE_CRT1
-#define DISPTYPE_DISP2      (DISPTYPE_CRT2 | DISPTYPE_LCD | DISPTYPE_TV)
-#define DISPMODE_SINGLE	    0x00000020L
-#define DISPMODE_MIRROR	    0x00000010L
-#define DISPMODE_DUALVIEW   0x00000040L
-
-/* Deprecated as of 1.6.02 - use vbflags instead */
-#define HASVB_NONE      	0x00
-#define HASVB_301       	0x01
-#define HASVB_LVDS      	0x02
-#define HASVB_TRUMPION  	0x04
-#define HASVB_LVDS_CHRONTEL	0x10
-#define HASVB_302       	0x20
-#define HASVB_303       	0x40
-#define HASVB_CHRONTEL  	0x80
-
-/* Useful macros */
-#define inSISREG(base)          inb(base)
-#define outSISREG(base,val)     outb(val,base)
-#define orSISREG(base,val)      do { \
-                                  unsigned char __Temp = inb(base); \
-                                  outSISREG(base, __Temp | (val)); \
-                                } while (0)
-#define andSISREG(base,val)     do { \
-                                  unsigned char __Temp = inb(base); \
-                                  outSISREG(base, __Temp & (val)); \
-                                } while (0)
-#define inSISIDXREG(base,idx,var)   do { \
-                                      outb(idx,base); var=inb((base)+1); \
-                                    } while (0)
-#define outSISIDXREG(base,idx,val)  do { \
-                                      outb(idx,base); outb((val),(base)+1); \
-                                    } while (0)
-#define orSISIDXREG(base,idx,val)   do { \
-                                      unsigned char __Temp; \
-                                      outb(idx,base);   \
-                                      __Temp = inb((base)+1)|(val); \
-                                      outSISIDXREG(base,idx,__Temp); \
-                                    } while (0)
-#define andSISIDXREG(base,idx,and)  do { \
-                                      unsigned char __Temp; \
-                                      outb(idx,base);   \
-                                      __Temp = inb((base)+1)&(and); \
-                                      outSISIDXREG(base,idx,__Temp); \
-                                    } while (0)
-#define setSISIDXREG(base,idx,and,or)   do { \
-                                          unsigned char __Temp; \
-                                          outb(idx,base);   \
-                                          __Temp = (inb((base)+1)&(and))|(or); \
-                                          outSISIDXREG(base,idx,__Temp); \
-                                        } while (0)
-
-/* ------------------- Global Variables ----------------------------- */
-
-/* Fbcon variables */
-static struct fb_info *sis_fb_info;
+#define MODE_INDEX_NONE           0  /* index for mode=none */
 
-static struct fb_var_screeninfo default_var = {
+/* Fbcon stuff */
+static struct fb_var_screeninfo my_default_var = {
 	.xres            = 0,
 	.yres            = 0,
 	.xres_virtual    = 0,
@@ -346,125 +58,110 @@
 	.vsync_len       = 0,
 	.sync            = 0,
 	.vmode           = FB_VMODE_NONINTERLACED,
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
-	.reserved        = {0, 0, 0, 0, 0, 0}
-#endif
 };
 
+/* Boot-time parameters */
+static int sisfb_off = 0;
+static int sisfb_parm_mem = 0;
+static int sisfb_accel = -1;
+static int sisfb_ypan = -1;
+static int sisfb_max = -1;
+static int sisfb_userom = 1;
+static int sisfb_useoem = -1;
+#ifdef MODULE
 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
-static struct fb_fix_screeninfo sisfb_fix = {
-	.id		= "SiS",
-	.type		= FB_TYPE_PACKED_PIXELS,
-	.xpanstep	= 0,
-	.ypanstep	= 1,
-};
-static char myid[40];
-static u32 pseudo_palette[17];
-#endif
-
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
-static struct display sis_disp;
-
-static struct display_switch sisfb_sw;	
-
-static struct {
-	u16 blue, green, red, pad;
-} sis_palette[256];
-
-static union {
-#ifdef FBCON_HAS_CFB16
-	u16 cfb16[16];
-#endif
-#ifdef FBCON_HAS_CFB32
-	u32 cfb32[16];
+static int sisfb_mode_idx = -1;
+#else
+static int sisfb_mode_idx = MODE_INDEX_NONE;  /* Don't use a mode by default if we are a module */
 #endif
-} sis_fbcon_cmap;
-
-static int sisfb_inverse = 0;
-static int currcon = 0;
+#else
+static int sisfb_mode_idx = -1;               /* Use a default mode if we are inside the kernel */
 #endif
-
-/* global flags */
-static int sisfb_off = 0;
+static int sisfb_parm_rate = -1;
 static int sisfb_crt1off = 0;
 static int sisfb_forcecrt1 = -1;
-static int sisvga_enabled = 0;
-static int sisfb_userom = 1;
-static int sisfb_useoem = -1;
-static int sisfb_parm_rate = -1;
-static int sisfb_registered = 0;
-static int sisfb_mem = 0;
-static int sisfb_pdc = 0;
-static int sisfb_ypan = -1;
-static int sisfb_max = -1;
-static int sisfb_nocrt2rate = 0;
+static int sisfb_crt2type  = -1;	/* CRT2 type (for overriding autodetection) */
+static int sisfb_crt2flags = 0;
+static int sisfb_pdc = 0xff;
+static int sisfb_pdca = 0xff;
+static int sisfb_scalelcd = -1;
+static int sisfb_specialtiming = CUT_NONE;
+static int sisfb_lvdshl = -1;
 static int sisfb_dstn = 0;
 static int sisfb_fstn = 0;
-
-VGA_ENGINE sisvga_engine = UNKNOWN_VGA;
-int 	   sisfb_accel = -1;
-
-/* These are to adapted according to VGA_ENGINE type */
-static int sisfb_hwcursor_size = 0;
-static int sisfb_CRT2_write_enable = 0;
-
-int sisfb_crt2type  = -1;	/* CRT2 type (for overriding autodetection) */
-int sisfb_tvplug    = -1;	/* Tv plug type (for overriding autodetection) */
-
-int sisfb_queuemode = -1; 	/* Use MMIO queue mode by default (315 series only) */
-
-unsigned char sisfb_detectedpdc = 0;
-
-unsigned char sisfb_detectedlcda = 0xff;
-
-/* data for sis hardware ("par") */
-struct video_info ivideo;
-
-/* For ioctl SISFB_GET_INFO */
-sisfb_info sisfbinfo;
-
-/* Hardware info; contains data on hardware */
-SIS_HW_INFO sishw_ext;
-
-/* SiS private structure */
-SiS_Private  SiS_Pr;
-
-/* Card parameters */
-static unsigned long sisfb_mmio_size = 0;
-static u8            sisfb_caps = 0;
-
-typedef enum _SIS_CMDTYPE {
-	MMIO_CMD = 0,
-	AGP_CMD_QUEUE,
-	VM_CMD_QUEUE,
-} SIS_CMDTYPE;
+static int sisfb_tvplug = -1;		/* Tv plug type (for overriding autodetection) */
+static int sisfb_tvstd  = -1;
+static int sisfb_tvxposoffset = 0;
+static int sisfb_tvyposoffset = 0;
+static int sisfb_filter = -1;
+static int sisfb_nocrt2rate = 0;
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
+static int  sisfb_inverse = 0;
+static char sisfb_fontname[40];
+#endif
+#if !defined(__i386__) && !defined(__x86_64__)
+static int sisfb_resetcard = 0;
+static int sisfb_videoram = 0;
+#endif
 
 /* List of supported chips */
-static struct board {
-	u16 vendor, device;
-	const char *name;
-} sisdev_list[] = {
-	{PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_300,     "SIS 300"},
-	{PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_540_VGA, "SIS 540 VGA"},
-	{PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_630_VGA, "SIS 630/730 VGA"},
-	{PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_315H,    "SIS 315H"},
-	{PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_315,     "SIS 315"},
-	{PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_315PRO,  "SIS 315PRO"},
-	{PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_550_VGA, "SIS 550 VGA"},
-	{PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_650_VGA, "SIS 65x/M65x/740 VGA"},
-	{PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_330,     "SIS 330"},
-	{PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_660_VGA, "SIS 661FX/M661FX/741/760 VGA"},
-	{0, 0, NULL}
+static struct sisfb_chip_info {
+        int 		chip;
+	int 		vgaengine;
+	int		mni;
+	int 		hwcursor_size;
+	int		CRT2_write_enable;
+	const char 	*chip_name;
+} sisfb_chip_info[] __devinitdata = {
+	{ SIS_300,    SIS_300_VGA, 0, HW_CURSOR_AREA_SIZE_300 * 2, SIS_CRT2_WENABLE_300, "SiS 300/305" },
+	{ SIS_540,    SIS_300_VGA, 0, HW_CURSOR_AREA_SIZE_300 * 2, SIS_CRT2_WENABLE_300, "SiS 540" },
+	{ SIS_630,    SIS_300_VGA, 0, HW_CURSOR_AREA_SIZE_300 * 2, SIS_CRT2_WENABLE_300, "SiS 630" },
+	{ SIS_315H,   SIS_315_VGA, 1, HW_CURSOR_AREA_SIZE_315 * 4, SIS_CRT2_WENABLE_315, "SiS 315H" },
+	{ SIS_315,    SIS_315_VGA, 1, HW_CURSOR_AREA_SIZE_315 * 4, SIS_CRT2_WENABLE_315, "SiS 315" },
+	{ SIS_315PRO, SIS_315_VGA, 1, HW_CURSOR_AREA_SIZE_315 * 4, SIS_CRT2_WENABLE_315, "SiS 315PRO" },
+	{ SIS_550,    SIS_315_VGA, 1, HW_CURSOR_AREA_SIZE_315 * 4, SIS_CRT2_WENABLE_315, "SiS 55x" },
+	{ SIS_650,    SIS_315_VGA, 1, HW_CURSOR_AREA_SIZE_315 * 4, SIS_CRT2_WENABLE_315, "SiS 650" },
+	{ SIS_330,    SIS_315_VGA, 1, HW_CURSOR_AREA_SIZE_315 * 4, SIS_CRT2_WENABLE_315, "SiS 330" },
+	{ SIS_660,    SIS_315_VGA, 1, HW_CURSOR_AREA_SIZE_315 * 4, SIS_CRT2_WENABLE_315, "SiS 660" },
 };
 
+static struct pci_device_id __devinitdata sisfb_pci_table[] = {
+#ifdef CONFIG_FB_SIS_300
+	{ PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_300,     PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{ PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_540_VGA, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 1},
+	{ PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_630_VGA, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 2},
+#endif
+#ifdef CONFIG_FB_SIS_315
+	{ PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_315H,    PCI_ANY_ID, PCI_ANY_ID, 0, 0, 3},
+	{ PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_315,     PCI_ANY_ID, PCI_ANY_ID, 0, 0, 4},
+	{ PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_315PRO,  PCI_ANY_ID, PCI_ANY_ID, 0, 0, 5},
+	{ PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_550_VGA, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 6},
+	{ PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_650_VGA, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 7},
+	{ PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_330,     PCI_ANY_ID, PCI_ANY_ID, 0, 0, 8},
+	{ PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_660_VGA, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 9},
+#endif
+	{ 0 }
+};
+
+MODULE_DEVICE_TABLE(pci, sisfb_pci_table);
+
+static struct sis_video_info *card_list = NULL;
+
+/* TODO: This is not handled card-wise because the DRM
+   does not refer to a unique fb when calling sis_alloc
+   or sis_free. Therefore, this is handled globally for
+   now (hoping that nobody is crazy enough to run two
+   SiS cards at the same time).
+ */
+SIS_HEAP       	sisfb_heap;
+
 #define MD_SIS300 1
 #define MD_SIS315 2
 
 /* Mode table */
-/* NOT const - will be patched for 1280x768 mode number chaos reasons */
-struct _sisbios_mode {
+static const struct _sisbios_mode {
 	char name[15];
-	u8 mode_no;
+	u8  mode_no[2];
 	u16 vesa_mode_no_1;  /* "SiS defined" VESA mode number */
 	u16 vesa_mode_no_2;  /* Real VESA mode numbers */
 	u16 xres;
@@ -475,190 +172,231 @@
 	u16 rows;
 	u8  chipset;
 } sisbios_mode[] = {
-#define MODE_INDEX_NONE           0  /* index for mode=none */
-	{"none",         0xff, 0x0000, 0x0000,    0,    0,  0, 0,   0,  0, MD_SIS300|MD_SIS315},
-	{"320x200x8",    0x59, 0x0138, 0x0000,  320,  200,  8, 1,  40, 12, MD_SIS300|MD_SIS315},
-	{"320x200x16",   0x41, 0x010e, 0x0000,  320,  200, 16, 1,  40, 12, MD_SIS300|MD_SIS315},
-	{"320x200x24",   0x4f, 0x0000, 0x0000,  320,  200, 32, 1,  40, 12, MD_SIS300|MD_SIS315},  /* TW: That's for people who mix up color- and fb depth */
-	{"320x200x32",   0x4f, 0x0000, 0x0000,  320,  200, 32, 1,  40, 12, MD_SIS300|MD_SIS315},
-	{"320x240x8",    0x50, 0x0132, 0x0000,  320,  240,  8, 1,  40, 15, MD_SIS300|MD_SIS315},
-	{"320x240x16",   0x56, 0x0135, 0x0000,  320,  240, 16, 1,  40, 15, MD_SIS300|MD_SIS315},
-	{"320x240x24",   0x53, 0x0000, 0x0000,  320,  240, 32, 1,  40, 15, MD_SIS300|MD_SIS315},
-	{"320x240x32",   0x53, 0x0000, 0x0000,  320,  240, 32, 1,  40, 15, MD_SIS300|MD_SIS315},
-	{"320x240x8",    0x5a, 0x0132, 0x0000,  320,  480,  8, 1,  40, 30,           MD_SIS315},  /* TW: FSTN */
-	{"320x240x16",   0x5b, 0x0135, 0x0000,  320,  480, 16, 1,  40, 30,           MD_SIS315},  /* TW: FSTN */
-	{"400x300x8",    0x51, 0x0133, 0x0000,  400,  300,  8, 1,  50, 18, MD_SIS300|MD_SIS315},
-	{"400x300x16",   0x57, 0x0136, 0x0000,  400,  300, 16, 1,  50, 18, MD_SIS300|MD_SIS315},
-	{"400x300x24",   0x54, 0x0000, 0x0000,  400,  300, 32, 1,  50, 18, MD_SIS300|MD_SIS315},
-	{"400x300x32",   0x54, 0x0000, 0x0000,  400,  300, 32, 1,  50, 18, MD_SIS300|MD_SIS315},
-	{"512x384x8",    0x52, 0x0000, 0x0000,  512,  384,  8, 1,  64, 24, MD_SIS300|MD_SIS315},
-	{"512x384x16",   0x58, 0x0000, 0x0000,  512,  384, 16, 1,  64, 24, MD_SIS300|MD_SIS315},
-	{"512x384x24",   0x5c, 0x0000, 0x0000,  512,  384, 32, 1,  64, 24, MD_SIS300|MD_SIS315},
-	{"512x384x32",   0x5c, 0x0000, 0x0000,  512,  384, 32, 1,  64, 24, MD_SIS300|MD_SIS315},
-	{"640x400x8",    0x2f, 0x0000, 0x0000,  640,  400,  8, 1,  80, 25, MD_SIS300|MD_SIS315},
-	{"640x400x16",   0x5d, 0x0000, 0x0000,  640,  400, 16, 1,  80, 25, MD_SIS300|MD_SIS315},
-	{"640x400x24",   0x5e, 0x0000, 0x0000,  640,  400, 32, 1,  80, 25, MD_SIS300|MD_SIS315},
-	{"640x400x32",   0x5e, 0x0000, 0x0000,  640,  400, 32, 1,  80, 25, MD_SIS300|MD_SIS315},
-	{"640x480x8",    0x2e, 0x0101, 0x0101,  640,  480,  8, 1,  80, 30, MD_SIS300|MD_SIS315},
-	{"640x480x16",   0x44, 0x0111, 0x0111,  640,  480, 16, 1,  80, 30, MD_SIS300|MD_SIS315},
-	{"640x480x24",   0x62, 0x013a, 0x0112,  640,  480, 32, 1,  80, 30, MD_SIS300|MD_SIS315},
-	{"640x480x32",   0x62, 0x013a, 0x0112,  640,  480, 32, 1,  80, 30, MD_SIS300|MD_SIS315},
-	{"720x480x8",    0x31, 0x0000, 0x0000,  720,  480,  8, 1,  90, 30, MD_SIS300|MD_SIS315},
-	{"720x480x16",   0x33, 0x0000, 0x0000,  720,  480, 16, 1,  90, 30, MD_SIS300|MD_SIS315},
-	{"720x480x24",   0x35, 0x0000, 0x0000,  720,  480, 32, 1,  90, 30, MD_SIS300|MD_SIS315},
-	{"720x480x32",   0x35, 0x0000, 0x0000,  720,  480, 32, 1,  90, 30, MD_SIS300|MD_SIS315},
-	{"720x576x8",    0x32, 0x0000, 0x0000,  720,  576,  8, 1,  90, 36, MD_SIS300|MD_SIS315},
-	{"720x576x16",   0x34, 0x0000, 0x0000,  720,  576, 16, 1,  90, 36, MD_SIS300|MD_SIS315},
-	{"720x576x24",   0x36, 0x0000, 0x0000,  720,  576, 32, 1,  90, 36, MD_SIS300|MD_SIS315},
-	{"720x576x32",   0x36, 0x0000, 0x0000,  720,  576, 32, 1,  90, 36, MD_SIS300|MD_SIS315},
-	{"768x576x8",    0x5f, 0x0000, 0x0000,  768,  576,  8, 1,  96, 36, MD_SIS300|MD_SIS315},
-	{"768x576x16",   0x60, 0x0000, 0x0000,  768,  576, 16, 1,  96, 36, MD_SIS300|MD_SIS315},
-	{"768x576x24",   0x61, 0x0000, 0x0000,  768,  576, 32, 1,  96, 36, MD_SIS300|MD_SIS315},
-	{"768x576x32",   0x61, 0x0000, 0x0000,  768,  576, 32, 1,  96, 36, MD_SIS300|MD_SIS315},
-	{"800x480x8",    0x70, 0x0000, 0x0000,  800,  480,  8, 1, 100, 30, MD_SIS300|MD_SIS315},
-	{"800x480x16",   0x7a, 0x0000, 0x0000,  800,  480, 16, 1, 100, 30, MD_SIS300|MD_SIS315},
-	{"800x480x24",   0x76, 0x0000, 0x0000,  800,  480, 32, 1, 100, 30, MD_SIS300|MD_SIS315},
-	{"800x480x32",   0x76, 0x0000, 0x0000,  800,  480, 32, 1, 100, 30, MD_SIS300|MD_SIS315},
+/*0*/	{"none",         {0xff,0xff}, 0x0000, 0x0000,    0,    0,  0, 0,   0,  0, MD_SIS300|MD_SIS315},
+	{"320x200x8",    {0x59,0x59}, 0x0138, 0x0000,  320,  200,  8, 1,  40, 12, MD_SIS300|MD_SIS315},
+	{"320x200x16",   {0x41,0x41}, 0x010e, 0x0000,  320,  200, 16, 1,  40, 12, MD_SIS300|MD_SIS315},
+	{"320x200x24",   {0x4f,0x4f}, 0x0000, 0x0000,  320,  200, 32, 1,  40, 12, MD_SIS300|MD_SIS315},  /* That's for people who mix up color- and fb depth */
+	{"320x200x32",   {0x4f,0x4f}, 0x0000, 0x0000,  320,  200, 32, 1,  40, 12, MD_SIS300|MD_SIS315},
+	{"320x240x8",    {0x50,0x50}, 0x0132, 0x0000,  320,  240,  8, 1,  40, 15, MD_SIS300|MD_SIS315},
+	{"320x240x16",   {0x56,0x56}, 0x0135, 0x0000,  320,  240, 16, 1,  40, 15, MD_SIS300|MD_SIS315},
+	{"320x240x24",   {0x53,0x53}, 0x0000, 0x0000,  320,  240, 32, 1,  40, 15, MD_SIS300|MD_SIS315},
+	{"320x240x32",   {0x53,0x53}, 0x0000, 0x0000,  320,  240, 32, 1,  40, 15, MD_SIS300|MD_SIS315},
+	{"320x240x8",    {0x5a,0x5a}, 0x0132, 0x0000,  320,  480,  8, 1,  40, 30,           MD_SIS315},  /* FSTN */
+/*10*/	{"320x240x16",   {0x5b,0x5b}, 0x0135, 0x0000,  320,  480, 16, 1,  40, 30,           MD_SIS315},  /* FSTN */
+	{"400x300x8",    {0x51,0x51}, 0x0133, 0x0000,  400,  300,  8, 1,  50, 18, MD_SIS300|MD_SIS315},
+	{"400x300x16",   {0x57,0x57}, 0x0136, 0x0000,  400,  300, 16, 1,  50, 18, MD_SIS300|MD_SIS315},
+	{"400x300x24",   {0x54,0x54}, 0x0000, 0x0000,  400,  300, 32, 1,  50, 18, MD_SIS300|MD_SIS315},
+	{"400x300x32",   {0x54,0x54}, 0x0000, 0x0000,  400,  300, 32, 1,  50, 18, MD_SIS300|MD_SIS315},
+	{"512x384x8",    {0x52,0x52}, 0x0000, 0x0000,  512,  384,  8, 1,  64, 24, MD_SIS300|MD_SIS315},
+	{"512x384x16",   {0x58,0x58}, 0x0000, 0x0000,  512,  384, 16, 1,  64, 24, MD_SIS300|MD_SIS315},
+	{"512x384x24",   {0x5c,0x5c}, 0x0000, 0x0000,  512,  384, 32, 1,  64, 24, MD_SIS300|MD_SIS315},
+	{"512x384x32",   {0x5c,0x5c}, 0x0000, 0x0000,  512,  384, 32, 1,  64, 24, MD_SIS300|MD_SIS315},
+	{"640x400x8",    {0x2f,0x2f}, 0x0000, 0x0000,  640,  400,  8, 1,  80, 25, MD_SIS300|MD_SIS315},
+/*20*/	{"640x400x16",   {0x5d,0x5d}, 0x0000, 0x0000,  640,  400, 16, 1,  80, 25, MD_SIS300|MD_SIS315},
+	{"640x400x24",   {0x5e,0x5e}, 0x0000, 0x0000,  640,  400, 32, 1,  80, 25, MD_SIS300|MD_SIS315},
+	{"640x400x32",   {0x5e,0x5e}, 0x0000, 0x0000,  640,  400, 32, 1,  80, 25, MD_SIS300|MD_SIS315},
+	{"640x480x8",    {0x2e,0x2e}, 0x0101, 0x0101,  640,  480,  8, 1,  80, 30, MD_SIS300|MD_SIS315},
+	{"640x480x16",   {0x44,0x44}, 0x0111, 0x0111,  640,  480, 16, 1,  80, 30, MD_SIS300|MD_SIS315},
+	{"640x480x24",   {0x62,0x62}, 0x013a, 0x0112,  640,  480, 32, 1,  80, 30, MD_SIS300|MD_SIS315},
+	{"640x480x32",   {0x62,0x62}, 0x013a, 0x0112,  640,  480, 32, 1,  80, 30, MD_SIS300|MD_SIS315},
+	{"720x480x8",    {0x31,0x31}, 0x0000, 0x0000,  720,  480,  8, 1,  90, 30, MD_SIS300|MD_SIS315},
+	{"720x480x16",   {0x33,0x33}, 0x0000, 0x0000,  720,  480, 16, 1,  90, 30, MD_SIS300|MD_SIS315},
+	{"720x480x24",   {0x35,0x35}, 0x0000, 0x0000,  720,  480, 32, 1,  90, 30, MD_SIS300|MD_SIS315},
+/*30*/	{"720x480x32",   {0x35,0x35}, 0x0000, 0x0000,  720,  480, 32, 1,  90, 30, MD_SIS300|MD_SIS315},
+	{"720x576x8",    {0x32,0x32}, 0x0000, 0x0000,  720,  576,  8, 1,  90, 36, MD_SIS300|MD_SIS315},
+	{"720x576x16",   {0x34,0x34}, 0x0000, 0x0000,  720,  576, 16, 1,  90, 36, MD_SIS300|MD_SIS315},
+	{"720x576x24",   {0x36,0x36}, 0x0000, 0x0000,  720,  576, 32, 1,  90, 36, MD_SIS300|MD_SIS315},
+	{"720x576x32",   {0x36,0x36}, 0x0000, 0x0000,  720,  576, 32, 1,  90, 36, MD_SIS300|MD_SIS315},
+	{"768x576x8",    {0x5f,0x5f}, 0x0000, 0x0000,  768,  576,  8, 1,  96, 36, MD_SIS300|MD_SIS315},
+	{"768x576x16",   {0x60,0x60}, 0x0000, 0x0000,  768,  576, 16, 1,  96, 36, MD_SIS300|MD_SIS315},
+	{"768x576x24",   {0x61,0x61}, 0x0000, 0x0000,  768,  576, 32, 1,  96, 36, MD_SIS300|MD_SIS315},
+	{"768x576x32",   {0x61,0x61}, 0x0000, 0x0000,  768,  576, 32, 1,  96, 36, MD_SIS300|MD_SIS315},
+	{"800x480x8",    {0x70,0x70}, 0x0000, 0x0000,  800,  480,  8, 1, 100, 30, MD_SIS300|MD_SIS315},
+/*40*/	{"800x480x16",   {0x7a,0x7a}, 0x0000, 0x0000,  800,  480, 16, 1, 100, 30, MD_SIS300|MD_SIS315},
+	{"800x480x24",   {0x76,0x76}, 0x0000, 0x0000,  800,  480, 32, 1, 100, 30, MD_SIS300|MD_SIS315},
+	{"800x480x32",   {0x76,0x76}, 0x0000, 0x0000,  800,  480, 32, 1, 100, 30, MD_SIS300|MD_SIS315},
 #define DEFAULT_MODE              43 /* index for 800x600x8 */
 #define DEFAULT_LCDMODE           43 /* index for 800x600x8 */
 #define DEFAULT_TVMODE            43 /* index for 800x600x8 */
-	{"800x600x8",    0x30, 0x0103, 0x0103,  800,  600,  8, 2, 100, 37, MD_SIS300|MD_SIS315},
-	{"800x600x16",   0x47, 0x0114, 0x0114,  800,  600, 16, 2, 100, 37, MD_SIS300|MD_SIS315},
-	{"800x600x24",   0x63, 0x013b, 0x0115,  800,  600, 32, 2, 100, 37, MD_SIS300|MD_SIS315},
-	{"800x600x32",   0x63, 0x013b, 0x0115,  800,  600, 32, 2, 100, 37, MD_SIS300|MD_SIS315},
-	{"848x480x8",    0x39, 0x0000, 0x0000,  848,  480,  8, 2, 106, 30, MD_SIS300|MD_SIS315},
-	{"848x480x16",   0x3b, 0x0000, 0x0000,  848,  480, 16, 2, 106, 30, MD_SIS300|MD_SIS315},
-	{"848x480x24",   0x3e, 0x0000, 0x0000,  848,  480, 32, 2, 106, 30, MD_SIS300|MD_SIS315},
-	{"848x480x32",   0x3e, 0x0000, 0x0000,  848,  480, 32, 2, 106, 30, MD_SIS300|MD_SIS315},
-	{"856x480x8",    0x3f, 0x0000, 0x0000,  856,  480,  8, 2, 107, 30, MD_SIS300|MD_SIS315},
-	{"856x480x16",   0x42, 0x0000, 0x0000,  856,  480, 16, 2, 107, 30, MD_SIS300|MD_SIS315},
-	{"856x480x24",   0x45, 0x0000, 0x0000,  856,  480, 32, 2, 107, 30, MD_SIS300|MD_SIS315},
-	{"856x480x32",   0x45, 0x0000, 0x0000,  856,  480, 32, 2, 107, 30, MD_SIS300|MD_SIS315},
-	{"1024x576x8",   0x71, 0x0000, 0x0000, 1024,  576,  8, 1, 128, 36, MD_SIS300|MD_SIS315},
-	{"1024x576x16",  0x74, 0x0000, 0x0000, 1024,  576, 16, 1, 128, 36, MD_SIS300|MD_SIS315},
-	{"1024x576x24",  0x77, 0x0000, 0x0000, 1024,  576, 32, 1, 128, 36, MD_SIS300|MD_SIS315},
-	{"1024x576x32",  0x77, 0x0000, 0x0000, 1024,  576, 32, 1, 128, 36, MD_SIS300|MD_SIS315},
-	{"1024x600x8",   0x20, 0x0000, 0x0000, 1024,  600,  8, 1, 128, 37, MD_SIS300          },
-	{"1024x600x16",  0x21, 0x0000, 0x0000, 1024,  600, 16, 1, 128, 37, MD_SIS300          },
-	{"1024x600x24",  0x22, 0x0000, 0x0000, 1024,  600, 32, 1, 128, 37, MD_SIS300          },
-	{"1024x600x32",  0x22, 0x0000, 0x0000, 1024,  600, 32, 1, 128, 37, MD_SIS300          },
-	{"1024x768x8",   0x38, 0x0105, 0x0105, 1024,  768,  8, 2, 128, 48, MD_SIS300|MD_SIS315},
-	{"1024x768x16",  0x4a, 0x0117, 0x0117, 1024,  768, 16, 2, 128, 48, MD_SIS300|MD_SIS315},
-	{"1024x768x24",  0x64, 0x013c, 0x0118, 1024,  768, 32, 2, 128, 48, MD_SIS300|MD_SIS315},
-	{"1024x768x32",  0x64, 0x013c, 0x0118, 1024,  768, 32, 2, 128, 48, MD_SIS300|MD_SIS315},
-	{"1152x768x8",   0x23, 0x0000, 0x0000, 1152,  768,  8, 1, 144, 48, MD_SIS300          },
-	{"1152x768x16",  0x24, 0x0000, 0x0000, 1152,  768, 16, 1, 144, 48, MD_SIS300          },
-	{"1152x768x24",  0x25, 0x0000, 0x0000, 1152,  768, 32, 1, 144, 48, MD_SIS300          },
-	{"1152x768x32",  0x25, 0x0000, 0x0000, 1152,  768, 32, 1, 144, 48, MD_SIS300          },
-	{"1152x864x8",   0x29, 0x0000, 0x0000, 1152,  864,  8, 1, 144, 54, MD_SIS300|MD_SIS315},
-	{"1152x864x16",  0x2a, 0x0000, 0x0000, 1152,  864, 16, 1, 144, 54, MD_SIS300|MD_SIS315},
-	{"1152x864x24",  0x2b, 0x0000, 0x0000, 1152,  864, 32, 1, 144, 54, MD_SIS300|MD_SIS315},
-	{"1152x864x32",  0x2b, 0x0000, 0x0000, 1152,  864, 32, 1, 144, 54, MD_SIS300|MD_SIS315},
-	{"1280x720x8",   0x79, 0x0000, 0x0000, 1280,  720,  8, 1, 160, 45, MD_SIS300|MD_SIS315},
-	{"1280x720x16",  0x75, 0x0000, 0x0000, 1280,  720, 16, 1, 160, 45, MD_SIS300|MD_SIS315},
-	{"1280x720x24",  0x78, 0x0000, 0x0000, 1280,  720, 32, 1, 160, 45, MD_SIS300|MD_SIS315},
-	{"1280x720x32",  0x78, 0x0000, 0x0000, 1280,  720, 32, 1, 160, 45, MD_SIS300|MD_SIS315},
-#define MODEINDEX_1280x768 79
-	{"1280x768x8",   0x23, 0x0000, 0x0000, 1280,  768,  8, 1, 160, 48, MD_SIS300|MD_SIS315},
-	{"1280x768x16",  0x24, 0x0000, 0x0000, 1280,  768, 16, 1, 160, 48, MD_SIS300|MD_SIS315},
-	{"1280x768x24",  0x25, 0x0000, 0x0000, 1280,  768, 32, 1, 160, 48, MD_SIS300|MD_SIS315},
-	{"1280x768x32",  0x25, 0x0000, 0x0000, 1280,  768, 32, 1, 160, 48, MD_SIS300|MD_SIS315},
-	{"1280x960x8",   0x7c, 0x0000, 0x0000, 1280,  960,  8, 1, 160, 60, MD_SIS300|MD_SIS315},
-	{"1280x960x16",  0x7d, 0x0000, 0x0000, 1280,  960, 16, 1, 160, 60, MD_SIS300|MD_SIS315},
-	{"1280x960x24",  0x7e, 0x0000, 0x0000, 1280,  960, 32, 1, 160, 60, MD_SIS300|MD_SIS315},
-	{"1280x960x32",  0x7e, 0x0000, 0x0000, 1280,  960, 32, 1, 160, 60, MD_SIS300|MD_SIS315},
-	{"1280x1024x8",  0x3a, 0x0107, 0x0107, 1280, 1024,  8, 2, 160, 64, MD_SIS300|MD_SIS315},
-	{"1280x1024x16", 0x4d, 0x011a, 0x011a, 1280, 1024, 16, 2, 160, 64, MD_SIS300|MD_SIS315},
-	{"1280x1024x24", 0x65, 0x013d, 0x011b, 1280, 1024, 32, 2, 160, 64, MD_SIS300|MD_SIS315},
-	{"1280x1024x32", 0x65, 0x013d, 0x011b, 1280, 1024, 32, 2, 160, 64, MD_SIS300|MD_SIS315},
-	{"1360x768x8",   0x48, 0x0000, 0x0000, 1360,  768,  8, 1, 170, 48, MD_SIS300|MD_SIS315},
-	{"1360x768x16",  0x4b, 0x0000, 0x0000, 1360,  768, 16, 1, 170, 48, MD_SIS300|MD_SIS315},
-	{"1360x768x24",  0x4e, 0x0000, 0x0000, 1360,  768, 32, 1, 170, 48, MD_SIS300|MD_SIS315},
-	{"1360x768x32",  0x4e, 0x0000, 0x0000, 1360,  768, 32, 1, 170, 48, MD_SIS300|MD_SIS315},
-	{"1360x1024x8",  0x67, 0x0000, 0x0000, 1360, 1024,  8, 1, 170, 64, MD_SIS300          },
-	{"1360x1024x16", 0x6f, 0x0000, 0x0000, 1360, 1024, 16, 1, 170, 64, MD_SIS300          },
-	{"1360x1024x24", 0x72, 0x0000, 0x0000, 1360, 1024, 32, 1, 170, 64, MD_SIS300          },
-	{"1360x1024x32", 0x72, 0x0000, 0x0000, 1360, 1024, 32, 1, 170, 64, MD_SIS300          },
-	{"1400x1050x8",  0x26, 0x0000, 0x0000, 1400, 1050,  8, 1, 175, 65,           MD_SIS315},
-	{"1400x1050x16", 0x27, 0x0000, 0x0000, 1400, 1050, 16, 1, 175, 65,           MD_SIS315},
-	{"1400x1050x24", 0x28, 0x0000, 0x0000, 1400, 1050, 32, 1, 175, 65,           MD_SIS315},
-	{"1400x1050x32", 0x28, 0x0000, 0x0000, 1400, 1050, 32, 1, 175, 65,           MD_SIS315},
-	{"1600x1200x8",  0x3c, 0x0130, 0x011c, 1600, 1200,  8, 1, 200, 75, MD_SIS300|MD_SIS315},
-	{"1600x1200x16", 0x3d, 0x0131, 0x011e, 1600, 1200, 16, 1, 200, 75, MD_SIS300|MD_SIS315},
-	{"1600x1200x24", 0x66, 0x013e, 0x011f, 1600, 1200, 32, 1, 200, 75, MD_SIS300|MD_SIS315},
-	{"1600x1200x32", 0x66, 0x013e, 0x011f, 1600, 1200, 32, 1, 200, 75, MD_SIS300|MD_SIS315},
-	{"1920x1440x8",  0x68, 0x013f, 0x0000, 1920, 1440,  8, 1, 240, 75, MD_SIS300|MD_SIS315},
-	{"1920x1440x16", 0x69, 0x0140, 0x0000, 1920, 1440, 16, 1, 240, 75, MD_SIS300|MD_SIS315},
-	{"1920x1440x24", 0x6b, 0x0141, 0x0000, 1920, 1440, 32, 1, 240, 75, MD_SIS300|MD_SIS315},
-	{"1920x1440x32", 0x6b, 0x0141, 0x0000, 1920, 1440, 32, 1, 240, 75, MD_SIS300|MD_SIS315},
-	{"2048x1536x8",  0x6c, 0x0000, 0x0000, 2048, 1536,  8, 1, 256, 96,           MD_SIS315},
-	{"2048x1536x16", 0x6d, 0x0000, 0x0000, 2048, 1536, 16, 1, 256, 96,           MD_SIS315},
-	{"2048x1536x24", 0x6e, 0x0000, 0x0000, 2048, 1536, 32, 1, 256, 96,           MD_SIS315},
-	{"2048x1536x32", 0x6e, 0x0000, 0x0000, 2048, 1536, 32, 1, 256, 96,           MD_SIS315},
-	{"\0", 0x00, 0, 0, 0, 0, 0, 0, 0}
+	{"800x600x8",    {0x30,0x30}, 0x0103, 0x0103,  800,  600,  8, 2, 100, 37, MD_SIS300|MD_SIS315},
+	{"800x600x16",   {0x47,0x47}, 0x0114, 0x0114,  800,  600, 16, 2, 100, 37, MD_SIS300|MD_SIS315},
+	{"800x600x24",   {0x63,0x63}, 0x013b, 0x0115,  800,  600, 32, 2, 100, 37, MD_SIS300|MD_SIS315},
+	{"800x600x32",   {0x63,0x63}, 0x013b, 0x0115,  800,  600, 32, 2, 100, 37, MD_SIS300|MD_SIS315},
+	{"848x480x8",    {0x39,0x39}, 0x0000, 0x0000,  848,  480,  8, 2, 106, 30, MD_SIS300|MD_SIS315},
+	{"848x480x16",   {0x3b,0x3b}, 0x0000, 0x0000,  848,  480, 16, 2, 106, 30, MD_SIS300|MD_SIS315},
+	{"848x480x24",   {0x3e,0x3e}, 0x0000, 0x0000,  848,  480, 32, 2, 106, 30, MD_SIS300|MD_SIS315},
+/*50*/	{"848x480x32",   {0x3e,0x3e}, 0x0000, 0x0000,  848,  480, 32, 2, 106, 30, MD_SIS300|MD_SIS315},
+	{"856x480x8",    {0x3f,0x3f}, 0x0000, 0x0000,  856,  480,  8, 2, 107, 30, MD_SIS300|MD_SIS315},
+	{"856x480x16",   {0x42,0x42}, 0x0000, 0x0000,  856,  480, 16, 2, 107, 30, MD_SIS300|MD_SIS315},
+	{"856x480x24",   {0x45,0x45}, 0x0000, 0x0000,  856,  480, 32, 2, 107, 30, MD_SIS300|MD_SIS315},
+	{"856x480x32",   {0x45,0x45}, 0x0000, 0x0000,  856,  480, 32, 2, 107, 30, MD_SIS300|MD_SIS315},
+	{"960x540x8",    {0x1d,0x1d}, 0x0000, 0x0000,  960,  540,  8, 1, 120, 33,           MD_SIS315},
+	{"960x540x16",   {0x1e,0x1e}, 0x0000, 0x0000,  960,  540, 16, 1, 120, 33,           MD_SIS315},
+	{"960x540x24",   {0x1f,0x1f}, 0x0000, 0x0000,  960,  540, 32, 1, 120, 33,           MD_SIS315},
+	{"960x540x32",   {0x1f,0x1f}, 0x0000, 0x0000,  960,  540, 32, 1, 120, 33,           MD_SIS315},
+	{"1024x576x8",   {0x71,0x71}, 0x0000, 0x0000, 1024,  576,  8, 1, 128, 36, MD_SIS300|MD_SIS315},
+/*60*/	{"1024x576x16",  {0x74,0x74}, 0x0000, 0x0000, 1024,  576, 16, 1, 128, 36, MD_SIS300|MD_SIS315},
+	{"1024x576x24",  {0x77,0x77}, 0x0000, 0x0000, 1024,  576, 32, 1, 128, 36, MD_SIS300|MD_SIS315},
+	{"1024x576x32",  {0x77,0x77}, 0x0000, 0x0000, 1024,  576, 32, 1, 128, 36, MD_SIS300|MD_SIS315},
+	{"1024x600x8",   {0x20,0x20}, 0x0000, 0x0000, 1024,  600,  8, 1, 128, 37, MD_SIS300          },
+	{"1024x600x16",  {0x21,0x21}, 0x0000, 0x0000, 1024,  600, 16, 1, 128, 37, MD_SIS300          },
+	{"1024x600x24",  {0x22,0x22}, 0x0000, 0x0000, 1024,  600, 32, 1, 128, 37, MD_SIS300          },
+	{"1024x600x32",  {0x22,0x22}, 0x0000, 0x0000, 1024,  600, 32, 1, 128, 37, MD_SIS300          },
+	{"1024x768x8",   {0x38,0x38}, 0x0105, 0x0105, 1024,  768,  8, 2, 128, 48, MD_SIS300|MD_SIS315},
+	{"1024x768x16",  {0x4a,0x4a}, 0x0117, 0x0117, 1024,  768, 16, 2, 128, 48, MD_SIS300|MD_SIS315},
+	{"1024x768x24",  {0x64,0x64}, 0x013c, 0x0118, 1024,  768, 32, 2, 128, 48, MD_SIS300|MD_SIS315},
+/*70*/	{"1024x768x32",  {0x64,0x64}, 0x013c, 0x0118, 1024,  768, 32, 2, 128, 48, MD_SIS300|MD_SIS315},
+	{"1152x768x8",   {0x23,0x23}, 0x0000, 0x0000, 1152,  768,  8, 1, 144, 48, MD_SIS300          },
+	{"1152x768x16",  {0x24,0x24}, 0x0000, 0x0000, 1152,  768, 16, 1, 144, 48, MD_SIS300          },
+	{"1152x768x24",  {0x25,0x25}, 0x0000, 0x0000, 1152,  768, 32, 1, 144, 48, MD_SIS300          },
+	{"1152x768x32",  {0x25,0x25}, 0x0000, 0x0000, 1152,  768, 32, 1, 144, 48, MD_SIS300          },
+	{"1152x864x8",   {0x29,0x29}, 0x0000, 0x0000, 1152,  864,  8, 1, 144, 54, MD_SIS300|MD_SIS315},
+	{"1152x864x16",  {0x2a,0x2a}, 0x0000, 0x0000, 1152,  864, 16, 1, 144, 54, MD_SIS300|MD_SIS315},
+	{"1152x864x24",  {0x2b,0x2b}, 0x0000, 0x0000, 1152,  864, 32, 1, 144, 54, MD_SIS300|MD_SIS315},
+	{"1152x864x32",  {0x2b,0x2b}, 0x0000, 0x0000, 1152,  864, 32, 1, 144, 54, MD_SIS300|MD_SIS315},
+	{"1280x720x8",   {0x79,0x79}, 0x0000, 0x0000, 1280,  720,  8, 1, 160, 45, MD_SIS300|MD_SIS315},
+/*80*/	{"1280x720x16",  {0x75,0x75}, 0x0000, 0x0000, 1280,  720, 16, 1, 160, 45, MD_SIS300|MD_SIS315},
+	{"1280x720x24",  {0x78,0x78}, 0x0000, 0x0000, 1280,  720, 32, 1, 160, 45, MD_SIS300|MD_SIS315},
+	{"1280x720x32",  {0x78,0x78}, 0x0000, 0x0000, 1280,  720, 32, 1, 160, 45, MD_SIS300|MD_SIS315},
+	{"1280x768x8",   {0x55,0x23}, 0x0000, 0x0000, 1280,  768,  8, 1, 160, 48, MD_SIS300|MD_SIS315},
+	{"1280x768x16",  {0x5a,0x24}, 0x0000, 0x0000, 1280,  768, 16, 1, 160, 48, MD_SIS300|MD_SIS315},
+	{"1280x768x24",  {0x5b,0x25}, 0x0000, 0x0000, 1280,  768, 32, 1, 160, 48, MD_SIS300|MD_SIS315},
+	{"1280x768x32",  {0x5b,0x25}, 0x0000, 0x0000, 1280,  768, 32, 1, 160, 48, MD_SIS300|MD_SIS315},
+	{"1280x800x8",   {0x14,0x14}, 0x0000, 0x0000, 1280,  800,  8, 1, 160, 50,           MD_SIS315},
+	{"1280x800x16",  {0x15,0x15}, 0x0000, 0x0000, 1280,  800, 16, 1, 160, 50,           MD_SIS315},
+	{"1280x800x24",  {0x16,0x16}, 0x0000, 0x0000, 1280,  800, 32, 1, 160, 50,           MD_SIS315},
+/*90*/	{"1280x800x32",  {0x16,0x16}, 0x0000, 0x0000, 1280,  800, 32, 1, 160, 50,           MD_SIS315},
+	{"1280x960x8",   {0x7c,0x7c}, 0x0000, 0x0000, 1280,  960,  8, 1, 160, 60, MD_SIS300|MD_SIS315},
+	{"1280x960x16",  {0x7d,0x7d}, 0x0000, 0x0000, 1280,  960, 16, 1, 160, 60, MD_SIS300|MD_SIS315},
+	{"1280x960x24",  {0x7e,0x7e}, 0x0000, 0x0000, 1280,  960, 32, 1, 160, 60, MD_SIS300|MD_SIS315},
+	{"1280x960x32",  {0x7e,0x7e}, 0x0000, 0x0000, 1280,  960, 32, 1, 160, 60, MD_SIS300|MD_SIS315},
+	{"1280x1024x8",  {0x3a,0x3a}, 0x0107, 0x0107, 1280, 1024,  8, 2, 160, 64, MD_SIS300|MD_SIS315},
+	{"1280x1024x16", {0x4d,0x4d}, 0x011a, 0x011a, 1280, 1024, 16, 2, 160, 64, MD_SIS300|MD_SIS315},
+	{"1280x1024x24", {0x65,0x65}, 0x013d, 0x011b, 1280, 1024, 32, 2, 160, 64, MD_SIS300|MD_SIS315},
+	{"1280x1024x32", {0x65,0x65}, 0x013d, 0x011b, 1280, 1024, 32, 2, 160, 64, MD_SIS300|MD_SIS315},
+	{"1360x768x8",   {0x48,0x48}, 0x0000, 0x0000, 1360,  768,  8, 1, 170, 48, MD_SIS300|MD_SIS315},
+/*100*/	{"1360x768x16",  {0x4b,0x4b}, 0x0000, 0x0000, 1360,  768, 16, 1, 170, 48, MD_SIS300|MD_SIS315},
+	{"1360x768x24",  {0x4e,0x4e}, 0x0000, 0x0000, 1360,  768, 32, 1, 170, 48, MD_SIS300|MD_SIS315},
+	{"1360x768x32",  {0x4e,0x4e}, 0x0000, 0x0000, 1360,  768, 32, 1, 170, 48, MD_SIS300|MD_SIS315},
+	{"1360x1024x8",  {0x67,0x67}, 0x0000, 0x0000, 1360, 1024,  8, 1, 170, 64, MD_SIS300          },
+	{"1360x1024x16", {0x6f,0x6f}, 0x0000, 0x0000, 1360, 1024, 16, 1, 170, 64, MD_SIS300          },
+	{"1360x1024x24", {0x72,0x72}, 0x0000, 0x0000, 1360, 1024, 32, 1, 170, 64, MD_SIS300          },
+	{"1360x1024x32", {0x72,0x72}, 0x0000, 0x0000, 1360, 1024, 32, 1, 170, 64, MD_SIS300          },
+	{"1400x1050x8",  {0x26,0x26}, 0x0000, 0x0000, 1400, 1050,  8, 1, 175, 65,           MD_SIS315},
+	{"1400x1050x16", {0x27,0x27}, 0x0000, 0x0000, 1400, 1050, 16, 1, 175, 65,           MD_SIS315},
+	{"1400x1050x24", {0x28,0x28}, 0x0000, 0x0000, 1400, 1050, 32, 1, 175, 65,           MD_SIS315},
+/*110*/	{"1400x1050x32", {0x28,0x28}, 0x0000, 0x0000, 1400, 1050, 32, 1, 175, 65,           MD_SIS315},
+	{"1600x1200x8",  {0x3c,0x3c}, 0x0130, 0x011c, 1600, 1200,  8, 1, 200, 75, MD_SIS300|MD_SIS315},
+	{"1600x1200x16", {0x3d,0x3d}, 0x0131, 0x011e, 1600, 1200, 16, 1, 200, 75, MD_SIS300|MD_SIS315},
+	{"1600x1200x24", {0x66,0x66}, 0x013e, 0x011f, 1600, 1200, 32, 1, 200, 75, MD_SIS300|MD_SIS315},
+	{"1600x1200x32", {0x66,0x66}, 0x013e, 0x011f, 1600, 1200, 32, 1, 200, 75, MD_SIS300|MD_SIS315},
+	{"1680x1050x8",  {0x17,0x17}, 0x0000, 0x0000, 1680, 1050,  8, 1, 210, 65,           MD_SIS315},
+	{"1680x1050x16", {0x18,0x18}, 0x0000, 0x0000, 1680, 1050, 16, 1, 210, 65,           MD_SIS315},
+	{"1680x1050x24", {0x19,0x19}, 0x0000, 0x0000, 1680, 1050, 32, 1, 210, 65,           MD_SIS315},
+	{"1680x1050x32", {0x19,0x19}, 0x0000, 0x0000, 1680, 1050, 32, 1, 210, 65,           MD_SIS315},
+	{"1920x1080x8",  {0x2c,0x2c}, 0x0000, 0x0000, 1920, 1080,  8, 1, 240, 67,           MD_SIS315},
+/*120*/	{"1920x1080x16", {0x2d,0x2d}, 0x0000, 0x0000, 1920, 1080, 16, 1, 240, 67,           MD_SIS315},
+	{"1920x1080x24", {0x73,0x73}, 0x0000, 0x0000, 1920, 1080, 32, 1, 240, 67,           MD_SIS315},
+	{"1920x1080x32", {0x73,0x73}, 0x0000, 0x0000, 1920, 1080, 32, 1, 240, 67,           MD_SIS315},
+	{"1920x1440x8",  {0x68,0x68}, 0x013f, 0x0000, 1920, 1440,  8, 1, 240, 75, MD_SIS300|MD_SIS315},
+	{"1920x1440x16", {0x69,0x69}, 0x0140, 0x0000, 1920, 1440, 16, 1, 240, 75, MD_SIS300|MD_SIS315},
+	{"1920x1440x24", {0x6b,0x6b}, 0x0141, 0x0000, 1920, 1440, 32, 1, 240, 75, MD_SIS300|MD_SIS315},
+	{"1920x1440x32", {0x6b,0x6b}, 0x0141, 0x0000, 1920, 1440, 32, 1, 240, 75, MD_SIS300|MD_SIS315},
+	{"2048x1536x8",  {0x6c,0x6c}, 0x0000, 0x0000, 2048, 1536,  8, 1, 256, 96,           MD_SIS315},
+	{"2048x1536x16", {0x6d,0x6d}, 0x0000, 0x0000, 2048, 1536, 16, 1, 256, 96,           MD_SIS315},
+	{"2048x1536x24", {0x6e,0x6e}, 0x0000, 0x0000, 2048, 1536, 32, 1, 256, 96,           MD_SIS315},
+/*130*/	{"2048x1536x32", {0x6e,0x6e}, 0x0000, 0x0000, 2048, 1536, 32, 1, 256, 96,           MD_SIS315},
+	{"\0", {0x00,0x00}, 0, 0, 0, 0, 0, 0, 0}
+};
+
+#define SIS_LCD_NUMBER 17
+static const struct _sis_lcd_data {
+	u32 lcdtype;
+	u16 xres;
+	u16 yres;
+	u8  default_mode_idx;
+} sis_lcd_data[] = {
+	{ LCD_640x480,    640,  480,  23 },
+	{ LCD_800x600,    800,  600,  43 },
+	{ LCD_1024x600,  1024,  600,  63 },
+	{ LCD_1024x768,  1024,  768,  67 },
+	{ LCD_1152x768,  1152,  768,  71 },
+	{ LCD_1152x864,  1152,  864,  75 },
+	{ LCD_1280x720,  1280,  720,  79 },
+	{ LCD_1280x768,  1280,  768,  83 },
+	{ LCD_1280x800,  1280,  800,  87 },
+	{ LCD_1280x960,  1280,  960,  91 },
+	{ LCD_1280x1024, 1280, 1024,  95 },
+	{ LCD_1400x1050, 1400, 1050, 107 },
+	{ LCD_1680x1050, 1680, 1050, 115 },
+	{ LCD_1600x1200, 1600, 1200, 111 },
+	{ LCD_640x480_2,  640,  480,  23 },
+	{ LCD_640x480_3,  640,  480,  23 },
+	{ LCD_320x480,    320,  480,   9 },
 };
 
-/* mode-related variables */
-#ifdef MODULE
-int sisfb_mode_idx = MODE_INDEX_NONE;  /* Don't use a mode by default if we are a module */
-#else
-int sisfb_mode_idx = -1;               /* Use a default mode if we are inside the kernel */
-#endif
-u8  sisfb_mode_no  = 0;
-u8  sisfb_rate_idx = 0;
-
 /* CR36 evaluation */
 const USHORT sis300paneltype[] =
     { LCD_UNKNOWN,   LCD_800x600,   LCD_1024x768,  LCD_1280x1024,
       LCD_1280x960,  LCD_640x480,   LCD_1024x600,  LCD_1152x768,
-      LCD_1024x768,  LCD_1024x768,  LCD_1024x768,  LCD_1024x768,
-      LCD_1024x768,  LCD_1024x768,  LCD_320x480,   LCD_1024x768 };
+      LCD_UNKNOWN,   LCD_UNKNOWN,   LCD_UNKNOWN,   LCD_UNKNOWN,
+      LCD_UNKNOWN,   LCD_UNKNOWN,   LCD_UNKNOWN,   LCD_UNKNOWN };
 
 const USHORT sis310paneltype[] =
     { LCD_UNKNOWN,   LCD_800x600,   LCD_1024x768,  LCD_1280x1024,
       LCD_640x480,   LCD_1024x600,  LCD_1152x864,  LCD_1280x960,
       LCD_1152x768,  LCD_1400x1050, LCD_1280x768,  LCD_1600x1200,
-      LCD_640x480_2, LCD_640x480_3, LCD_320x480,   LCD_1024x768 };
+      LCD_640x480_2, LCD_640x480_3, LCD_UNKNOWN,   LCD_UNKNOWN };
+
+const USHORT sis661paneltype[] =
+    { LCD_UNKNOWN,   LCD_800x600,   LCD_1024x768,  LCD_1280x1024,
+      LCD_640x480,   LCD_1024x600,  LCD_1152x864,  LCD_1280x960,
+      LCD_1152x768,  LCD_1400x1050, LCD_1280x768,  LCD_1600x1200,
+      LCD_1280x800,  LCD_1680x1050, LCD_1280x720,  LCD_UNKNOWN };
 
 #define FL_550_DSTN 0x01
 #define FL_550_FSTN 0x02
+#define FL_300      0x04
+#define FL_315      0x08
 
-static const struct _sis_crt2type {
-	char name[10];
-	int type_no;
-	int tvplug_no;
-	unsigned short flags;
-} sis_crt2type[] = {
-	{"NONE", 	0, 		-1,        0},
-	{"LCD",  	CRT2_LCD, 	-1,        0},
-	{"TV",   	CRT2_TV, 	-1,        0},
-	{"VGA",  	CRT2_VGA, 	-1,        0},
-	{"SVIDEO", 	CRT2_TV, 	TV_SVIDEO, 0},
-	{"COMPOSITE", 	CRT2_TV, 	TV_AVIDEO, 0},
-	{"SCART", 	CRT2_TV, 	TV_SCART,  0},
-	{"DSTN",        CRT2_LCD,       -1,        FL_550_DSTN},
-	{"FSTN",        CRT2_LCD,       -1,        FL_550_FSTN},
-	{"\0",  	-1, 		-1,        0}
-};
-
-/* Queue mode selection for 310 series */
-static const struct _sis_queuemode {
-	char name[6];
-	int type_no;
-} sis_queuemode[] = {
-	{"AGP",  	AGP_CMD_QUEUE},
-	{"VRAM", 	VM_CMD_QUEUE},
-	{"MMIO", 	MMIO_CMD},
-	{"\0",   	-1}
+static struct _sis_crt2type {
+	char name[32];
+	u32 type_no;
+	u32 tvplug_no;
+	u16 flags;
+} sis_crt2type[] __initdata = {
+	{"NONE", 	     0, 	-1,                     FL_300|FL_315},
+	{"LCD",  	     CRT2_LCD, 	-1,                     FL_300|FL_315},
+	{"TV",   	     CRT2_TV, 	-1,                     FL_300|FL_315},
+	{"VGA",  	     CRT2_VGA, 	-1,                     FL_300|FL_315},
+	{"SVIDEO", 	     CRT2_TV, 	TV_SVIDEO,              FL_300|FL_315},
+	{"COMPOSITE", 	     CRT2_TV, 	TV_AVIDEO,              FL_300|FL_315},
+	{"CVBS", 	     CRT2_TV, 	TV_AVIDEO,              FL_300|FL_315},
+	{"SVIDEO+COMPOSITE", CRT2_TV,   TV_AVIDEO|TV_SVIDEO,    FL_300|FL_315},
+	{"COMPOSITE+SVIDEO", CRT2_TV,   TV_AVIDEO|TV_SVIDEO,    FL_300|FL_315},
+	{"SVIDEO+CVBS",      CRT2_TV,   TV_AVIDEO|TV_SVIDEO,    FL_300|FL_315},
+	{"CVBS+SVIDEO",      CRT2_TV,   TV_AVIDEO|TV_SVIDEO,    FL_300|FL_315},
+	{"SCART", 	     CRT2_TV, 	TV_SCART,               FL_300|FL_315},
+	{"HIVISION",	     CRT2_TV,   TV_HIVISION,            FL_315},
+	{"YPBPR480I",	     CRT2_TV,   TV_YPBPR|TV_YPBPR525I,  FL_315},
+	{"YPBPR480P",	     CRT2_TV,   TV_YPBPR|TV_YPBPR525P,  FL_315},
+	{"YPBPR720P",	     CRT2_TV,   TV_YPBPR|TV_YPBPR750P,  FL_315},
+	{"YPBPR1080I",	     CRT2_TV,   TV_YPBPR|TV_YPBPR1080I, FL_315},
+	{"DSTN",             CRT2_LCD,  -1,                     FL_315|FL_550_DSTN},
+	{"FSTN",             CRT2_LCD,  -1,                     FL_315|FL_550_FSTN},
+	{"\0",  	     -1, 	-1,                     0}
 };
 
 /* TV standard */
-static const struct _sis_tvtype {
+static struct _sis_tvtype {
 	char name[6];
-	int type_no;
-} sis_tvtype[] = {
+	u32 type_no;
+} sis_tvtype[] __initdata = {
 	{"PAL",  	TV_PAL},
 	{"NTSC", 	TV_NTSC},
+	{"PALM",  	TV_PAL|TV_PALM},
+	{"PALN",  	TV_PAL|TV_PALN},
+	{"NTSCJ",  	TV_NTSC|TV_NTSCJ},
 	{"\0",   	-1}
 };
 
@@ -687,6 +425,7 @@
 	{7,  800,  600, 120,  TRUE}, {8,  800,  600, 160,  TRUE},
 	{1,  848,  480,  39,  TRUE}, {2,  848,  480,  60,  TRUE},
 	{1,  856,  480,  39,  TRUE}, {2,  856,  480,  60,  TRUE},
+	{1,  960,  540,  60,  TRUE},
 	{1, 1024,  576,  60,  TRUE}, {2, 1024,  576,  75,  TRUE}, {3, 1024,  576,  85,  TRUE},
 	{1, 1024,  600,  60,  TRUE},
 	{1, 1024,  768,  43,  TRUE}, {2, 1024,  768,  60,  TRUE}, {3, 1024,  768,  70, FALSE},
@@ -696,6 +435,7 @@
 	{1, 1152,  864,  75,  TRUE}, {2, 1152,  864,  84,  TRUE},
 	{1, 1280,  720,  60,  TRUE}, {2, 1280,  720,  75,  TRUE}, {3, 1280,  720,  85,  TRUE},
 	{1, 1280,  768,  60,  TRUE},
+	{1, 1280,  800,  60,  TRUE},
 	{1, 1280,  960,  60,  TRUE}, {2, 1280,  960,  85,  TRUE},
 	{1, 1280, 1024,  43,  TRUE}, {2, 1280, 1024,  60,  TRUE}, {3, 1280, 1024,  75,  TRUE},
 	{4, 1280, 1024,  85,  TRUE},
@@ -705,6 +445,8 @@
 	{1, 1600, 1200,  60,  TRUE}, {2, 1600, 1200,  65,  TRUE}, {3, 1600, 1200,  70,  TRUE},
 	{4, 1600, 1200,  75,  TRUE}, {5, 1600, 1200,  85,  TRUE}, {6, 1600, 1200, 100,  TRUE},
 	{7, 1600, 1200, 120,  TRUE},
+	{1, 1680, 1050,  60,  TRUE},
+	{1, 1920, 1080,  30,  TRUE},
 	{1, 1920, 1440,  60,  TRUE}, {2, 1920, 1440,  65,  TRUE}, {3, 1920, 1440,  70,  TRUE},
 	{4, 1920, 1440,  75,  TRUE}, {5, 1920, 1440,  85,  TRUE}, {6, 1920, 1440, 100,  TRUE},
 	{1, 2048, 1536,  60,  TRUE}, {2, 2048, 1536,  65,  TRUE}, {3, 2048, 1536,  70,  TRUE},
@@ -712,16 +454,6 @@
 	{0,    0,    0,   0, FALSE}
 };
 
-static struct sisfb_monitor {
-	u16 hmin;
-	u16 hmax;
-	u16 vmin;
-	u16 vmax;
-	u32 dclockmax;
-	u8  feature;
-	BOOLEAN datavalid;
-} sisfb_thismonitor;
-
 static const struct _sisfbddcsmodes {
 	u32 mask;
 	u16 h;
@@ -760,35 +492,33 @@
        { 1920, 1440, 75, 113,297000}
 };
 
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
-static u8 sisfb_lastrates[128];
-#endif
-
-static const struct _chswtable {
-    int subsysVendor;
-    int subsysCard;
+#ifdef CONFIG_FB_SIS_300
+static struct _chswtable {
+    u16  subsysVendor;
+    u16  subsysCard;
     char *vendorName;
     char *cardName;
-} mychswtable[] = {
+} mychswtable[] __devinitdata = {
         { 0x1631, 0x1002, "Mitachi", "0x1002" },
 	{ 0x1071, 0x7521, "Mitac"  , "7521P"  },
 	{ 0,      0,      ""       , ""       }
 };
+#endif
 
-static const struct _customttable {
-    unsigned short chipID;
-    char *biosversion;
-    char *biosdate;
-    unsigned long bioschksum;
-    unsigned short biosFootprintAddr[5];
-    unsigned char biosFootprintData[5];
-    unsigned short pcisubsysvendor;
-    unsigned short pcisubsyscard;
-    char *vendorName;
-    char *cardName;
-    unsigned long SpecialID;
-    char *optionName;
-} mycustomttable[] = {
+static struct _customttable {
+    u16   chipID;
+    char  *biosversion;
+    char  *biosdate;
+    u32   bioschksum;
+    u16   biosFootprintAddr[5];
+    u8    biosFootprintData[5];
+    u16   pcisubsysvendor;
+    u16   pcisubsyscard;
+    char  *vendorName;
+    char  *cardName;
+    u32   SpecialID;
+    char  *optionName;
+} mycustomttable[] __devinitdata = {
 	{ SIS_630, "2.00.07", "09/27/2002-13:38:25",
 	  0x3240A8,
 	  { 0x220, 0x227, 0x228, 0x229, 0x0ee },
@@ -917,46 +647,6 @@
 	}
 };
 
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
-/* Offscreen layout */
-typedef struct _SIS_GLYINFO {
-	unsigned char ch;
-	int fontwidth;
-	int fontheight;
-	u8 gmask[72];
-	int ngmask;
-} SIS_GLYINFO;
-
-static char sisfb_fontname[40];
-#endif
-
-typedef struct _SIS_OH {
-	struct _SIS_OH *poh_next;
-	struct _SIS_OH *poh_prev;
-	unsigned long offset;
-	unsigned long size;
-} SIS_OH;
-
-typedef struct _SIS_OHALLOC {
-	struct _SIS_OHALLOC *poha_next;
-	SIS_OH aoh[1];
-} SIS_OHALLOC;
-
-typedef struct _SIS_HEAP {
-	SIS_OH oh_free;
-	SIS_OH oh_used;
-	SIS_OH *poh_freelist;
-	SIS_OHALLOC *poha_chain;
-	unsigned long max_freesize;
-} SIS_HEAP;
-
-static unsigned long sisfb_hwcursor_vbase;
-
-static unsigned long sisfb_heap_start;
-static unsigned long sisfb_heap_end;
-static unsigned long sisfb_heap_size;
-static SIS_HEAP      sisfb_heap;
-
 static const struct _sis_TV_filter {
 	u8 filter[9][4];
 } sis_TV_filter[] = {
@@ -1106,9 +796,6 @@
 	   {0xFF,0xFF,0xFF,0xFF} }}
 };
 
-static int           filter = -1;
-static unsigned char filter_tb;
-
 /* ---------------------- Prototypes ------------------------- */
 
 /* Interface used by the world */
@@ -1119,7 +806,11 @@
 /* Interface to the low level console driver */
 int             sisfb_init(void);
 
+
 /* fbdev routines */
+static int      sisfb_get_fix(struct fb_fix_screeninfo *fix, int con,
+			      struct fb_info *info);
+
 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
 static int      sisfb_get_fix(struct fb_fix_screeninfo *fix, 
 			      int con,
@@ -1130,7 +821,8 @@
 static int      sisfb_set_var(struct fb_var_screeninfo *var, 
 			      int con,
 			      struct fb_info *info);
-static void     sisfb_crtc_to_var(struct fb_var_screeninfo *var);			      
+static void     sisfb_crtc_to_var(struct sis_video_info *ivideo,
+			          struct fb_var_screeninfo *var);
 static int      sisfb_get_cmap(struct fb_cmap *cmap, 
 			       int kspc, 
 			       int con,
@@ -1153,108 +845,67 @@
 			      struct fb_info *fb_info);
 static void     sisfb_do_install_cmap(int con, 
                                       struct fb_info *info);
-static void     sis_get_glyph(struct fb_info *info, 
-                              SIS_GLYINFO *gly);
-static int 	sisfb_mmap(struct fb_info *info, struct file *file,
-		           struct vm_area_struct *vma);	
 static int      sisfb_ioctl(struct inode *inode, struct file *file,
 		       	    unsigned int cmd, unsigned long arg, int con,
 		       	    struct fb_info *info);		      
 #endif			
 
 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
+static int      sisfb_ioctl(struct inode *inode, struct file *file,
+		       	    unsigned int cmd, unsigned long arg,
+		       	    struct fb_info *info);
 static int      sisfb_set_par(struct fb_info *info);
 static int      sisfb_blank(int blank, 
                             struct fb_info *info);			
-static int 	sisfb_mmap(struct fb_info *info, struct file *file,
-		           struct vm_area_struct *vma);			    
 extern void     fbcon_sis_fillrect(struct fb_info *info, 
                                    const struct fb_fillrect *rect);
 extern void     fbcon_sis_copyarea(struct fb_info *info, 
                                    const struct fb_copyarea *area);
 extern int      fbcon_sis_sync(struct fb_info *info);
-static int      sisfb_ioctl(struct inode *inode, 
-	 		    struct file *file,
-		       	    unsigned int cmd, 
-			    unsigned long arg, 
-		       	    struct fb_info *info);
-extern int	sisfb_mode_rate_to_dclock(SiS_Private *SiS_Pr, 
-			      PSIS_HW_INFO HwDeviceExtension,
-			      unsigned char modeno, unsigned char rateindex);	
-extern int      sisfb_mode_rate_to_ddata(SiS_Private *SiS_Pr, PSIS_HW_INFO HwDeviceExtension,
-			 unsigned char modeno, unsigned char rateindex,
-			 unsigned int *left_margin, unsigned int *right_margin, 
-			 unsigned int *upper_margin, unsigned int *lower_margin,
-			 unsigned int *hsync_len, unsigned int *vsync_len,
-			 unsigned int *sync, unsigned int *vmode);
 #endif
 			
-static int      sisfb_get_fix(struct fb_fix_screeninfo *fix, int con,
-			      struct fb_info *info);
-
 /* Internal 2D accelerator functions */
-extern int      sisfb_initaccel(void);
-extern void     sisfb_syncaccel(void);
+extern int      sisfb_initaccel(struct sis_video_info *ivideo);
+extern void     sisfb_syncaccel(struct sis_video_info *ivideo);
 
 /* Internal general routines */
 static void     sisfb_search_mode(char *name, BOOLEAN quiet);
-static int      sisfb_validate_mode(int modeindex, unsigned long vbflags);
-static u8       sisfb_search_refresh_rate(unsigned int rate, int index);
+static int      sisfb_validate_mode(struct sis_video_info *ivideo, int modeindex, u32 vbflags);
+static u8       sisfb_search_refresh_rate(struct sis_video_info *ivideo, unsigned int rate,
+			int index);
 static int      sisfb_setcolreg(unsigned regno, unsigned red, unsigned green,
 			unsigned blue, unsigned transp,
 			struct fb_info *fb_info);
 static int      sisfb_do_set_var(struct fb_var_screeninfo *var, int isactive,
 		      	struct fb_info *info);
-static void     sisfb_pre_setmode(void);
-static void     sisfb_post_setmode(void);
+static void     sisfb_pre_setmode(struct sis_video_info *ivideo);
+static void     sisfb_post_setmode(struct sis_video_info *ivideo);
+static char *   sis_find_rom(struct pci_dev *pdev);
+static BOOLEAN  sisfb_CheckVBRetrace(struct sis_video_info *ivideo);
+static BOOLEAN  sisfbcheckvretracecrt2(struct sis_video_info *ivideo);
+static BOOLEAN  sisfbcheckvretracecrt1(struct sis_video_info *ivideo);
+static BOOLEAN  sisfb_bridgeisslave(struct sis_video_info *ivideo);
+static void     sisfb_detect_VB_connect(struct sis_video_info *ivideo);
+static void     sisfb_get_VB_type(struct sis_video_info *ivideo);
+static void     sisfb_set_TVxposoffset(struct sis_video_info *ivideo, int val);
+static void     sisfb_set_TVyposoffset(struct sis_video_info *ivideo, int val);
 
-static char *   sis_find_rom(void);
-static BOOLEAN  sisfb_CheckVBRetrace(void);
-static BOOLEAN  sisfbcheckvretracecrt2(void);
-static BOOLEAN  sisfbcheckvretracecrt1(void);
-static BOOLEAN  sisfb_bridgeisslave(void);
-static void     sisfb_detect_VB_connect(void);
-static void     sisfb_get_VB_type(void);
-
-static void     sisfb_handle_ddc(struct sisfb_monitor *monitor, int crtno);
-static BOOLEAN  sisfb_interpret_edid(struct sisfb_monitor *monitor, unsigned char *buffer);
-
-/* SiS-specific Export functions */
-void            sis_dispinfo(struct ap_data *rec);
+/* SiS-specific exported functions */
 void            sis_malloc(struct sis_memreq *req);
-void            sis_free(unsigned long base);
-
-/* Internal hardware access routines */
-void            sisfb_set_reg4(u16 port, unsigned long data);
-u32             sisfb_get_reg3(u16 port);
-
-/* Chipset-dependent internal routines */
-#ifdef CONFIG_FB_SIS_300
-static int      sisfb_get_dram_size_300(void);
-#endif
-#ifdef CONFIG_FB_SIS_315
-static int      sisfb_get_dram_size_315(void);
-#endif
+void            sis_free(u32 base);
 
 /* Internal heap routines */
-static int      sisfb_heap_init(void);
+static int      sisfb_heap_init(struct sis_video_info *ivideo);
 static SIS_OH   *sisfb_poh_new_node(void);
-static SIS_OH   *sisfb_poh_allocate(unsigned long size);
+static SIS_OH   *sisfb_poh_allocate(u32 size);
 static void     sisfb_delete_node(SIS_OH *poh);
 static void     sisfb_insert_node(SIS_OH *pohList, SIS_OH *poh);
-static SIS_OH   *sisfb_poh_free(unsigned long base);
+static SIS_OH   *sisfb_poh_free(u32 base);
 static void     sisfb_free_node(SIS_OH *poh);
 
-/* Internal routines to access PCI configuration space */
-BOOLEAN         sisfb_query_VGA_config_space(PSIS_HW_INFO psishw_ext,
-	          	unsigned long offset, unsigned long set, unsigned long *value);
-BOOLEAN         sisfb_query_north_bridge_space(PSIS_HW_INFO psishw_ext,
-	         	unsigned long offset, unsigned long set, unsigned long *value);
-
 /* Sensing routines */
-static void     SiS_Sense30x(void);
-static int      SISDoSense(int tempbl, int tempbh, int tempcl, int tempch);
-static void     SiS_SenseCh(void);
+static void     SiS_Sense30x(struct sis_video_info *ivideo);
+static void     SiS_SenseCh(struct sis_video_info *ivideo);
 
 /* Routines from init.c/init301.c */
 extern USHORT   SiS_GetModeID(int VGAEngine, ULONG VBFlags, int HDisplay, int VDisplay, int Depth, BOOLEAN FSTN);
@@ -1268,10 +919,20 @@
 extern void     SiS_SetEnableDstn(SiS_Private *SiS_Pr, int enable);
 extern void     SiS_SetEnableFstn(SiS_Private *SiS_Pr, int enable);
 
+extern BOOLEAN  SiSDetermineROMLayout661(SiS_Private *SiS_Pr, PSIS_HW_INFO HwInfo);
+
 extern BOOLEAN  sisfb_gettotalfrommode(SiS_Private *SiS_Pr, PSIS_HW_INFO HwDeviceExtension,
 		       unsigned char modeno, int *htotal, int *vtotal, unsigned char rateindex);
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
+extern int	sisfb_mode_rate_to_dclock(SiS_Private *SiS_Pr,
+		    	PSIS_HW_INFO HwDeviceExtension,
+			unsigned char modeno, unsigned char rateindex);
+extern int      sisfb_mode_rate_to_ddata(SiS_Private *SiS_Pr, PSIS_HW_INFO HwDeviceExtension,
+			unsigned char modeno, unsigned char rateindex,
+			struct fb_var_screeninfo *var);
+#endif
 
-/* Chrontel TV functions */
+/* Chrontel TV, DDC and DPMS functions */
 extern USHORT 	SiS_GetCH700x(SiS_Private *SiS_Pr, USHORT tempbx);
 extern void 	SiS_SetCH700x(SiS_Private *SiS_Pr, USHORT tempbx);
 extern USHORT 	SiS_GetCH701x(SiS_Private *SiS_Pr, USHORT tempbx);
@@ -1279,13 +940,13 @@
 extern void     SiS_SetCH70xxANDOR(SiS_Private *SiS_Pr, USHORT tempax,USHORT tempbh);
 extern void     SiS_DDC2Delay(SiS_Private *SiS_Pr, USHORT delaytime);
 extern void     SiS_SetChrontelGPIO(SiS_Private *SiS_Pr, USHORT myvbinfo);
-extern USHORT   SiS_HandleDDC(SiS_Private *SiS_Pr, unsigned long VBFlags, int VGAEngine,
+extern USHORT   SiS_HandleDDC(SiS_Private *SiS_Pr, ULONG VBFlags, int VGAEngine,
 		              USHORT adaptnum, USHORT DDCdatatype, unsigned char *buffer);
 extern USHORT   SiS_ReadDDC1Bit(SiS_Private *SiS_Pr);
 extern void 	SiS_Chrontel701xBLOn(SiS_Private *SiS_Pr, PSIS_HW_INFO HwDeviceInfo);
 extern void 	SiS_Chrontel701xBLOff(SiS_Private *SiS_Pr);
 extern void 	SiS_SiS30xBLOn(SiS_Private *SiS_Pr, PSIS_HW_INFO HwDeviceInfo);
 extern void 	SiS_SiS30xBLOff(SiS_Private *SiS_Pr, PSIS_HW_INFO HwDeviceInfo);
-
-			
 #endif
+
+
--- diff/drivers/video/sis/vgatypes.h	2004-05-19 22:12:23.000000000 +0100
+++ source/drivers/video/sis/vgatypes.h	2004-06-11 19:22:05.000000000 +0100
@@ -1,4 +1,5 @@
 /* $XFree86$ */
+/* $XdotOrg$ */
 /*
  * General type definitions for universal mode switching modules
  *
@@ -31,13 +32,10 @@
  * * 2) Redistributions in binary form must reproduce the above copyright
  * *    notice, this list of conditions and the following disclaimer in the
  * *    documentation and/or other materials provided with the distribution.
- * * 3) All advertising materials mentioning features or use of this software
- * *    must display the following acknowledgement: "This product includes
- * *    software developed by Thomas Winischhofer, Vienna, Austria."
- * * 4) The name of the author may not be used to endorse or promote products
+ * * 3) The name of the author may not be used to endorse or promote products
  * *    derived from this software without specific prior written permission.
  * *
- * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESSED OR
  * * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
  * * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
  * * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
@@ -121,21 +119,17 @@
 #endif
 #endif
 
-#ifndef LINUX_KERNEL   /* For the linux kernel, this is defined in sisfb.h */
-#ifndef SIS_CHIP_TYPE
-typedef enum _SIS_CHIP_TYPE {
+enum _SIS_CHIP_TYPE {
     SIS_VGALegacy = 0,
-#ifdef LINUX_XF86
     SIS_530,
     SIS_OLD,
-#endif
     SIS_300,
     SIS_630,
     SIS_730,
     SIS_540,
     SIS_315H,   /* SiS 310 */
     SIS_315,
-    SIS_315PRO, /* SiS 325 */
+    SIS_315PRO,
     SIS_550,
     SIS_650,
     SIS_740,
@@ -144,29 +138,13 @@
     SIS_741,
     SIS_660,
     SIS_760,
+    SIS_761,
+    SIS_340,
     MAX_SIS_CHIP
-} SIS_CHIP_TYPE;
-#endif
-#endif
-
-#ifndef SIS_VB_CHIP_TYPE
-typedef enum _SIS_VB_CHIP_TYPE {
-    VB_CHIP_Legacy = 0,
-    VB_CHIP_301,
-    VB_CHIP_301B,
-    VB_CHIP_301LV,
-    VB_CHIP_302,
-    VB_CHIP_302B,
-    VB_CHIP_302LV,
-    VB_CHIP_301C,
-    VB_CHIP_302ELV,
-    VB_CHIP_UNKNOWN, /* other video bridge or no video bridge */
-    MAX_VB_CHIP
-} SIS_VB_CHIP_TYPE;
-#endif
+};
 
-#ifndef SIS_LCD_TYPE
-typedef enum _SIS_LCD_TYPE {
+#ifdef LINUX_KERNEL
+enum _SIS_LCD_TYPE {
     LCD_INVALID = 0,
     LCD_800x600,
     LCD_1024x768,
@@ -176,28 +154,22 @@
     LCD_1600x1200,
     LCD_1920x1440,
     LCD_2048x1536,
-    LCD_320x480,       /* FSTN, DSTN */
+    LCD_320x480,       /* FSTN */
     LCD_1400x1050,
     LCD_1152x864,
     LCD_1152x768,
     LCD_1280x768,
     LCD_1024x600,
-    LCD_640x480_2,     /* FSTN, DSTN */
-    LCD_640x480_3,     /* FSTN, DSTN */
+    LCD_640x480_2,     /* DSTN */
+    LCD_640x480_3,     /* DSTN */
     LCD_848x480,
     LCD_1280x800,
     LCD_1680x1050,
+    LCD_1280x720,
     LCD_CUSTOM,
     LCD_UNKNOWN
-} SIS_LCD_TYPE;
-#endif
-
-#ifndef PSIS_DSReg
-typedef struct _SIS_DSReg
-{
-  UCHAR  jIdx;
-  UCHAR  jVal;
-} SIS_DSReg, *PSIS_DSReg;
+};
+typedef unsigned int SIS_LCD_TYPE;
 #endif
 
 #ifndef SIS_HW_INFO
@@ -220,97 +192,84 @@
                                  /* of Linear VGA memory */
 
     ULONG  ulVideoMemorySize;    /* size, in bytes, of the memory on the board */
-    SISIOADDRESS ulIOAddress;    /* base I/O address of VGA ports (0x3B0) */
+
+    SISIOADDRESS ulIOAddress;    /* base I/O address of VGA ports (0x3B0; relocated) */
+
     UCHAR  jChipType;            /* Used to Identify SiS Graphics Chip */
-                                 /* defined in the data structure type  */
-                                 /* "SIS_CHIP_TYPE" */
+                                 /* defined in the enum "SIS_CHIP_TYPE" (above or sisfb.h) */
 
     UCHAR  jChipRevision;        /* Used to Identify SiS Graphics Chip Revision */
-    UCHAR  ujVBChipID;           /* the ID of video bridge */
-                                 /* defined in the data structure type */
-                                 /* "SIS_VB_CHIP_TYPE" */
-#ifdef LINUX_KERNEL
-    BOOLEAN Is301BDH;
-#endif
 
-    USHORT usExternalChip;       /* NO VB or other video bridge (other than  */
-                                 /* SiS video bridge) */
-
-    ULONG  ulCRT2LCDType;        /* defined in the data structure type */
-                                 /* "SIS_LCD_TYPE" */
-                                     
     BOOLEAN bIntegratedMMEnabled;/* supporting integration MM enable */
-                                      
-    BOOLEAN bSkipDramSizing;     /* True: Skip video memory sizing. */
 
 #ifdef LINUX_KERNEL
-    PSIS_DSReg  pSR;             /* restore SR registers in initial function. */
-                                 /* end data :(idx, val) =  (FF, FF). */
-                                 /* Note : restore SR registers if  */
-                                 /* bSkipDramSizing = TRUE */
-
-    PSIS_DSReg  pCR;             /* restore CR registers in initial function. */
-                                 /* end data :(idx, val) =  (FF, FF) */
-                                 /* Note : restore cR registers if  */
-                                 /* bSkipDramSizing = TRUE */
-#endif
-
-    PSIS_QUERYSPACE  pQueryVGAConfigSpace; /* Get/Set VGA Configuration  */
-                                           /* space */
- 
-    PSIS_QUERYSPACE  pQueryNorthBridgeSpace;/* Get/Set North Bridge  */
-                                            /* space  */
+    ULONG  ulCRT2LCDType;        /* defined in the data structure type */
+                                 /* "SIS_LCD_TYPE" */
+#endif
 };
 #endif
 
-/* Addtional IOCTL for communication sisfb <> X driver        */
+/* Addtional IOCTLs for communication sisfb <> X driver        */
 /* If changing this, sisfb.h must also be changed (for sisfb) */
 
 #ifdef LINUX_XF86  /* We don't want the X driver to depend on the kernel source */
 
 /* ioctl for identifying and giving some info (esp. memory heap start) */
-#define SISFB_GET_INFO    0x80046ef8  /* Wow, what a terrible hack... */
+#define SISFB_GET_INFO_SIZE	0x8004f300
+#define SISFB_GET_INFO		0x8000f301  /* Must be patched with result from ..._SIZE at D[29:16] */
+/* deprecated ioctl number (for older versions of sisfb) */
+#define SISFB_GET_INFO_OLD    	0x80046ef8
+
+/* ioctls for tv parameters (position) */
+#define SISFB_SET_TVPOSOFFSET   0x4004f304
+
+/* lock sisfb from register access */
+#define SISFB_SET_LOCK		0x4004f306
 
 /* Structure argument for SISFB_GET_INFO ioctl  */
 typedef struct _SISFB_INFO sisfb_info, *psisfb_info;
 
 struct _SISFB_INFO {
-	unsigned long sisfb_id;         /* for identifying sisfb */
+	CARD32 	sisfb_id;         	/* for identifying sisfb */
 #ifndef SISFB_ID
 #define SISFB_ID	  0x53495346    /* Identify myself with 'SISF' */
 #endif
- 	int    chip_id;			/* PCI ID of detected chip */
-	int    memory;			/* video memory in KB which sisfb manages */
-	int    heapstart;               /* heap start (= sisfb "mem" argument) in KB */
-	unsigned char fbvidmode;	/* current sisfb mode */
+ 	CARD32 	chip_id;		/* PCI ID of detected chip */
+	CARD32	memory;			/* video memory in KB which sisfb manages */
+	CARD32	heapstart;             	/* heap start (= sisfb "mem" argument) in KB */
+	CARD8 	fbvidmode;		/* current sisfb mode */
+
+	CARD8 	sisfb_version;
+	CARD8	sisfb_revision;
+	CARD8 	sisfb_patchlevel;
+
+	CARD8 	sisfb_caps;		/* sisfb's capabilities */
+
+	CARD32 	sisfb_tqlen;		/* turbo queue length (in KB) */
 
-	unsigned char sisfb_version;
-	unsigned char sisfb_revision;
-	unsigned char sisfb_patchlevel;
+	CARD32 	sisfb_pcibus;      	/* The card's PCI ID */
+	CARD32 	sisfb_pcislot;
+	CARD32 	sisfb_pcifunc;
 
-	unsigned char sisfb_caps;	/* sisfb's capabilities */
+	CARD8 	sisfb_lcdpdc;
 
-	int    sisfb_tqlen;		/* turbo queue length (in KB) */
+	CARD8	sisfb_lcda;
 
-	unsigned int sisfb_pcibus;      /* The card's PCI ID */
-	unsigned int sisfb_pcislot;
-	unsigned int sisfb_pcifunc;
+	CARD32	sisfb_vbflags;
+	CARD32	sisfb_currentvbflags;
 
-	unsigned char sisfb_lcdpdc;
-	
-	unsigned char sisfb_lcda;
+	CARD32 	sisfb_scalelcd;
+	CARD32 	sisfb_specialtiming;
 
-	unsigned long sisfb_vbflags;
-	unsigned long sisfb_currentvbflags;
+	CARD8 	sisfb_haveemi;
+	CARD8 	sisfb_emi30,sisfb_emi31,sisfb_emi32,sisfb_emi33;
+	CARD8 	sisfb_haveemilcd;
 
-	int sisfb_scalelcd;
-	unsigned long sisfb_specialtiming;
+	CARD8 	sisfb_lcdpdca;
 
-	unsigned char sisfb_haveemi;
-	unsigned char sisfb_emi30,sisfb_emi31,sisfb_emi32,sisfb_emi33;
-	unsigned char sisfb_haveemilcd;
+	CARD16  sisfb_tvxpos, sisfb_tvypos;  	/* Warning: Values + 32 ! */
 
-	char reserved[213]; 		/* for future use */
+	CARD8 reserved[208]; 			/* for future use */
 };
 #endif
 
--- diff/drivers/video/sis/vstruct.h	2004-05-19 22:12:23.000000000 +0100
+++ source/drivers/video/sis/vstruct.h	2004-06-11 19:22:05.000000000 +0100
@@ -1,4 +1,5 @@
 /* $XFree86$ */
+/* $XdotOrg$ */
 /*
  * General structure definitions for universal mode switching modules
  *
@@ -31,13 +32,10 @@
  * * 2) Redistributions in binary form must reproduce the above copyright
  * *    notice, this list of conditions and the following disclaimer in the
  * *    documentation and/or other materials provided with the distribution.
- * * 3) All advertising materials mentioning features or use of this software
- * *    must display the following acknowledgement: "This product includes
- * *    software developed by Thomas Winischhofer, Vienna, Austria."
- * * 4) The name of the author may not be used to endorse or promote products
+ * * 3) The name of the author may not be used to endorse or promote products
  * *    derived from this software without specific prior written permission.
  * *
- * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESSED OR
  * * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
  * * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
  * * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
@@ -164,7 +162,6 @@
 {
 	UCHAR  Ext_ModeID;
 	USHORT Ext_ModeFlag;
-	UCHAR  Ext_ModeOffset;
 	USHORT Ext_VESAID;
 	UCHAR  Ext_RESINFO;
 	UCHAR  VB_ExtTVFlickerIndex;
@@ -172,6 +169,7 @@
 	UCHAR  VB_ExtTVYFilterIndex;
 	UCHAR  VB_ExtTVYFilterIndexROM661;
 	UCHAR  REFindex;
+	CHAR   ROMMODEIDX661;
 } SiS_ExtStruct;
 
 typedef struct _SiS_Ext2Struct
@@ -180,6 +178,7 @@
 	UCHAR  Ext_CRT1CRTC;
 	UCHAR  Ext_CRTVCLK;
 	UCHAR  Ext_CRT2CRTC;
+	UCHAR  Ext_CRT2CRTC_NS;
 	UCHAR  ModeID;
 	USHORT XRes;
 	USHORT YRes;
@@ -228,6 +227,8 @@
 	UCHAR  YChar;
 } SiS_ModeResInfoStruct;
 
+
+
 typedef UCHAR DRAM4Type[4];
 
 /* Defines for SiS_CustomT */
@@ -289,18 +290,21 @@
         USHORT SiS_CP1, SiS_CP2, SiS_CP3, SiS_CP4;
 #endif
 	BOOLEAN SiS_UseROM;
-	int    SiS_CHOverScan;
+	BOOLEAN SiS_ROMNew;
+	BOOLEAN SiS_NeedRomModeData;
+	BOOLEAN PanelSelfDetected;
+	int     SiS_CHOverScan;
 	BOOLEAN SiS_CHSOverScan;
 	BOOLEAN SiS_ChSW;
 	BOOLEAN SiS_UseLCDA;
-	int    SiS_UseOEM;
-	ULONG  SiS_CustomT;
-	USHORT SiS_Backup70xx;
+	int     SiS_UseOEM;
+	ULONG   SiS_CustomT;
+	USHORT  SiS_Backup70xx;
 	BOOLEAN HaveEMI;
 	BOOLEAN HaveEMILCD;
 	BOOLEAN OverruleEMI;
 	UCHAR  EMI_30,EMI_31,EMI_32,EMI_33;
-	UCHAR  PDC;
+	SHORT  PDC, PDCA;
 	UCHAR  SiS_MyCR63;
 	USHORT SiS_CRT1Mode;
 	USHORT SiS_flag_clearbuffer;
@@ -346,28 +350,13 @@
 	USHORT SiS_DDC_DeviceAddr;
 	USHORT SiS_DDC_ReadAddr;
 	USHORT SiS_DDC_SecAddr;
+	USHORT SiS_ChrontelInit;
 	BOOLEAN SiS_SensibleSR11;
-	USHORT SiS_Panel800x600;
-	USHORT SiS_Panel1024x768;
-	USHORT SiS_Panel1280x1024;
-	USHORT SiS_Panel1600x1200;
-	USHORT SiS_Panel1280x960;
-	USHORT SiS_Panel1400x1050;
-	USHORT SiS_Panel320x480;
-	USHORT SiS_Panel1152x768;
-	USHORT SiS_Panel1280x768;
-	USHORT SiS_Panel1024x600;
-	USHORT SiS_Panel640x480;
-	USHORT SiS_Panel640x480_2;
-	USHORT SiS_Panel640x480_3;
-	USHORT SiS_Panel1152x864;
-	USHORT SiS_PanelCustom;
-	USHORT SiS_PanelBarco1366;
-	USHORT SiS_PanelMax;
+	USHORT SiS661LCD2TableSize;
+
 	USHORT SiS_PanelMinLVDS;
 	USHORT SiS_PanelMin301;
-	USHORT SiS_ChrontelInit;
-	
+
 	const SiS_StStruct          *SiS_SModeIDTable;
 	SiS_StandTableStruct        *SiS_StandTable;
 	const SiS_ExtStruct         *SiS_EModeIDTable;
@@ -376,11 +365,10 @@
 	const SiS_CRT1TableStruct   *SiS_CRT1Table;
 	const SiS_MCLKDataStruct    *SiS_MCLKData_0;
 	const SiS_MCLKDataStruct    *SiS_MCLKData_1;
-	const SiS_VCLKDataStruct    *SiS_VCLKData;
-	const SiS_VBVCLKDataStruct  *SiS_VBVCLKData;
+	SiS_VCLKDataStruct    	    *SiS_VCLKData;
+	SiS_VBVCLKDataStruct        *SiS_VBVCLKData;
 	const SiS_StResInfoStruct   *SiS_StResInfo;
 	const SiS_ModeResInfoStruct *SiS_ModeResInfo;
-	const UCHAR                 *SiS_ScreenOffset;
 
 	const UCHAR                 *pSiS_OutputSelect;
 	const UCHAR                 *pSiS_SoftSetting;
@@ -410,6 +398,12 @@
 	const USHORT *pSiS_VideoSenseData2;
 	const USHORT *pSiS_YCSenseData2;
 #endif
+
+	const SiS_PanelDelayTblStruct *SiS_PanelDelayTbl;
+	const SiS_PanelDelayTblStruct *SiS_PanelDelayTblLVDS;
+
+	/* SiS bridge */
+
 	const UCHAR *SiS_NTSCPhase;
 	const UCHAR *SiS_PALPhase;
 	const UCHAR *SiS_NTSCPhase2;
@@ -421,24 +415,21 @@
 	const UCHAR *SiS_SpecialPhase;
 	const UCHAR *SiS_SpecialPhaseM;
 	const UCHAR *SiS_SpecialPhaseJ;
-	const SiS_LCDDataStruct  *SiS_StLCD1024x768Data;
 	const SiS_LCDDataStruct  *SiS_ExtLCD1024x768Data;
 	const SiS_LCDDataStruct  *SiS_St2LCD1024x768Data;
-	const SiS_LCDDataStruct  *SiS_StLCD1280x1024Data;
+	const SiS_LCDDataStruct  *SiS_LCD1280x720Data;
+	const SiS_LCDDataStruct  *SiS_StLCD1280x768_2Data;
+	const SiS_LCDDataStruct  *SiS_ExtLCD1280x768_2Data;
+	const SiS_LCDDataStruct  *SiS_LCD1280x768_3Data;
+	const SiS_LCDDataStruct  *SiS_LCD1280x800Data;
+	const SiS_LCDDataStruct  *SiS_LCD1280x960Data;
 	const SiS_LCDDataStruct  *SiS_ExtLCD1280x1024Data;
 	const SiS_LCDDataStruct  *SiS_St2LCD1280x1024Data;
-	const SiS_LCDDataStruct  *SiS_NoScaleData1024x768;
-	const SiS_LCDDataStruct  *SiS_NoScaleData1280x1024;
-	const SiS_LCDDataStruct  *SiS_LCD1280x960Data;
-	const SiS_LCDDataStruct  *SiS_NoScaleData1400x1050;
-	const SiS_LCDDataStruct  *SiS_NoScaleData1600x1200;
-	const SiS_LCDDataStruct  *SiS_NoScaleData1280x768;
 	const SiS_LCDDataStruct  *SiS_StLCD1400x1050Data;
-	const SiS_LCDDataStruct  *SiS_StLCD1600x1200Data;
-	const SiS_LCDDataStruct  *SiS_StLCD1280x768Data;
 	const SiS_LCDDataStruct  *SiS_ExtLCD1400x1050Data;
+	const SiS_LCDDataStruct  *SiS_StLCD1600x1200Data;
 	const SiS_LCDDataStruct  *SiS_ExtLCD1600x1200Data;
-	const SiS_LCDDataStruct  *SiS_ExtLCD1280x768Data;
+	const SiS_LCDDataStruct  *SiS_LCD1680x1050Data;
 	const SiS_LCDDataStruct  *SiS_NoScaleData;
 	const SiS_TVDataStruct   *SiS_StPALData;
 	const SiS_TVDataStruct   *SiS_ExtPALData;
@@ -464,8 +455,16 @@
 	const UCHAR *SiS_HiTVTextTiming;
 	const UCHAR *SiS_HiTVGroup3Text;
 #endif
-	const SiS_PanelDelayTblStruct *SiS_PanelDelayTbl;
-	const SiS_PanelDelayTblStruct *SiS_PanelDelayTblLVDS;
+
+	const SiS_Part2PortTblStruct *SiS_CRT2Part2_1024x768_1;
+	const SiS_Part2PortTblStruct *SiS_CRT2Part2_1280x1024_1;
+	const SiS_Part2PortTblStruct *SiS_CRT2Part2_1024x768_2;
+	const SiS_Part2PortTblStruct *SiS_CRT2Part2_1280x1024_2;
+	const SiS_Part2PortTblStruct *SiS_CRT2Part2_1024x768_3;
+	const SiS_Part2PortTblStruct *SiS_CRT2Part2_1280x1024_3;
+
+	/* LVDS, Chrontel */
+
 	const SiS_LVDSDataStruct  *SiS_LVDS800x600Data_1;
 	const SiS_LVDSDataStruct  *SiS_LVDS800x600Data_2;
 	const SiS_LVDSDataStruct  *SiS_LVDS1024x768Data_1;
@@ -487,14 +486,6 @@
 	const SiS_LVDSDataStruct  *SiS_LVDS640x480Data_1;
 	const SiS_LVDSDataStruct  *SiS_LVDS640x480Data_2;
 	const SiS_LVDSDataStruct  *SiS_LVDS320x480Data_1;
-	const SiS_LVDSDataStruct  *SiS_LCDA1024x768Data_1;
-	const SiS_LVDSDataStruct  *SiS_LCDA1024x768Data_2;
-	const SiS_LVDSDataStruct  *SiS_LCDA1280x1024Data_1;
-	const SiS_LVDSDataStruct  *SiS_LCDA1280x1024Data_2;
-	const SiS_LVDSDataStruct  *SiS_LCDA1400x1050Data_1;
-	const SiS_LVDSDataStruct  *SiS_LCDA1400x1050Data_2;
-	const SiS_LVDSDataStruct  *SiS_LCDA1600x1200Data_1;
-	const SiS_LVDSDataStruct  *SiS_LCDA1600x1200Data_2;
 	const SiS_LVDSDataStruct  *SiS_LVDSXXXxXXXData_1;
 	const SiS_LVDSDataStruct  *SiS_LVDSBARCO1366Data_1;
 	const SiS_LVDSDataStruct  *SiS_LVDSBARCO1366Data_2;
@@ -511,6 +502,7 @@
 	const SiS_LVDSDataStruct  *SiS_CHTVUPALNData;
 	const SiS_LVDSDataStruct  *SiS_CHTVOPALNData;
 	const SiS_LVDSDataStruct  *SiS_CHTVSOPALData;
+
 	const SiS_LVDSDesStruct  *SiS_PanelType00_1;
 	const SiS_LVDSDesStruct  *SiS_PanelType01_1;
 	const SiS_LVDSDesStruct  *SiS_PanelType02_1;
@@ -545,20 +537,11 @@
 	const SiS_LVDSDesStruct  *SiS_PanelType0e_2;
 	const SiS_LVDSDesStruct  *SiS_PanelType0f_2;
 	const SiS_LVDSDesStruct  *SiS_PanelTypeNS_2;
-
-	const SiS_LVDSDesStruct  *LVDS1024x768Des_1;
-	const SiS_LVDSDesStruct  *LVDS1280x1024Des_1;
-	const SiS_LVDSDesStruct  *LVDS1400x1050Des_1;
-	const SiS_LVDSDesStruct  *LVDS1600x1200Des_1;
-	const SiS_LVDSDesStruct  *LVDS1024x768Des_2;
-	const SiS_LVDSDesStruct  *LVDS1280x1024Des_2;
-	const SiS_LVDSDesStruct  *LVDS1400x1050Des_2;
-	const SiS_LVDSDesStruct  *LVDS1600x1200Des_2;
-
 	const SiS_LVDSDesStruct  *SiS_CHTVUNTSCDesData;
 	const SiS_LVDSDesStruct  *SiS_CHTVONTSCDesData;
 	const SiS_LVDSDesStruct  *SiS_CHTVUPALDesData;
 	const SiS_LVDSDesStruct  *SiS_CHTVOPALDesData;
+
 	const SiS_LVDSCRT1DataStruct  *SiS_LVDSCRT1800x600_1;
 	const SiS_LVDSCRT1DataStruct  *SiS_LVDSCRT11024x768_1;
 	const SiS_LVDSCRT1DataStruct  *SiS_LVDSCRT11280x1024_1;
@@ -599,44 +582,13 @@
 	const SiS_LVDSCRT1DataStruct  *SiS_LVDSCRT1640x480_2_H;
 	const SiS_LVDSCRT1DataStruct  *SiS_LVDSCRT1640x480_3;
 	const SiS_LVDSCRT1DataStruct  *SiS_LVDSCRT1640x480_3_H;
+	const SiS_LVDSCRT1DataStruct  *SiS_LVDSCRT1320x480_1;
 	const SiS_LVDSCRT1DataStruct  *SiS_CHTVCRT1UNTSC;
 	const SiS_LVDSCRT1DataStruct  *SiS_CHTVCRT1ONTSC;
 	const SiS_LVDSCRT1DataStruct  *SiS_CHTVCRT1UPAL;
 	const SiS_LVDSCRT1DataStruct  *SiS_CHTVCRT1OPAL;
 	const SiS_LVDSCRT1DataStruct  *SiS_CHTVCRT1SOPAL;
 
-	const SiS_LVDSCRT1DataStruct  *SiS_LVDSCRT1320x480_1;
-
-	const SiS_LCDACRT1DataStruct  *SiS_LCDACRT11024x768_1;
-	const SiS_LCDACRT1DataStruct  *SiS_LCDACRT11280x1024_1;
-	const SiS_LCDACRT1DataStruct  *SiS_LCDACRT11400x1050_1;
-	const SiS_LCDACRT1DataStruct  *SiS_LCDACRT11600x1200_1;
-	const SiS_LCDACRT1DataStruct  *SiS_LCDACRT11024x768_1_H;
-	const SiS_LCDACRT1DataStruct  *SiS_LCDACRT11280x1024_1_H;
-	const SiS_LCDACRT1DataStruct  *SiS_LCDACRT11400x1050_1_H;
-	const SiS_LCDACRT1DataStruct  *SiS_LCDACRT11600x1200_1_H;
-	const SiS_LCDACRT1DataStruct  *SiS_LCDACRT11024x768_2;
-	const SiS_LCDACRT1DataStruct  *SiS_LCDACRT11280x1024_2;
-	const SiS_LCDACRT1DataStruct  *SiS_LCDACRT11400x1050_2;
-	const SiS_LCDACRT1DataStruct  *SiS_LCDACRT11600x1200_2;
-	const SiS_LCDACRT1DataStruct  *SiS_LCDACRT11024x768_2_H;
-	const SiS_LCDACRT1DataStruct  *SiS_LCDACRT11280x1024_2_H;
-	const SiS_LCDACRT1DataStruct  *SiS_LCDACRT11400x1050_2_H;
-	const SiS_LCDACRT1DataStruct  *SiS_LCDACRT11600x1200_2_H;
-
-	const SiS_Part2PortTblStruct *SiS_CRT2Part2_1024x768_1;
-	const SiS_Part2PortTblStruct *SiS_CRT2Part2_1280x1024_1;
-	const SiS_Part2PortTblStruct *SiS_CRT2Part2_1400x1050_1;
-	const SiS_Part2PortTblStruct *SiS_CRT2Part2_1600x1200_1;
-	const SiS_Part2PortTblStruct *SiS_CRT2Part2_1024x768_2;
-	const SiS_Part2PortTblStruct *SiS_CRT2Part2_1280x1024_2;
-	const SiS_Part2PortTblStruct *SiS_CRT2Part2_1400x1050_2;
-	const SiS_Part2PortTblStruct *SiS_CRT2Part2_1600x1200_2;
-	const SiS_Part2PortTblStruct *SiS_CRT2Part2_1024x768_3;
-	const SiS_Part2PortTblStruct *SiS_CRT2Part2_1280x1024_3;
-	const SiS_Part2PortTblStruct *SiS_CRT2Part2_1400x1050_3;
-	const SiS_Part2PortTblStruct *SiS_CRT2Part2_1600x1200_3;
-
 	const SiS_CHTVRegDataStruct *SiS_CHTVReg_UNTSC;
 	const SiS_CHTVRegDataStruct *SiS_CHTVReg_ONTSC;
 	const SiS_CHTVRegDataStruct *SiS_CHTVReg_UPAL;
@@ -646,6 +598,7 @@
 	const SiS_CHTVRegDataStruct *SiS_CHTVReg_UPALN;
 	const SiS_CHTVRegDataStruct *SiS_CHTVReg_OPALN;
 	const SiS_CHTVRegDataStruct *SiS_CHTVReg_SOPAL;
+
 	const UCHAR *SiS_CHTVVCLKUNTSC;
 	const UCHAR *SiS_CHTVVCLKONTSC;
 	const UCHAR *SiS_CHTVVCLKUPAL;
@@ -656,9 +609,13 @@
 	const UCHAR *SiS_CHTVVCLKOPALN;
 	const UCHAR *SiS_CHTVVCLKSOPAL;
 
-	USHORT  PanelXRes;
-	USHORT  PanelYRes;
-	
+	USHORT  PanelXRes, PanelHT;
+	USHORT  PanelYRes, PanelVT;
+	USHORT  PanelHRS,  PanelHRE;
+  	USHORT 	PanelVRS,  PanelVRE;
+	USHORT  PanelVCLKIdx300;
+	USHORT  PanelVCLKIdx315;
+
 	BOOLEAN UseCustomMode;
 	BOOLEAN CRT1UsesCustomMode;
 	USHORT  CHDisplay;
@@ -700,10 +657,11 @@
 	UCHAR Backup_1d;
 	
 	int     UsePanelScaler;
+	int	CenterScreen;
 
 	USHORT  CP_Vendor, CP_Product;
 	BOOLEAN CP_HaveCustomData;
-	int     CP_PreferredX, CP_PreferredY;
+	int     CP_PreferredX, CP_PreferredY, CP_PreferredIndex;
 	int	CP_MaxX, CP_MaxY, CP_MaxClock;
 	BOOLEAN CP_Supports64048075;
 	int     CP_HDisplay[7], CP_VDisplay[7];	/* For Custom LCD panel dimensions */
--- diff/drivers/video/skeletonfb.c	2004-05-19 22:12:21.000000000 +0100
+++ source/drivers/video/skeletonfb.c	2004-06-11 19:22:05.000000000 +0100
@@ -539,7 +539,13 @@
     info.fbops = &xxxfb_ops;
     info.fix = xxxfb_fix;
     info.pseudo_palette = pseudo_palette;
-    info.flags = FBINFO_FLAG_DEFAULT;
+
+    /*
+     * Set up flags to indicate what sort of acceleration your
+     * driver can provide (pan/wrap/copyarea/etc.) and whether it
+     * is a module -- see FBINFO_* in include/linux/fb.h
+     */
+    info.flags = FBINFO_DEFAULT;
     info.par = current_par;
 
     /*
--- diff/drivers/video/vga16fb.c	2004-06-11 19:17:32.000000000 +0100
+++ source/drivers/video/vga16fb.c	2004-06-11 19:22:05.000000000 +0100
@@ -1372,8 +1372,6 @@
 	vga16fb.par = &vga16_par;
 	vga16fb.flags = FBINFO_FLAG_DEFAULT;
 
-	vga16fb.fix.smem_start	= VGA_MAP_MEM(vga16fb.fix.smem_start);
-
 	i = (vga16fb_defined.bits_per_pixel == 8) ? 256 : 16;
 	ret = fb_alloc_cmap(&vga16fb.cmap, i, 0);
 	if (ret) {
--- diff/fs/affs/symlink.c	2004-05-19 22:12:24.000000000 +0100
+++ source/fs/affs/symlink.c	2004-06-11 19:22:05.000000000 +0100
@@ -78,7 +78,8 @@
 };
 
 struct inode_operations affs_symlink_inode_operations = {
-	.readlink	= page_readlink,
-	.follow_link	= page_follow_link,
+	.readlink	= generic_readlink,
+	.follow_link	= page_follow_link_light,
+	.put_link	= page_put_link,
 	.setattr	= affs_notify_change,
 };
--- diff/fs/aio.c	2004-06-11 19:17:32.000000000 +0100
+++ source/fs/aio.c	2004-06-11 19:22:05.000000000 +0100
@@ -15,7 +15,7 @@
 #include <linux/aio_abi.h>
 #include <linux/module.h>
 
-//#define DEBUG 1
+#define DEBUG 0
 
 #include <linux/sched.h>
 #include <linux/fs.h>
--- diff/fs/autofs/symlink.c	2004-05-19 22:12:25.000000000 +0100
+++ source/fs/autofs/symlink.c	2004-06-11 19:22:05.000000000 +0100
@@ -12,19 +12,14 @@
 
 #include "autofs_i.h"
 
-static int autofs_readlink(struct dentry *dentry, char *buffer, int buflen)
-{
-	char *s=((struct autofs_symlink *)dentry->d_inode->u.generic_ip)->data;
-	return vfs_readlink(dentry, buffer, buflen, s);
-}
-
 static int autofs_follow_link(struct dentry *dentry, struct nameidata *nd)
 {
 	char *s=((struct autofs_symlink *)dentry->d_inode->u.generic_ip)->data;
-	return vfs_follow_link(nd, s);
+	nd_set_link(nd, s);
+	return 0;
 }
 
 struct inode_operations autofs_symlink_inode_operations = {
-	.readlink	= autofs_readlink,
+	.readlink	= generic_readlink,
 	.follow_link	= autofs_follow_link
 };
--- diff/fs/autofs4/symlink.c	2004-05-19 22:12:25.000000000 +0100
+++ source/fs/autofs4/symlink.c	2004-06-11 19:22:05.000000000 +0100
@@ -12,21 +12,14 @@
 
 #include "autofs_i.h"
 
-static int autofs4_readlink(struct dentry *dentry, char *buffer, int buflen)
-{
-	struct autofs_info *ino = autofs4_dentry_ino(dentry);
-
-	return vfs_readlink(dentry, buffer, buflen, ino->u.symlink);
-}
-
 static int autofs4_follow_link(struct dentry *dentry, struct nameidata *nd)
 {
 	struct autofs_info *ino = autofs4_dentry_ino(dentry);
-
-	return vfs_follow_link(nd, ino->u.symlink);
+	nd_set_link(nd, (char *)ino->u.symlink);
+	return 0;
 }
 
 struct inode_operations autofs4_symlink_inode_operations = {
-	.readlink	= autofs4_readlink,
+	.readlink	= generic_readlink,
 	.follow_link	= autofs4_follow_link
 };
--- diff/fs/bad_inode.c	2004-05-19 22:12:24.000000000 +0100
+++ source/fs/bad_inode.c	2004-06-11 19:22:05.000000000 +0100
@@ -21,7 +21,8 @@
  */
 static int bad_follow_link(struct dentry *dent, struct nameidata *nd)
 {
-	return vfs_follow_link(nd, ERR_PTR(-EIO));
+	nd_set_link(nd, ERR_PTR(-EIO));
+	return 0;
 }
 
 static int return_EIO(void)
--- diff/fs/befs/linuxvfs.c	2004-06-11 19:17:32.000000000 +0100
+++ source/fs/befs/linuxvfs.c	2004-06-11 19:22:05.000000000 +0100
@@ -40,8 +40,8 @@
 static void befs_destroy_inode(struct inode *inode);
 static int befs_init_inodecache(void);
 static void befs_destroy_inodecache(void);
-static int befs_readlink(struct dentry *, char __user *, int);
-static int befs_follow_link(struct dentry *, struct nameidata *nd);
+static int befs_follow_link(struct dentry *, struct nameidata *);
+static void befs_put_link(struct dentry *, struct nameidata *);
 static int befs_utf2nls(struct super_block *sb, const char *in, int in_len,
 			char **out, int *out_len);
 static int befs_nls2utf(struct super_block *sb, const char *in, int in_len,
@@ -85,8 +85,9 @@
 };
 
 static struct inode_operations befs_symlink_inode_operations = {
-	.readlink	= befs_readlink,
+	.readlink	= generic_readlink,
 	.follow_link	= befs_follow_link,
+	.put_link	= befs_put_link,
 };
 
 /* 
@@ -462,71 +463,40 @@
 static int
 befs_follow_link(struct dentry *dentry, struct nameidata *nd)
 {
-	struct super_block *sb = dentry->d_sb;
 	befs_inode_info *befs_ino = BEFS_I(dentry->d_inode);
 	char *link;
-	int res;
 
 	if (befs_ino->i_flags & BEFS_LONG_SYMLINK) {
+		struct super_block *sb = dentry->d_sb;
 		befs_data_stream *data = &befs_ino->i_data.ds;
-		befs_off_t linklen = data->size;
+		befs_off_t len = data->size;
 
 		befs_debug(sb, "Follow long symlink");
 
-		link = kmalloc(linklen, GFP_NOFS);
-		if (link == NULL)
-			return -ENOMEM;
-
-		if (befs_read_lsymlink(sb, data, link, linklen) != linklen) {
+		link = kmalloc(len, GFP_NOFS);
+		if (!link) {
+			link = ERR_PTR(-ENOMEM);
+		} else if (befs_read_lsymlink(sb, data, link, len) != len) {
 			kfree(link);
 			befs_error(sb, "Failed to read entire long symlink");
-			return -EIO;
+			link = ERR_PTR(-EIO);
 		}
-
-		res = vfs_follow_link(nd, link);
-
-		kfree(link);
 	} else {
 		link = befs_ino->i_data.symlink;
-		res = vfs_follow_link(nd, link);
 	}
 
-	return res;
+	nd_set_link(nd, link);
+	return 0;
 }
 
-static int
-befs_readlink(struct dentry *dentry, char __user *buffer, int buflen)
+static void befs_put_link(struct dentry *dentry, struct nameidata *nd)
 {
-	struct super_block *sb = dentry->d_sb;
 	befs_inode_info *befs_ino = BEFS_I(dentry->d_inode);
-	char *link;
-	int res;
-
 	if (befs_ino->i_flags & BEFS_LONG_SYMLINK) {
-		befs_data_stream *data = &befs_ino->i_data.ds;
-		befs_off_t linklen = data->size;
-
-		befs_debug(sb, "Read long symlink");
-
-		link = kmalloc(linklen, GFP_NOFS);
-		if (link == NULL)
-			return -ENOMEM;
-
-		if (befs_read_lsymlink(sb, data, link, linklen) != linklen) {
-			kfree(link);
-			befs_error(sb, "Failed to read entire long symlink");
-			return -EIO;
-		}
-
-		res = vfs_readlink(dentry, buffer, buflen, link);
-
-		kfree(link);
-	} else {
-		link = befs_ino->i_data.symlink;
-		res = vfs_readlink(dentry, buffer, buflen, link);
+		char *p = nd_get_link(nd);
+		if (!IS_ERR(p))
+			kfree(p);
 	}
-
-	return res;
 }
 
 /*
--- diff/fs/binfmt_aout.c	2004-06-11 19:17:32.000000000 +0100
+++ source/fs/binfmt_aout.c	2004-06-11 19:22:05.000000000 +0100
@@ -27,7 +27,6 @@
 
 #include <asm/system.h>
 #include <asm/uaccess.h>
-#include <asm/pgalloc.h>
 #include <asm/cacheflush.h>
 
 static int load_aout_binary(struct linux_binprm *, struct pt_regs * regs);
--- diff/fs/binfmt_elf.c	2004-06-11 19:17:32.000000000 +0100
+++ source/fs/binfmt_elf.c	2004-06-11 19:22:05.000000000 +0100
@@ -40,7 +40,6 @@
 
 #include <asm/uaccess.h>
 #include <asm/param.h>
-#include <asm/pgalloc.h>
 
 #include <linux/elf.h>
 
--- diff/fs/binfmt_flat.c	2004-06-11 19:17:32.000000000 +0100
+++ source/fs/binfmt_flat.c	2004-06-11 19:22:05.000000000 +0100
@@ -40,7 +40,6 @@
 #include <asm/byteorder.h>
 #include <asm/system.h>
 #include <asm/uaccess.h>
-#include <asm/pgalloc.h>
 #include <asm/unaligned.h>
 #include <asm/cacheflush.h>
 
--- diff/fs/binfmt_misc.c	2004-06-11 19:17:32.000000000 +0100
+++ source/fs/binfmt_misc.c	2004-06-11 19:22:05.000000000 +0100
@@ -39,6 +39,8 @@
 
 enum {Enabled, Magic};
 #define MISC_FMT_PRESERVE_ARGV0 (1<<31)
+#define MISC_FMT_OPEN_BINARY (1<<30)
+#define MISC_FMT_CREDENTIALS (1<<29)
 
 typedef struct {
 	struct list_head list;
@@ -102,10 +104,13 @@
 static int load_misc_binary(struct linux_binprm *bprm, struct pt_regs *regs)
 {
 	Node *fmt;
-	struct file * file;
+	struct file * interp_file = NULL;
 	char iname[BINPRM_BUF_SIZE];
 	char *iname_addr = iname;
 	int retval;
+	int fd_binary = -1;
+	char fd_str[12];
+	struct files_struct *files = NULL;
 
 	retval = -ENOEXEC;
 	if (!enabled)
@@ -120,33 +125,102 @@
 	if (!fmt)
 		goto _ret;
 
-	allow_write_access(bprm->file);
-	fput(bprm->file);
-	bprm->file = NULL;
-
-	/* Build args for interpreter */
 	if (!(fmt->flags & MISC_FMT_PRESERVE_ARGV0)) {
 		remove_arg_zero(bprm);
 	}
-	retval = copy_strings_kernel(1, &bprm->interp, bprm);
-	if (retval < 0) goto _ret; 
-	bprm->argc++;
-	retval = copy_strings_kernel(1, &iname_addr, bprm);
-	if (retval < 0) goto _ret; 
-	bprm->argc++;
-	bprm->interp = iname;	/* for binfmt_script */
 
-	file = open_exec(iname);
-	retval = PTR_ERR(file);
-	if (IS_ERR(file))
-		goto _ret;
-	bprm->file = file;
+	if (fmt->flags & MISC_FMT_OPEN_BINARY) {
+		char *fdsp = fd_str;
+
+		files = current->files;
+		retval = unshare_files();
+		if (retval < 0)
+			goto _ret;
+		if (files == current->files) {
+			put_files_struct(files);
+			files = NULL;
+		}
+		/* if the binary should be opened on behalf of the
+		 * interpreter than keep it open and assign descriptor
+		 * to it */
+ 		fd_binary = get_unused_fd();
+ 		if (fd_binary < 0) {
+ 			retval = fd_binary;
+ 			goto _unshare;
+ 		}
+ 		fd_install(fd_binary, bprm->file);
+
+		/* if the binary is not readable than enforce mm->dumpable=0
+		   regardless of the interpreter's permissions */
+		if (permission(bprm->file->f_dentry->d_inode, MAY_READ, NULL))
+			bprm->interp_flags |= BINPRM_FLAGS_ENFORCE_NONDUMP;
+
+		allow_write_access(bprm->file);
+		bprm->file = NULL;
+
+		/* make argv[1] be the file descriptor of the binary */
+ 		snprintf(fd_str, sizeof(fd_str), "%d", fd_binary);
+ 		retval = copy_strings_kernel(1, &fdsp, bprm);
+		if (retval < 0)
+			goto _error;
+		bprm->argc++;
+
+ 	} else {
+ 		allow_write_access(bprm->file);
+ 		fput(bprm->file);
+ 		bprm->file = NULL;
+		/* make argv[1] be the path to the binary */
+ 		retval = copy_strings_kernel (1, &bprm->interp, bprm);
+		if (retval < 0)
+			goto _error;
+		bprm->argc++;
+ 	}
+	retval = copy_strings_kernel (1, &iname_addr, bprm);
+	if (retval < 0)
+		goto _error;
+	bprm->argc ++;
+	bprm->interp = iname;	/* for binfmt_script */
 
-	retval = prepare_binprm(bprm);
-	if (retval >= 0)
-		retval = search_binary_handler(bprm, regs);
+	interp_file = open_exec (iname);
+	retval = PTR_ERR (interp_file);
+	if (IS_ERR (interp_file))
+		goto _error;
+
+	bprm->file = interp_file;
+	if (fmt->flags & MISC_FMT_CREDENTIALS) {
+		/*
+		 * No need to call prepare_binprm(), it's already been
+		 * done.  bprm->buf is stale, update from interp_file.
+		 */
+		memset(bprm->buf, 0, BINPRM_BUF_SIZE);
+		retval = kernel_read(bprm->file, 0, bprm->buf, BINPRM_BUF_SIZE);
+	} else
+		retval = prepare_binprm (bprm);
+
+	if (retval < 0)
+		goto _error;
+
+	retval = search_binary_handler (bprm, regs);
+	if (retval < 0)
+		goto _error;
+
+	if (files) {
+		steal_locks(files);
+		put_files_struct(files);
+		files = NULL;
+	}
 _ret:
 	return retval;
+_error:
+	if (fd_binary > 0)
+		sys_close(fd_binary);
+	bprm->interp_flags = 0;
+_unshare:
+	if (files) {
+		put_files_struct(current->files);
+		current->files = files;
+	}
+	goto _ret;
 }
 
 /* Command parsers */
@@ -191,9 +265,39 @@
 	return p - from;
 }
 
+static inline char * check_special_flags (char * sfs, Node * e)
+{
+	char * p = sfs;
+	int cont = 1;
+
+	/* special flags */
+	while (cont) {
+		switch (*p) {
+			case 'P':
+				p++;
+				e->flags |= MISC_FMT_PRESERVE_ARGV0;
+				break;
+			case 'O':
+				p++;
+				e->flags |= MISC_FMT_OPEN_BINARY;
+				break;
+			case 'C':
+				p++;
+				/* this flags also implies the
+				   open-binary flag */
+				e->flags |= (MISC_FMT_CREDENTIALS |
+						MISC_FMT_OPEN_BINARY);
+				break;
+			default:
+				cont = 0;
+		}
+	}
+
+	return p;
+}
 /*
  * This registers a new binary format, it recognises the syntax
- * ':name:type:offset:magic:mask:interpreter:'
+ * ':name:type:offset:magic:mask:interpreter:flags'
  * where the ':' is the IFS, that can be chosen with the first char
  */
 static Node *create_entry(const char __user *buffer, size_t count)
@@ -293,10 +397,8 @@
 	if (!e->interpreter[0])
 		goto Einval;
 
-	if (*p == 'P') {
-		p++;
-		e->flags |= MISC_FMT_PRESERVE_ARGV0;
-	}
+
+	p = check_special_flags (p, e);
 
 	if (*p == '\n')
 		p++;
@@ -346,6 +448,7 @@
 {
 	char *dp;
 	char *status = "disabled";
+	const char * flags = "flags: ";
 
 	if (test_bit(Enabled, &e->flags))
 		status = "enabled";
@@ -357,6 +460,22 @@
 
 	sprintf(page, "%s\ninterpreter %s\n", status, e->interpreter);
 	dp = page + strlen(page);
+
+	/* print the special flags */
+	sprintf (dp, "%s", flags);
+	dp += strlen (flags);
+	if (e->flags & MISC_FMT_PRESERVE_ARGV0) {
+		*dp ++ = 'P';
+	}
+	if (e->flags & MISC_FMT_OPEN_BINARY) {
+		*dp ++ = 'O';
+	}
+	if (e->flags & MISC_FMT_CREDENTIALS) {
+		*dp ++ = 'C';
+	}
+	*dp ++ = '\n';
+
+
 	if (!test_bit(Magic, &e->flags)) {
 		sprintf(dp, "extension .%s\n", e->magic);
 	} else {
--- diff/fs/buffer.c	2004-06-11 19:17:32.000000000 +0100
+++ source/fs/buffer.c	2004-06-11 19:22:05.000000000 +0100
@@ -947,7 +947,7 @@
 	spin_unlock(&mapping->private_lock);
 
 	if (!TestSetPageDirty(page)) {
-		spin_lock_irq(&mapping->tree_lock);
+		read_lock_irq(&mapping->tree_lock);
 		if (page->mapping) {	/* Race with truncate? */
 			if (!mapping->backing_dev_info->memory_backed)
 				inc_page_state(nr_dirty);
@@ -955,7 +955,7 @@
 						page_index(page),
 						PAGECACHE_TAG_DIRTY);
 		}
-		spin_unlock_irq(&mapping->tree_lock);
+		read_unlock_irq(&mapping->tree_lock);
 		__mark_inode_dirty(mapping->host, I_DIRTY_PAGES);
 	}
 	
@@ -2753,21 +2753,31 @@
 	if (bio->bi_size)
 		return 1;
 
+	if (err == -EOPNOTSUPP)
+		set_bit(BIO_EOPNOTSUPP, &bio->bi_flags);
+
 	bh->b_end_io(bh, test_bit(BIO_UPTODATE, &bio->bi_flags));
 	bio_put(bio);
 	return 0;
 }
 
-void submit_bh(int rw, struct buffer_head * bh)
+int submit_bh(int rw, struct buffer_head * bh)
 {
 	struct bio *bio;
+	int ret = 0;
 
 	BUG_ON(!buffer_locked(bh));
 	BUG_ON(!buffer_mapped(bh));
 	BUG_ON(!bh->b_end_io);
 
-	/* Only clear out a write error when rewriting */
-	if (test_set_buffer_req(bh) && rw == WRITE)
+	if (buffer_ordered(bh) && (rw == WRITE))
+		rw = WRITE_BARRIER;
+
+	/*
+	 * Only clear out a write error when rewriting, should this
+	 * include WRITE_SYNC as well?
+	 */
+	if (test_set_buffer_req(bh) && (rw == WRITE || rw == WRITE_BARRIER))
 		clear_buffer_write_io_error(bh);
 
 	/*
@@ -2789,7 +2799,14 @@
 	bio->bi_end_io = end_bio_bh_io_sync;
 	bio->bi_private = bh;
 
+	bio_get(bio);
 	submit_bio(rw, bio);
+
+	if (bio_flagged(bio, BIO_EOPNOTSUPP))
+		ret = -EOPNOTSUPP;
+
+	bio_put(bio);
+	return ret;
 }
 
 /**
@@ -2848,20 +2865,26 @@
 
 /*
  * For a data-integrity writeout, we need to wait upon any in-progress I/O
- * and then start new I/O and then wait upon it.
+ * and then start new I/O and then wait upon it.  The caller must have a ref on
+ * the buffer_head.
  */
-void sync_dirty_buffer(struct buffer_head *bh)
+int sync_dirty_buffer(struct buffer_head *bh)
 {
+	int ret = 0;
+
 	WARN_ON(atomic_read(&bh->b_count) < 1);
 	lock_buffer(bh);
 	if (test_clear_buffer_dirty(bh)) {
 		get_bh(bh);
 		bh->b_end_io = end_buffer_write_sync;
-		submit_bh(WRITE, bh);
+		ret = submit_bh(WRITE, bh);
 		wait_on_buffer(bh);
+		if (!ret && !buffer_uptodate(bh))
+			ret = -EIO;
 	} else {
 		unlock_buffer(bh);
 	}
+	return ret;
 }
 
 /*
--- diff/fs/cifs/AUTHORS	2004-06-11 19:17:32.000000000 +0100
+++ source/fs/cifs/AUTHORS	2004-06-11 19:22:05.000000000 +0100
@@ -23,6 +23,7 @@
 Shobhit Dayal
 Sergey Vlasov
 Richard Hughes
+Yury Umanets
 
 Test case and Bug Report contributors
 -------------------------------------
@@ -30,5 +31,7 @@
 and debug of problems they have found:  Jochen Dolze, David Blaine,
 Rene Scharfe, Martin Josefsson, Alexander Wild, Anthony Liguori,
 Lars Muller, Urban Widmark, Massimiliano Ferrero, Howard Owen,
-Kieron Briggs and others. 
+Olaf Kirch, Kieron Briggs and others. 
 
+And thanks to the IBM LTC and Power test teams and SuSE testers for
+finding multiple bugs during excellent stress test runs.
--- diff/fs/cifs/CHANGES	2004-06-11 19:17:32.000000000 +0100
+++ source/fs/cifs/CHANGES	2004-06-11 19:22:05.000000000 +0100
@@ -1,3 +1,12 @@
+Version 1.17
+------------
+Update number of blocks in file so du command is happier (in Linux a fake
+blocksize of 512 is required for calculating number of blocks in inode).
+Fix prepare write of partial pages to read in data from server if possible.
+Fix race on tcpStatus field between unmount and reconnection code, causing
+cifsd process sometimes to hang around forever. Improve out of memory
+checks in cifs_filldir
+
 Version 1.16
 ------------
 Fix incorrect file size in file handle based setattr on big endian hardware.
--- diff/fs/cifs/cifs_debug.c	2004-06-11 19:17:32.000000000 +0100
+++ source/fs/cifs/cifs_debug.c	2004-06-11 19:22:05.000000000 +0100
@@ -142,30 +142,10 @@
 			    sprintf(buf, " type: %d ",
 				    tcon->fsDevInfo.DeviceType);
 		buf += length;
-		if(tcon->tidStatus == CifsNeedReconnect)
+		if(tcon->tidStatus == CifsNeedReconnect) {
 			buf += sprintf(buf, "\tDISCONNECTED ");
-#ifdef CONFIG_CIFS_STATS
-		length = sprintf(buf,"\nSMBs: %d Oplock Breaks: %d",
-			atomic_read(&tcon->num_smbs_sent),
-			atomic_read(&tcon->num_oplock_brks));
-		buf += length;
-		length = sprintf(buf,"\nReads: %d Bytes %lld",
-			atomic_read(&tcon->num_reads),
-			(long long)(tcon->bytes_read));
-		buf += length;
-		length = sprintf(buf,"\nWrites: %d Bytes: %lld",
-			atomic_read(&tcon->num_writes),
-			(long long)(tcon->bytes_written));
-		buf += length;
-		length = sprintf(buf,
-                        "\nOpens: %d Deletes: %d\nMkdirs: %d Rmdirs: %d",
-			atomic_read(&tcon->num_opens),
-			atomic_read(&tcon->num_deletes),
-			atomic_read(&tcon->num_mkdirs),
-			atomic_read(&tcon->num_rmdirs));
-		buf += length;
-#endif
-
+			length += 14;
+		}
 	}
 	read_unlock(&GlobalSMBSeslock);
 
@@ -200,32 +180,80 @@
 	return length;
 }
 
+#ifdef CONFIG_CIFS_STATS
 int
 cifs_stats_read(char *buf, char **beginBuffer, off_t offset,
 		  int length, int *eof, void *data)
 {
-	int item_length;
-	length =
-	    sprintf(buf,
-		    "Currently Allocated structures\nCIFS Sessions: %d\n",sesInfoAllocCount.counter);
+	int item_length,i;
+	struct list_head *tmp;
+	struct cifsTconInfo *tcon;
+
+	length = sprintf(buf,
+			"Currently Allocated structures\nCIFS Sessions: %d\n",
+			sesInfoAllocCount.counter);
 	buf += length;
 	item_length = 
-		sprintf(buf,"Shares (unique mount targets): %d\n",tconInfoAllocCount.counter);
+		sprintf(buf,"Shares (unique mount targets): %d\n",
+			tconInfoAllocCount.counter);
 	length += item_length;
 	buf += item_length;      
 	item_length = 
-			sprintf(buf,"Allocated SMB Request and Response Buffers: %d\n",bufAllocCount.counter);
+		sprintf(buf,"Allocated SMB Request/Response Buffers: %d\n",
+			bufAllocCount.counter);
 	length += item_length;
 	buf += item_length;      
 	item_length = 
-		sprintf(buf,"Active Operations (MIDs in use): %d\n",midCount.counter);
+		sprintf(buf,"Active Operations (MIDs in use): %d\n",
+			midCount.counter);
 	length += item_length;
 	buf += item_length;
-	item_length = sprintf(buf,"%d sessions and %d shares reconnected after failure\n",tcpSesReconnectCount.counter,tconInfoReconnectCount.counter);
+	item_length = sprintf(buf,
+		"%d sessions and %d shares reconnected after failure\n",
+		tcpSesReconnectCount.counter,tconInfoReconnectCount.counter);
 	length += item_length;
+	buf += item_length;
+
+	i = 0;
+	read_lock(&GlobalSMBSeslock);
+	list_for_each(tmp, &GlobalTreeConnectionList) {
+		i++;
+		tcon = list_entry(tmp, struct cifsTconInfo, cifsConnectionList);
+		item_length = sprintf(buf,"\n%d) %s",i, tcon->treeName);
+		buf += item_length;
+		length += item_length;
+		if(tcon->tidStatus == CifsNeedReconnect) {
+			buf += sprintf(buf, "\tDISCONNECTED ");
+			length += 14;
+		}
+		item_length = sprintf(buf,"\nSMBs: %d Oplock Breaks: %d",
+			atomic_read(&tcon->num_smbs_sent),
+			atomic_read(&tcon->num_oplock_brks));
+		buf += item_length;
+		length += item_length;
+		item_length = sprintf(buf,"\nReads: %d Bytes %lld",
+			atomic_read(&tcon->num_reads),
+			(long long)(tcon->bytes_read));
+		buf += item_length;
+		item_length = sprintf(buf,"\nWrites: %d Bytes: %lld",
+			atomic_read(&tcon->num_writes),
+			(long long)(tcon->bytes_written));
+		buf += item_length;
+		item_length = sprintf(buf,
+			"\nOpens: %d Deletes: %d\nMkdirs: %d Rmdirs: %d",
+			atomic_read(&tcon->num_opens),
+			atomic_read(&tcon->num_deletes),
+			atomic_read(&tcon->num_mkdirs),
+			atomic_read(&tcon->num_rmdirs));
+		buf += item_length;
+		length += item_length;
+	}
+	read_unlock(&GlobalSMBSeslock);
+
 
 	return length;
 }
+#endif
 
 struct proc_dir_entry *proc_fs_cifs;
 read_proc_t cifs_txanchor_read;
@@ -265,10 +293,10 @@
 
 	create_proc_read_entry("SimultaneousOps", 0, proc_fs_cifs,
 				cifs_total_xid_read, 0);
-
+#ifdef CONFIG_CIFS_STATS
 	create_proc_read_entry("Stats", 0, proc_fs_cifs,
 				cifs_stats_read, 0);
-
+#endif
 	pde = create_proc_read_entry("cifsFYI", 0, proc_fs_cifs,
 				cifsFYI_read, 0);
 	if (pde)
@@ -336,7 +364,9 @@
 	remove_proc_entry("cifsFYI", proc_fs_cifs);
 	remove_proc_entry("traceSMB", proc_fs_cifs);
 	remove_proc_entry("SimultaneousOps", proc_fs_cifs);
+#ifdef CONFIG_CIFS_STATS
 	remove_proc_entry("Stats", proc_fs_cifs);
+#endif
 	remove_proc_entry("MultiuserMount", proc_fs_cifs);
 	remove_proc_entry("OplockEnabled", proc_fs_cifs);
 	remove_proc_entry("NTLMV2Enabled",proc_fs_cifs);
--- diff/fs/cifs/cifsfs.h	2004-06-11 19:17:32.000000000 +0100
+++ source/fs/cifs/cifsfs.h	2004-06-11 19:22:05.000000000 +0100
@@ -93,5 +93,5 @@
 			 size_t, int);
 extern ssize_t	cifs_getxattr(struct dentry *, const char *, void *, size_t);
 extern ssize_t	cifs_listxattr(struct dentry *, char *, size_t);
-#define CIFS_VERSION   "1.16"
+#define CIFS_VERSION   "1.17"
 #endif				/* _CIFSFS_H */
--- diff/fs/cifs/cifspdu.h	2004-06-11 19:17:32.000000000 +0100
+++ source/fs/cifs/cifspdu.h	2004-06-11 19:22:05.000000000 +0100
@@ -862,6 +862,10 @@
 	__u16 ByteCount;	/* bct = 0 */
 } CREATE_DIRECTORY_RSP;
 
+/***************************************************/
+/* NT Transact structure defintions follow         */
+/* Currently only ioctl and notify are implemented */
+/***************************************************/
 typedef struct smb_com_transaction_ioctl_req {
 	struct smb_hdr hdr;	/* wct = 23 */
 	__u8 MaxSetupCount;
@@ -904,29 +908,45 @@
 } TRANSACT_IOCTL_RSP;
 
 typedef struct smb_com_transaction_change_notify_req {
-        struct smb_hdr hdr;     /* wct = 23 */
-        __u8 MaxSetupCount;
-        __u16 Reserved;
-        __u32 TotalParameterCount;
-        __u32 TotalDataCount;
-        __u32 MaxParameterCount;
-        __u32 MaxDataCount;
-        __u32 ParameterCount;
-        __u32 ParameterOffset;
-        __u32 DataCount;
-        __u32 DataOffset;
-        __u8 SetupCount; /* four setup words follow subcommand */
-        /* SNIA spec incorrectly included spurious pad here */
-        __u16 SubCommand;/* 4 = Change Notify */
+	struct smb_hdr hdr;     /* wct = 23 */
+	__u8 MaxSetupCount;
+	__u16 Reserved;
+	__u32 TotalParameterCount;
+	__u32 TotalDataCount;
+	__u32 MaxParameterCount;
+	__u32 MaxDataCount;
+	__u32 ParameterCount;
+	__u32 ParameterOffset;
+	__u32 DataCount;
+	__u32 DataOffset;
+	__u8 SetupCount; /* four setup words follow subcommand */
+	/* SNIA spec incorrectly included spurious pad here */
+	__u16 SubCommand;/* 4 = Change Notify */
 	__u32 CompletionFilter;  /* operation to monitor */
 	__u16 Fid;
 	__u8 WatchTree;  /* 1 = Monitor subdirectories */
+	__u8 Reserved2;
 	__u16 ByteCount;
-	__u8 Pad[3];
-	__u8 Data[1];
+/* __u8 Pad[3];*/
+/*	__u8 Data[1];*/
 } TRANSACT_CHANGE_NOTIFY_REQ;
 
-/* Completion Filter flags */
+typedef struct smb_com_transaction_change_notify_rsp {
+	struct smb_hdr hdr;	/* wct = 18 */
+	__u8 Reserved[3];
+	__u32 TotalParameterCount;
+	__u32 TotalDataCount;
+	__u32 ParameterCount;
+	__u32 ParameterOffset;
+	__u32 ParameterDisplacement;
+	__u32 DataCount;
+	__u32 DataOffset;
+	__u32 DataDisplacement;
+	__u8 SetupCount;   /* 0 */
+	__u16 ByteCount;
+	/* __u8 Pad[3]; */
+} TRANSACT_CHANGE_NOTIFY_RSP;
+/* Completion Filter flags for Notify */
 #define FILE_NOTIFY_CHANGE_FILE_NAME    0x00000001
 #define FILE_NOTIFY_CHANGE_DIR_NAME     0x00000002
 #define FILE_NOTIFY_CHANGE_NAME         0x00000003
--- diff/fs/cifs/cifsproto.h	2004-06-11 19:17:32.000000000 +0100
+++ source/fs/cifs/cifsproto.h	2004-06-11 19:22:05.000000000 +0100
@@ -244,4 +244,7 @@
 			const __u16 target_tid,
 			const char *toName, const int flags,
 			const struct nls_table *nls_codepage);
+extern int CIFSSMBNotify(const int xid, struct cifsTconInfo *tcon, 
+			const int notify_subdirs,const __u16 netfid,__u32 filter,
+			const struct nls_table *nls_codepage);
 #endif			/* _CIFSPROTO_H */
--- diff/fs/cifs/cifssmb.c	2004-06-11 19:17:32.000000000 +0100
+++ source/fs/cifs/cifssmb.c	2004-06-11 19:22:05.000000000 +0100
@@ -383,8 +383,11 @@
 			 smb_buffer_response, &length, 0);
 	if (ses->server) {
 		atomic_dec(&ses->server->socketUseCount);
-		if (atomic_read(&ses->server->socketUseCount) == 0)
+		if (atomic_read(&ses->server->socketUseCount) == 0) {
+			spin_lock(&GlobalMid_Lock);
 			ses->server->tcpStatus = CifsExiting;
+			spin_unlock(&GlobalMid_Lock);
+		}
 	}
 	if (pSMB)
 		cifs_buf_release(pSMB);
@@ -1464,9 +1467,9 @@
 
 	pSMB->TotalParameterCount = 0 ;
 	pSMB->TotalDataCount = 0;
-	pSMB->MaxParameterCount = cpu_to_le16(2);
+	pSMB->MaxParameterCount = cpu_to_le32(2);
 	/* BB find exact data count max from sess structure BB */
-	pSMB->MaxDataCount = cpu_to_le16(4000);
+	pSMB->MaxDataCount = cpu_to_le32(4000);
 	pSMB->MaxSetupCount = 4;
 	pSMB->Reserved = 0;
 	pSMB->ParameterOffset = 0;
@@ -2828,3 +2831,51 @@
 		goto setPermsRetry;
 	return rc;
 }
+
+int CIFSSMBNotify(const int xid, struct cifsTconInfo *tcon, 
+			const int notify_subdirs, const __u16 netfid,
+			__u32 filter, const struct nls_table *nls_codepage)
+{
+	int rc = 0;
+	struct smb_com_transaction_change_notify_req * pSMB = NULL;
+	struct smb_com_transaction_change_notify_rsp * pSMBr = NULL;
+	int bytes_returned;
+
+	cFYI(1, ("In CIFSSMBNotify for file handle %d",(int)netfid));
+	rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
+                      (void **) &pSMBr);
+	if (rc)
+		return rc;
+
+	pSMB->TotalParameterCount = 0 ;
+	pSMB->TotalDataCount = 0;
+	pSMB->MaxParameterCount = cpu_to_le32(2);
+	/* BB find exact data count max from sess structure BB */
+	pSMB->MaxDataCount = 0; /* same in little endian or be */
+	pSMB->MaxSetupCount = 4;
+	pSMB->Reserved = 0;
+	pSMB->ParameterOffset = 0;
+	pSMB->DataCount = 0;
+	pSMB->DataOffset = 0;
+	pSMB->SetupCount = 4; /* single byte does not need le conversion */
+	pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_NOTIFY_CHANGE);
+	pSMB->ParameterCount = pSMB->TotalParameterCount;
+	if(notify_subdirs)
+		pSMB->WatchTree = 1; /* one byte - no le conversion needed */
+	pSMB->Reserved2 = 0;
+	pSMB->CompletionFilter = cpu_to_le32(filter);
+	pSMB->Fid = netfid; /* file handle always le */
+	pSMB->ByteCount = 0;
+
+	pSMB->hdr.smb_buf_length += pSMB->ByteCount;
+	rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
+			(struct smb_hdr *) pSMBr, &bytes_returned, 0);
+	if (rc) {
+		cFYI(1, ("Error in Notify = %d", rc));
+	}
+	if (pSMB)
+		cifs_buf_release(pSMB);
+/*		if (rc == -EAGAIN)
+			goto NotifyRetry; */
+	return rc;	
+}
--- diff/fs/cifs/connect.c	2004-06-11 19:17:32.000000000 +0100
+++ source/fs/cifs/connect.c	2004-06-11 19:22:05.000000000 +0100
@@ -95,9 +95,15 @@
 	struct cifsTconInfo *tcon;
 	struct mid_q_entry * mid_entry;
 	
-	if(server->tcpStatus == CifsExiting)
+	spin_lock(&GlobalMid_Lock);
+	if(server->tcpStatus == CifsExiting) {
+		/* the demux thread will exit normally 
+		next time through the loop */
+		spin_unlock(&GlobalMid_Lock);
 		return rc;
-	server->tcpStatus = CifsNeedReconnect;
+	} else
+		server->tcpStatus = CifsNeedReconnect;
+	spin_unlock(&GlobalMid_Lock);
 	server->maxBuf = 0;
 
 	cFYI(1, ("Reconnecting tcp session "));
@@ -164,7 +170,10 @@
 			schedule_timeout(3 * HZ);
 		} else {
 			atomic_inc(&tcpSesReconnectCount);
-			server->tcpStatus = CifsGood;
+			spin_lock(&GlobalMid_Lock);
+			if(server->tcpStatus != CifsExiting)
+				server->tcpStatus = CifsGood;
+			spin_unlock(&GlobalMid_Lock);
 			atomic_set(&server->inFlight,0);
 			wake_up(&server->response_q);
 		}
@@ -243,12 +252,14 @@
 				/* some servers kill tcp session rather than returning
 					smb negprot error in which case reconnecting here is
 					not going to help - return error to mount */
+				spin_lock(&GlobalMid_Lock);
 				server->tcpStatus = CifsExiting;
+				spin_unlock(&GlobalMid_Lock);
 				wake_up(&server->response_q);
 				break;
 			}
 
-			cFYI(1,("Reconnecting after unexpected rcvmsg error "));
+			cFYI(1,("Reconnecting after unexpected peek error %d",length));
 			cifs_reconnect(server);
 			csocket = server->ssocket;
 			wake_up(&server->response_q);
@@ -280,7 +291,9 @@
 					/* if nack on negprot (rather than 
 					ret of smb negprot error) reconnecting
 					not going to help, ret error to mount */
+					spin_lock(&GlobalMid_Lock);
 					server->tcpStatus = CifsExiting;
+					spin_unlock(&GlobalMid_Lock);
 					/* wake up thread doing negprot */
 					wake_up(&server->response_q);
 					break;
@@ -391,7 +404,9 @@
 			}
 		}
 	}
+	spin_lock(&GlobalMid_Lock);
 	server->tcpStatus = CifsExiting;
+	spin_unlock(&GlobalMid_Lock);
 	atomic_set(&server->inFlight, 0);
 	/* Although there should not be any requests blocked on 
 	this queue it can not hurt to be paranoid and try to wake up requests
@@ -595,6 +610,8 @@
 			}
 			if ((temp_len = strnlen(value, 300)) < 300) {
 				vol->UNC = kmalloc(temp_len+1,GFP_KERNEL);
+				if(vol->UNC == NULL)
+					return 1;
 				strcpy(vol->UNC,value);
 				if (strncmp(vol->UNC, "//", 2) == 0) {
 					vol->UNC[0] = '\\';
@@ -742,6 +759,8 @@
 		}
 		if ((temp_len = strnlen(devname, 300)) < 300) {
 			vol->UNC = kmalloc(temp_len+1,GFP_KERNEL);
+			if(vol->UNC == NULL)
+				return 1;
 			strcpy(vol->UNC,devname);
 			if (strncmp(vol->UNC, "//", 2) == 0) {
 				vol->UNC[0] = '\\';
@@ -1030,7 +1049,7 @@
 		} else {
 		/* BB other socket options to set KEEPALIVE, NODELAY? */
 			 cFYI(1,("ipv6 Socket created"));
-                        (*csocket)->sk->sk_allocation = GFP_NOFS;
+			(*csocket)->sk->sk_allocation = GFP_NOFS;
 		}
 	}
 
@@ -1226,6 +1245,9 @@
 			init_waitqueue_head(&srvTcp->response_q);
 			init_waitqueue_head(&srvTcp->request_q);
 			INIT_LIST_HEAD(&srvTcp->pending_mid_q);
+			/* at this point we are the only ones with the pointer
+			to the struct since the kernel thread not created yet
+			so no need to spinlock this init of tcpStatus */
 			srvTcp->tcpStatus = CifsNew;
 			init_MUTEX(&srvTcp->tcpSem);
 			kernel_thread((void *)(void *)cifs_demultiplex_thread, srvTcp,
@@ -1342,9 +1364,12 @@
 
 /* on error free sesinfo and tcon struct if needed */
 	if (rc) {
-		if(atomic_read(&srvTcp->socketUseCount) == 0)
-                	srvTcp->tcpStatus = CifsExiting;
-		           /* If find_unc succeeded then rc == 0 so we can not end */
+		if(atomic_read(&srvTcp->socketUseCount) == 0) {
+			spin_lock(&GlobalMid_Lock);
+			srvTcp->tcpStatus = CifsExiting;
+			spin_unlock(&GlobalMid_Lock);
+		}
+		 /* If find_unc succeeded then rc == 0 so we can not end */
 		if (tcon)  /* up here accidently freeing someone elses tcon struct */
 			tconInfoFree(tcon);
 		if (existingCifsSes == 0) {
@@ -2791,7 +2816,7 @@
 	char ntlm_session_key[CIFS_SESSION_KEY_SIZE];
 	int ntlmv2_flag = FALSE;
 
-    /* what if server changes its buffer size after dropping the session? */
+	/* what if server changes its buffer size after dropping the session? */
 	if(pSesInfo->server->maxBuf == 0) /* no need to send on reconnect */ {
 		rc = CIFSSMBNegotiate(xid, pSesInfo);
 		if(rc == -EAGAIN) /* retry only once on 1st time connection */ {
@@ -2799,8 +2824,15 @@
 			if(rc == -EAGAIN) 
 				rc = -EHOSTDOWN;
 		}
-		if(rc == 0)
-			pSesInfo->server->tcpStatus = CifsGood;
+		if(rc == 0) {
+			spin_lock(&GlobalMid_Lock);
+			if(pSesInfo->server->tcpStatus != CifsExiting)
+				pSesInfo->server->tcpStatus = CifsGood;
+			else
+				rc = -EHOSTDOWN;
+			spin_unlock(&GlobalMid_Lock);
+
+		}
 	}
 	if (!rc) {
 		pSesInfo->capabilities = pSesInfo->server->capabilities;
--- diff/fs/cifs/dir.c	2004-06-11 19:17:32.000000000 +0100
+++ source/fs/cifs/dir.c	2004-06-11 19:22:05.000000000 +0100
@@ -159,6 +159,7 @@
 	struct cifsFileInfo * pCifsFile = NULL;
 	struct cifsInodeInfo * pCifsInode;
 	int disposition = FILE_OVERWRITE_IF;
+	int write_only = FALSE;
 
 	xid = GetXid();
 
@@ -176,9 +177,10 @@
 	if(nd) {
 		if ((nd->intent.open.flags & O_ACCMODE) == O_RDONLY)
 			desiredAccess = GENERIC_READ;
-		else if ((nd->intent.open.flags & O_ACCMODE) == O_WRONLY)
+		else if ((nd->intent.open.flags & O_ACCMODE) == O_WRONLY) {
 			desiredAccess = GENERIC_WRITE;
-		else if ((nd->intent.open.flags & O_ACCMODE) == O_RDWR) {
+			write_only = TRUE;
+		} else if ((nd->intent.open.flags & O_ACCMODE) == O_RDWR) {
 			/* GENERIC_ALL is too much permission to request */
 			/* can cause unnecessary access denied on create */
 			/* desiredAccess = GENERIC_ALL; */
@@ -262,16 +264,25 @@
 				pCifsFile->invalidHandle = FALSE;
 				pCifsFile->closePend     = FALSE;
 				init_MUTEX(&pCifsFile->fh_sem);
-				/* pCifsFile->pfile = file; */ /* put in at open time */
+				/* put the following in at open now */
+				/* pCifsFile->pfile = file; */ 
 				write_lock(&GlobalSMBSeslock);
 				list_add(&pCifsFile->tlist,&pTcon->openFileList);
 				pCifsInode = CIFS_I(newinode);
 				if(pCifsInode) {
-					list_add(&pCifsFile->flist,&pCifsInode->openFileList);
+				/* if readable file instance put first in list*/
+					if (write_only == TRUE) {
+                                        	list_add_tail(&pCifsFile->flist,
+							&pCifsInode->openFileList);
+					} else {
+						list_add(&pCifsFile->flist,
+							&pCifsInode->openFileList);
+					}
 					if((oplock & 0xF) == OPLOCK_EXCLUSIVE) {
 						pCifsInode->clientCanCacheAll = TRUE;
 						pCifsInode->clientCanCacheRead = TRUE;
-						cFYI(1,("Exclusive Oplock granted on inode %p",newinode));
+						cFYI(1,("Exclusive Oplock granted on inode %p",
+							newinode));
 					} else if((oplock & 0xF) == OPLOCK_READ)
 						pCifsInode->clientCanCacheRead = TRUE;
 				}
--- diff/fs/cifs/fcntl.c	2004-06-11 19:17:32.000000000 +0100
+++ source/fs/cifs/fcntl.c	2004-06-11 19:22:05.000000000 +0100
@@ -32,9 +32,12 @@
 {
 	int xid;
 	int rc = -EINVAL;
+	int oplock = FALSE;
 	struct cifs_sb_info *cifs_sb;
 	struct cifsTconInfo *pTcon;
 	char *full_path = NULL;
+	__u32 filter = FILE_NOTIFY_CHANGE_NAME | FILE_NOTIFY_CHANGE_ATTRIBUTES;
+    __u16 netfid;
 
 	xid = GetXid();
 	cifs_sb = CIFS_SB(file->f_dentry->d_sb);
@@ -48,7 +51,20 @@
 		rc = -ENOMEM;
 	} else {
 		cFYI(1,("cifs dir notify on file %s",full_path));
-		/* CIFSSMBNotify(xid, pTcon, full_path, cifs_sb->local_nls);*/
+		rc = CIFSSMBOpen(xid, pTcon, full_path, FILE_OPEN, 
+			GENERIC_READ | SYNCHRONIZE, 0 /* create options */,
+			&netfid, &oplock,NULL, cifs_sb->local_nls);
+		/* BB fixme - add this handle to a notify handle list */
+		if(rc) {
+			cFYI(1,("Could not open directory for notify"));
+		} else {
+			rc = CIFSSMBNotify(xid, pTcon, 1 /* subdirs */, netfid, 
+				filter, cifs_sb->local_nls);
+			/* BB add code to close file eventually (at unmount
+			it would close automatically but may be a way
+			to do it easily when inode freed or when
+			notify info is cleared/changed */
+		}
 	}
 	
 	FreeXid(xid);
--- diff/fs/cifs/file.c	2004-06-11 19:17:32.000000000 +0100
+++ source/fs/cifs/file.c	2004-06-11 19:22:05.000000000 +0100
@@ -173,7 +173,14 @@
 			list_add(&pCifsFile->tlist,&pTcon->openFileList);
 			pCifsInode = CIFS_I(file->f_dentry->d_inode);
 			if(pCifsInode) {
-				list_add(&pCifsFile->flist,&pCifsInode->openFileList);
+				/* want handles we can use to read with first */
+				/* in the list so we do not have to walk the */
+				/* list to search for one in prepare_write */
+				if ((file->f_flags & O_ACCMODE) == O_WRONLY) {
+					list_add_tail(&pCifsFile->flist,&pCifsInode->openFileList);
+				} else {
+					list_add(&pCifsFile->flist,&pCifsInode->openFileList);
+				}
 				write_unlock(&GlobalSMBSeslock);
 				write_unlock(&file->f_owner.lock);
 				if(pCifsInode->clientCanCacheRead) {
@@ -701,6 +708,7 @@
 
 	cifsInode = CIFS_I(mapping->host);
 	read_lock(&GlobalSMBSeslock); 
+	/* BB we should start at the end */
 	list_for_each_safe(tmp, tmp1, &cifsInode->openFileList) {            
 		open_file = list_entry(tmp,struct cifsFileInfo, flist);
 		if(open_file->closePend)
@@ -770,6 +778,9 @@
 	xid = GetXid();
 /* BB add check for wbc flags */
 	page_cache_get(page);
+        if (!PageUptodate(page)) {
+		cFYI(1,("ppw - page not up to date"));
+	}
 	
 	rc = cifs_partialpagewrite(page,0,PAGE_CACHE_SIZE);
 	SetPageUptodate(page); /* BB add check for error and Clearuptodate? */
@@ -787,8 +798,7 @@
 	int rc = 0;
 	struct inode *inode = page->mapping->host;
 	loff_t position = ((loff_t)page->index << PAGE_CACHE_SHIFT) + to;
-	/* struct cifsFileInfo *open_file;
-	struct cifs_sb_info *cifs_sb; */
+	char * page_data;
 
 	xid = GetXid();
 	cFYI(1,("commit write for page %p up to position %lld for %d",page,position,to));
@@ -819,7 +829,31 @@
 			cFYI(1,(" SetEOF (commit write) rc = %d",rc));
 		}*/
 	}
-	set_page_dirty(page);
+        if (!PageUptodate(page)) {
+		position =  ((loff_t)page->index << PAGE_CACHE_SHIFT) + offset;
+		/* can not rely on (or let) writepage write this data */
+		if(to < offset) {
+			cFYI(1,("Illegal offsets, can not copy from %d to %d",
+				offset,to));
+			FreeXid(xid);
+			return rc;
+		}
+		/* this is probably better than directly calling 
+		partialpage_write since in this function
+		the file handle is known which we might as well
+		leverage */
+		/* BB check if anything else missing out of ppw */
+		/* such as updating last write time */
+		page_data = kmap(page);
+		rc = cifs_write(file, page_data+offset,to-offset,
+                                        &position);
+		if(rc > 0)
+			rc = 0;
+		/* else if rc < 0 should we set writebehind rc? */
+		kunmap(page);
+	} else {	
+		set_page_dirty(page);
+	}
 
 	FreeXid(xid);
 	return rc;
@@ -924,6 +958,10 @@
 	}
 	open_file = (struct cifsFileInfo *)file->private_data;
 
+	if((file->f_flags & O_ACCMODE) == O_WRONLY) {
+		cFYI(1,("attempting read on write only file instance"));
+	}
+
 	for (total_read = 0,current_offset=read_data; read_size > total_read;
 				total_read += bytes_read,current_offset+=bytes_read) {
 		current_read_size = min_t(const int,read_size - total_read,cifs_sb->rsize);
@@ -1169,49 +1207,58 @@
 	return rc;
 }
 
-static int
-cifs_readpage(struct file *file, struct page *page)
+static int cifs_readpage_worker(struct file *file, struct page *page, loff_t * poffset)
 {
-	loff_t offset = (loff_t)page->index << PAGE_CACHE_SHIFT;
 	char * read_data;
-	int rc = -EACCES;
-	int xid;
-
-	xid = GetXid();
-
-	if (file->private_data == NULL) {
-		FreeXid(xid);
-		return -EBADF;
-	}
-
-	cFYI(0,("readpage %p at offset %d 0x%x\n",page,(int)offset,(int)offset));
+	int rc;
 
 	page_cache_get(page);
 	read_data = kmap(page);
 	/* for reads over a certain size could initiate async read ahead */
-
-	rc = cifs_read(file, read_data, PAGE_CACHE_SIZE, &offset);
-
+                                                                                                                           
+	rc = cifs_read(file, read_data, PAGE_CACHE_SIZE, poffset);
+                                                                                                                           
 	if (rc < 0)
 		goto io_error;
 	else {
 		cFYI(1,("Bytes read %d ",rc));
 	}
-
+                                                                                                                           
 	file->f_dentry->d_inode->i_atime = CURRENT_TIME;
-
+                                                                                                                           
 	if(PAGE_CACHE_SIZE > rc) {
 		memset(read_data+rc, 0, PAGE_CACHE_SIZE - rc);
 	}
 	flush_dcache_page(page);
 	SetPageUptodate(page);
 	rc = 0;
-
+                                                                                                                           
 io_error:
-	kunmap(page);
+        kunmap(page);
+	page_cache_release(page);
+	return rc;
+}
+
+static int
+cifs_readpage(struct file *file, struct page *page)
+{
+	loff_t offset = (loff_t)page->index << PAGE_CACHE_SHIFT;
+	int rc = -EACCES;
+	int xid;
+
+	xid = GetXid();
+
+	if (file->private_data == NULL) {
+		FreeXid(xid);
+		return -EBADF;
+	}
+
+	cFYI(1,("readpage %p at offset %d 0x%x\n",page,(int)offset,(int)offset));
+
+	rc = cifs_readpage_worker(file,page,&offset);
+
 	unlock_page(page);
 
-	page_cache_release(page);
 	FreeXid(xid);
 	return rc;
 }
@@ -1276,8 +1323,11 @@
 	}
 
 	i_size_write(tmp_inode,pfindData->EndOfFile);
-	tmp_inode->i_blocks =
-		(tmp_inode->i_blksize - 1 + pfindData->AllocationSize) >> tmp_inode->i_blkbits;
+
+	/* 512 bytes (2**9) is the fake blocksize that must be used */
+	/* for this calculation, even though the reported blocksize is larger */
+	tmp_inode->i_blocks = (512 - 1 + pfindData->AllocationSize) >> 9;
+
 	if (pfindData->AllocationSize < pfindData->EndOfFile)
 		cFYI(1, ("Possible sparse file: allocation size less than end of file "));
 	cFYI(1,
@@ -1350,8 +1400,10 @@
 	pfindData->NumOfBytes = le64_to_cpu(pfindData->NumOfBytes);
 	pfindData->EndOfFile = le64_to_cpu(pfindData->EndOfFile);
 	i_size_write(tmp_inode,pfindData->EndOfFile);
-	tmp_inode->i_blocks =
-                (tmp_inode->i_blksize - 1 + pfindData->NumOfBytes) >> tmp_inode->i_blkbits;
+
+	/* 512 bytes (2**9) is the fake blocksize that must be used */
+	/* for this calculation, not the real blocksize */
+	tmp_inode->i_blocks = (512 - 1 + pfindData->NumOfBytes) >> 9;
 
 	if (S_ISREG(tmp_inode->i_mode)) {
 		cFYI(1, ("File inode"));
@@ -1393,12 +1445,15 @@
 		/* BB overwrite the old name? i.e. tmp_dentry->d_name and tmp_dentry->d_name.len ?? */
 		if(*ptmp_inode == NULL) {
 	                *ptmp_inode = new_inode(file->f_dentry->d_sb);
+			if(*ptmp_inode == NULL)
+				return;
 			d_instantiate(tmp_dentry, *ptmp_inode);
 		}
 	} else {
 		tmp_dentry = d_alloc(file->f_dentry, qstring);
 		if(tmp_dentry == NULL) {
 			cERROR(1,("Failed allocating dentry"));
+			*ptmp_inode = NULL;
 			return;
 		}
 			
@@ -1406,6 +1461,8 @@
 		tmp_dentry->d_op = &cifs_dentry_ops;
 		cFYI(0, (" instantiate dentry 0x%p with inode 0x%p ",
 			 tmp_dentry, *ptmp_inode));
+		if(*ptmp_inode == NULL)
+			return;
 		d_instantiate(tmp_dentry, *ptmp_inode);
 		d_rehash(tmp_dentry);
 	}
@@ -1462,7 +1519,9 @@
 	pqstring->len = pfindData->FileNameLength;
 
 	construct_dentry(pqstring, file, &tmp_inode, &tmp_dentry);
-
+	if((tmp_inode == NULL) || (tmp_dentry == NULL)) {
+		return -ENOMEM;
+	}
 	fill_in_inode(tmp_inode, pfindData, &object_type);
 	rc = filldir(direntry, pfindData->FileName, pqstring->len, file->f_pos,
 		tmp_inode->i_ino, object_type);
@@ -1488,6 +1547,9 @@
 	pqstring->len = strnlen(pUnixFindData->FileName, MAX_PATHCONF);
 
 	construct_dentry(pqstring, file, &tmp_inode, &tmp_dentry);
+        if((tmp_inode == NULL) || (tmp_dentry == NULL)) {
+                return -ENOMEM;
+        }
 
 	unix_fill_in_inode(tmp_inode, pUnixFindData, &object_type);
 	rc = filldir(direntry, pUnixFindData->FileName, pqstring->len,
@@ -1950,17 +2012,34 @@
 int cifs_prepare_write(struct file *file, struct page *page,
 			unsigned from, unsigned to)
 {
+	int rc = 0;
+        loff_t offset = (loff_t)page->index << PAGE_CACHE_SHIFT;
 	cFYI(1,("prepare write for page %p from %d to %d",page,from,to));
 	if (!PageUptodate(page)) {
-		if (to - from != PAGE_CACHE_SIZE) {
+	/*	if (to - from != PAGE_CACHE_SIZE) {
 			void *kaddr = kmap_atomic(page, KM_USER0);
 			memset(kaddr, 0, from);
 			memset(kaddr + to, 0, PAGE_CACHE_SIZE - to);
 			flush_dcache_page(page);
 			kunmap_atomic(kaddr, KM_USER0);
+		} */
+		/* If we are writing a full page it will be up to date,
+		no need to read from the server */
+		if((to==PAGE_CACHE_SIZE) && (from == 0))
+			SetPageUptodate(page);
+
+		/* might as well read a page, it is fast enough */
+		if((file->f_flags & O_ACCMODE) != O_WRONLY) {
+			rc = cifs_readpage_worker(file,page,&offset);
+		} else {
+		/* should we try using another
+		file handle if there is one - how would we lock it
+		to prevent close of that handle racing with this read? */
+		/* In any case this will be written out by commit_write */
 		}
-		SetPageUptodate(page);
 	}
+
+	/* BB should we pass any errors back? e.g. if we do not have read access to the file */
 	return 0;
 }
 
@@ -1969,8 +2048,7 @@
 	.readpage = cifs_readpage,
 	.readpages = cifs_readpages,
 	.writepage = cifs_writepage,
-	.prepare_write = simple_prepare_write, /* BB fixme BB */
-/*	.prepare_write = cifs_prepare_write, */  /* BB removeme BB */
+	.prepare_write = cifs_prepare_write, 
 	.commit_write = cifs_commit_write,
    /* .sync_page = cifs_sync_page, */
 	/*.direct_IO = */
--- diff/fs/cifs/inode.c	2004-06-11 19:17:32.000000000 +0100
+++ source/fs/cifs/inode.c	2004-06-11 19:22:05.000000000 +0100
@@ -130,8 +130,18 @@
 	and blkbits set in superblock so 2**blkbits and blksize will match */
 /*		inode->i_blksize =
 		    (pTcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE) & 0xFFFFFE00;*/
-		inode->i_blocks = 
-	                (inode->i_blksize - 1 + findData.NumOfBytes) >> inode->i_blkbits;
+
+		/* This seems incredibly stupid but it turns out that
+		i_blocks is not related to (i_size / i_blksize), instead a
+		size of 512 is required to be used for calculating num blocks */
+		 
+
+/*		inode->i_blocks = 
+	                (inode->i_blksize - 1 + findData.NumOfBytes) >> inode->i_blkbits;*/
+
+		/* 512 bytes (2**9) is the fake blocksize that must be used */
+		/* for this calculation */
+		inode->i_blocks = (512 - 1 + findData.NumOfBytes) >> 9;
 
 		if (findData.NumOfBytes < findData.EndOfFile)
 			cFYI(1, ("Server inconsistency Error: it says allocation size less than end of file "));
@@ -275,8 +285,10 @@
 		}
 		i_size_write(inode,le64_to_cpu(pfindData->EndOfFile));
 		pfindData->AllocationSize = le64_to_cpu(pfindData->AllocationSize);
-		inode->i_blocks =
-			(inode->i_blksize - 1 + pfindData->AllocationSize) >> inode->i_blkbits;
+
+		/* 512 bytes (2**9) is the fake blocksize that must be used */
+		/* for this calculation */
+		inode->i_blocks = (512 - 1 + pfindData->AllocationSize) >> 9;
 
 		inode->i_nlink = le32_to_cpu(pfindData->NumberOfLinks);
 
--- diff/fs/cifs/transport.c	2004-06-11 19:17:32.000000000 +0100
+++ source/fs/cifs/transport.c	2004-06-11 19:22:05.000000000 +0100
@@ -126,7 +126,6 @@
 
 	if(ssocket == NULL)
 		return -ENOTSOCK; /* BB eventually add reconnect code here */
-/*  ssocket->sk->allocation = GFP_BUFFER; *//* BB is this spurious? */
 	iov.iov_base = smb_buffer;
 	iov.iov_len = smb_buf_length + 4;
 
--- diff/fs/coda/cnode.c	2004-05-19 22:12:25.000000000 +0100
+++ source/fs/coda/cnode.c	2004-06-11 19:22:05.000000000 +0100
@@ -17,8 +17,9 @@
 }
 
 static struct inode_operations coda_symlink_inode_operations = {
-	.readlink	= page_readlink,
-	.follow_link	= page_follow_link,
+	.readlink	= generic_readlink,
+	.follow_link	= page_follow_link_light,
+	.put_link	= page_put_link,
 	.setattr	= coda_setattr,
 };
 
--- diff/fs/compat.c	2004-06-11 19:17:32.000000000 +0100
+++ source/fs/compat.c	2004-06-11 19:22:05.000000000 +0100
@@ -34,6 +34,7 @@
 #include <linux/syscalls.h>
 #include <linux/ctype.h>
 #include <linux/module.h>
+#include <linux/dirent.h>
 #include <linux/dnotify.h>
 #include <linux/highuid.h>
 #include <linux/sunrpc/svc.h>
@@ -797,6 +798,260 @@
 	return retval;
 }
 
+#define NAME_OFFSET(de) ((int) ((de)->d_name - (char __user *) (de)))
+#define COMPAT_ROUND_UP(x) (((x)+sizeof(compat_long_t)-1) & \
+				~(sizeof(compat_long_t)-1))
+
+struct compat_old_linux_dirent {
+	compat_ulong_t	d_ino;
+	compat_ulong_t	d_offset;
+	unsigned short	d_namlen;
+	char		d_name[1];
+};
+
+struct compat_readdir_callback {
+	struct compat_old_linux_dirent __user *dirent;
+	int result;
+};
+
+static int compat_fillonedir(void *__buf, const char *name, int namlen,
+			loff_t offset, ino_t ino, unsigned int d_type)
+{
+	struct compat_readdir_callback *buf = __buf;
+	struct compat_old_linux_dirent __user *dirent;
+
+	if (buf->result)
+		return -EINVAL;
+	buf->result++;
+	dirent = buf->dirent;
+	if (!access_ok(VERIFY_WRITE, (unsigned long)dirent,
+			(unsigned long)(dirent->d_name + namlen + 1) -
+				(unsigned long)dirent))
+		goto efault;
+	if (	__put_user(ino, &dirent->d_ino) ||
+		__put_user(offset, &dirent->d_offset) ||
+		__put_user(namlen, &dirent->d_namlen) ||
+		__copy_to_user(dirent->d_name, name, namlen) ||
+		__put_user(0, dirent->d_name + namlen))
+		goto efault;
+	return 0;
+efault:
+	buf->result = -EFAULT;
+	return -EFAULT;
+}
+
+asmlinkage long compat_old_readdir(unsigned int fd,
+	struct compat_old_linux_dirent __user *dirent, unsigned int count)
+{
+	int error;
+	struct file *file;
+	struct compat_readdir_callback buf;
+
+	error = -EBADF;
+	file = fget(fd);
+	if (!file)
+		goto out;
+
+	buf.result = 0;
+	buf.dirent = dirent;
+
+	error = vfs_readdir(file, compat_fillonedir, &buf);
+	if (error >= 0)
+		error = buf.result;
+
+	fput(file);
+out:
+	return error;
+}
+
+struct compat_linux_dirent {
+	compat_ulong_t	d_ino;
+	compat_ulong_t	d_off;
+	unsigned short	d_reclen;
+	char		d_name[1];
+};
+
+struct compat_getdents_callback {
+	struct compat_linux_dirent __user *current_dir;
+	struct compat_linux_dirent __user *previous;
+	int count;
+	int error;
+};
+
+static int compat_filldir(void *__buf, const char *name, int namlen,
+		loff_t offset, ino_t ino, unsigned int d_type)
+{
+	struct compat_linux_dirent __user * dirent;
+	struct compat_getdents_callback *buf = __buf;
+	int reclen = COMPAT_ROUND_UP(NAME_OFFSET(dirent) + namlen + 2);
+
+	buf->error = -EINVAL;	/* only used if we fail.. */
+	if (reclen > buf->count)
+		return -EINVAL;
+	dirent = buf->previous;
+	if (dirent) {
+		if (__put_user(offset, &dirent->d_off))
+			goto efault;
+	}
+	dirent = buf->current_dir;
+	if (__put_user(ino, &dirent->d_ino))
+		goto efault;
+	if (__put_user(reclen, &dirent->d_reclen))
+		goto efault;
+	if (copy_to_user(dirent->d_name, name, namlen))
+		goto efault;
+	if (__put_user(0, dirent->d_name + namlen))
+		goto efault;
+	if (__put_user(d_type, (char  __user *) dirent + reclen - 1))
+		goto efault;
+	buf->previous = dirent;
+	dirent = (void __user *)dirent + reclen;
+	buf->current_dir = dirent;
+	buf->count -= reclen;
+	return 0;
+efault:
+	buf->error = -EFAULT;
+	return -EFAULT;
+}
+
+asmlinkage long compat_sys_getdents(unsigned int fd,
+		struct compat_linux_dirent __user *dirent, unsigned int count)
+{
+	struct file * file;
+	struct compat_linux_dirent __user * lastdirent;
+	struct compat_getdents_callback buf;
+	int error;
+
+	error = -EFAULT;
+	if (!access_ok(VERIFY_WRITE, dirent, count))
+		goto out;
+
+	error = -EBADF;
+	file = fget(fd);
+	if (!file)
+		goto out;
+
+	buf.current_dir = dirent;
+	buf.previous = NULL;
+	buf.count = count;
+	buf.error = 0;
+
+	error = vfs_readdir(file, compat_filldir, &buf);
+	if (error < 0)
+		goto out_putf;
+	error = buf.error;
+	lastdirent = buf.previous;
+	if (lastdirent) {
+		if (put_user(file->f_pos, &lastdirent->d_off))
+			error = -EFAULT;
+		else
+			error = count - buf.count;
+	}
+
+out_putf:
+	fput(file);
+out:
+	return error;
+}
+
+#ifndef __ARCH_OMIT_COMPAT_SYS_GETDENTS64
+#define COMPAT_ROUND_UP64(x) (((x)+sizeof(u64)-1) & ~(sizeof(u64)-1))
+
+struct compat_getdents_callback64 {
+	struct linux_dirent64 __user *current_dir;
+	struct linux_dirent64 __user *previous;
+	int count;
+	int error;
+};
+
+static int compat_filldir64(void * __buf, const char * name, int namlen, loff_t offset,
+		     ino_t ino, unsigned int d_type)
+{
+	struct linux_dirent64 __user *dirent;
+	struct compat_getdents_callback64 *buf = __buf;
+	int jj = NAME_OFFSET(dirent);
+	int reclen = COMPAT_ROUND_UP64(jj + namlen + 1);
+	u64 off;
+
+	buf->error = -EINVAL;	/* only used if we fail.. */
+	if (reclen > buf->count)
+		return -EINVAL;
+	dirent = buf->previous;
+
+	if (dirent) {
+		if (__put_user(offset, (u32 __user *)&dirent->d_off))
+			goto efault;
+		if (__put_user(offset >> 32,
+				((u32 __user *)&dirent->d_off) + 1))
+			goto efault;
+	}
+	dirent = buf->current_dir;
+	if ((__put_user(ino, (u32 __user *)&dirent->d_ino))
+	 || (__put_user(ino >> 32, ((u32 __user *)&dirent->d_ino) + 1)))
+		goto efault;
+	off = 0;
+	if ((__put_user(off, (u32 __user *)&dirent->d_off))
+	 || (__put_user(off >> 32, ((u32 __user *)&dirent->d_off) + 1)))
+		goto efault;
+	if (__put_user(reclen, &dirent->d_reclen))
+		goto efault;
+	if (__put_user(d_type, &dirent->d_type))
+		goto efault;
+	if (copy_to_user(dirent->d_name, name, namlen))
+		goto efault;
+	if (__put_user(0, dirent->d_name + namlen))
+		goto efault;
+	buf->previous = dirent;
+	dirent = (void __user *)dirent + reclen;
+	buf->current_dir = dirent;
+	buf->count -= reclen;
+	return 0;
+efault:
+	buf->error = -EFAULT;
+	return -EFAULT;
+}
+
+asmlinkage long compat_sys_getdents64(unsigned int fd,
+		struct linux_dirent64 __user * dirent, unsigned int count)
+{
+	struct file * file;
+	struct linux_dirent64 __user * lastdirent;
+	struct compat_getdents_callback64 buf;
+	int error;
+
+	error = -EFAULT;
+	if (!access_ok(VERIFY_WRITE, dirent, count))
+		goto out;
+
+	error = -EBADF;
+	file = fget(fd);
+	if (!file)
+		goto out;
+
+	buf.current_dir = dirent;
+	buf.previous = NULL;
+	buf.count = count;
+	buf.error = 0;
+
+	error = vfs_readdir(file, compat_filldir64, &buf);
+	if (error < 0)
+		goto out_putf;
+	error = buf.error;
+	lastdirent = buf.previous;
+	if (lastdirent) {
+		typeof(lastdirent->d_off) d_off = file->f_pos;
+		__put_user(d_off, (u32 __user *)&lastdirent->d_off);
+		__put_user(d_off >> 32, ((u32 __user *)&lastdirent->d_off) + 1);
+		error = count - buf.count;
+	}
+
+out_putf:
+	fput(file);
+out:
+	return error;
+}
+#endif /* ! __ARCH_OMIT_COMPAT_SYS_GETDENTS64 */
+
 static ssize_t compat_do_readv_writev(int type, struct file *file,
 			       const struct compat_iovec __user *uvector,
 			       unsigned long nr_segs, loff_t *pos)
--- diff/fs/compat_ioctl.c	2004-06-11 19:17:32.000000000 +0100
+++ source/fs/compat_ioctl.c	2004-06-11 19:22:05.000000000 +0100
@@ -115,6 +115,8 @@
 #include <linux/filter.h>
 #include <linux/msdos_fs.h>
 
+#include <linux/hiddev.h>
+
 #undef INCLUDES
 #endif
 
--- diff/fs/devfs/base.c	2004-06-11 19:17:32.000000000 +0100
+++ source/fs/devfs/base.c	2004-06-11 19:22:05.000000000 +0100
@@ -2490,28 +2490,11 @@
 	return 0;
 }				/*  End Function devfs_mknod  */
 
-static int devfs_readlink(struct dentry *dentry, char *buffer, int buflen)
-{
-	int err;
-	struct devfs_entry *de;
-
-	de = get_devfs_entry_from_vfs_inode(dentry->d_inode);
-	if (!de)
-		return -ENODEV;
-	err = vfs_readlink(dentry, buffer, buflen, de->u.symlink.linkname);
-	return err;
-}				/*  End Function devfs_readlink  */
-
 static int devfs_follow_link(struct dentry *dentry, struct nameidata *nd)
 {
-	int err;
-	struct devfs_entry *de;
-
-	de = get_devfs_entry_from_vfs_inode(dentry->d_inode);
-	if (!de)
-		return -ENODEV;
-	err = vfs_follow_link(nd, de->u.symlink.linkname);
-	return err;
+	struct devfs_entry *p = get_devfs_entry_from_vfs_inode(dentry->d_inode);
+	nd_set_link(nd, p ? p->u.symlink.linkname : ERR_PTR(-ENODEV));
+	return 0;
 }				/*  End Function devfs_follow_link  */
 
 static struct inode_operations devfs_iops = {
@@ -2529,7 +2512,7 @@
 };
 
 static struct inode_operations devfs_symlink_iops = {
-	.readlink = devfs_readlink,
+	.readlink = generic_readlink,
 	.follow_link = devfs_follow_link,
 	.setattr = devfs_notify_change,
 };
--- diff/fs/exec.c	2004-06-11 19:17:32.000000000 +0100
+++ source/fs/exec.c	2004-06-11 19:22:05.000000000 +0100
@@ -48,7 +48,6 @@
 #include <linux/rmap.h>
 
 #include <asm/uaccess.h>
-#include <asm/pgalloc.h>
 #include <asm/mmu_context.h>
 
 #ifdef CONFIG_KMOD
@@ -839,7 +838,8 @@
 	flush_thread();
 
 	if (bprm->e_uid != current->euid || bprm->e_gid != current->egid || 
-	    permission(bprm->file->f_dentry->d_inode,MAY_READ, NULL))
+	    permission(bprm->file->f_dentry->d_inode,MAY_READ, NULL) ||
+	    (bprm->interp_flags & BINPRM_FLAGS_ENFORCE_NONDUMP))
 		current->mm->dumpable = 0;
 
 	/* An exec changes our domain. We are no longer part of the thread
@@ -1088,6 +1088,7 @@
 	bprm.file = file;
 	bprm.filename = filename;
 	bprm.interp = filename;
+	bprm.interp_flags = 0;
 	bprm.sh_bang = 0;
 	bprm.loader = 0;
 	bprm.exec = 0;
--- diff/fs/ext2/symlink.c	2004-05-19 22:12:26.000000000 +0100
+++ source/fs/ext2/symlink.c	2004-06-11 19:22:05.000000000 +0100
@@ -20,22 +20,17 @@
 #include "ext2.h"
 #include "xattr.h"
 
-static int
-ext2_readlink(struct dentry *dentry, char __user *buffer, int buflen)
-{
-	struct ext2_inode_info *ei = EXT2_I(dentry->d_inode);
-	return vfs_readlink(dentry, buffer, buflen, (char *)ei->i_data);
-}
-
 static int ext2_follow_link(struct dentry *dentry, struct nameidata *nd)
 {
 	struct ext2_inode_info *ei = EXT2_I(dentry->d_inode);
-	return vfs_follow_link(nd, (char *)ei->i_data);
+	nd_set_link(nd, (char *)ei->i_data);
+	return 0;
 }
 
 struct inode_operations ext2_symlink_inode_operations = {
-	.readlink	= page_readlink,
-	.follow_link	= page_follow_link,
+	.readlink	= generic_readlink,
+	.follow_link	= page_follow_link_light,
+	.put_link	= page_put_link,
 	.setxattr	= ext2_setxattr,
 	.getxattr	= ext2_getxattr,
 	.listxattr	= ext2_listxattr,
@@ -43,7 +38,7 @@
 };
  
 struct inode_operations ext2_fast_symlink_inode_operations = {
-	.readlink	= ext2_readlink,
+	.readlink	= generic_readlink,
 	.follow_link	= ext2_follow_link,
 	.setxattr	= ext2_setxattr,
 	.getxattr	= ext2_getxattr,
--- diff/fs/ext3/acl.c	2004-05-19 22:12:26.000000000 +0100
+++ source/fs/ext3/acl.c	2004-06-11 19:22:05.000000000 +0100
@@ -428,7 +428,9 @@
 	error = posix_acl_chmod_masq(clone, inode->i_mode);
 	if (!error) {
 		handle_t *handle;
+		int retries = 0;
 
+	retry:
 		handle = ext3_journal_start(inode, EXT3_DATA_TRANS_BLOCKS);
 		if (IS_ERR(handle)) {
 			error = PTR_ERR(handle);
@@ -437,6 +439,9 @@
 		}
 		error = ext3_set_acl(handle, inode, ACL_TYPE_ACCESS, clone);
 		ext3_journal_stop(handle);
+		if (error == -ENOSPC &&
+		    ext3_should_retry_alloc(inode->i_sb, &retries))
+			goto retry;
 	}
 out:
 	posix_acl_release(clone);
@@ -516,7 +521,7 @@
 {
 	handle_t *handle;
 	struct posix_acl *acl;
-	int error;
+	int error, retries = 0;
 
 	if (!test_opt(inode->i_sb, POSIX_ACL))
 		return -EOPNOTSUPP;
@@ -535,11 +540,14 @@
 	} else
 		acl = NULL;
 
+retry:
 	handle = ext3_journal_start(inode, EXT3_DATA_TRANS_BLOCKS);
 	if (IS_ERR(handle))
 		return PTR_ERR(handle);
 	error = ext3_set_acl(handle, inode, type, acl);
 	ext3_journal_stop(handle);
+	if (error == -ENOSPC && ext3_should_retry_alloc(inode->i_sb, &retries))
+		goto retry;
 
 release_and_out:
 	posix_acl_release(acl);
--- diff/fs/ext3/balloc.c	2004-05-19 22:12:26.000000000 +0100
+++ source/fs/ext3/balloc.c	2004-06-11 19:22:05.000000000 +0100
@@ -96,9 +96,87 @@
 error_out:
 	return bh;
 }
+/*
+ * The reservation window structure operations
+ * --------------------------------------------
+ * Operations include:
+ * dump, find, add, remove, is_empty, find_next_reservable_window, etc.
+ *
+ * We use sorted double linked list for the per-filesystem reservation
+ * window list. (like in vm_region).
+ *
+ * Initially, we keep those small operations in the abstract functions,
+ * so later if we need a better searching tree than double linked-list,
+ * we could easily switch to that without changing too much
+ * code.
+ */
+static inline void rsv_window_dump(struct reserve_window *head, char *fn)
+{
+	struct reserve_window *rsv;
+
+	printk("Block Allocation Reservation Windows Map (%s):\n", fn);
+	list_for_each_entry(rsv, &head->rsv_list, rsv_list) {
+		printk("reservation window 0x%p start:  %d, end:  %d\n",
+			 rsv, rsv->rsv_start, rsv->rsv_end);
+	}
+}
+
+static int
+goal_in_my_reservation(struct reserve_window *rsv, int goal,
+			unsigned int group, struct super_block * sb)
+{
+	unsigned long group_first_block, group_last_block;
+
+	group_first_block = le32_to_cpu(EXT3_SB(sb)->s_es->s_first_data_block) +
+				group * EXT3_BLOCKS_PER_GROUP(sb);
+	group_last_block = group_first_block + EXT3_BLOCKS_PER_GROUP(sb) - 1;
+
+	if ((rsv->rsv_start > group_last_block) ||
+	    (rsv->rsv_end < group_first_block))
+		return 0;
+	if ((goal >= 0) && ((goal + group_first_block < rsv->rsv_start)
+		|| (goal + group_first_block > rsv->rsv_end)))
+		return 0;
+	return 1;
+}
+
+static inline void rsv_window_add(struct reserve_window *rsv,
+					struct reserve_window *prev)
+{
+	/* insert the new reservation window after the head */
+	list_add(&rsv->rsv_list, &prev->rsv_list);
+}
+
+static inline void rsv_window_remove(struct reserve_window *rsv)
+{
+	rsv->rsv_start = 0;
+	rsv->rsv_end = 0;
+		rsv->rsv_alloc_hit = 0;
+	list_del(&rsv->rsv_list);
+	INIT_LIST_HEAD(&rsv->rsv_list);
+}
+
+static inline int rsv_is_empty(struct reserve_window *rsv)
+{
+	/* a valid reservation end block could not be 0 */
+	return (rsv->rsv_end == 0);
+}
+
+void ext3_discard_reservation(struct inode *inode)
+{
+	struct ext3_inode_info *ei = EXT3_I(inode);
+	struct reserve_window *rsv = &ei->i_rsv_window;
+	spinlock_t *rsv_lock = &EXT3_SB(inode->i_sb)->s_rsv_window_lock;
+
+	if (!rsv_is_empty(rsv)) {
+		spin_lock(rsv_lock);
+		rsv_window_remove(rsv);
+		spin_unlock(rsv_lock);
+	}
+}
 
 /* Free given blocks, update quota and i_blocks field */
-void ext3_free_blocks (handle_t *handle, struct inode * inode,
+void ext3_free_blocks(handle_t *handle, struct inode *inode,
 			unsigned long block, unsigned long count)
 {
 	struct buffer_head *bitmap_bh = NULL;
@@ -296,7 +374,7 @@
  * data-writes at some point, and disable it for metadata allocations or
  * sync-data inodes.
  */
-static inline int ext3_test_allocatable(int nr, struct buffer_head *bh)
+static int ext3_test_allocatable(int nr, struct buffer_head *bh)
 {
 	int ret;
 	struct journal_head *jh = bh2jh(bh);
@@ -313,6 +391,33 @@
 	return ret;
 }
 
+static int
+bitmap_search_next_usable_block(int start, struct buffer_head *bh,
+					int maxblocks)
+{
+	int next;
+	struct journal_head *jh = bh2jh(bh);
+
+	/*
+	 * The bitmap search --- search forward alternately through the actual
+	 * bitmap and the last-committed copy until we find a bit free in
+	 * both
+	 */
+	while (start < maxblocks) {
+		next = ext3_find_next_zero_bit(bh->b_data, maxblocks, start);
+		if (next >= maxblocks)
+			return -1;
+		if (ext3_test_allocatable(next, bh))
+			return next;
+		jbd_lock_bh_state(bh);
+		if (jh->b_committed_data)
+			start = ext3_find_next_zero_bit(jh->b_committed_data,
+						 	maxblocks, next);
+		jbd_unlock_bh_state(bh);
+	}
+	return -1;
+}
+
 /*
  * Find an allocatable block in a bitmap.  We honour both the bitmap and
  * its last-committed copy (if that exists), and perform the "most
@@ -325,7 +430,6 @@
 {
 	int here, next;
 	char *p, *r;
-	struct journal_head *jh = bh2jh(bh);
 
 	if (start > 0) {
 		/*
@@ -337,6 +441,8 @@
 		 * next 64-bit boundary is simple..
 		 */
 		int end_goal = (start + 63) & ~63;
+		if (end_goal > maxblocks)
+			end_goal = maxblocks;
 		here = ext3_find_next_zero_bit(bh->b_data, end_goal, start);
 		if (here < end_goal && ext3_test_allocatable(here, bh))
 			return here;
@@ -351,7 +457,7 @@
 	r = memscan(p, 0, (maxblocks - here + 7) >> 3);
 	next = (r - ((char *)bh->b_data)) << 3;
 
-	if (next < maxblocks && ext3_test_allocatable(next, bh))
+	if (next < maxblocks && next >= start && ext3_test_allocatable(next, bh))
 		return next;
 
 	/*
@@ -359,19 +465,8 @@
 	 * bitmap and the last-committed copy until we find a bit free in
 	 * both
 	 */
-	while (here < maxblocks) {
-		next = ext3_find_next_zero_bit(bh->b_data, maxblocks, here);
-		if (next >= maxblocks)
-			return -1;
-		if (ext3_test_allocatable(next, bh))
-			return next;
-		jbd_lock_bh_state(bh);
-		if (jh->b_committed_data)
-			here = ext3_find_next_zero_bit(jh->b_committed_data,
-						 	maxblocks, next);
-		jbd_unlock_bh_state(bh);
-	}
-	return -1;
+	here = bitmap_search_next_usable_block(here, bh, maxblocks);
+	return here;
 }
 
 /*
@@ -407,62 +502,494 @@
  */
 static int
 ext3_try_to_allocate(struct super_block *sb, handle_t *handle, int group,
-		struct buffer_head *bitmap_bh, int goal, int *errp)
+	struct buffer_head *bitmap_bh, int goal, struct reserve_window *my_rsv)
 {
-	int i;
-	int fatal;
-	int credits = 0;
+	int group_first_block, start, end;
 
-	*errp = 0;
-
-	/*
-	 * Make sure we use undo access for the bitmap, because it is critical
-	 * that we do the frozen_data COW on bitmap buffers in all cases even
-	 * if the buffer is in BJ_Forget state in the committing transaction.
-	 */
-	BUFFER_TRACE(bitmap_bh, "get undo access for new block");
-	fatal = ext3_journal_get_undo_access(handle, bitmap_bh, &credits);
-	if (fatal) {
-		*errp = fatal;
-		goto fail;
+	/* we do allocation within the reservation window if we have a window */
+	if (my_rsv) {
+		group_first_block =
+			le32_to_cpu(EXT3_SB(sb)->s_es->s_first_data_block) +
+			group * EXT3_BLOCKS_PER_GROUP(sb);
+		if (my_rsv->rsv_start >= group_first_block)
+			start = my_rsv->rsv_start - group_first_block;
+		else
+			/* reservation window cross group boundary */
+			start = 0;
+		end = my_rsv->rsv_end - group_first_block + 1;
+		if (end > EXT3_BLOCKS_PER_GROUP(sb))
+			/* reservation window crosses group boundary */
+			end = EXT3_BLOCKS_PER_GROUP(sb);
+		if ((start <= goal) && (goal < end))
+			start = goal;
+		else
+			goal = -1;
+	} else {
+		if (goal > 0)
+			start = goal;
+		else
+			start = 0;
+		end = EXT3_BLOCKS_PER_GROUP(sb);
 	}
 
+	BUG_ON(start > EXT3_BLOCKS_PER_GROUP(sb));
+
 repeat:
 	if (goal < 0 || !ext3_test_allocatable(goal, bitmap_bh)) {
-		goal = find_next_usable_block(goal, bitmap_bh,
-					EXT3_BLOCKS_PER_GROUP(sb));
+		goal = find_next_usable_block(start, bitmap_bh, end);
 		if (goal < 0)
 			goto fail_access;
+		if (!my_rsv) {
+			int i;
 
-		for (i = 0; i < 7 && goal > 0 &&
-				ext3_test_allocatable(goal - 1, bitmap_bh);
-			i++, goal--);
+			for (i = 0; i < 7 && goal > start &&
+					ext3_test_allocatable(goal - 1,
+								bitmap_bh);
+					i++, goal--)
+				;
+		}
 	}
+	start = goal;
 
 	if (!claim_block(sb_bgl_lock(EXT3_SB(sb), group), goal, bitmap_bh)) {
 		/*
 		 * The block was allocated by another thread, or it was
 		 * allocated and then freed by another thread
 		 */
+		start++;
 		goal++;
-		if (goal >= EXT3_BLOCKS_PER_GROUP(sb))
+		if (start >= end)
 			goto fail_access;
 		goto repeat;
 	}
+	if (my_rsv)
+		my_rsv->rsv_alloc_hit++;
+	return goal;
+fail_access:
+	return -1;
+}
+
+/**
+ * 	find_next_reservable_window():
+ *		find a reservable space within the given range
+ *		It does not allocate the reservation window for now
+ *		alloc_new_reservation() will do the work later.
+ *
+ * 	@search_head: the head of the searching list;
+ *		This is not necessary the list head of the whole filesystem
+ *
+ *		we have both head and start_block to assist the search
+ *		for the reservable space. The list start from head,
+ *		but we will shift to the place where start_block is,
+ *		then start from there, we looking for a resevable space.
+ *
+ *	@fs_rsv_head: per-filesystem reervation list head.
+ *
+ * 	@size: the target new reservation window size
+ * 	@group_first_block: the first block we consider to start
+ *			the real search from
+ *
+ * 	@last_block:
+ *		the maxium block number that our goal reservable space
+ *		could start from. This is normally the last block in this
+ *		group. The search will end when we found the start of next
+ *		possiblereservable space is out of this boundary.
+ *		This could handle the cross bounday reservation window request.
+ *
+ * 	basically we search from the given range, rather than the whole
+ * 	reservation double linked list, (start_block, last_block)
+ * 	to find a free region that of of my size and has not
+ * 	been reserved.
+ *
+ *	on succeed, it returns the reservation window to be append to.
+ *	failed, return NULL.
+ */
+static inline
+struct reserve_window *find_next_reservable_window(
+				struct reserve_window *search_head,
+				struct reserve_window *fs_rsv_head,
+				unsigned long size, int *start_block,
+				int last_block)
+{
+	struct reserve_window *rsv;
+	int cur;
+
+	/* TODO:make the start of the reservation window byte alligned */
+	/*cur = *start_block & 8;*/
+	cur = *start_block;
+	rsv = list_entry(search_head->rsv_list.next,
+				struct reserve_window, rsv_list);
+	while (rsv != fs_rsv_head) {
+		if (cur + size <= rsv->rsv_start) {
+	 		/*
+			 * Found a reserveable space big enough.  We could
+			 * have a reservation across the group boundary here
+		 	 */
+			break;
+		}
+		if (cur <= rsv->rsv_end)
+			cur = rsv->rsv_end + 1;
+
+		/* TODO?
+		 * in the case we could not find a reservable space
+		 * that is what is expected, during the re-search, we could
+		 * remember what's the largest reservable space we could have
+		 * and return that one.
+		 *
+		 * For now it will fail if we could not find the reservable
+		 * space with expected-size (or more)...
+		 */
+		rsv = list_entry(rsv->rsv_list.next,
+				struct reserve_window, rsv_list);
+		if (cur > last_block)
+			return NULL;		/* fail */
+	}
+	/*
+	 * we come here either :
+	 * when we rearch to the end of the whole list,
+	 * and there is empty reservable space after last entry in the list.
+	 * append it to the end of the list.
+	 *
+	 * or we found one reservable space in the middle of the list,
+	 * return the reservation window that we could append to.
+	 * succeed.
+	 */
+	*start_block = cur;
+	return list_entry(rsv->rsv_list.prev, struct reserve_window, rsv_list);
+}
+
+/**
+ * 	alloc_new_reservation()--allocate a new reservation window
+ *		if there is an existing reservation, discard it first
+ *		then allocate the new one from there
+ *		otherwise allocate the new reservation from the given
+ *		start block, or the beginning of the group, if a goal
+ *		is not given.
+ *
+ *		To make a new reservation, we search part of the filesystem
+ *		reservation list(the list that inside the group).
+ *
+ *		If we have a old reservation, the search goal is the end of
+ *		last reservation. If we do not have a old reservatio, then we
+ *		start from a given goal, or the first block of the group, if
+ *		the goal is not given.
+ *
+ *		We first find a reservable space after the goal, then from
+ *		there,we check the bitmap for the first free block after
+ *		it. If there is no free block until the end of group, then the
+ *		whole group is full, we failed. Otherwise, check if the free
+ *		block is inside the expected reservable space, if so, we
+ *		succeed.
+ *		If the first free block is outside the reseravle space, then
+ *		start from the first free block, we search for next avalibale
+ *		space, and go on.
+ *
+ *	on succeed, a new reservation will be found and inserted into the list
+ *	It contains at least one free block, and it is not overlap with other
+ *	reservation window.
+ *
+ *	failed: we failed to found a reservation window in this group
+ *
+ *	@rsv: the reservation
+ *
+ *	@goal: The goal.  It is where the search for a
+ *		free reservable space should start from.
+ *		if we have a old reservation, start_block is the end of
+ *		old reservation. Otherwise,
+ *		if we have a goal(goal >0 ), then start from there,
+ *		no goal(goal = -1), we start from the first block
+ *		of the group.
+ *
+ *	@sb: the super block
+ *	@group: the group we are trying to do allocate in
+ *	@bitmap_bh: the block group block bitmap
+ */
+static int alloc_new_reservation(struct reserve_window *my_rsv,
+		int goal, struct super_block *sb,
+		unsigned int group, struct buffer_head *bitmap_bh)
+{
+	struct reserve_window *search_head;
+	int group_first_block, group_end_block, start_block;
+	int first_free_block;
+	int reservable_space_start;
+	struct reserve_window *prev_rsv;
+	struct reserve_window *fs_rsv_head = &EXT3_SB(sb)->s_rsv_window_head;
+	unsigned long size;
+
+	group_first_block = le32_to_cpu(EXT3_SB(sb)->s_es->s_first_data_block) +
+				group * EXT3_BLOCKS_PER_GROUP(sb);
+	group_end_block = group_first_block + EXT3_BLOCKS_PER_GROUP(sb) - 1;
+
+	if (goal < 0)
+		start_block = group_first_block;
+	else
+		start_block = goal + group_first_block;
+
+	size = atomic_read(&my_rsv->rsv_goal_size);
+	/* if we have a old reservation, start the search from the old rsv */
+	if (!rsv_is_empty(my_rsv)) {
+		/*
+		 * if the old reservation is cross group boundary
+		 * we will come here when we just failed to allocate from
+		 * the first part of the window. We still have another part
+		 * that belongs to the next group. In this case, there is no
+		 * point to discard our window and try to allocate a new one
+		 * in this group(which will fail). we should
+		 * keep the reservation window, just simply move on.
+		 *
+		 * Maybe we could shift the start block of the reservation
+		 * window to the first block of next group.
+		 */
+
+		if ((my_rsv->rsv_start <= group_end_block) &&
+				(my_rsv->rsv_end > group_end_block))
+			return -1;
+
+		/* remember where we are before we discard the old one */
+		if (my_rsv->rsv_end + 1 > start_block)
+			start_block = my_rsv->rsv_end + 1;
+		search_head = my_rsv;
+		if ((my_rsv->rsv_alloc_hit > (my_rsv->rsv_end - my_rsv->rsv_start + 1) / 2)) {
+			/*
+			 * if we previously allocation hit ration is greater than half
+			 * we double the size of reservation window next time
+			 * otherwise keep the same
+			 */
+			size = size * 2;
+			if (size > EXT3_MAX_RESERVE_BLOCKS)
+				size = EXT3_MAX_RESERVE_BLOCKS;
+			atomic_set(&my_rsv->rsv_goal_size, size);
+		}
+	}
+	else {
+		/*
+		 * we don't have a reservation,
+		 * we set our goal(start_block) and
+		 * the list head for the search
+		 */
+		search_head = fs_rsv_head;
+	}
+
+	/*
+	 * find_next_reservable_window() simply find a reservable window
+	 * inside the given range(start_block, group_end_block).
+	 *
+	 * To make sure the reservation window has a free bit inside it, we
+	 * need to check the bitmap after we found a reservable window.
+	 */
+retry:
+	prev_rsv = find_next_reservable_window(search_head, fs_rsv_head, size,
+						&start_block, group_end_block);
+	if (prev_rsv == NULL)
+		goto failed;
+	reservable_space_start = start_block;
+	/*
+	 * On success, find_next_reservable_window() returns the
+	 * reservation window where there is a reservable space after it.
+	 * Before we reserve this reservable space, we need
+	 * to make sure there is at least a free block inside this region.
+	 *
+	 * searching the first free bit on the block bitmap and copy of
+	 * last committed bitmap alternatively, until we found a allocatable
+	 * block. Search start from the start block of the reservable space
+	 * we just found.
+	 */
+	first_free_block = bitmap_search_next_usable_block(
+			reservable_space_start - group_first_block,
+			bitmap_bh, group_end_block - group_first_block + 1);
 
-	BUFFER_TRACE(bitmap_bh, "journal_dirty_metadata for bitmap block");
-	fatal = ext3_journal_dirty_metadata(handle, bitmap_bh);
+	if (first_free_block < 0) {
+		/*
+		 * no free block left on the bitmap, no point
+		 * to reserve the space. return failed.
+		 */
+		goto failed;
+	}
+	start_block = first_free_block + group_first_block;
+	/*
+	 * check if the first free block is within the
+	 * free space we just found
+	 */
+	if ((start_block >= reservable_space_start) &&
+	  (start_block < reservable_space_start + size))
+		goto found_rsv_window;
+	/*
+	 * if the first free bit we found is out of the reservable space
+	 * this means there is no free block on the reservable space
+	 * we should continue search for next reservable space,
+	 * start from where the free block is,
+	 * we also shift the list head to where we stopped last time
+	 */
+	search_head = prev_rsv;
+	goto retry;
+
+found_rsv_window:
+	/*
+	 * great! the reservable space contains some free blocks.
+	 * if the search returns that we should add the new
+	 * window just next to where the old window, we don't
+ 	 * need to remove the old window first then add it to the
+	 * same place, just update the new start and new end.
+	 */
+	if (my_rsv != prev_rsv)  {
+		if (!rsv_is_empty(my_rsv))
+			rsv_window_remove(my_rsv);
+		rsv_window_add(my_rsv, prev_rsv);
+	}
+	my_rsv->rsv_start = reservable_space_start;
+	my_rsv->rsv_end = my_rsv->rsv_start + size - 1;
+	return 0;		/* succeed */
+failed:
+	return -1;		/* failed */
+}
+
+/*
+ * This is the main function used to allocate a new block and its reservation
+ * window.
+ *
+ * Each time when a new block allocation is need, first try to allocate from
+ * its own reservation.  If it does not have a reservation window, instead of
+ * looking for a free bit on bitmap first, then look up the reservation list to
+ * see if it is inside somebody else's reservation window, we try to allocate a
+ * reservation window for it start from the goal first. Then do the block
+ * allocation within the reservation window.
+ *
+ * This will aviod keep searching the reservation list again and again when
+ * someboday is looking for a free block(without reservation), and there are
+ * lots of free blocks, but they are all being reserved
+ *
+ * We use a sorted double linked list for the per-filesystem reservation list.
+ * The insert, remove and find a free space(non-reserved) operations for the
+ * sorted double linked list should be fast.
+ *
+ */
+static int
+ext3_try_to_allocate_with_rsv(struct super_block *sb, handle_t *handle,
+			unsigned int group, struct buffer_head *bitmap_bh,
+			int goal, struct reserve_window * my_rsv,
+			int *errp)
+{
+	spinlock_t *rsv_lock;
+	unsigned long group_first_block;
+	int ret = 0;
+	int fatal;
+	int credits = 0;
+
+	*errp = 0;
+
+	/*
+	 * Make sure we use undo access for the bitmap, because it is critical
+	 * that we do the frozen_data COW on bitmap buffers in all cases even
+	 * if the buffer is in BJ_Forget state in the committing transaction.
+	 */
+	BUFFER_TRACE(bitmap_bh, "get undo access for new block");
+	fatal = ext3_journal_get_undo_access(handle, bitmap_bh, &credits);
 	if (fatal) {
 		*errp = fatal;
-		goto fail;
+		return -1;
+	}
+
+	/*
+	 * we don't deal with reservation when
+	 * filesystem is mounted without reservation
+	 * or the file is not a regular file
+	 * of last attemp of allocating a block with reservation turn on failed
+	 */
+	if (my_rsv == NULL ) {
+		ret = ext3_try_to_allocate(sb, handle, group, bitmap_bh, goal, NULL);
+		goto out;
+	}
+	rsv_lock = &EXT3_SB(sb)->s_rsv_window_lock;
+	/*
+	 * goal is a group relative block number (if there is a goal)
+	 * 0 < goal < EXT3_BLOCKS_PER_GROUP(sb)
+	 * first block is a filesystem wide block number
+	 * first block is the block number of the first block in this group
+	 */
+	group_first_block = le32_to_cpu(EXT3_SB(sb)->s_es->s_first_data_block) +
+			group * EXT3_BLOCKS_PER_GROUP(sb);
+
+	/*
+	 * Basically we will allocate a new block from inode's reservation
+	 * window.
+	 *
+	 * We need to allocate a new reservation window, if:
+	 * a) inode does not have a reservation window; or
+	 * b) last attemp of allocating a block from existing reservation
+	 *    failed; or
+	 * c) we come here with a goal and with a reservation window
+	 *
+	 * We do not need to allocate a new reservation window if we come here
+	 * at the beginning with a goal and the goal is inside the window, or
+	 * or we don't have a goal but already have a reservation window.
+	 * then we could go to allocate from the reservation window directly.
+	 */
+	while (1) {
+		if (rsv_is_empty(my_rsv) || (ret < 0) ||
+			!goal_in_my_reservation(my_rsv, goal, group, sb)) {
+			spin_lock(rsv_lock);
+			ret = alloc_new_reservation(my_rsv, goal, sb,
+							group, bitmap_bh);
+			spin_unlock(rsv_lock);
+			if (ret < 0)
+				break;			/* failed */
+
+			if (!goal_in_my_reservation(my_rsv, goal, group, sb))
+				goal = -1;
+		}
+		if ((my_rsv->rsv_start >= group_first_block + EXT3_BLOCKS_PER_GROUP(sb))
+			|| (my_rsv->rsv_end < group_first_block))
+			BUG();
+		ret = ext3_try_to_allocate(sb, handle, group, bitmap_bh, goal,
+					my_rsv);
+		if (ret >= 0)
+			break;				/* succeed */
+	}
+out:
+	if (ret >= 0) {
+		BUFFER_TRACE(bitmap_bh, "journal_dirty_metadata for "
+					"bitmap block");
+		fatal = ext3_journal_dirty_metadata(handle, bitmap_bh);
+		if (fatal) {
+			*errp = fatal;
+			return -1;
+		}
+		return ret;
 	}
-	return goal;
 
-fail_access:
 	BUFFER_TRACE(bitmap_bh, "journal_release_buffer");
 	ext3_journal_release_buffer(handle, bitmap_bh, credits);
-fail:
-	return -1;
+	return ret;
+}
+
+static int ext3_has_free_blocks(struct ext3_sb_info *sbi)
+{
+	int free_blocks, root_blocks;
+
+	free_blocks = percpu_counter_read_positive(&sbi->s_freeblocks_counter);
+	root_blocks = le32_to_cpu(sbi->s_es->s_r_blocks_count);
+	if (free_blocks < root_blocks + 1 && !capable(CAP_SYS_RESOURCE) &&
+		sbi->s_resuid != current->fsuid &&
+		(sbi->s_resgid == 0 || !in_group_p (sbi->s_resgid))) {
+		return 0;
+	}
+	return 1;
+}
+
+/*
+ * ext3_should_retry_alloc() is called when ENOSPC is returned, and if
+ * it is profitable to retry the operation, this function will wait
+ * for the current or commiting transaction to complete, and then
+ * return TRUE.
+ */
+int ext3_should_retry_alloc(struct super_block *sb, int *retries)
+{
+	if (!ext3_has_free_blocks(EXT3_SB(sb)) || (*retries)++ > 3)
+		return 0;
+
+	jbd_debug(1, "%s: retrying operation after ENOSPC\n", sb->s_id);
+
+	return journal_force_commit_nested(EXT3_SB(sb)->s_journal);
 }
 
 /*
@@ -473,23 +1000,24 @@
  * bitmap, and then for any free bit if that fails.
  * This function also updates quota and i_blocks field.
  */
-int
-ext3_new_block(handle_t *handle, struct inode *inode, unsigned long goal,
-		u32 *prealloc_count, u32 *prealloc_block, int *errp)
-{
-	struct buffer_head *bitmap_bh = NULL;	/* bh */
-	struct buffer_head *gdp_bh;		/* bh2 */
-	int group_no;				/* i */
-	int ret_block;				/* j */
-	int bgi;				/* blockgroup iteration index */
-	int target_block;			/* tmp */
+int ext3_new_block(handle_t *handle, struct inode *inode,
+			unsigned long goal, int *errp)
+{
+	struct buffer_head *bitmap_bh = NULL;
+	struct buffer_head *gdp_bh;
+	int group_no;
+	int goal_group;
+	int ret_block;
+	int bgi;			/* blockgroup iteration index */
+	int target_block;
 	int fatal = 0, err;
 	int performed_allocation = 0;
-	int free_blocks, root_blocks;
+	int free_blocks;
 	struct super_block *sb;
 	struct ext3_group_desc *gdp;
 	struct ext3_super_block *es;
 	struct ext3_sb_info *sbi;
+	struct reserve_window *my_rsv = NULL;
 #ifdef EXT3FS_DEBUG
 	static int goal_hits, goal_attempts;
 #endif
@@ -511,12 +1039,9 @@
 	sbi = EXT3_SB(sb);
 	es = EXT3_SB(sb)->s_es;
 	ext3_debug("goal=%lu.\n", goal);
-
-	free_blocks = percpu_counter_read_positive(&sbi->s_freeblocks_counter);
-	root_blocks = le32_to_cpu(es->s_r_blocks_count);
-	if (free_blocks < root_blocks + 1 && !capable(CAP_SYS_RESOURCE) &&
-		sbi->s_resuid != current->fsuid &&
-		(sbi->s_resgid == 0 || !in_group_p (sbi->s_resgid))) {
+	if (test_opt(sb, RESERVATION) && S_ISREG(inode->i_mode))
+		my_rsv = &EXT3_I(inode)->i_rsv_window;
+	if (!ext3_has_free_blocks(sbi)) {
 		*errp = -ENOSPC;
 		goto out;
 	}
@@ -533,6 +1058,8 @@
 	if (!gdp)
 		goto io_error;
 
+	goal_group = group_no;
+retry:
 	free_blocks = le16_to_cpu(gdp->bg_free_blocks_count);
 	if (free_blocks > 0) {
 		ret_block = ((goal - le32_to_cpu(es->s_first_data_block)) %
@@ -540,8 +1067,8 @@
 		bitmap_bh = read_block_bitmap(sb, group_no);
 		if (!bitmap_bh)
 			goto io_error;
-		ret_block = ext3_try_to_allocate(sb, handle, group_no,
-					bitmap_bh, ret_block, &fatal);
+		ret_block = ext3_try_to_allocate_with_rsv(sb, handle, group_no,
+					bitmap_bh, ret_block, my_rsv, &fatal);
 		if (fatal)
 			goto out;
 		if (ret_block >= 0)
@@ -569,14 +1096,25 @@
 		bitmap_bh = read_block_bitmap(sb, group_no);
 		if (!bitmap_bh)
 			goto io_error;
-		ret_block = ext3_try_to_allocate(sb, handle, group_no,
-						bitmap_bh, -1, &fatal);
+		ret_block = ext3_try_to_allocate_with_rsv(sb, handle, group_no,
+					bitmap_bh, -1, my_rsv, &fatal);
 		if (fatal)
 			goto out;
 		if (ret_block >= 0) 
 			goto allocated;
 	}
-
+	/*
+	 * We may end up a bogus ealier ENOSPC error due to
+	 * filesystem is "full" of reservations, but
+	 * there maybe indeed free blocks avaliable on disk
+	 * In this case, we just forget about the reservations
+	 * just do block allocation as without reservations.
+	 */
+	if (my_rsv) {
+		my_rsv = NULL;
+		group_no = goal_group;
+		goto retry;
+	}
 	/* No space left on the device */
 	*errp = -ENOSPC;
 	goto out;
--- diff/fs/ext3/file.c	2004-05-19 22:12:26.000000000 +0100
+++ source/fs/ext3/file.c	2004-06-11 19:22:05.000000000 +0100
@@ -33,8 +33,10 @@
  */
 static int ext3_release_file (struct inode * inode, struct file * filp)
 {
-	if (filp->f_mode & FMODE_WRITE)
-		ext3_discard_prealloc (inode);
+	/* if we are the last writer on the inode, drop the block reservation */
+	if ((filp->f_mode & FMODE_WRITE) &&
+			(atomic_read(&inode->i_writecount) == 1))
+		ext3_discard_reservation(inode);
 	if (is_dx(inode) && filp->private_data)
 		ext3_htree_free_dir_info(filp->private_data);
 
--- diff/fs/ext3/ialloc.c	2004-05-19 22:12:26.000000000 +0100
+++ source/fs/ext3/ialloc.c	2004-06-11 19:22:05.000000000 +0100
@@ -581,10 +581,11 @@
 	ei->i_file_acl = 0;
 	ei->i_dir_acl = 0;
 	ei->i_dtime = 0;
-#ifdef EXT3_PREALLOCATE
-	ei->i_prealloc_block = 0;
-	ei->i_prealloc_count = 0;
-#endif
+	ei->i_rsv_window.rsv_start = 0;
+	ei->i_rsv_window.rsv_end = 0;
+	atomic_set(&ei->i_rsv_window.rsv_goal_size, EXT3_DEFAULT_RESERVE_BLOCKS);
+	ei->i_rsv_window.rsv_alloc_hit = 0;
+	INIT_LIST_HEAD(&ei->i_rsv_window.rsv_list);
 	ei->i_block_group = group;
 
 	ext3_set_inode_flags(inode);
--- diff/fs/ext3/inode.c	2004-06-11 19:17:32.000000000 +0100
+++ source/fs/ext3/inode.c	2004-06-11 19:22:05.000000000 +0100
@@ -177,19 +177,6 @@
 }
 
 /*
- * Called at each iput()
- *
- * The inode may be "bad" if ext3_read_inode() saw an error from
- * ext3_get_inode(), so we need to check that to avoid freeing random disk
- * blocks.
- */
-void ext3_put_inode(struct inode *inode)
-{
-	if (!is_bad_inode(inode))
-		ext3_discard_prealloc(inode);
-}
-
-/*
  * Called at the last iput() if i_nlink is zero.
  */
 void ext3_delete_inode (struct inode * inode)
@@ -242,62 +229,12 @@
 	clear_inode(inode);	/* We must guarantee clearing of inode... */
 }
 
-void ext3_discard_prealloc (struct inode * inode)
-{
-#ifdef EXT3_PREALLOCATE
-	struct ext3_inode_info *ei = EXT3_I(inode);
-	/* Writer: ->i_prealloc* */
-	if (ei->i_prealloc_count) {
-		unsigned short total = ei->i_prealloc_count;
-		unsigned long block = ei->i_prealloc_block;
-		ei->i_prealloc_count = 0;
-		ei->i_prealloc_block = 0;
-		/* Writer: end */
-		ext3_free_blocks (inode, block, total);
-	}
-#endif
-}
-
 static int ext3_alloc_block (handle_t *handle,
 			struct inode * inode, unsigned long goal, int *err)
 {
 	unsigned long result;
 
-#ifdef EXT3_PREALLOCATE
-#ifdef EXT3FS_DEBUG
-	static unsigned long alloc_hits, alloc_attempts;
-#endif
-	struct ext3_inode_info *ei = EXT3_I(inode);
-	/* Writer: ->i_prealloc* */
-	if (ei->i_prealloc_count &&
-	    (goal == ei->i_prealloc_block ||
-	     goal + 1 == ei->i_prealloc_block))
-	{
-		result = ei->i_prealloc_block++;
-		ei->i_prealloc_count--;
-		/* Writer: end */
-		ext3_debug ("preallocation hit (%lu/%lu).\n",
-			    ++alloc_hits, ++alloc_attempts);
-	} else {
-		ext3_discard_prealloc (inode);
-		ext3_debug ("preallocation miss (%lu/%lu).\n",
-			    alloc_hits, ++alloc_attempts);
-		if (S_ISREG(inode->i_mode))
-			result = ext3_new_block (inode, goal, 
-				 &ei->i_prealloc_count,
-				 &ei->i_prealloc_block, err);
-		else
-			result = ext3_new_block (inode, goal, 0, 0, err);
-		/*
-		 * AKPM: this is somewhat sticky.  I'm not surprised it was
-		 * disabled in 2.2's ext3.  Need to integrate b_committed_data
-		 * guarding with preallocation, if indeed preallocation is
-		 * effective.
-		 */
-	}
-#else
-	result = ext3_new_block (handle, inode, goal, 0, 0, err);
-#endif
+	result = ext3_new_block (handle, inode, goal, err);
 	return result;
 }
 
@@ -965,38 +902,6 @@
 	bh = ext3_getblk (handle, inode, block, create, err);
 	if (!bh)
 		return bh;
-#ifdef EXT3_PREALLOCATE
-	/*
-	 * If the inode has grown, and this is a directory, then use a few
-	 * more of the preallocated blocks to keep directory fragmentation
-	 * down.  The preallocated blocks are guaranteed to be contiguous.
-	 */
-	if (create &&
-	    S_ISDIR(inode->i_mode) &&
-	    inode->i_blocks > prev_blocks &&
-	    EXT3_HAS_COMPAT_FEATURE(inode->i_sb,
-				    EXT3_FEATURE_COMPAT_DIR_PREALLOC)) {
-		int i;
-		struct buffer_head *tmp_bh;
-
-		for (i = 1;
-		     EXT3_I(inode)->i_prealloc_count &&
-		     i < EXT3_SB(inode->i_sb)->s_es->s_prealloc_dir_blocks;
-		     i++) {
-			/*
-			 * ext3_getblk will zero out the contents of the
-			 * directory for us
-			 */
-			tmp_bh = ext3_getblk(handle, inode,
-						block+i, create, err);
-			if (!tmp_bh) {
-				brelse (bh);
-				return 0;
-			}
-			brelse (tmp_bh);
-		}
-	}
-#endif
 	if (buffer_uptodate(bh))
 		return bh;
 	ll_rw_block (READ, 1, &bh);
@@ -1080,7 +985,7 @@
 	struct inode *inode = page->mapping->host;
 	int ret, needed_blocks = ext3_writepage_trans_blocks(inode);
 	handle_t *handle;
-	int tried_commit = 0;
+	int retries = 0;
 
 retry:
 	handle = ext3_journal_start(inode, needed_blocks);
@@ -1089,19 +994,8 @@
 		goto out;
 	}
 	ret = block_prepare_write(page, from, to, ext3_get_block);
-	if (ret) {
-		if (ret != -ENOSPC || tried_commit)
-			goto prepare_write_failed;
-		/*
-		 * It could be that there _is_ free space, but it's all tied up
-		 * in uncommitted bitmaps.  So force a commit here, which makes
-		 * those blocks allocatable and try again.
-		 */
-		tried_commit = 1;
-		handle->h_sync = 1;
-		ext3_journal_stop(handle);
-		goto retry;
-	}
+	if (ret)
+		goto prepare_write_failed;
 
 	if (ext3_should_journal_data(inode)) {
 		ret = walk_page_buffers(handle, page_buffers(page),
@@ -1110,6 +1004,8 @@
 prepare_write_failed:
 	if (ret)
 		ext3_journal_stop(handle);
+	if (ret == -ENOSPC && ext3_should_retry_alloc(inode->i_sb, &retries))
+		goto retry;
 out:
 	return ret;
 }
@@ -2148,7 +2044,7 @@
 	if (IS_APPEND(inode) || IS_IMMUTABLE(inode))
 		return;
 
-	ext3_discard_prealloc(inode);
+	ext3_discard_reservation(inode);
 
 	/*
 	 * We have to lock the EOF page here, because lock_page() nests
@@ -2541,11 +2437,11 @@
 	}
 	ei->i_disksize = inode->i_size;
 	inode->i_generation = le32_to_cpu(raw_inode->i_generation);
-#ifdef EXT3_PREALLOCATE
-	ei->i_prealloc_count = 0;
-#endif
 	ei->i_block_group = iloc.block_group;
-
+	ei->i_rsv_window.rsv_start = 0;
+	ei->i_rsv_window.rsv_end= 0;
+	atomic_set(&ei->i_rsv_window.rsv_goal_size, EXT3_DEFAULT_RESERVE_BLOCKS);
+	INIT_LIST_HEAD(&ei->i_rsv_window.rsv_list);
 	/*
 	 * NOTE! The in-memory inode i_data array is in little-endian order
 	 * even on big-endian machines: we do NOT byteswap the block numbers!
--- diff/fs/ext3/ioctl.c	2004-06-11 19:17:32.000000000 +0100
+++ source/fs/ext3/ioctl.c	2004-06-11 19:22:05.000000000 +0100
@@ -20,6 +20,7 @@
 {
 	struct ext3_inode_info *ei = EXT3_I(inode);
 	unsigned int flags;
+	unsigned short rsv_window_size;
 
 	ext3_debug ("cmd = %u, arg = %lu\n", cmd, arg);
 
@@ -151,6 +152,29 @@
 			return ret;
 		}
 #endif
+	case EXT3_IOC_GETRSVSZ:
+		if (test_opt(inode->i_sb, RESERVATION) && S_ISREG(inode->i_mode)) {
+			rsv_window_size = atomic_read(&ei->i_rsv_window.rsv_goal_size);
+			return put_user(rsv_window_size, (int *)arg);
+		}
+		return -ENOTTY;
+	case EXT3_IOC_SETRSVSZ:
+		if (!test_opt(inode->i_sb, RESERVATION) ||!S_ISREG(inode->i_mode))
+			return -ENOTTY;
+
+		if (IS_RDONLY(inode))
+			return -EROFS;
+
+		if ((current->fsuid != inode->i_uid) && !capable(CAP_FOWNER))
+			return -EACCES;
+
+		if (get_user(rsv_window_size, (int *)arg))
+			return -EFAULT;
+
+		if (rsv_window_size > EXT3_MAX_RESERVE_BLOCKS)
+			rsv_window_size = EXT3_MAX_RESERVE_BLOCKS;
+		atomic_set(&ei->i_rsv_window.rsv_goal_size, rsv_window_size);
+		return 0;
 	default:
 		return -ENOTTY;
 	}
--- diff/fs/ext3/namei.c	2004-06-11 19:17:32.000000000 +0100
+++ source/fs/ext3/namei.c	2004-06-11 19:22:05.000000000 +0100
@@ -1630,8 +1630,9 @@
 {
 	handle_t *handle; 
 	struct inode * inode;
-	int err;
+	int err, retries = 0;
 
+retry:
 	handle = ext3_journal_start(dir, EXT3_DATA_TRANS_BLOCKS +
 					EXT3_INDEX_EXTRA_TRANS_BLOCKS + 3 +
 					2*EXT3_QUOTA_INIT_BLOCKS);
@@ -1650,6 +1651,8 @@
 		err = ext3_add_nondir(handle, dentry, inode);
 	}
 	ext3_journal_stop(handle);
+	if (err == -ENOSPC && ext3_should_retry_alloc(dir->i_sb, &retries))
+		goto retry;
 	return err;
 }
 
@@ -1658,11 +1661,12 @@
 {
 	handle_t *handle;
 	struct inode *inode;
-	int err;
+	int err, retries = 0;
 
 	if (!new_valid_dev(rdev))
 		return -EINVAL;
 
+retry:
 	handle = ext3_journal_start(dir, EXT3_DATA_TRANS_BLOCKS +
 			 		EXT3_INDEX_EXTRA_TRANS_BLOCKS + 3 +
 					2*EXT3_QUOTA_INIT_BLOCKS);
@@ -1682,6 +1686,8 @@
 		err = ext3_add_nondir(handle, dentry, inode);
 	}
 	ext3_journal_stop(handle);
+	if (err == -ENOSPC && ext3_should_retry_alloc(dir->i_sb, &retries))
+		goto retry;
 	return err;
 }
 
@@ -1691,11 +1697,12 @@
 	struct inode * inode;
 	struct buffer_head * dir_block;
 	struct ext3_dir_entry_2 * de;
-	int err;
+	int err, retries = 0;
 
 	if (dir->i_nlink >= EXT3_LINK_MAX)
 		return -EMLINK;
 
+retry:
 	handle = ext3_journal_start(dir, EXT3_DATA_TRANS_BLOCKS +
 					EXT3_INDEX_EXTRA_TRANS_BLOCKS + 3 +
 					2*EXT3_QUOTA_INIT_BLOCKS);
@@ -1753,6 +1760,8 @@
 	d_instantiate(dentry, inode);
 out_stop:
 	ext3_journal_stop(handle);
+	if (err == -ENOSPC && ext3_should_retry_alloc(dir->i_sb, &retries))
+		goto retry;
 	return err;
 }
 
@@ -2092,12 +2101,13 @@
 {
 	handle_t *handle;
 	struct inode * inode;
-	int l, err;
+	int l, err, retries = 0;
 
 	l = strlen(symname)+1;
 	if (l > dir->i_sb->s_blocksize)
 		return -ENAMETOOLONG;
 
+retry:
 	handle = ext3_journal_start(dir, EXT3_DATA_TRANS_BLOCKS +
 			 		EXT3_INDEX_EXTRA_TRANS_BLOCKS + 5 +
 					2*EXT3_QUOTA_INIT_BLOCKS);
@@ -2136,6 +2146,8 @@
 	err = ext3_add_nondir(handle, dentry, inode);
 out_stop:
 	ext3_journal_stop(handle);
+	if (err == -ENOSPC && ext3_should_retry_alloc(dir->i_sb, &retries))
+		goto retry;
 	return err;
 }
 
@@ -2144,11 +2156,12 @@
 {
 	handle_t *handle;
 	struct inode *inode = old_dentry->d_inode;
-	int err;
+	int err, retries = 0;
 
 	if (inode->i_nlink >= EXT3_LINK_MAX)
 		return -EMLINK;
 
+retry:
 	handle = ext3_journal_start(dir, EXT3_DATA_TRANS_BLOCKS +
 					EXT3_INDEX_EXTRA_TRANS_BLOCKS);
 	if (IS_ERR(handle))
@@ -2163,6 +2176,8 @@
 
 	err = ext3_add_nondir(handle, dentry, inode);
 	ext3_journal_stop(handle);
+	if (err == -ENOSPC && ext3_should_retry_alloc(dir->i_sb, &retries))
+		goto retry;
 	return err;
 }
 
--- diff/fs/ext3/super.c	2004-06-11 19:17:32.000000000 +0100
+++ source/fs/ext3/super.c	2004-06-11 19:22:05.000000000 +0100
@@ -493,10 +493,9 @@
 		printk(KERN_INFO "ext3_inode_cache: not all structures were freed\n");
 }
 
-#ifdef CONFIG_EXT3_FS_POSIX_ACL
-
 static void ext3_clear_inode(struct inode *inode)
 {
+#ifdef CONFIG_EXT3_FS_POSIX_ACL
        if (EXT3_I(inode)->i_acl &&
            EXT3_I(inode)->i_acl != EXT3_ACL_NOT_CACHED) {
                posix_acl_release(EXT3_I(inode)->i_acl);
@@ -507,11 +506,10 @@
                posix_acl_release(EXT3_I(inode)->i_default_acl);
                EXT3_I(inode)->i_default_acl = EXT3_ACL_NOT_CACHED;
        }
-}
-
-#else
-# define ext3_clear_inode NULL
 #endif
+	if (!is_bad_inode(inode))
+		ext3_discard_reservation(inode);
+}
 
 #ifdef CONFIG_QUOTA
 
@@ -561,7 +559,6 @@
 	.read_inode	= ext3_read_inode,
 	.write_inode	= ext3_write_inode,
 	.dirty_inode	= ext3_dirty_inode,
-	.put_inode	= ext3_put_inode,
 	.delete_inode	= ext3_delete_inode,
 	.put_super	= ext3_put_super,
 	.write_super	= ext3_write_super,
@@ -582,12 +579,13 @@
 	Opt_bsd_df, Opt_minix_df, Opt_grpid, Opt_nogrpid,
 	Opt_resgid, Opt_resuid, Opt_sb, Opt_err_cont, Opt_err_panic, Opt_err_ro,
 	Opt_nouid32, Opt_check, Opt_nocheck, Opt_debug, Opt_oldalloc, Opt_orlov,
-	Opt_user_xattr, Opt_nouser_xattr, Opt_acl, Opt_noacl, Opt_noload,
+	Opt_user_xattr, Opt_nouser_xattr, Opt_acl, Opt_noacl,
+	Opt_reservation, Opt_noreservation, Opt_noload,
 	Opt_commit, Opt_journal_update, Opt_journal_inum,
 	Opt_abort, Opt_data_journal, Opt_data_ordered, Opt_data_writeback,
 	Opt_usrjquota, Opt_grpjquota, Opt_offusrjquota, Opt_offgrpjquota,
 	Opt_jqfmt_vfsold, Opt_jqfmt_vfsv0,
-	Opt_ignore, Opt_err,
+	Opt_ignore, Opt_barrier, Opt_err,
 };
 
 static match_table_t tokens = {
@@ -614,6 +612,8 @@
 	{Opt_nouser_xattr, "nouser_xattr"},
 	{Opt_acl, "acl"},
 	{Opt_noacl, "noacl"},
+	{Opt_reservation, "reservation"},
+	{Opt_noreservation, "noreservation"},
 	{Opt_noload, "noload"},
 	{Opt_commit, "commit=%u"},
 	{Opt_journal_update, "journal=update"},
@@ -632,6 +632,7 @@
 	{Opt_ignore, "noquota"},
 	{Opt_ignore, "quota"},
 	{Opt_ignore, "usrquota"},
+	{Opt_barrier, "barrier=%u"},
 	{Opt_err, NULL}
 };
 
@@ -767,6 +768,12 @@
 			printk("EXT3 (no)acl options not supported\n");
 			break;
 #endif
+		case Opt_reservation:
+			set_opt(sbi->s_mount_opt, RESERVATION);
+			break;
+		case Opt_noreservation:
+			clear_opt(sbi->s_mount_opt, RESERVATION);
+			break;
 		case Opt_journal_update:
 			/* @@@ FIXME */
 			/* Eventually we will want to be able to create
@@ -897,6 +904,14 @@
 		case Opt_abort:
 			set_opt(sbi->s_mount_opt, ABORT);
 			break;
+		case Opt_barrier:
+			if (match_int(&args[0], &option))
+				return 0;
+			if (option)
+				set_opt(sbi->s_mount_opt, BARRIER);
+			else
+				clear_opt(sbi->s_mount_opt, BARRIER);
+			break;
 		case Opt_ignore:
 			break;
 		default:
@@ -1288,6 +1303,8 @@
 	sbi->s_resuid = le16_to_cpu(es->s_def_resuid);
 	sbi->s_resgid = le16_to_cpu(es->s_def_resgid);
 
+	set_opt(sbi->s_mount_opt, RESERVATION);
+
 	if (!parse_options ((char *) data, sb, &journal_inum, 0))
 		goto failed_mount;
 
@@ -1462,6 +1479,14 @@
 	sbi->s_gdb_count = db_count;
 	get_random_bytes(&sbi->s_next_generation, sizeof(u32));
 	spin_lock_init(&sbi->s_next_gen_lock);
+	/* per fileystem reservation list head & lock */
+	spin_lock_init(&sbi->s_rsv_window_lock);
+	INIT_LIST_HEAD(&sbi->s_rsv_window_head.rsv_list);
+	sbi->s_rsv_window_head.rsv_start = 0;
+	sbi->s_rsv_window_head.rsv_end = 0;
+	sbi->s_rsv_window_head.rsv_alloc_hit = 0;
+	atomic_set(&sbi->s_rsv_window_head.rsv_goal_size, 0);
+
 	/*
 	 * set up enough so that it can read an inode
 	 */
@@ -1599,16 +1624,23 @@
  * initial mount, once the journal has been initialised but before we've
  * done any recovery; and again on any subsequent remount. 
  */
-static void ext3_init_journal_params(struct ext3_sb_info *sbi, 
-				     journal_t *journal)
+static void ext3_init_journal_params(struct super_block *sb, journal_t *journal)
 {
+	struct ext3_sb_info *sbi = EXT3_SB(sb);
+
 	if (sbi->s_commit_interval)
 		journal->j_commit_interval = sbi->s_commit_interval;
 	/* We could also set up an ext3-specific default for the commit
 	 * interval here, but for now we'll just fall back to the jbd
 	 * default. */
-}
 
+	spin_lock(&journal->j_state_lock);
+	if (test_opt(sb, BARRIER))
+		journal->j_flags |= JFS_BARRIER;
+	else
+		journal->j_flags &= ~JFS_BARRIER;
+	spin_unlock(&journal->j_state_lock);
+}
 
 static journal_t *ext3_get_journal(struct super_block *sb, int journal_inum)
 {
@@ -1646,7 +1678,7 @@
 		return NULL;
 	}
 	journal->j_private = sb;
-	ext3_init_journal_params(EXT3_SB(sb), journal);
+	ext3_init_journal_params(sb, journal);
 	return journal;
 }
 
@@ -1731,7 +1763,7 @@
 		goto out_journal;
 	}
 	EXT3_SB(sb)->journal_bdev = bdev;
-	ext3_init_journal_params(EXT3_SB(sb), journal);
+	ext3_init_journal_params(sb, journal);
 	return journal;
 out_journal:
 	journal_destroy(journal);
@@ -1875,13 +1907,17 @@
 static void ext3_mark_recovery_complete(struct super_block * sb,
 					struct ext3_super_block * es)
 {
-	journal_flush(EXT3_SB(sb)->s_journal);
+	journal_t *journal = EXT3_SB(sb)->s_journal;
+
+	journal_lock_updates(journal);
+	journal_flush(journal);
 	if (EXT3_HAS_INCOMPAT_FEATURE(sb, EXT3_FEATURE_INCOMPAT_RECOVER) &&
 	    sb->s_flags & MS_RDONLY) {
 		EXT3_CLEAR_INCOMPAT_FEATURE(sb, EXT3_FEATURE_INCOMPAT_RECOVER);
 		sb->s_dirt = 0;
 		ext3_commit_super(sb, es, 1);
 	}
+	journal_unlock_updates(journal);
 }
 
 /*
@@ -2024,7 +2060,7 @@
 
 	es = sbi->s_es;
 
-	ext3_init_journal_params(sbi, sbi->s_journal);
+	ext3_init_journal_params(sb, sbi->s_journal);
 
 	if ((*flags & MS_RDONLY) != (sb->s_flags & MS_RDONLY)) {
 		if (sbi->s_mount_opt & EXT3_MOUNT_ABORT)
--- diff/fs/ext3/symlink.c	2004-05-19 22:12:26.000000000 +0100
+++ source/fs/ext3/symlink.c	2004-06-11 19:22:05.000000000 +0100
@@ -22,22 +22,17 @@
 #include <linux/ext3_fs.h>
 #include "xattr.h"
 
-static int
-ext3_readlink(struct dentry *dentry, char __user *buffer, int buflen)
-{
-	struct ext3_inode_info *ei = EXT3_I(dentry->d_inode);
-	return vfs_readlink(dentry, buffer, buflen, (char*)ei->i_data);
-}
-
 static int ext3_follow_link(struct dentry *dentry, struct nameidata *nd)
 {
 	struct ext3_inode_info *ei = EXT3_I(dentry->d_inode);
-	return vfs_follow_link(nd, (char*)ei->i_data);
+	nd_set_link(nd, (char*)ei->i_data);
+	return 0;
 }
 
 struct inode_operations ext3_symlink_inode_operations = {
-	.readlink	= page_readlink,
-	.follow_link	= page_follow_link,
+	.readlink	= generic_readlink,
+	.follow_link	= page_follow_link_light,
+	.put_link	= page_put_link,
 	.setxattr	= ext3_setxattr,
 	.getxattr	= ext3_getxattr,
 	.listxattr	= ext3_listxattr,
@@ -45,8 +40,8 @@
 };
 
 struct inode_operations ext3_fast_symlink_inode_operations = {
-	.readlink	= ext3_readlink,	/* BKL not held.  Don't need */
-	.follow_link	= ext3_follow_link,	/* BKL not held.  Don't need */
+	.readlink	= generic_readlink,
+	.follow_link	= ext3_follow_link,
 	.setxattr	= ext3_setxattr,
 	.getxattr	= ext3_getxattr,
 	.listxattr	= ext3_listxattr,
--- diff/fs/ext3/xattr.c	2004-05-19 22:12:26.000000000 +0100
+++ source/fs/ext3/xattr.c	2004-06-11 19:22:05.000000000 +0100
@@ -787,7 +787,7 @@
 				EXT3_I(inode)->i_block_group *
 				EXT3_BLOCKS_PER_GROUP(sb);
 			int block = ext3_new_block(handle,
-				inode, goal, 0, 0, &error);
+				inode, goal, &error);
 			if (error)
 				goto cleanup;
 			ea_idebug(inode, "creating block %d", block);
@@ -875,8 +875,9 @@
 	       const void *value, size_t value_len, int flags)
 {
 	handle_t *handle;
-	int error;
+	int error, retries = 0;
 
+retry:
 	handle = ext3_journal_start(inode, EXT3_DATA_TRANS_BLOCKS);
 	if (IS_ERR(handle)) {
 		error = PTR_ERR(handle);
@@ -886,6 +887,9 @@
 		error = ext3_xattr_set_handle(handle, inode, name_index, name,
 					      value, value_len, flags);
 		error2 = ext3_journal_stop(handle);
+		if (error == -ENOSPC &&
+		    ext3_should_retry_alloc(inode->i_sb, &retries))
+			goto retry;
 		if (error == 0)
 			error = error2;
 	}
--- diff/fs/freevxfs/vxfs_immed.c	2004-05-19 22:12:26.000000000 +0100
+++ source/fs/freevxfs/vxfs_immed.c	2004-06-11 19:22:05.000000000 +0100
@@ -37,7 +37,6 @@
 #include "vxfs_inode.h"
 
 
-static int	vxfs_immed_readlink(struct dentry *, char __user *, int);
 static int	vxfs_immed_follow_link(struct dentry *, struct nameidata *);
 
 static int	vxfs_immed_readpage(struct file *, struct page *);
@@ -49,7 +48,7 @@
  * but do all work directly on the inode.
  */
 struct inode_operations vxfs_immed_symlink_iops = {
-	.readlink =		vxfs_immed_readlink,
+	.readlink =		generic_readlink,
 	.follow_link =		vxfs_immed_follow_link,
 };
 
@@ -60,28 +59,6 @@
 	.readpage =		vxfs_immed_readpage,
 };
 
-
-/**
- * vxfs_immed_readlink - read immed symlink
- * @dp:		dentry for the link
- * @bp:		output buffer
- * @buflen:	length of @bp
- *
- * Description:
- *   vxfs_immed_readlink calls vfs_readlink to read the link
- *   described by @dp into userspace.
- *
- * Returns:
- *   Number of bytes successfully copied to userspace.
- */
-static int
-vxfs_immed_readlink(struct dentry *dp, char __user *bp, int buflen)
-{
-	struct vxfs_inode_info		*vip = VXFS_INO(dp->d_inode);
-
-	return (vfs_readlink(dp, bp, buflen, vip->vii_immed.vi_immed));
-}
-
 /**
  * vxfs_immed_follow_link - follow immed symlink
  * @dp:		dentry for the link
@@ -98,8 +75,8 @@
 vxfs_immed_follow_link(struct dentry *dp, struct nameidata *np)
 {
 	struct vxfs_inode_info		*vip = VXFS_INO(dp->d_inode);
-
-	return (vfs_follow_link(np, vip->vii_immed.vi_immed));
+	nd_set_link(np, vip->vii_immed.vi_immed);
+	return 0;
 }
 
 /**
--- diff/fs/fs-writeback.c	2004-06-11 19:17:32.000000000 +0100
+++ source/fs/fs-writeback.c	2004-06-11 19:22:05.000000000 +0100
@@ -396,9 +396,19 @@
 	sb = sb_entry(super_blocks.prev);
 	for (; sb != sb_entry(&super_blocks); sb = sb_entry(sb->s_list.prev)) {
 		if (!list_empty(&sb->s_dirty) || !list_empty(&sb->s_io)) {
+			/* we're making our own get_super here */
 			sb->s_count++;
 			spin_unlock(&sb_lock);
-			sync_sb_inodes(sb, wbc);
+			/*
+			 * If we can't get the readlock, there's no sense in
+			 * waiting around, most of the time the FS is going to
+			 * be unmounted by the time it is released.
+			 */
+			if (down_read_trylock(&sb->s_umount)) {
+				if (sb->s_root)
+					sync_sb_inodes(sb, wbc);
+				up_read(&sb->s_umount);
+			}
 			spin_lock(&sb_lock);
 			if (__put_super(sb))
 				goto restart;
@@ -425,10 +435,7 @@
 {
 	struct page_state ps;
 	struct writeback_control wbc = {
-		.bdi		= NULL,
 		.sync_mode	= wait ? WB_SYNC_ALL : WB_SYNC_HOLD,
-		.older_than_this = NULL,
-		.nr_to_write	= 0,
 	};
 
 	get_page_state(&ps);
@@ -439,6 +446,9 @@
 	spin_lock(&inode_lock);
 	sync_sb_inodes(sb, &wbc);
 	spin_unlock(&inode_lock);
+	if (wbc.nr_to_write <= 0)
+		printk(KERN_ERR "%s: not all pages were written!\n",
+				__FUNCTION__);
 }
 
 /*
--- diff/fs/hugetlbfs/inode.c	2004-06-11 19:17:32.000000000 +0100
+++ source/fs/hugetlbfs/inode.c	2004-06-11 19:22:05.000000000 +0100
@@ -196,6 +196,7 @@
 
 	hlist_del_init(&inode->i_hash);
 	list_del_init(&inode->i_list);
+	list_del_init(&inode->i_sb_list);
 	inode->i_state |= I_FREEING;
 	inodes_stat.nr_inodes--;
 	spin_unlock(&inode_lock);
@@ -238,6 +239,7 @@
 	hlist_del_init(&inode->i_hash);
 out_truncate:
 	list_del_init(&inode->i_list);
+	list_del_init(&inode->i_sb_list);
 	inode->i_state |= I_FREEING;
 	inodes_stat.nr_inodes--;
 	spin_unlock(&inode_lock);
@@ -720,8 +722,11 @@
 
 static int can_do_hugetlb_shm(void)
 {
-	return likely(capable(CAP_IPC_LOCK) ||
-			in_group_p(sysctl_hugetlb_shm_group));
+	if (capable(CAP_IPC_LOCK))
+		return 1;
+	if (sysctl_hugetlb_shm_group == 0)
+		return 0;
+	return in_group_p(sysctl_hugetlb_shm_group);
 }
 
 struct file *hugetlb_zero_setup(size_t size)
--- diff/fs/inode.c	2004-06-11 19:17:32.000000000 +0100
+++ source/fs/inode.c	2004-06-11 19:22:05.000000000 +0100
@@ -195,7 +195,7 @@
 	sema_init(&inode->i_sem, 1);
 	init_rwsem(&inode->i_alloc_sem);
 	INIT_RADIX_TREE(&inode->i_data.page_tree, GFP_ATOMIC);
-	spin_lock_init(&inode->i_data.tree_lock);
+	rwlock_init(&inode->i_data.tree_lock);
 	spin_lock_init(&inode->i_data.i_mmap_lock);
 	atomic_set(&inode->i_data.truncate_count, 0);
 	INIT_LIST_HEAD(&inode->i_data.private_list);
@@ -294,7 +294,7 @@
 /*
  * Invalidate all inodes for a device.
  */
-static int invalidate_list(struct list_head *head, struct super_block * sb, struct list_head * dispose)
+static int invalidate_list(struct list_head *head, struct list_head *dispose)
 {
 	struct list_head *next;
 	int busy = 0, count = 0;
@@ -307,12 +307,11 @@
 		next = next->next;
 		if (tmp == head)
 			break;
-		inode = list_entry(tmp, struct inode, i_list);
-		if (inode->i_sb != sb)
-			continue;
+		inode = list_entry(tmp, struct inode, i_sb_list);
 		invalidate_inode_buffers(inode);
 		if (!atomic_read(&inode->i_count)) {
 			hlist_del_init(&inode->i_hash);
+			list_del(&inode->i_sb_list);
 			list_move(&inode->i_list, dispose);
 			inode->i_state |= I_FREEING;
 			count++;
@@ -348,10 +347,7 @@
 
 	down(&iprune_sem);
 	spin_lock(&inode_lock);
-	busy = invalidate_list(&inode_in_use, sb, &throw_away);
-	busy |= invalidate_list(&inode_unused, sb, &throw_away);
-	busy |= invalidate_list(&sb->s_dirty, sb, &throw_away);
-	busy |= invalidate_list(&sb->s_io, sb, &throw_away);
+	busy = invalidate_list(&sb->s_inodes, &throw_away);
 	spin_unlock(&inode_lock);
 
 	dispose_list(&throw_away);
@@ -451,6 +447,7 @@
 				continue;
 		}
 		hlist_del_init(&inode->i_hash);
+		list_del_init(&inode->i_sb_list);
 		list_move(&inode->i_list, &freeable);
 		inode->i_state |= I_FREEING;
 		nr_pruned++;
@@ -561,6 +558,7 @@
 		spin_lock(&inode_lock);
 		inodes_stat.nr_inodes++;
 		list_add(&inode->i_list, &inode_in_use);
+		list_add(&inode->i_sb_list, &sb->s_inodes);
 		inode->i_ino = ++last_ino;
 		inode->i_state = 0;
 		spin_unlock(&inode_lock);
@@ -609,6 +607,7 @@
 
 			inodes_stat.nr_inodes++;
 			list_add(&inode->i_list, &inode_in_use);
+			list_add(&inode->i_sb_list, &sb->s_inodes);
 			hlist_add_head(&inode->i_hash, head);
 			inode->i_state = I_LOCK|I_NEW;
 			spin_unlock(&inode_lock);
@@ -657,6 +656,7 @@
 			inode->i_ino = ino;
 			inodes_stat.nr_inodes++;
 			list_add(&inode->i_list, &inode_in_use);
+			list_add(&inode->i_sb_list, &sb->s_inodes);
 			hlist_add_head(&inode->i_hash, head);
 			inode->i_state = I_LOCK|I_NEW;
 			spin_unlock(&inode_lock);
@@ -993,6 +993,7 @@
 	struct super_operations *op = inode->i_sb->s_op;
 
 	list_del_init(&inode->i_list);
+	list_del_init(&inode->i_sb_list);
 	inode->i_state|=I_FREEING;
 	inodes_stat.nr_inodes--;
 	spin_unlock(&inode_lock);
@@ -1038,6 +1039,7 @@
 		hlist_del_init(&inode->i_hash);
 	}
 	list_del_init(&inode->i_list);
+	list_del_init(&inode->i_sb_list);
 	inode->i_state|=I_FREEING;
 	inodes_stat.nr_inodes--;
 	spin_unlock(&inode_lock);
@@ -1226,36 +1228,23 @@
 /* Function back in dquot.c */
 int remove_inode_dquot_ref(struct inode *, int, struct list_head *);
 
-void remove_dquot_ref(struct super_block *sb, int type, struct list_head *tofree_head)
+void remove_dquot_ref(struct super_block *sb, int type,
+			struct list_head *tofree_head)
 {
 	struct inode *inode;
-	struct list_head *act_head;
 
 	if (!sb->dq_op)
 		return;	/* nothing to do */
 	spin_lock(&inode_lock);	/* This lock is for inodes code */
-	/* We don't have to lock against quota code - test IS_QUOTAINIT is just for speedup... */
- 
-	list_for_each(act_head, &inode_in_use) {
-		inode = list_entry(act_head, struct inode, i_list);
-		if (inode->i_sb == sb && IS_QUOTAINIT(inode))
-			remove_inode_dquot_ref(inode, type, tofree_head);
-	}
-	list_for_each(act_head, &inode_unused) {
-		inode = list_entry(act_head, struct inode, i_list);
-		if (inode->i_sb == sb && IS_QUOTAINIT(inode))
-			remove_inode_dquot_ref(inode, type, tofree_head);
-	}
-	list_for_each(act_head, &sb->s_dirty) {
-		inode = list_entry(act_head, struct inode, i_list);
-		if (IS_QUOTAINIT(inode))
-			remove_inode_dquot_ref(inode, type, tofree_head);
-	}
-	list_for_each(act_head, &sb->s_io) {
-		inode = list_entry(act_head, struct inode, i_list);
+	/*
+	 * We don't have to lock against quota code - test IS_QUOTAINIT is
+	 * just for speedup...
+	 */
+
+	list_for_each_entry(inode, &sb->s_inodes, i_sb_list)
 		if (IS_QUOTAINIT(inode))
 			remove_inode_dquot_ref(inode, type, tofree_head);
-	}
+
 	spin_unlock(&inode_lock);
 }
 
--- diff/fs/isofs/Makefile	2004-05-19 22:12:28.000000000 +0100
+++ source/fs/isofs/Makefile	2004-06-11 19:22:05.000000000 +0100
@@ -4,7 +4,7 @@
 
 obj-$(CONFIG_ISO9660_FS) += isofs.o
 
-isofs-objs-y 			:= namei.o inode.o dir.o util.o rock.o
+isofs-objs-y 			:= namei.o inode.o dir.o util.o rock.o export.o
 isofs-objs-$(CONFIG_JOLIET)	+= joliet.o
 isofs-objs-$(CONFIG_ZISOFS)	+= compress.o
 isofs-objs			:= $(isofs-objs-y)
--- diff/fs/isofs/dir.c	2004-05-19 22:12:28.000000000 +0100
+++ source/fs/isofs/dir.c	2004-06-11 19:22:05.000000000 +0100
@@ -106,8 +106,8 @@
 {
 	unsigned long bufsize = ISOFS_BUFFER_SIZE(inode);
 	unsigned char bufbits = ISOFS_BUFFER_BITS(inode);
-	unsigned int block, offset;
-	int inode_number = 0;	/* Quiet GCC */
+	unsigned long block, offset;
+	unsigned long inode_number = 0;	/* Quiet GCC */
 	struct buffer_head *bh = NULL;
 	int len;
 	int map;
@@ -130,7 +130,7 @@
 
 		de = (struct iso_directory_record *) (bh->b_data + offset);
 		if (first_de)
-			inode_number = (bh->b_blocknr << bufbits) + offset;
+			inode_number = isofs_get_ino(de);
 
 		de_len = *(unsigned char *) de;
 
--- diff/fs/isofs/inode.c	2004-06-11 19:17:32.000000000 +0100
+++ source/fs/isofs/inode.c	2004-06-11 19:22:05.000000000 +0100
@@ -7,6 +7,8 @@
  *      1995  Mark Dobie - allow mounting of some weird VideoCDs and PhotoCDs.
  *	1997  Gordon Chaffee - Joliet CDs
  *	1998  Eric Lammerts - ISO 9660 Level 3
+ *	2004  Paul Serice - Comprehensive Inode Scheme
+ *	2004  Paul Serice - NFS Export Operations
  */
 
 #include <linux/config.h>
@@ -135,20 +137,6 @@
 	.remount_fs	= isofs_remount,
 };
 
-/* the export_operations structure for describing
- * how to export (e.g. via kNFSd) is deliberately
- * empty.
- * This means that the filesystem want to use iget
- * to map an inode number into an inode.
- * The lack of a get_parent operation means that 
- * if something isn't in the cache, then you cannot
- * access it.
- * It should be possible to write a get_parent,
- * but it would be a bit hairy...
- */
-static struct export_operations isofs_export_ops = {
-};
-
 
 static struct dentry_operations isofs_dentry_ops[] = {
 	{
@@ -738,19 +726,14 @@
 	/* Set this for reference. Its not currently used except on write
 	   which we don't have .. */
 	   
-	/* RDE: data zone now byte offset! */
-
-	first_data_zone = ((isonum_733 (rootp->extent) +
-			  isonum_711 (rootp->ext_attr_length))
-			 << sbi->s_log_zone_size);
+	first_data_zone = isonum_733 (rootp->extent) +
+			  isonum_711 (rootp->ext_attr_length);
 	sbi->s_firstdatazone = first_data_zone;
 #ifndef BEQUIET
 	printk(KERN_DEBUG "Max size:%ld   Log zone size:%ld\n",
 	       sbi->s_max_size,
 	       1UL << sbi->s_log_zone_size);
-	printk(KERN_DEBUG "First datazone:%ld   Root inode number:%ld\n",
-	       sbi->s_firstdatazone >> sbi->s_log_zone_size,
-	       sbi->s_firstdatazone);
+	printk(KERN_DEBUG "First datazone:%ld\n", sbi->s_firstdatazone);
 	if(sbi->s_high_sierra)
 		printk(KERN_DEBUG "Disc in High Sierra format.\n");
 #endif
@@ -767,9 +750,8 @@
 		pri = (struct iso_primary_descriptor *) sec;
 		rootp = (struct iso_directory_record *)
 			pri->root_directory_record;
-		first_data_zone = ((isonum_733 (rootp->extent) +
-			  	isonum_711 (rootp->ext_attr_length))
-				 << sbi->s_log_zone_size);
+		first_data_zone = isonum_733 (rootp->extent) +
+			  	isonum_711 (rootp->ext_attr_length);
 	}
 
 	/*
@@ -835,7 +817,7 @@
 	 * the s_rock flag. Once we have the final s_rock value,
 	 * we then decide whether to use the Joliet descriptor.
 	 */
-	inode = iget(s, sbi->s_firstdatazone);
+	inode = isofs_iget(s, sbi->s_firstdatazone, 0);
 
 	/*
 	 * If this disk has both Rock Ridge and Joliet on it, then we
@@ -854,7 +836,7 @@
 			printk(KERN_DEBUG 
 				"ISOFS: changing to secondary root\n");
 			iput(inode);
-			inode = iget(s, sbi->s_firstdatazone);
+			inode = isofs_iget(s, sbi->s_firstdatazone, 0);
 		}
 	}
 
@@ -952,7 +934,7 @@
 	unsigned long b_off;
 	unsigned offset, sect_size;
 	unsigned int firstext;
-	unsigned long nextino;
+	unsigned long nextblk, nextoff;
 	long iblock = (long)iblock_s;
 	int section, rv;
 	struct iso_inode_info *ei = ISOFS_I(inode);
@@ -970,7 +952,8 @@
 	offset    = 0;
 	firstext  = ei->i_first_extent;
 	sect_size = ei->i_section_size >> ISOFS_BUFFER_BITS(inode);
-	nextino   = ei->i_next_section_ino;
+	nextblk   = ei->i_next_section_block;
+	nextoff   = ei->i_next_section_offset;
 	section   = 0;
 
 	while ( nblocks ) {
@@ -987,25 +970,28 @@
 			goto abort;
 		}
 		
-		if (nextino) {
+		if (nextblk) {
 			while (b_off >= (offset + sect_size)) {
 				struct inode *ninode;
 				
 				offset += sect_size;
-				if (nextino == 0)
+				if (nextblk == 0)
 					goto abort;
-				ninode = iget(inode->i_sb, nextino);
+				ninode = isofs_iget(inode->i_sb, nextblk, nextoff);
 				if (!ninode)
 					goto abort;
 				firstext  = ISOFS_I(ninode)->i_first_extent;
-				sect_size = ISOFS_I(ninode)->i_section_size;
-				nextino   = ISOFS_I(ninode)->i_next_section_ino;
+				sect_size = ISOFS_I(ninode)->i_section_size >> ISOFS_BUFFER_BITS(ninode);
+				nextblk   = ISOFS_I(ninode)->i_next_section_block;
+				nextoff   = ISOFS_I(ninode)->i_next_section_offset;
 				iput(ninode);
 				
 				if (++section > 100) {
 					printk("isofs_get_blocks: More than 100 file sections ?!?, aborting...\n");
-					printk("isofs_get_blocks: ino=%lu block=%ld firstext=%u sect_size=%u nextino=%lu\n",
-					       inode->i_ino, iblock, firstext, (unsigned) sect_size, nextino);
+					printk("isofs_get_blocks: block=%ld firstext=%u sect_size=%u "
+					       "nextblk=%lu nextoff=%lu\n",
+					       iblock, firstext, (unsigned) sect_size,
+					       nextblk, nextoff);
 					goto abort;
 				}
 			}
@@ -1044,7 +1030,7 @@
 	return isofs_get_blocks(inode, iblock, &bh_result, 1) ? 0 : -EIO;
 }
 
-static int isofs_bmap(struct inode *inode, int block)
+static int isofs_bmap(struct inode *inode, sector_t block)
 {
 	struct buffer_head dummy;
 	int error;
@@ -1097,21 +1083,25 @@
 
 static int isofs_read_level3_size(struct inode * inode)
 {
-	unsigned long f_pos = inode->i_ino;
 	unsigned long bufsize = ISOFS_BUFFER_SIZE(inode);
 	int high_sierra = ISOFS_SB(inode->i_sb)->s_high_sierra;
 	struct buffer_head * bh = NULL;
-	unsigned long block, offset;
+	unsigned long block, offset, block_saved, offset_saved;
 	int i = 0;
 	int more_entries = 0;
 	struct iso_directory_record * tmpde = NULL;
 	struct iso_inode_info *ei = ISOFS_I(inode);
 
 	inode->i_size = 0;
-	ei->i_next_section_ino = 0;
 
-	block = f_pos >> ISOFS_BUFFER_BITS(inode);
-	offset = f_pos & (bufsize-1);
+	/* The first 16 blocks are reserved as the System Area.  Thus,
+	 * no inodes can appear in block 0.  We use this to flag that
+	 * this is the last section. */
+	ei->i_next_section_block = 0;
+	ei->i_next_section_offset = 0;
+
+	block = ei->i_iget5_block;
+	offset = ei->i_iget5_offset;
 
 	do {
 		struct iso_directory_record * de;
@@ -1128,12 +1118,13 @@
 		if (de_len == 0) {
 			brelse(bh);
 			bh = NULL;
-			f_pos = (f_pos + ISOFS_BLOCK_SIZE) & ~(ISOFS_BLOCK_SIZE - 1);
-			block = f_pos >> ISOFS_BUFFER_BITS(inode);
+			++block;
 			offset = 0;
 			continue;
 		}
 
+		block_saved = block;
+		offset_saved = offset;
 		offset += de_len;
 
 		/* Make sure we have a full directory entry */
@@ -1159,12 +1150,13 @@
 		}
 
 		inode->i_size += isonum_733(de->size);
-		if (i == 1)
-			ei->i_next_section_ino = f_pos;
+		if (i == 1) {
+			ei->i_next_section_block = block_saved;
+			ei->i_next_section_offset = offset_saved;
+		}
 
 		more_entries = de->flags[-high_sierra] & 0x80;
 
-		f_pos += de_len;
 		i++;
 		if(i > 100)
 			goto out_toomany;
@@ -1190,8 +1182,8 @@
 out_toomany:
 	printk(KERN_INFO "isofs_read_level3_size: "
 		"More than 100 file sections ?!?, aborting...\n"
-	  	"isofs_read_level3_size: inode=%lu ino=%lu\n",
-		inode->i_ino, f_pos);
+	  	"isofs_read_level3_size: inode=%lu\n",
+		inode->i_ino);
 	goto out;
 }
 
@@ -1200,7 +1192,7 @@
 	struct super_block *sb = inode->i_sb;
 	struct isofs_sb_info *sbi = ISOFS_SB(sb);
 	unsigned long bufsize = ISOFS_BUFFER_SIZE(inode);
-	int block = inode->i_ino >> ISOFS_BUFFER_BITS(inode);
+	unsigned long block;
 	int high_sierra = sbi->s_high_sierra;
 	struct buffer_head * bh = NULL;
 	struct iso_directory_record * de;
@@ -1210,11 +1202,13 @@
 	int i;
 	struct iso_inode_info *ei = ISOFS_I(inode);
 
+	block = ei->i_iget5_block;
 	bh = sb_bread(inode->i_sb, block);
 	if (!bh)
 		goto out_badread;
 
-	offset = (inode->i_ino & (bufsize - 1));
+	offset = ei->i_iget5_offset;
+
 	de = (struct iso_directory_record *) (bh->b_data + offset);
 	de_len = *(unsigned char *) de;
 
@@ -1235,6 +1229,8 @@
 		de = tmpde;
 	}
 
+	inode->i_ino = isofs_get_ino(de);
+
 	/* Assume it is a normal-format file unless told otherwise */
 	ei->i_file_format = isofs_file_normal;
 
@@ -1271,7 +1267,8 @@
 	if(de->flags[-high_sierra] & 0x80) {
 		if(isofs_read_level3_size(inode)) goto fail;
 	} else {
-		ei->i_next_section_ino = 0;
+		ei->i_next_section_block = 0;
+		ei->i_next_section_offset = 0;
 		inode->i_size = isonum_733 (de->size);
 	}
 
@@ -1385,6 +1382,61 @@
 	goto out;
 }
 
+struct isofs_iget5_callback_data {
+	unsigned long block;
+	unsigned long offset;
+};
+
+static int isofs_iget5_test(struct inode *ino, void *data)
+{
+	struct iso_inode_info *i = ISOFS_I(ino);
+	struct isofs_iget5_callback_data *d =
+		(struct isofs_iget5_callback_data*)data;
+	return (i->i_iget5_block == d->block)
+	       && (i->i_iget5_offset == d->offset);
+}
+
+static int isofs_iget5_set(struct inode *ino, void *data)
+{
+	struct iso_inode_info *i = ISOFS_I(ino);
+	struct isofs_iget5_callback_data *d =
+		(struct isofs_iget5_callback_data*)data;
+	i->i_iget5_block = d->block;
+	i->i_iget5_offset = d->offset;
+	return 0;
+}
+
+/* Store, in the inode's containing structure, the block and block
+ * offset that point to the underlying meta-data for the inode.  The
+ * code below is otherwise similar to the iget() code in
+ * include/linux/fs.h */
+struct inode *isofs_iget(struct super_block *sb,
+			 unsigned long block,
+			 unsigned long offset)
+{
+	unsigned long hashval;
+	struct inode *inode;
+	struct isofs_iget5_callback_data data;
+
+	data.block = block;
+	data.offset = offset;
+
+	hashval = (block << sb->s_blocksize_bits) | offset;
+
+	inode = iget5_locked(sb,
+			     hashval,
+			     &isofs_iget5_test,
+			     &isofs_iget5_set,
+			     &data);
+
+	if (inode && (inode->i_state & I_NEW)) {
+		sb->s_op->read_inode(inode);
+		unlock_new_inode(inode);
+	}
+
+	return inode;
+}
+
 #ifdef LEAK_CHECK
 #undef malloc
 #undef free_s
--- diff/fs/isofs/namei.c	2004-05-19 22:12:28.000000000 +0100
+++ source/fs/isofs/namei.c	2004-06-11 19:22:05.000000000 +0100
@@ -17,6 +17,7 @@
 #include <linux/config.h>	/* Joliet? */
 #include <linux/smp_lock.h>
 #include <linux/buffer_head.h>
+#include <linux/dcache.h>
 
 #include <asm/uaccess.h>
 
@@ -59,12 +60,12 @@
  */
 static unsigned long
 isofs_find_entry(struct inode *dir, struct dentry *dentry,
+	unsigned long *block_rv, unsigned long* offset_rv,
 	char * tmpname, struct iso_directory_record * tmpde)
 {
-	unsigned long inode_number;
 	unsigned long bufsize = ISOFS_BUFFER_SIZE(dir);
 	unsigned char bufbits = ISOFS_BUFFER_BITS(dir);
-	unsigned int block, f_pos, offset;
+	unsigned long block, f_pos, offset, block_saved, offset_saved;
 	struct buffer_head * bh = NULL;
 	struct isofs_sb_info *sbi = ISOFS_SB(dir->i_sb);
 
@@ -87,7 +88,6 @@
 		}
 
 		de = (struct iso_directory_record *) (bh->b_data + offset);
-		inode_number = (bh->b_blocknr << bufbits) + offset;
 
 		de_len = *(unsigned char *) de;
 		if (!de_len) {
@@ -99,6 +99,8 @@
 			continue;
 		}
 
+		block_saved = bh->b_blocknr;
+		offset_saved = offset;
 		offset += de_len;
 		f_pos += de_len;
 
@@ -150,8 +152,13 @@
 			match = (isofs_cmp(dentry,dpnt,dlen) == 0);
 		}
 		if (match) {
+			isofs_normalize_block_and_offset(de,
+							 &block_saved,
+							 &offset_saved);
+                        *block_rv = block_saved;
+                        *offset_rv = offset_saved;
 			if (bh) brelse(bh);
-			return inode_number;
+			return 1;
 		}
 	}
 	if (bh) brelse(bh);
@@ -160,7 +167,8 @@
 
 struct dentry *isofs_lookup(struct inode * dir, struct dentry * dentry, struct nameidata *nd)
 {
-	unsigned long ino;
+	int found;
+	unsigned long block, offset;
 	struct inode *inode;
 	struct page *page;
 
@@ -171,19 +179,23 @@
 		return ERR_PTR(-ENOMEM);
 
 	lock_kernel();
-	ino = isofs_find_entry(dir, dentry, page_address(page),
-			       1024 + page_address(page));
+	found = isofs_find_entry(dir, dentry,
+				 &block, &offset,
+				 page_address(page),
+				 1024 + page_address(page));
 	__free_page(page);
 
 	inode = NULL;
-	if (ino) {
-		inode = iget(dir->i_sb, ino);
+	if (found) {
+		inode = isofs_iget(dir->i_sb, block, offset);
 		if (!inode) {
 			unlock_kernel();
 			return ERR_PTR(-EACCES);
 		}
 	}
 	unlock_kernel();
+	if (inode)
+		return d_splice_alias(inode, dentry);
 	d_add(dentry, inode);
 	return NULL;
 }
--- diff/fs/isofs/rock.c	2004-05-19 22:12:28.000000000 +0100
+++ source/fs/isofs/rock.c	2004-06-11 19:22:05.000000000 +0100
@@ -306,9 +306,7 @@
 	goto out;
       case SIG('C','L'):
 	ISOFS_I(inode)->i_first_extent = isonum_733(rr->u.CL.location);
-	reloc = iget(inode->i_sb,
-		     (ISOFS_I(inode)->i_first_extent <<
-		      ISOFS_SB(inode->i_sb)->s_log_zone_size));
+	reloc = isofs_iget(inode->i_sb, ISOFS_I(inode)->i_first_extent, 0);
 	if (!reloc)
 		goto out;
 	inode->i_mode = reloc->i_mode;
@@ -447,15 +445,15 @@
 static int rock_ridge_symlink_readpage(struct file *file, struct page *page)
 {
 	struct inode *inode = page->mapping->host;
+        struct iso_inode_info *ei = ISOFS_I(inode);
 	char *link = kmap(page);
 	unsigned long bufsize = ISOFS_BUFFER_SIZE(inode);
-	unsigned char bufbits = ISOFS_BUFFER_BITS(inode);
 	struct buffer_head *bh;
 	char *rpnt = link;
 	unsigned char *pnt;
 	struct iso_directory_record *raw_inode;
 	CONTINUE_DECLS;
-	int block;
+	unsigned long block, offset;
 	int sig;
 	int len;
 	unsigned char *chr;
@@ -464,20 +462,21 @@
 	if (!ISOFS_SB(inode->i_sb)->s_rock)
 		panic ("Cannot have symlink with high sierra variant of iso filesystem\n");
 
-	block = inode->i_ino >> bufbits;
+	block = ei->i_iget5_block;
 	lock_kernel();
 	bh = sb_bread(inode->i_sb, block);
 	if (!bh)
 		goto out_noread;
 
-	pnt = (unsigned char *) bh->b_data + (inode->i_ino & (bufsize - 1));
+        offset = ei->i_iget5_offset;
+	pnt = (unsigned char *) bh->b_data + offset;
 
 	raw_inode = (struct iso_directory_record *) pnt;
 
 	/*
 	 * If we go past the end of the buffer, there is some sort of error.
 	 */
-	if ((inode->i_ino & (bufsize - 1)) + *pnt > bufsize)
+	if (offset + *pnt > bufsize)
 		goto out_bad_span;
 
 	/* Now test for possible Rock Ridge extensions which will override
--- diff/fs/jbd/commit.c	2004-05-19 22:12:28.000000000 +0100
+++ source/fs/jbd/commit.c	2004-06-11 19:22:05.000000000 +0100
@@ -412,7 +412,8 @@
 			tagp = &bh->b_data[sizeof(journal_header_t)];
 			space_left = bh->b_size - sizeof(journal_header_t);
 			first_tag = 1;
-			set_bit(BH_JWrite, &bh->b_state);
+			set_buffer_jwrite(bh);
+			set_buffer_dirty(bh);
 			wbuf[bufs++] = bh;
 
 			/* Record it so that we can wait for IO
@@ -638,9 +639,29 @@
 	JBUFFER_TRACE(descriptor, "write commit block");
 	{
 		struct buffer_head *bh = jh2bh(descriptor);
-		set_buffer_uptodate(bh);
-		sync_dirty_buffer(bh);
-		if (unlikely(!buffer_uptodate(bh)))
+		int ret;
+
+		set_buffer_dirty(bh);
+		if (journal->j_flags & JFS_BARRIER)
+			set_buffer_ordered(bh);
+		ret = sync_dirty_buffer(bh);
+		if (ret == -EOPNOTSUPP && (journal->j_flags & JFS_BARRIER)) {
+			char b[BDEVNAME_SIZE];
+
+			printk(KERN_WARNING
+				"JBD: barrier-based sync failed on %s - "
+				"disabling barriers\n",
+				bdevname(journal->j_dev, b));
+			spin_lock(&journal->j_state_lock);
+			journal->j_flags &= ~JFS_BARRIER;
+			spin_unlock(&journal->j_state_lock);
+
+			/* And try again, without the barrier */
+			clear_buffer_ordered(bh);
+			set_buffer_dirty(bh);
+			ret = sync_dirty_buffer(bh);
+		}
+		if (unlikely(ret == -EIO))
 			err = -EIO;
 		put_bh(bh);		/* One for getblk() */
 		journal_put_journal_head(descriptor);
--- diff/fs/jbd/journal.c	2004-05-19 22:12:28.000000000 +0100
+++ source/fs/jbd/journal.c	2004-06-11 19:22:05.000000000 +0100
@@ -73,6 +73,7 @@
 EXPORT_SYMBOL(journal_clear_err);
 EXPORT_SYMBOL(log_wait_commit);
 EXPORT_SYMBOL(journal_start_commit);
+EXPORT_SYMBOL(journal_force_commit_nested);
 EXPORT_SYMBOL(journal_wipe);
 EXPORT_SYMBOL(journal_blocks_per_page);
 EXPORT_SYMBOL(journal_invalidatepage);
@@ -465,6 +466,39 @@
 }
 
 /*
+ * Force and wait upon a commit if the calling process is not within
+ * transaction.  This is used for forcing out undo-protected data which contains
+ * bitmaps, when the fs is running out of space.
+ *
+ * We can only force the running transaction if we don't have an active handle;
+ * otherwise, we will deadlock.
+ *
+ * Returns true if a transaction was started.
+ */
+int journal_force_commit_nested(journal_t *journal)
+{
+	transaction_t *transaction = NULL;
+	tid_t tid;
+
+	spin_lock(&journal->j_state_lock);
+	if (journal->j_running_transaction && !current->journal_info) {
+		transaction = journal->j_running_transaction;
+		__log_start_commit(journal, transaction->t_tid);
+	} else if (journal->j_committing_transaction)
+		transaction = journal->j_committing_transaction;
+
+	if (!transaction) {
+		spin_unlock(&journal->j_state_lock);
+		return 0;	/* Nothing to retry */
+	}
+
+	tid = transaction->t_tid;
+	spin_unlock(&journal->j_state_lock);
+	log_wait_commit(journal, tid);
+	return 1;
+}
+
+/*
  * Start a commit of the current running transaction (if any).  Returns true
  * if a transaction was started, and fills its tid in at *ptid
  */
@@ -585,9 +619,13 @@
  * We play buffer_head aliasing tricks to write data/metadata blocks to
  * the journal without copying their contents, but for journal
  * descriptor blocks we do need to generate bona fide buffers.
+ *
+ * After the caller of journal_get_descriptor_buffer() has finished modifying
+ * the buffer's contents they really should run flush_dcache_page(bh->b_page).
+ * But we don't bother doing that, so there will be coherency problems with
+ * mmaps of blockdevs which hold live JBD-controlled filesystems.
  */
-
-struct journal_head * journal_get_descriptor_buffer(journal_t *journal)
+struct journal_head *journal_get_descriptor_buffer(journal_t *journal)
 {
 	struct buffer_head *bh;
 	unsigned long blocknr;
@@ -599,8 +637,10 @@
 		return NULL;
 
 	bh = __getblk(journal->j_dev, blocknr, journal->j_blocksize);
+	lock_buffer(bh);
 	memset(bh->b_data, 0, journal->j_blocksize);
-	bh->b_state |= (1 << BH_Dirty);
+	set_buffer_uptodate(bh);
+	unlock_buffer(bh);
 	BUFFER_TRACE(bh, "return this buffer");
 	return journal_add_journal_head(bh);
 }
@@ -1674,9 +1714,17 @@
 	if (buffer_jbd(bh)) {
 		jh = bh2jh(bh);
 	} else {
-		J_ASSERT_BH(bh,
-			(atomic_read(&bh->b_count) > 0) ||
-			(bh->b_page && bh->b_page->mapping));
+		if (!(atomic_read(&bh->b_count) > 0 ||
+				(bh->b_page && bh->b_page->mapping))) {
+			printk(KERN_EMERG "%s: bh->b_count=%d\n",
+				__FUNCTION__, atomic_read(&bh->b_count));
+			printk(KERN_EMERG "%s: bh->b_page=%p\n",
+				__FUNCTION__, bh->b_page);
+			if (bh->b_page)
+				printk(KERN_EMERG "%s: "
+						"bh->b_page->mapping=%p\n",
+					__FUNCTION__, bh->b_page->mapping);
+		}
 
 		if (!new_jh) {
 			jbd_unlock_bh_journal_head(bh);
--- diff/fs/jbd/revoke.c	2004-05-19 22:12:28.000000000 +0100
+++ source/fs/jbd/revoke.c	2004-06-11 19:22:05.000000000 +0100
@@ -522,7 +522,7 @@
 			kmem_cache_free(revoke_record_cache, record);
 		}
 	}
-	if (descriptor) 
+	if (descriptor)
 		flush_descriptor(journal, descriptor, offset);
 	jbd_debug(1, "Wrote %d revoke records\n", count);
 }
@@ -606,7 +606,7 @@
 	header->r_count = htonl(offset);
 	set_buffer_jwrite(bh);
 	BUFFER_TRACE(bh, "write");
-	set_buffer_uptodate(bh);
+	set_buffer_dirty(bh);
 	ll_rw_block(WRITE, 1, &bh);
 }
 #endif
--- diff/fs/jbd/transaction.c	2004-06-11 19:17:32.000000000 +0100
+++ source/fs/jbd/transaction.c	2004-06-11 19:22:05.000000000 +0100
@@ -939,7 +939,6 @@
 int journal_dirty_data(handle_t *handle, struct buffer_head *bh)
 {
 	journal_t *journal = handle->h_transaction->t_journal;
-	int need_brelse = 0;
 	struct journal_head *jh;
 
 	if (is_handle_aborted(handle))
@@ -1024,24 +1023,6 @@
 				goto no_journal;
 			}
 
-			/*
-			 * This buffer may be undergoing writeout in commit.  We
-			 * can't return from here and let the caller dirty it
-			 * again because that can cause the write-out loop in
-			 * commit to never terminate.
-			 */
-			if (buffer_dirty(bh)) {
-				get_bh(bh);
-				spin_unlock(&journal->j_list_lock);
-				jbd_unlock_bh_state(bh);
-				need_brelse = 1;
-				sync_dirty_buffer(bh);
-				jbd_lock_bh_state(bh);
-				spin_lock(&journal->j_list_lock);
-				/* The buffer may become locked again at any
-				   time if it is redirtied */
-			}
-
 			/* journal_clean_data_list() may have got there first */
 			if (jh->b_transaction != NULL) {
 				JBUFFER_TRACE(jh, "unfile from commit");
@@ -1071,10 +1052,6 @@
 no_journal:
 	spin_unlock(&journal->j_list_lock);
 	jbd_unlock_bh_state(bh);
-	if (need_brelse) {
-		BUFFER_TRACE(bh, "brelse");
-		__brelse(bh);
-	}
 	JBUFFER_TRACE(jh, "exit");
 	journal_put_journal_head(jh);
 	return 0;
--- diff/fs/jffs2/symlink.c	2004-05-19 22:12:28.000000000 +0100
+++ source/fs/jffs2/symlink.c	2004-06-11 19:22:05.000000000 +0100
@@ -17,41 +17,28 @@
 #include <linux/fs.h>
 #include "nodelist.h"
 
-int jffs2_readlink(struct dentry *dentry, char *buffer, int buflen);
-int jffs2_follow_link(struct dentry *dentry, struct nameidata *nd);
+static int jffs2_follow_link(struct dentry *dentry, struct nameidata *nd);
+static void jffs2_put_link(struct dentry *dentry, struct nameidata *nd);
 
 struct inode_operations jffs2_symlink_inode_operations =
 {	
-	.readlink =	jffs2_readlink,
+	.readlink =	generic_readlink,
 	.follow_link =	jffs2_follow_link,
+	.put_link =	jffs2_put_link,
 	.setattr =	jffs2_setattr
 };
 
-int jffs2_readlink(struct dentry *dentry, char *buffer, int buflen)
-{
-	unsigned char *kbuf;
-	int ret;
-
-	kbuf = jffs2_getlink(JFFS2_SB_INFO(dentry->d_inode->i_sb), JFFS2_INODE_INFO(dentry->d_inode));
-	if (IS_ERR(kbuf))
-		return PTR_ERR(kbuf);
-
-	ret = vfs_readlink(dentry, buffer, buflen, kbuf);
-	kfree(kbuf);
-	return ret;
-}
-
-int jffs2_follow_link(struct dentry *dentry, struct nameidata *nd)
+static int jffs2_follow_link(struct dentry *dentry, struct nameidata *nd)
 {
 	unsigned char *buf;
-	int ret;
-
 	buf = jffs2_getlink(JFFS2_SB_INFO(dentry->d_inode->i_sb), JFFS2_INODE_INFO(dentry->d_inode));
+	nd_set_link(nd, buf);
+	return 0;
+}
 
-	if (IS_ERR(buf))
-		return PTR_ERR(buf);
-
-	ret = vfs_follow_link(nd, buf);
-	kfree(buf);
-	return ret;
+static void jffs2_put_link(struct dentry *dentry, struct nameidata *nd)
+{
+	char *s = nd_get_link(nd);
+	if (!IS_ERR(s))
+		kfree(s);
 }
--- diff/fs/jfs/symlink.c	2004-05-19 22:12:29.000000000 +0100
+++ source/fs/jfs/symlink.c	2004-06-11 19:22:05.000000000 +0100
@@ -23,17 +23,12 @@
 static int jfs_follow_link(struct dentry *dentry, struct nameidata *nd)
 {
 	char *s = JFS_IP(dentry->d_inode)->i_inline;
-	return vfs_follow_link(nd, s);
-}
-
-static int jfs_readlink(struct dentry *dentry, char __user *buffer, int buflen)
-{
-	char *s = JFS_IP(dentry->d_inode)->i_inline;
-	return vfs_readlink(dentry, buffer, buflen, s);
+	nd_set_link(nd, s);
+	return 0;
 }
 
 struct inode_operations jfs_symlink_inode_operations = {
-	.readlink	= jfs_readlink,
+	.readlink	= generic_readlink,
 	.follow_link	= jfs_follow_link,
 	.setxattr	= jfs_setxattr,
 	.getxattr	= jfs_getxattr,
--- diff/fs/minix/inode.c	2004-05-19 22:12:29.000000000 +0100
+++ source/fs/minix/inode.c	2004-06-11 19:22:05.000000000 +0100
@@ -343,8 +343,9 @@
 };
 
 static struct inode_operations minix_symlink_inode_operations = {
-	.readlink	= page_readlink,
-	.follow_link	= page_follow_link,
+	.readlink	= generic_readlink,
+	.follow_link	= page_follow_link_light,
+	.put_link	= page_put_link,
 	.getattr	= minix_getattr,
 };
 
--- diff/fs/namei.c	2004-06-11 19:17:32.000000000 +0100
+++ source/fs/namei.c	2004-06-11 19:22:05.000000000 +0100
@@ -395,6 +395,21 @@
 	return result;
 }
 
+inline void nd_set_link(struct nameidata *nd, char *path)
+{
+	nd->saved_names[current->link_count] = path;
+}
+
+inline char *nd_get_link(struct nameidata *nd)
+{
+	return nd->saved_names[current->link_count];
+}
+
+EXPORT_SYMBOL(nd_set_link);
+EXPORT_SYMBOL(nd_get_link);
+
+static inline int __vfs_follow_link(struct nameidata *, const char *);
+
 /*
  * This limits recursive symlink follows to 8, while
  * limiting consecutive symlinks to 40.
@@ -405,7 +420,7 @@
 static inline int do_follow_link(struct dentry *dentry, struct nameidata *nd)
 {
 	int err = -ELOOP;
-	if (current->link_count >= 5)
+	if (current->link_count >= MAX_NESTED_LINKS)
 		goto loop;
 	if (current->total_link_count >= 40)
 		goto loop;
@@ -416,7 +431,15 @@
 	current->link_count++;
 	current->total_link_count++;
 	touch_atime(nd->mnt, dentry);
+	nd_set_link(nd, NULL);
 	err = dentry->d_inode->i_op->follow_link(dentry, nd);
+	if (!err) {
+		char *s = nd_get_link(nd);
+		if (s)
+			err = __vfs_follow_link(nd, s);
+		if (dentry->d_inode->i_op->put_link)
+			dentry->d_inode->i_op->put_link(dentry, nd);
+	}
 	current->link_count--;
 	return err;
 loop:
@@ -1380,7 +1403,15 @@
 	if (error)
 		goto exit_dput;
 	touch_atime(nd->mnt, dentry);
+	nd_set_link(nd, NULL);
 	error = dentry->d_inode->i_op->follow_link(dentry, nd);
+	if (!error) {
+		char *s = nd_get_link(nd);
+		if (s)
+			error = __vfs_follow_link(nd, s);
+		if (dentry->d_inode->i_op->put_link)
+			dentry->d_inode->i_op->put_link(dentry, nd);
+	}
 	dput(dentry);
 	if (error)
 		return error;
@@ -2161,6 +2192,23 @@
 	return len;
 }
 
+/*
+ * A helper for ->readlink().  This should be used *ONLY* for symlinks that
+ * have ->follow_link() touching nd only in nd_set_link().  Using (or not
+ * using) it for any given inode is up to filesystem.
+ */
+int generic_readlink(struct dentry *dentry, char __user *buffer, int buflen)
+{
+	struct nameidata nd;
+	int res = dentry->d_inode->i_op->follow_link(dentry, &nd);
+	if (!res) {
+		res = vfs_readlink(dentry, buffer, buflen, nd_get_link(&nd));
+		if (dentry->d_inode->i_op->put_link)
+			dentry->d_inode->i_op->put_link(dentry, &nd);
+	}
+	return res;
+}
+
 static inline int
 __vfs_follow_link(struct nameidata *nd, const char *link)
 {
@@ -2237,6 +2285,30 @@
 	return res;
 }
 
+int page_follow_link_light(struct dentry *dentry, struct nameidata *nd)
+{
+	struct page *page;
+	char *s = page_getlink(dentry, &page);
+	if (!IS_ERR(s)) {
+		nd_set_link(nd, s);
+		s = NULL;
+	}
+	return PTR_ERR(s);
+}
+
+void page_put_link(struct dentry *dentry, struct nameidata *nd)
+{
+	if (!IS_ERR(nd_get_link(nd))) {
+		struct page *page;
+		page = find_get_page(dentry->d_inode->i_mapping, 0);
+		if (!page)
+			BUG();
+		kunmap(page);
+		page_cache_release(page);
+		page_cache_release(page);
+	}
+}
+
 int page_follow_link(struct dentry *dentry, struct nameidata *nd)
 {
 	struct page *page = NULL;
@@ -2291,8 +2363,9 @@
 }
 
 struct inode_operations page_symlink_inode_operations = {
-	.readlink	= page_readlink,
-	.follow_link	= page_follow_link,
+	.readlink	= generic_readlink,
+	.follow_link	= page_follow_link_light,
+	.put_link	= page_put_link,
 };
 
 EXPORT_SYMBOL(__user_walk);
@@ -2305,6 +2378,8 @@
 EXPORT_SYMBOL(lookup_hash);
 EXPORT_SYMBOL(lookup_one_len);
 EXPORT_SYMBOL(page_follow_link);
+EXPORT_SYMBOL(page_follow_link_light);
+EXPORT_SYMBOL(page_put_link);
 EXPORT_SYMBOL(page_readlink);
 EXPORT_SYMBOL(page_symlink);
 EXPORT_SYMBOL(page_symlink_inode_operations);
@@ -2324,3 +2399,4 @@
 EXPORT_SYMBOL(vfs_rmdir);
 EXPORT_SYMBOL(vfs_symlink);
 EXPORT_SYMBOL(vfs_unlink);
+EXPORT_SYMBOL(generic_readlink);
--- diff/fs/nfs/write.c	2004-06-11 19:17:32.000000000 +0100
+++ source/fs/nfs/write.c	2004-06-11 19:22:05.000000000 +0100
@@ -314,7 +314,7 @@
 		if (err >= 0) {
 			err = 0;
 			if (wbc->for_reclaim)
-				err = WRITEPAGE_ACTIVATE;
+				nfs_flush_inode(inode, 0, 0, FLUSH_STABLE);
 		}
 	} else {
 		err = nfs_writepage_sync(NULL, inode, page, 0,
@@ -327,8 +327,7 @@
 	}
 	unlock_kernel();
 out:
-	if (err != WRITEPAGE_ACTIVATE)
-		unlock_page(page);
+	unlock_page(page);
 	if (inode_referenced)
 		iput(inode);
 	return err; 
--- diff/fs/ntfs/ChangeLog	2004-06-11 19:17:32.000000000 +0100
+++ source/fs/ntfs/ChangeLog	2004-06-11 19:22:05.000000000 +0100
@@ -1,4 +1,4 @@
-ToDo:
+ToDo/Notes:
 	- Find and fix bugs.
 	- Either invalidate quotas or update the quota charges on NTFS 3.x
 	  volumes with quota tracking enabled ($Quota).
@@ -11,8 +11,10 @@
 	  pages as nothing can dirty a page other than ourselves. Should this
 	  change, we will really need to roll our own ->set_page_dirty().
 	- Implement sops->dirty_inode() to implement {a,m,c}time updates and
-	  such things.
-	- Implement sops->write_inode().
+	  such things.  This should probably just flag the ntfs inode such that
+	  sops->write_inode(), i.e. ntfs_write_inode(), will copy the times
+	  when it is invoked rather than having to update the mft record
+	  every time.
 	- In between ntfs_prepare/commit_write, need exclusion between
 	  simultaneous file extensions. Need perhaps an NInoResizeUnderway()
 	  flag which we can set in ntfs_prepare_write() and clear again in
@@ -24,6 +26,61 @@
 	  OTOH, perhaps i_sem, which is held accross generic_file_write is
 	  sufficient for synchronisation here. We then just need to make sure
 	  ntfs_readpage/writepage/truncate interoperate properly with us.
+	- Implement mft.c::sync_mft_mirror_umount().  We currently will just
+	  leave the volume dirty on umount if the final iput(vol->mft_ino)
+	  causes a write of any mirrored mft records due to the mft mirror
+	  inode having been discarded already.  Whether this can actually ever
+	  happen is unclear however so it is worth waiting until someone hits
+	  the problem.
+	- Enable the code for setting the NT4 compatibility flag when we start
+	  making NTFS 1.2 specific modifications.
+
+2.1.13 - Enable overwriting of resident files and housekeeping of system files.
+
+	- Implement writing of mft records (fs/ntfs/mft.[hc]), which includes
+	  keeping the mft mirror in sync with the mft when mirrored mft records
+	  are written.  The functions are write_mft_record{,_nolock}().  The
+	  implementation is quite rudimentary for now with lots of things not
+	  implemented yet but I am not sure any of them can actually occur so
+	  I will wait for people to hit each one and only then implement it.
+	- Commit open system inodes at umount time.  This should make it
+	  virtually impossible for sync_mft_mirror_umount() to ever be needed.
+	- Implement ->write_inode (fs/ntfs/inode.c::ntfs_write_inode()) for the
+	  ntfs super operations.  This gives us inode writing via the VFS inode
+	  dirty code paths.  Note:  Access time updates are not implemented yet.
+	- Implement fs/ntfs/mft.[hc]::{,__}mark_mft_record_dirty() and make
+	  fs/ntfs/aops.c::ntfs_writepage() and ntfs_commit_write() use it, thus
+	  finally enabling resident file overwrite!  (-8  This also includes a
+	  placeholder for ->writepage (ntfs_mft_writepage()), which for now
+	  just redirties the page and returns.  Also, at umount time, we for
+	  now throw away all mft data page cache pages after the last call to
+	  ntfs_commit_inode() in the hope that all inodes will have been
+	  written out by then and hence no dirty (meta)data will be lost.  We
+	  also check for this case and emit an error message telling the user
+	  to run chkdsk.
+	- Use set_page_writeback() and end_page_writeback() in the resident
+	  attribute code path of fs/ntfs/aops.c::ntfs_writepage() otherwise
+	  the radix-tree tag PAGECACHE_TAG_DIRTY remains set even though the
+	  page is clean.
+	- Implement ntfs_mft_writepage() so it now checks if any of the mft
+	  records in the page are dirty and if so redirties the page and
+	  returns.  Otherwise it just returns (after doing set_page_writeback(),
+	  unlock_page(), end_page_writeback() or the radix-tree tag
+	  PAGECACHE_TAG_DIRTY remains set even though the page is clean), thus
+	  alowing the VM to do with the page as it pleases.  Also, at umount
+	  time, now only throw away dirty mft (meta)data pages if dirty inodes
+	  are present and ask the user to email us if they see this happening.
+	- Add functions ntfs_{clear,set}_volume_flags(), to modify the volume
+	  information flags (fs/ntfs/super.c).
+	- Mark the volume dirty when (re)mounting read-write and mark it clean
+	  when unmounting or remounting read-only.  If any volume errors are
+	  found, the volume is left marked dirty to force chkdsk to run.
+	- Add code to set the NT4 compatibility flag when (re)mounting
+	  read-write for newer NTFS versions but leave it commented out for now
+	  since we do not make any modifications that are NTFS 1.2 specific yet
+	  and since setting this flag breaks Captive-NTFS which is not nice.
+	  This code must be enabled once we start writing NTFS 1.2 specific
+	  changes otherwise Windows NTFS driver might crash / cause corruption.
 
 2.1.12 - Fix the second fix to the decompression engine and some cleanups.
 
--- diff/fs/ntfs/Makefile	2004-06-11 19:17:32.000000000 +0100
+++ source/fs/ntfs/Makefile	2004-06-11 19:22:05.000000000 +0100
@@ -5,7 +5,7 @@
 ntfs-objs := aops.o attrib.o compress.o debug.o dir.o file.o inode.o mft.o \
 	     mst.o namei.o super.o sysctl.o unistr.o upcase.o
 
-EXTRA_CFLAGS = -DNTFS_VERSION=\"2.1.12\"
+EXTRA_CFLAGS = -DNTFS_VERSION=\"2.1.13\"
 
 ifeq ($(CONFIG_NTFS_DEBUG),y)
 EXTRA_CFLAGS += -DDEBUG
--- diff/fs/ntfs/aops.c	2004-06-11 19:17:32.000000000 +0100
+++ source/fs/ntfs/aops.c	2004-06-11 19:22:05.000000000 +0100
@@ -478,8 +478,8 @@
 	ni = NTFS_I(vi);
 	vol = ni->vol;
 
-	ntfs_debug("Entering for inode %li, attribute type 0x%x, page index "
-			"0x%lx.\n", vi->i_ino, ni->type, page->index);
+	ntfs_debug("Entering for inode 0x%lx, attribute type 0x%x, page index "
+			"0x%lx.", vi->i_ino, ni->type, page->index);
 
 	BUG_ON(!NInoNonResident(ni));
 	BUG_ON(NInoMstProtected(ni));
@@ -778,9 +778,8 @@
  *
  * For resident attributes, OTOH, ntfs_writepage() writes the @page by copying
  * the data to the mft record (which at this stage is most likely in memory).
- * Thus, in this case, I/O is synchronous, as even if the mft record is not
- * cached at this point in time, we need to wait for it to be read in before we
- * can do the copy.
+ * The mft record is then marked dirty and written out asynchronously via the
+ * vfs inode dirty code path.
  *
  * Note the caller clears the page dirty flag before calling ntfs_writepage().
  *
@@ -875,16 +874,6 @@
 	BUG_ON(page_has_buffers(page));
 	BUG_ON(!PageUptodate(page));
 
-	// TODO: Consider using PageWriteback() + unlock_page() in 2.5 once the
-	// "VM fiddling has ended". Note, don't forget to replace all the
-	// unlock_page() calls further below with end_page_writeback() ones.
-	// FIXME: Make sure it is ok to SetPageError() on unlocked page under
-	// writeback before doing the change!
-#if 0
-	set_page_writeback(page);
-	unlock_page(page);
-#endif
-
 	if (!NInoAttr(ni))
 		base_ni = ni;
 	else
@@ -935,6 +924,14 @@
 		bytes = PAGE_CACHE_SIZE;
 
 	/*
+	 * Keep the VM happy.  This must be done otherwise the radix-tree tag
+	 * PAGECACHE_TAG_DIRTY remains set even though the page is clean.
+	 */
+	BUG_ON(PageWriteback(page));
+	set_page_writeback(page);
+	unlock_page(page);
+
+	/*
 	 * Here, we don't need to zero the out of bounds area everytime because
 	 * the below memcpy() already takes care of the mmap-at-end-of-file
 	 * requirements. If the file is converted to a non-resident one, then
@@ -948,7 +945,10 @@
 	 * expose data to userspace/disk which should never have been exposed.
 	 *
 	 * FIXME: Ensure that i_size increases do the zeroing/overwriting and
-	 * if we cannot guarantee that, then enable the zeroing below.
+	 * if we cannot guarantee that, then enable the zeroing below.  If the
+	 * zeroing below is enabled, we MUST move the unlock_page() from above
+	 * to after the kunmap_atomic(), i.e. just before the
+	 * end_page_writeback().
 	 */
 
 	kaddr = kmap_atomic(page, KM_USER0);
@@ -966,11 +966,10 @@
 #endif
 	kunmap_atomic(kaddr, KM_USER0);
 
-	unlock_page(page);
+	end_page_writeback(page);
 
-	// TODO: Mark mft record dirty so it gets written back.
-	ntfs_error(vi->i_sb, "Writing to resident files is not supported yet. "
-			"Wrote to memory only...");
+	/* Mark the mft record dirty, so it gets written back. */
+	mark_mft_record_dirty(ctx->ntfs_ino);
 
 	put_attr_search_ctx(ctx);
 	unmap_mft_record(base_ni);
@@ -1022,7 +1021,7 @@
 	ni = NTFS_I(vi);
 	vol = ni->vol;
 
-	ntfs_debug("Entering for inode %li, attribute type 0x%x, page index "
+	ntfs_debug("Entering for inode 0x%lx, attribute type 0x%x, page index "
 			"0x%lx, from = %u, to = %u.", vi->i_ino, ni->type,
 			page->index, from, to);
 
@@ -1379,7 +1378,7 @@
 	struct inode *vi = page->mapping->host;
 	ntfs_inode   *ni = NTFS_I(vi);
 
-	ntfs_debug("Entering for inode %li, attribute type 0x%x, page index "
+	ntfs_debug("Entering for inode 0x%lx, attribute type 0x%x, page index "
 			"0x%lx, from = %u, to = %u.", vi->i_ino, ni->type,
 			page->index, from, to);
 
@@ -1487,7 +1486,7 @@
 
 	vi = page->mapping->host;
 
-	ntfs_debug("Entering for inode %li, attribute type 0x%x, page index "
+	ntfs_debug("Entering for inode 0x%lx, attribute type 0x%x, page index "
 			"0x%lx, from = %u, to = %u.", vi->i_ino,
 			NTFS_I(vi)->type, page->index, from, to);
 
@@ -1583,7 +1582,7 @@
 	vi = page->mapping->host;
 	ni = NTFS_I(vi);
 
-	ntfs_debug("Entering for inode %li, attribute type 0x%x, page index "
+	ntfs_debug("Entering for inode 0x%lx, attribute type 0x%x, page index "
 			"0x%lx, from = %u, to = %u.", vi->i_ino, ni->type,
 			page->index, from, to);
 
@@ -1734,9 +1733,8 @@
 	}
 	kunmap_atomic(kaddr, KM_USER0);
 
-	// TODO: Mark mft record dirty so it gets written back.
-	ntfs_error(vi->i_sb, "Writing to resident files is not supported yet. "
-			"Wrote to memory only...");
+	/* Mark the mft record dirty, so it gets written back. */
+	mark_mft_record_dirty(ctx->ntfs_ino);
 
 	put_attr_search_ctx(ctx);
 	unmap_mft_record(base_ni);
--- diff/fs/ntfs/attrib.c	2004-06-11 19:17:32.000000000 +0100
+++ source/fs/ntfs/attrib.c	2004-06-11 19:22:05.000000000 +0100
@@ -624,7 +624,7 @@
 
 			if (drl[ds].vcn == marker_vcn) {
 				ntfs_debug("Old marker = 0x%llx, replacing "
-						"with LCN_ENOENT.\n",
+						"with LCN_ENOENT.",
 						(unsigned long long)
 						drl[ds].lcn);
 				drl[ds].lcn = (LCN)LCN_ENOENT;
@@ -1565,7 +1565,7 @@
 		goto do_next_attr_loop;
 	}
 	ntfs_error(base_ni->vol->sb, "Inode contains corrupt attribute list "
-			"attribute.\n");
+			"attribute.");
 	if (ni != base_ni) {
 		unmap_extent_mft_record(ni);
 		ctx->ntfs_ino = base_ni;
--- diff/fs/ntfs/compress.c	2004-06-11 19:17:32.000000000 +0100
+++ source/fs/ntfs/compress.c	2004-06-11 19:22:05.000000000 +0100
@@ -433,7 +433,7 @@
 	goto do_next_tag;
 
 return_overflow:
-	ntfs_error(NULL, "Failed. Returning -EOVERFLOW.\n");
+	ntfs_error(NULL, "Failed. Returning -EOVERFLOW.");
 	goto return_error;
 }
 
@@ -851,7 +851,7 @@
 		if (err) {
 			ntfs_error(vol->sb, "ntfs_decompress() failed in inode "
 					"0x%lx with error code %i. Skipping "
-					"this compression block.\n",
+					"this compression block.",
 					ni->mft_no, -err);
 			/* Release the unfinished pages. */
 			for (; prev_cur_page < cur_page; prev_cur_page++) {
--- diff/fs/ntfs/inode.c	2004-06-11 19:17:32.000000000 +0100
+++ source/fs/ntfs/inode.c	2004-06-11 19:22:05.000000000 +0100
@@ -1960,49 +1960,134 @@
 	return err;
 }
 
+/**
+ * ntfs_write_inode - write out a dirty inode
+ * @vi:		inode to write out
+ * @sync:	if true, write out synchronously
+ *
+ * Write out a dirty inode to disk including any extent inodes if present.
+ *
+ * If @sync is true, commit the inode to disk and wait for io completion.  This
+ * is done using write_mft_record().
+ *
+ * If @sync is false, just schedule the write to happen but do not wait for i/o
+ * completion.  In 2.6 kernels, scheduling usually happens just by virtue of
+ * marking the page (and in this case mft record) dirty but we do not implement
+ * this yet as write_mft_record() largely ignores the @sync parameter and
+ * always performs synchronous writes.
+ */
 void ntfs_write_inode(struct inode *vi, int sync)
 {
 	ntfs_inode *ni = NTFS_I(vi);
+#if 0
+	attr_search_context *ctx;
+#endif
+	MFT_RECORD *m;
+	int err = 0;
 
 	ntfs_debug("Entering for %sinode 0x%lx.", NInoAttr(ni) ? "attr " : "",
 			vi->i_ino);
-
 	/*
 	 * Dirty attribute inodes are written via their real inodes so just
-	 * clean them here.
+	 * clean them here.  TODO:  Take care of access time updates.
 	 */
 	if (NInoAttr(ni)) {
 		NInoClearDirty(ni);
 		return;
 	}
-
-	/* Write this base mft record. */
-	if (NInoDirty(ni)) {
-		ntfs_warning(vi->i_sb, "Cleaning dirty inode 0x%lx without "
-				"writing to disk as this is not yet "
-				"implemented.", vi->i_ino);
-		NInoClearDirty(ni);
+	/* Map, pin, and lock the mft record belonging to the inode. */
+	m = map_mft_record(ni);
+	if (unlikely(IS_ERR(m))) {
+		err = PTR_ERR(m);
+		goto err_out;
 	}
-
+#if 0
+	/* Obtain the standard information attribute. */
+	ctx = get_attr_search_ctx(ni, m);
+	if (unlikely(!ctx)) {
+		err = -ENOMEM;
+		goto unm_err_out;
+	}
+	if (unlikely(!lookup_attr(AT_STANDARD_INFORMATION, NULL, 0,
+			IGNORE_CASE, 0, NULL, 0, ctx))) {
+		put_attr_search_ctx(ctx);
+		err = -ENOENT;
+		goto unm_err_out;
+	}
+	// TODO:  Update the access times in the standard information attribute
+	// which is now in ctx->attr.
+	// - Probably want to have use sops->dirty_inode() to set a flag that
+	//   we need to update the times here rather than having to blindly do
+	//   it every time.  Or even don't do it here at all and do it in
+	//   sops->dirty_inode() instead.  Problem with this would be that
+	//   sops->dirty_inode() must be atomic under certain circumstances
+	//   and mapping mft records and such like is not atomic.
+	// - For atime updates also need to check whether they are enabled in
+	//   the superblock flags.
+	ntfs_warning(vi->i_sb, "Access time updates not implement yet.");
+	/*
+	 * We just modified the mft record containing the standard information
+	 * attribute.  So need to mark the mft record dirty, too, but we do it
+	 * manually so that mark_inode_dirty() is not called again.
+	 * TODO:  Only do this if there was a change in any of the times!
+	 */
+	if (!NInoTestSetDirty(ctx->ntfs_ino))
+		__set_page_dirty_nobuffers(ctx->ntfs_ino->page);
+	put_attr_search_ctx(ctx);
+#endif
+	/* Write this base mft record. */
+	if (NInoDirty(ni))
+		err = write_mft_record(ni, m, sync);
 	/* Write all attached extent mft records. */
 	down(&ni->extent_lock);
 	if (ni->nr_extents > 0) {
-		int i;
 		ntfs_inode **extent_nis = ni->ext.extent_ntfs_inos;
+		int i;
 
+		ntfs_debug("Writing %i extent inodes.", ni->nr_extents);
 		for (i = 0; i < ni->nr_extents; i++) {
 			ntfs_inode *tni = extent_nis[i];
 
 			if (NInoDirty(tni)) {
-				ntfs_warning(vi->i_sb, "Cleaning dirty extent "
-						"inode 0x%lx without writing "
-						"to disk as this is not yet "
-						"implemented.", tni->mft_no);
-				NInoClearDirty(tni);
+				MFT_RECORD *tm = map_mft_record(tni);
+				int ret;
+
+				if (unlikely(IS_ERR(tm))) {
+					if (!err || err == -ENOMEM)
+						err = PTR_ERR(tm);
+					continue;
+				}
+				ret = write_mft_record(tni, tm, sync);
+				unmap_mft_record(tni);
+				if (unlikely(ret)) {
+					if (!err || err == -ENOMEM)
+						err = ret;
+				}
 			}
 		}
 	}
 	up(&ni->extent_lock);
+	unmap_mft_record(ni);
+	if (unlikely(err))
+		goto err_out;
+	ntfs_debug("Done.");
+	return;
+#if 0
+unm_err_out:
+	unmap_mft_record(ni);
+#endif
+err_out:
+	if (err == -ENOMEM) {
+		ntfs_warning(vi->i_sb, "Not enough memory to write inode.  "
+				"Marking the inode dirty again, so the VFS "
+				"retries later.");
+		mark_inode_dirty(vi);
+	} else {
+		ntfs_error(vi->i_sb, "Failed (error code %i):  Marking inode "
+				"as bad.  You should run chkdsk.", -err);
+		make_bad_inode(vi);
+	}
+	return;
 }
 
 #endif /* NTFS_RW */
--- diff/fs/ntfs/mft.c	2004-06-11 19:17:32.000000000 +0100
+++ source/fs/ntfs/mft.c	2004-06-11 19:22:05.000000000 +0100
@@ -102,6 +102,13 @@
  */
 extern int ntfs_readpage(struct file *, struct page *);
 
+#ifdef NTFS_RW
+/**
+ * ntfs_mft_writepage - forward declaration, function is further below
+ */
+static int ntfs_mft_writepage(struct page *page, struct writeback_control *wbc);
+#endif /* NTFS_RW */
+
 /**
  * ntfs_mft_aops - address space operations for access to $MFT
  *
@@ -112,6 +119,10 @@
 	.readpage	= ntfs_readpage,	/* Fill page with data. */
 	.sync_page	= block_sync_page,	/* Currently, just unplugs the
 						   disk request queue. */
+#ifdef NTFS_RW
+	.writepage	= ntfs_mft_writepage,	/* Write out the dirty mft
+						   records in a page. */
+#endif /* NTFS_RW */
 };
 
 /**
@@ -429,3 +440,654 @@
 		ntfs_clear_extent_inode(ni);
 	return m;
 }
+
+#ifdef NTFS_RW
+
+/**
+ * __mark_mft_record_dirty - set the mft record and the page containing it dirty
+ * @ni:		ntfs inode describing the mapped mft record
+ *
+ * Internal function.  Users should call mark_mft_record_dirty() instead.
+ *
+ * Set the mapped (extent) mft record of the (base or extent) ntfs inode @ni,
+ * as well as the page containing the mft record, dirty.  Also, mark the base
+ * vfs inode dirty.  This ensures that any changes to the mft record are
+ * written out to disk.
+ *
+ * NOTE:  We only set I_DIRTY_SYNC and I_DIRTY_DATASYNC (and not I_DIRTY_PAGES)
+ * on the base vfs inode, because even though file data may have been modified,
+ * it is dirty in the inode meta data rather than the data page cache of the
+ * inode, and thus there are no data pages that need writing out.  Therefore, a
+ * full mark_inode_dirty() is overkill.  A mark_inode_dirty_sync(), on the
+ * other hand, is not sufficient, because I_DIRTY_DATASYNC needs to be set to
+ * ensure ->write_inode is called from generic_osync_inode() and this needs to
+ * happen or the file data would not necessarily hit the device synchronously,
+ * even though the vfs inode has the O_SYNC flag set.  Also, I_DIRTY_DATASYNC
+ * simply "feels" better than just I_DIRTY_SYNC, since the file data has not
+ * actually hit the block device yet, which is not what I_DIRTY_SYNC on its own
+ * would suggest.
+ */
+void __mark_mft_record_dirty(ntfs_inode *ni)
+{
+	struct page *page = ni->page;
+	ntfs_inode *base_ni;
+
+	ntfs_debug("Entering for inode 0x%lx.", ni->mft_no);
+	BUG_ON(!page);
+	BUG_ON(NInoAttr(ni));
+
+	/*
+	 * Set the page containing the mft record dirty.  This also marks the
+	 * $MFT inode dirty (I_DIRTY_PAGES).
+	 */
+	__set_page_dirty_nobuffers(page);
+
+	/* Determine the base vfs inode and mark it dirty, too. */
+	down(&ni->extent_lock);
+	if (likely(ni->nr_extents >= 0))
+		base_ni = ni;
+	else
+		base_ni = ni->ext.base_ntfs_ino;
+	up(&ni->extent_lock);
+	__mark_inode_dirty(VFS_I(base_ni), I_DIRTY_SYNC | I_DIRTY_DATASYNC);
+}
+
+static const char *ntfs_please_email = "Please email "
+		"linux-ntfs-dev@lists.sourceforge.net and say that you saw "
+		"this message.  Thank you.";
+
+/**
+ * sync_mft_mirror_umount - synchronise an mft record to the mft mirror
+ * @ni:		ntfs inode whose mft record to synchronize
+ * @m:		mapped, mst protected (extent) mft record to synchronize
+ *
+ * Write the mapped, mst protected (extent) mft record @m described by the
+ * (regular or extent) ntfs inode @ni to the mft mirror ($MFTMirr) bypassing
+ * the page cache and the $MFTMirr inode itself.
+ *
+ * This function is only for use at umount time when the mft mirror inode has
+ * already been disposed off.  We BUG() if we are called while the mft mirror
+ * inode is still attached to the volume.
+ *
+ * On success return 0.  On error return -errno.
+ *
+ * NOTE:  This function is not implemented yet as I am not convinced it can
+ * actually be triggered considering the sequence of commits we do in super.c::
+ * ntfs_put_super().  But just in case we provide this place holder as the
+ * alternative would be either to BUG() or to get a NULL pointer dereference
+ * and Oops.
+ */
+static int sync_mft_mirror_umount(ntfs_inode *ni, MFT_RECORD *m)
+{
+	ntfs_volume *vol = ni->vol;
+
+	BUG_ON(vol->mftmirr_ino);
+	ntfs_error(vol->sb, "Umount time mft mirror syncing is not "
+			"implemented yet.  %s", ntfs_please_email);
+	return -EOPNOTSUPP;
+}
+
+/**
+ * sync_mft_mirror - synchronize an mft record to the mft mirror
+ * @ni:		ntfs inode whose mft record to synchronize
+ * @m:		mapped, mst protected (extent) mft record to synchronize
+ * @sync:	if true, wait for i/o completion
+ *
+ * Write the mapped, mst protected (extent) mft record @m described by the
+ * (regular or extent) ntfs inode @ni to the mft mirror ($MFTMirr).
+ *
+ * On success return 0.  On error return -errno and set the volume errors flag
+ * in the ntfs_volume to which @ni belongs.
+ *
+ * NOTE:  We always perform synchronous i/o and ignore the @sync parameter.
+ *
+ * TODO:  If @sync is false, want to do truly asynchronous i/o, i.e. just
+ * schedule i/o via ->writepage or do it via kntfsd or whatever.
+ */
+static int sync_mft_mirror(ntfs_inode *ni, MFT_RECORD *m, int sync)
+{
+	ntfs_volume *vol = ni->vol;
+	struct page *page;
+	unsigned int blocksize = vol->sb->s_blocksize;
+	int max_bhs = vol->mft_record_size / blocksize;
+	struct buffer_head *bhs[max_bhs];
+	struct buffer_head *bh, *head;
+	u8 *kmirr;
+	unsigned int block_start, block_end, m_start, m_end;
+	int i_bhs, nr_bhs, err = 0;
+
+	ntfs_debug("Entering for inode 0x%lx.", ni->mft_no);
+	BUG_ON(!max_bhs);
+	if (unlikely(!vol->mftmirr_ino)) {
+		/* This could happen during umount... */
+		err = sync_mft_mirror_umount(ni, m);
+		if (likely(!err))
+			return err;
+		goto err_out;
+	}
+	/* Get the page containing the mirror copy of the mft record @m. */
+	page = ntfs_map_page(vol->mftmirr_ino->i_mapping, ni->mft_no >>
+			(PAGE_CACHE_SHIFT - vol->mft_record_size_bits));
+	if (unlikely(IS_ERR(page))) {
+		ntfs_error(vol->sb, "Failed to map mft mirror page.");
+		err = PTR_ERR(page);
+		goto err_out;
+	}
+	/*
+	 * Exclusion against other writers.   This should never be a problem
+	 * since the page in which the mft record @m resides is also locked and
+	 * hence any other writers would be held up there but it is better to
+	 * make sure no one is writing from elsewhere.
+	 */
+	lock_page(page);
+	/* The address in the page of the mirror copy of the mft record @m. */
+	kmirr = page_address(page) + ((ni->mft_no << vol->mft_record_size_bits)
+			& ~PAGE_CACHE_MASK);
+	/* Copy the mst protected mft record to the mirror. */
+	memcpy(kmirr, m, vol->mft_record_size);
+	/* Make sure we have mapped buffers. */
+	if (!page_has_buffers(page)) {
+no_buffers_err_out:
+		ntfs_error(vol->sb, "Writing mft mirror records without "
+				"existing buffers is not implemented yet.  %s",
+				ntfs_please_email);
+		err = -EOPNOTSUPP;
+		goto unlock_err_out;
+	}
+	bh = head = page_buffers(page);
+	if (!bh)
+		goto no_buffers_err_out;
+	nr_bhs = 0;
+	block_start = 0;
+	m_start = kmirr - (u8*)page_address(page);
+	m_end = m_start + vol->mft_record_size;
+	do {
+		block_end = block_start + blocksize;
+		/*
+		 * If the buffer is outside the mft record, just skip it,
+		 * clearing it if it is dirty to make sure it is not written
+		 * out.  It should never be marked dirty but better be safe.
+		 */
+		if ((block_end <= m_start) || (block_start >= m_end)) {
+			if (buffer_dirty(bh)) {
+				ntfs_warning(vol->sb, "Clearing dirty mft "
+						"record page buffer.  %s",
+						ntfs_please_email);
+				clear_buffer_dirty(bh);
+			}
+			continue;
+		}
+		if (!buffer_mapped(bh)) {
+			ntfs_error(vol->sb, "Writing mft mirror records "
+					"without existing mapped buffers is "
+					"not implemented yet.  %s",
+					ntfs_please_email);
+			err = -EOPNOTSUPP;
+			continue;
+		}
+		if (!buffer_uptodate(bh)) {
+			ntfs_error(vol->sb, "Writing mft mirror records "
+					"without existing uptodate buffers is "
+					"not implemented yet.  %s",
+					ntfs_please_email);
+			err = -EOPNOTSUPP;
+			continue;
+		}
+		BUG_ON(!nr_bhs && (m_start != block_start));
+		BUG_ON(nr_bhs >= max_bhs);
+		bhs[nr_bhs++] = bh;
+		BUG_ON((nr_bhs >= max_bhs) && (m_end != block_end));
+	} while (block_start = block_end, (bh = bh->b_this_page) != head);
+	if (likely(!err)) {
+		/* Lock buffers and start synchronous write i/o on them. */
+		for (i_bhs = 0; i_bhs < nr_bhs; i_bhs++) {
+			struct buffer_head *tbh = bhs[i_bhs];
+
+			if (unlikely(test_set_buffer_locked(tbh)))
+				BUG();
+			BUG_ON(!buffer_uptodate(tbh));
+			if (buffer_dirty(tbh))
+				clear_buffer_dirty(tbh);
+			get_bh(tbh);
+			tbh->b_end_io = end_buffer_write_sync;
+			submit_bh(WRITE, tbh);
+		}
+		/* Wait on i/o completion of buffers. */
+		for (i_bhs = 0; i_bhs < nr_bhs; i_bhs++) {
+			struct buffer_head *tbh = bhs[i_bhs];
+
+			wait_on_buffer(tbh);
+			if (unlikely(!buffer_uptodate(tbh))) {
+				err = -EIO;
+				/*
+				 * Set the buffer uptodate so the page & buffer
+				 * states don't become out of sync.
+				 */
+				if (PageUptodate(page))
+					set_buffer_uptodate(tbh);
+			}
+		}
+	} else /* if (unlikely(err)) */ {
+		/* Clean the buffers. */
+		for (i_bhs = 0; i_bhs < nr_bhs; i_bhs++)
+			clear_buffer_dirty(bhs[i_bhs]);
+	}
+unlock_err_out:
+	/* Current state: all buffers are clean, unlocked, and uptodate. */
+	/* Remove the mst protection fixups again. */
+	post_write_mst_fixup((NTFS_RECORD*)kmirr);
+	flush_dcache_page(page);
+	unlock_page(page);
+	ntfs_unmap_page(page);
+	if (unlikely(err)) {
+		/* I/O error during writing.  This is really bad! */
+		ntfs_error(vol->sb, "I/O error while writing mft mirror "
+				"record 0x%lx!  You should unmount the volume "
+				"and run chkdsk or ntfsfix.", ni->mft_no);
+		goto err_out;
+	}
+	ntfs_debug("Done.");
+	return 0;
+err_out:
+	ntfs_error(vol->sb, "Failed to synchronize $MFTMirr (error code %i).  "
+			"Volume will be left marked dirty on umount.  Run "
+			"ntfsfix on the partition after umounting to correct "
+			"this.", -err);
+	/* We don't want to clear the dirty bit on umount. */
+	NVolSetErrors(vol);
+	return err;
+}
+
+/**
+ * write_mft_record_nolock - write out a mapped (extent) mft record
+ * @ni:		ntfs inode describing the mapped (extent) mft record
+ * @m:		mapped (extent) mft record to write
+ * @sync:	if true, wait for i/o completion
+ *
+ * Write the mapped (extent) mft record @m described by the (regular or extent)
+ * ntfs inode @ni to backing store.  If the mft record @m has a counterpart in
+ * the mft mirror, that is also updated.
+ *
+ * On success, clean the mft record and return 0.  On error, leave the mft
+ * record dirty and return -errno.  The caller should call make_bad_inode() on
+ * the base inode to ensure no more access happens to this inode.  We do not do
+ * it here as the caller may want to finish writing other extent mft records
+ * first to minimize on-disk metadata inconsistencies.
+ *
+ * NOTE:  We always perform synchronous i/o and ignore the @sync parameter.
+ * However, if the mft record has a counterpart in the mft mirror and @sync is
+ * true, we write the mft record, wait for i/o completion, and only then write
+ * the mft mirror copy.  This ensures that if the system crashes either the mft
+ * or the mft mirror will contain a self-consistent mft record @m.  If @sync is
+ * false on the other hand, we start i/o on both and then wait for completion
+ * on them.  This provides a speedup but no longer guarantees that you will end
+ * up with a self-consistent mft record in the case of a crash but if you asked
+ * for asynchronous writing you probably do not care about that anyway.
+ *
+ * TODO:  If @sync is false, want to do truly asynchronous i/o, i.e. just
+ * schedule i/o via ->writepage or do it via kntfsd or whatever.
+ */
+int write_mft_record_nolock(ntfs_inode *ni, MFT_RECORD *m, int sync)
+{
+	ntfs_volume *vol = ni->vol;
+	struct page *page = ni->page;
+	unsigned int blocksize = vol->sb->s_blocksize;
+	int max_bhs = vol->mft_record_size / blocksize;
+	struct buffer_head *bhs[max_bhs];
+	struct buffer_head *bh, *head;
+	unsigned int block_start, block_end, m_start, m_end;
+	int i_bhs, nr_bhs, err = 0;
+
+	ntfs_debug("Entering for inode 0x%lx.", ni->mft_no);
+	BUG_ON(NInoAttr(ni));
+	BUG_ON(!max_bhs);
+	BUG_ON(!page);
+	BUG_ON(!PageLocked(page));
+	/*
+	 * If the ntfs_inode is clean no need to do anything.  If it is dirty,
+	 * mark it as clean now so that it can be redirtied later on if needed.
+	 * There is no danger of races as as long as the caller is holding the
+	 * locks for the mft record @m and the page it is in.
+	 */
+	if (!NInoTestClearDirty(ni))
+		goto done;
+	/* Make sure we have mapped buffers. */
+	if (!page_has_buffers(page)) {
+no_buffers_err_out:
+		ntfs_error(vol->sb, "Writing mft records without existing "
+				"buffers is not implemented yet.  %s",
+				ntfs_please_email);
+		err = -EOPNOTSUPP;
+		goto err_out;
+	}
+	bh = head = page_buffers(page);
+	if (!bh)
+		goto no_buffers_err_out;
+	nr_bhs = 0;
+	block_start = 0;
+	m_start = ni->page_ofs;
+	m_end = m_start + vol->mft_record_size;
+	do {
+		block_end = block_start + blocksize;
+		/*
+		 * If the buffer is outside the mft record, just skip it,
+		 * clearing it if it is dirty to make sure it is not written
+		 * out.  It should never be marked dirty but better be safe.
+		 */
+		if ((block_end <= m_start) || (block_start >= m_end)) {
+			if (buffer_dirty(bh)) {
+				ntfs_warning(vol->sb, "Clearing dirty mft "
+						"record page buffer.  %s",
+						ntfs_please_email);
+				clear_buffer_dirty(bh);
+			}
+			continue;
+		}
+		if (!buffer_mapped(bh)) {
+			ntfs_error(vol->sb, "Writing mft records without "
+					"existing mapped buffers is not "
+					"implemented yet.  %s",
+					ntfs_please_email);
+			err = -EOPNOTSUPP;
+			continue;
+		}
+		if (!buffer_uptodate(bh)) {
+			ntfs_error(vol->sb, "Writing mft records without "
+					"existing uptodate buffers is not "
+					"implemented yet.  %s",
+					ntfs_please_email);
+			err = -EOPNOTSUPP;
+			continue;
+		}
+		BUG_ON(!nr_bhs && (m_start != block_start));
+		BUG_ON(nr_bhs >= max_bhs);
+		bhs[nr_bhs++] = bh;
+		BUG_ON((nr_bhs >= max_bhs) && (m_end != block_end));
+	} while (block_start = block_end, (bh = bh->b_this_page) != head);
+	if (unlikely(err))
+		goto cleanup_out;
+	/* Apply the mst protection fixups. */
+	err = pre_write_mst_fixup((NTFS_RECORD*)m, vol->mft_record_size);
+	if (err) {
+		ntfs_error(vol->sb, "Failed to apply mst fixups!");
+		goto cleanup_out;
+	}
+	flush_dcache_mft_record_page(ni);
+	/* Lock buffers and start synchronous write i/o on them. */
+	for (i_bhs = 0; i_bhs < nr_bhs; i_bhs++) {
+		struct buffer_head *tbh = bhs[i_bhs];
+
+		if (unlikely(test_set_buffer_locked(tbh)))
+			BUG();
+		BUG_ON(!buffer_uptodate(tbh));
+		if (buffer_dirty(tbh))
+			clear_buffer_dirty(tbh);
+		get_bh(tbh);
+		tbh->b_end_io = end_buffer_write_sync;
+		submit_bh(WRITE, tbh);
+	}
+	/* Synchronize the mft mirror now if not @sync. */
+	if (!sync && ni->mft_no < vol->mftmirr_size)
+		sync_mft_mirror(ni, m, sync);
+	/* Wait on i/o completion of buffers. */
+	for (i_bhs = 0; i_bhs < nr_bhs; i_bhs++) {
+		struct buffer_head *tbh = bhs[i_bhs];
+
+		wait_on_buffer(tbh);
+		if (unlikely(!buffer_uptodate(tbh))) {
+			err = -EIO;
+			/*
+			 * Set the buffer uptodate so the page & buffer states
+			 * don't become out of sync.
+			 */
+			if (PageUptodate(page))
+				set_buffer_uptodate(tbh);
+		}
+	}
+	/* If @sync, now synchronize the mft mirror. */
+	if (sync && ni->mft_no < vol->mftmirr_size)
+		sync_mft_mirror(ni, m, sync);
+	/* Remove the mst protection fixups again. */
+	post_write_mst_fixup((NTFS_RECORD*)m);
+	flush_dcache_mft_record_page(ni);
+	if (unlikely(err)) {
+		/* I/O error during writing.  This is really bad! */
+		ntfs_error(vol->sb, "I/O error while writing mft record "
+				"0x%lx!  Marking base inode as bad.  You "
+				"should unmount the volume and run chkdsk.",
+				ni->mft_no);
+		goto err_out;
+	}
+done:
+	ntfs_debug("Done.");
+	return 0;
+cleanup_out:
+	/* Clean the buffers. */
+	for (i_bhs = 0; i_bhs < nr_bhs; i_bhs++)
+		clear_buffer_dirty(bhs[i_bhs]);
+err_out:
+	/*
+	 * Current state: all buffers are clean, unlocked, and uptodate.
+	 * The caller should mark the base inode as bad so that no more i/o
+	 * happens.  ->clear_inode() will still be invoked so all extent inodes
+	 * and other allocated memory will be freed.
+	 */
+	if (err == -ENOMEM) {
+		ntfs_error(vol->sb, "Not enough memory to write mft record.  "
+				"Redirtying so the write is retried later.");
+		mark_mft_record_dirty(ni);
+		err = 0;
+	}
+	return err;
+}
+
+/**
+ * ntfs_mft_writepage - check if a metadata page contains dirty mft records
+ * @page:	metadata page possibly containing dirty mft records
+ * @wbc:	writeback control structure
+ *
+ * This is called from the VM when it wants to have a dirty $MFT/$DATA metadata
+ * page cache page cleaned.  The VM has already locked the page and marked it
+ * clean.  Instead of writing the page as a conventional ->writepage function
+ * would do, we check if the page still contains any dirty mft records (it must
+ * have done at some point in the past since the page was marked dirty) and if
+ * none are found, i.e. all mft records are clean, we unlock the page and
+ * return.  The VM is then free to do with the page as it pleases.  If on the
+ * other hand we do find any dirty mft records in the page, we redirty the page
+ * before unlocking it and returning so the VM knows that the page is still
+ * busy and cannot be thrown out.
+ *
+ * Note, we do not actually write any dirty mft records here because they are
+ * dirty inodes and hence will be written by the VFS inode dirty code paths.
+ * There is no need to write them from the VM page dirty code paths, too and in
+ * fact once we implement journalling it would be a complete nightmare having
+ * two code paths leading to mft record writeout.
+ */
+static int ntfs_mft_writepage(struct page *page, struct writeback_control *wbc)
+{
+	struct inode *mft_vi = page->mapping->host;
+	struct super_block *sb = mft_vi->i_sb;
+	ntfs_volume *vol = NTFS_SB(sb);
+	u8 *maddr;
+	MFT_RECORD *m;
+	ntfs_inode **extent_nis;
+	unsigned long mft_no;
+	int nr, i, j;
+	BOOL is_dirty = FALSE;
+
+	BUG_ON(mft_vi != vol->mft_ino);
+	/* The first mft record number in the page. */
+	mft_no = page->index << (PAGE_CACHE_SHIFT - vol->mft_record_size_bits);
+	/* Number of mft records in the page. */
+	nr = PAGE_CACHE_SIZE >> vol->mft_record_size_bits;
+	BUG_ON(!nr);
+	ntfs_debug("Entering for %i inodes starting at 0x%lx.", nr, mft_no);
+	/* Iterate over the mft records in the page looking for a dirty one. */
+	maddr = (u8*)kmap(page);
+	for (i = 0; i < nr; ++i, ++mft_no, maddr += vol->mft_record_size) {
+		struct inode *vi;
+		ntfs_inode *ni, *eni;
+		ntfs_attr na;
+
+		na.mft_no = mft_no;
+		na.name = NULL;
+		na.name_len = 0;
+		na.type = AT_UNUSED;
+		/*
+		 * Check if the inode corresponding to this mft record is in
+		 * the VFS inode cache and obtain a reference to it if it is.
+		 */
+		ntfs_debug("Looking for inode 0x%lx in icache.", mft_no);
+		/*
+		 * For inode 0, i.e. $MFT itself, we cannot use ilookup5() from
+		 * here or we deadlock because the inode is already locked by
+		 * the kernel (fs/fs-writeback.c::__sync_single_inode()) and
+		 * ilookup5() waits until the inode is unlocked before
+		 * returning it and it never gets unlocked because
+		 * ntfs_mft_writepage() never returns.  )-:  Fortunately, we
+		 * have inode 0 pinned in icache for the duration of the mount
+		 * so we can access it directly.
+		 */
+		if (!mft_no) {
+			/* Balance the below iput(). */
+			vi = igrab(mft_vi);
+			BUG_ON(vi != mft_vi);
+		} else
+			vi = ilookup5(sb, mft_no, (test_t)ntfs_test_inode, &na);
+		if (vi) {
+			ntfs_debug("Inode 0x%lx is in icache.", mft_no);
+			/* The inode is in icache.  Check if it is dirty. */
+			ni = NTFS_I(vi);
+			if (!NInoDirty(ni)) {
+				/* The inode is not dirty, skip this record. */
+				ntfs_debug("Inode 0x%lx is not dirty, "
+						"continuing search.", mft_no);
+				iput(vi);
+				continue;
+			}
+			ntfs_debug("Inode 0x%lx is dirty, aborting search.",
+					mft_no);
+			/* The inode is dirty, no need to search further. */
+			iput(vi);
+			is_dirty = TRUE;
+			break;
+		}
+		ntfs_debug("Inode 0x%lx is not in icache.", mft_no);
+		/* The inode is not in icache. */
+		/* Skip the record if it is not a mft record (type "FILE"). */
+		if (!ntfs_is_mft_recordp(maddr)) {
+			ntfs_debug("Mft record 0x%lx is not a FILE record, "
+					"continuing search.", mft_no);
+			continue;
+		}
+		m = (MFT_RECORD*)maddr;
+		/*
+		 * Skip the mft record if it is not in use.  FIXME:  What about
+		 * deleted/deallocated (extent) inodes?  (AIA)
+		 */
+		if (!(m->flags & MFT_RECORD_IN_USE)) {
+			ntfs_debug("Mft record 0x%lx is not in use, "
+					"continuing search.", mft_no);
+			continue;
+		}
+		/* Skip the mft record if it is a base inode. */
+		if (!m->base_mft_record) {
+			ntfs_debug("Mft record 0x%lx is a base record, "
+					"continuing search.", mft_no);
+			continue;
+		}
+		/*
+		 * This is an extent mft record.  Check if the inode
+		 * corresponding to its base mft record is in icache.
+		 */
+		na.mft_no = MREF_LE(m->base_mft_record);
+		ntfs_debug("Mft record 0x%lx is an extent record.  Looking "
+				"for base inode 0x%lx in icache.", mft_no,
+				na.mft_no);
+		vi = ilookup5(sb, na.mft_no, (test_t)ntfs_test_inode,
+				&na);
+		if (!vi) {
+			/*
+			 * The base inode is not in icache.  Skip this extent
+			 * mft record.
+			 */
+			ntfs_debug("Base inode 0x%lx is not in icache, "
+					"continuing search.", na.mft_no);
+			continue;
+		}
+		ntfs_debug("Base inode 0x%lx is in icache.", na.mft_no);
+		/*
+		 * The base inode is in icache.  Check if it has the extent
+		 * inode corresponding to this extent mft record attached.
+		 */
+		ni = NTFS_I(vi);
+		down(&ni->extent_lock);
+		if (ni->nr_extents <= 0) {
+			/*
+			 * The base inode has no attached extent inodes.  Skip
+			 * this extent mft record.
+			 */
+			up(&ni->extent_lock);
+			iput(vi);
+			continue;
+		}
+		/* Iterate over the attached extent inodes. */
+		extent_nis = ni->ext.extent_ntfs_inos;
+		for (eni = NULL, j = 0; j < ni->nr_extents; ++j) {
+			if (mft_no == extent_nis[j]->mft_no) {
+				/*
+				 * Found the extent inode corresponding to this
+				 * extent mft record.
+				 */
+				eni = extent_nis[j];
+				break;
+			}
+		}
+		/*
+		 * If the extent inode was not attached to the base inode, skip
+		 * this extent mft record.
+		 */
+		if (!eni) {
+			up(&ni->extent_lock);
+			iput(vi);
+			continue;
+		}
+		/*
+		 * Found the extent inode corrsponding to this extent mft
+		 * record.  If it is dirty, no need to search further.
+		 */
+		if (NInoDirty(eni)) {
+			up(&ni->extent_lock);
+			iput(vi);
+			is_dirty = TRUE;
+			break;
+		}
+		/* The extent inode is not dirty, so do the next record. */
+		up(&ni->extent_lock);
+		iput(vi);
+	}
+	kunmap(page);
+	/* If a dirty mft record was found, redirty the page. */
+	if (is_dirty) {
+		ntfs_debug("Inode 0x%lx is dirty.  Redirtying the page "
+				"starting at inode 0x%lx.", mft_no,
+				page->index << (PAGE_CACHE_SHIFT -
+				vol->mft_record_size_bits));
+		redirty_page_for_writepage(wbc, page);
+		unlock_page(page);
+	} else {
+		/*
+		 * Keep the VM happy.  This must be done otherwise the
+		 * radix-tree tag PAGECACHE_TAG_DIRTY remains set even though
+		 * the page is clean.
+		 */
+		BUG_ON(PageWriteback(page));
+		set_page_writeback(page);
+		unlock_page(page);
+		end_page_writeback(page);
+	}
+	ntfs_debug("Done.");
+	return 0;
+}
+
+#endif /* NTFS_RW */
--- diff/fs/ntfs/mft.h	2004-06-11 19:17:32.000000000 +0100
+++ source/fs/ntfs/mft.h	2004-06-11 19:22:05.000000000 +0100
@@ -57,6 +57,60 @@
 	flush_dcache_page(ni->page);
 }
 
+extern void __mark_mft_record_dirty(ntfs_inode *ni);
+
+/**
+ * mark_mft_record_dirty - set the mft record and the page containing it dirty
+ * @ni:		ntfs inode describing the mapped mft record
+ *
+ * Set the mapped (extent) mft record of the (base or extent) ntfs inode @ni,
+ * as well as the page containing the mft record, dirty.  Also, mark the base
+ * vfs inode dirty.  This ensures that any changes to the mft record are
+ * written out to disk.
+ *
+ * NOTE:  Do not do anything if the mft record is already marked dirty.
+ */
+static inline void mark_mft_record_dirty(ntfs_inode *ni)
+{
+	if (!NInoTestSetDirty(ni))
+		__mark_mft_record_dirty(ni);
+}
+
+extern int write_mft_record_nolock(ntfs_inode *ni, MFT_RECORD *m, int sync);
+
+/**
+ * write_mft_record - write out a mapped (extent) mft record
+ * @ni:		ntfs inode describing the mapped (extent) mft record
+ * @m:		mapped (extent) mft record to write
+ * @sync:	if true, wait for i/o completion
+ *
+ * This is just a wrapper for write_mft_record_nolock() (see mft.c), which
+ * locks the page for the duration of the write.  This ensures that there are
+ * no race conditions between writing the mft record via the dirty inode code
+ * paths and via the page cache write back code paths or between writing
+ * neighbouring mft records residing in the same page.
+ *
+ * Locking the page also serializes us against ->readpage() if the page is not
+ * uptodate.
+ *
+ * On success, clean the mft record and return 0.  On error, leave the mft
+ * record dirty and return -errno.  The caller should call make_bad_inode() on
+ * the base inode to ensure no more access happens to this inode.  We do not do
+ * it here as the caller may want to finish writing other extent mft records
+ * first to minimize on-disk metadata inconsistencies.
+ */
+static inline int write_mft_record(ntfs_inode *ni, MFT_RECORD *m, int sync)
+{
+	struct page *page = ni->page;
+	int err;
+
+	BUG_ON(!page);
+	lock_page(page);
+	err = write_mft_record_nolock(ni, m, sync);
+	unlock_page(page);
+	return err;
+}
+
 #endif /* NTFS_RW */
 
 #endif /* _LINUX_NTFS_MFT_H */
--- diff/fs/ntfs/super.c	2004-06-11 19:17:32.000000000 +0100
+++ source/fs/ntfs/super.c	2004-06-11 19:22:05.000000000 +0100
@@ -291,6 +291,101 @@
 	return FALSE;
 }
 
+#ifdef NTFS_RW
+
+/**
+ * ntfs_write_volume_flags - write new flags to the volume information flags
+ * @vol:	ntfs volume on which to modify the flags
+ * @flags:	new flags value for the volume information flags
+ *
+ * Internal function.  You probably want to use ntfs_{set,clear}_volume_flags()
+ * instead (see below).
+ *
+ * Replace the volume information flags on the volume @vol with the value
+ * supplied in @flags.  Note, this overwrites the volume information flags, so
+ * make sure to combine the flags you want to modify with the old flags and use
+ * the result when calling ntfs_write_volume_flags().
+ *
+ * Return 0 on success and -errno on error.
+ */
+static int ntfs_write_volume_flags(ntfs_volume *vol, const VOLUME_FLAGS flags)
+{
+	ntfs_inode *ni = NTFS_I(vol->vol_ino);
+	MFT_RECORD *m;
+	VOLUME_INFORMATION *vi;
+	attr_search_context *ctx;
+	int err;
+
+	ntfs_debug("Entering, old flags = 0x%x, new flags = 0x%x.",
+			vol->vol_flags, flags);
+	if (vol->vol_flags == flags)
+		goto done;
+	BUG_ON(!ni);
+	m = map_mft_record(ni);
+	if (IS_ERR(m)) {
+		err = PTR_ERR(m);
+		goto err_out;
+	}
+	ctx = get_attr_search_ctx(ni, m);
+	if (!ctx) {
+		err = -ENOMEM;
+		goto put_unm_err_out;
+	}
+	if (!lookup_attr(AT_VOLUME_INFORMATION, NULL, 0, 0, 0, NULL, 0, ctx)) {
+		err = -EIO;
+		goto put_unm_err_out;
+	}
+	vi = (VOLUME_INFORMATION*)((u8*)ctx->attr +
+			le16_to_cpu(ctx->attr->data.resident.value_offset));
+	vol->vol_flags = vi->flags = flags;
+	flush_dcache_mft_record_page(ctx->ntfs_ino);
+	mark_mft_record_dirty(ctx->ntfs_ino);
+	put_attr_search_ctx(ctx);
+	unmap_mft_record(ni);
+done:
+	ntfs_debug("Done.");
+	return 0;
+put_unm_err_out:
+	if (ctx)
+		put_attr_search_ctx(ctx);
+	unmap_mft_record(ni);
+err_out:
+	ntfs_error(vol->sb, "Failed with error code %i.", -err);
+	return err;
+}
+
+/**
+ * ntfs_set_volume_flags - set bits in the volume information flags
+ * @vol:	ntfs volume on which to modify the flags
+ * @flags:	flags to set on the volume
+ *
+ * Set the bits in @flags in the volume information flags on the volume @vol.
+ *
+ * Return 0 on success and -errno on error.
+ */
+static inline int ntfs_set_volume_flags(ntfs_volume *vol, VOLUME_FLAGS flags)
+{
+	flags &= VOLUME_FLAGS_MASK;
+	return ntfs_write_volume_flags(vol, vol->vol_flags | flags);
+}
+
+/**
+ * ntfs_clear_volume_flags - clear bits in the volume information flags
+ * @vol:	ntfs volume on which to modify the flags
+ * @flags:	flags to clear on the volume
+ *
+ * Clear the bits in @flags in the volume information flags on the volume @vol.
+ *
+ * Return 0 on success and -errno on error.
+ */
+static inline int ntfs_clear_volume_flags(ntfs_volume *vol, VOLUME_FLAGS flags)
+{
+	flags &= VOLUME_FLAGS_MASK;
+	return ntfs_write_volume_flags(vol, vol->vol_flags & ~flags);
+}
+
+#endif /* NTFS_RW */
+
 /**
  * ntfs_remount - change the mount options of a mounted ntfs filesystem
  * @sb:		superblock of mounted ntfs filesystem
@@ -316,30 +411,72 @@
 	 * For the read-write compiled driver, if we are remounting read-write,
 	 * make sure there are no volume errors and that no unsupported volume
 	 * flags are set.  Also, empty the logfile journal as it would become
-	 * stale as soon as something is written to the volume.
+	 * stale as soon as something is written to the volume and mark the
+	 * volume dirty so that chkdsk is run if the volume is not umounted
+	 * cleanly.
+	 *
+	 * When remounting read-only, mark the volume clean if no volume errors
+	 * have occured.
 	 */
 	if ((sb->s_flags & MS_RDONLY) && !(*flags & MS_RDONLY)) {
 		static const char *es = ".  Cannot remount read-write.";
 
+		/* Remounting read-write. */
 		if (NVolErrors(vol)) {
 			ntfs_error(sb, "Volume has errors and is read-only%s",
 					es);
 			return -EROFS;
 		}
+		if (vol->vol_flags & VOLUME_IS_DIRTY) {
+			ntfs_error(sb, "Volume is dirty and read-only%s", es);
+			return -EROFS;
+		}
 		if (vol->vol_flags & VOLUME_MUST_MOUNT_RO_MASK) {
 			ntfs_error(sb, "Volume has unsupported flags set and "
 					"is read-only%s", es);
 			return -EROFS;
 		}
+		if (ntfs_set_volume_flags(vol, VOLUME_IS_DIRTY)) {
+			ntfs_error(sb, "Failed to set dirty bit in volume "
+					"information flags%s", es);
+			return -EROFS;
+		}
+#if 0
+		// TODO: Enable this code once we start modifying anything that
+		//	 is different between NTFS 1.2 and 3.x...
+		/* Set NT4 compatibility flag on newer NTFS version volumes. */
+		if ((vol->major_ver > 1)) {
+			if (ntfs_set_volume_flags(vol, VOLUME_MOUNTED_ON_NT4)) {
+				ntfs_error(sb, "Failed to set NT4 "
+						"compatibility flag%s", es);
+				NVolSetErrors(vol);
+				return -EROFS;
+			}
+		}
+#endif
 		if (!ntfs_empty_logfile(vol->logfile_ino)) {
 			ntfs_error(sb, "Failed to empty journal $LogFile%s",
 					es);
 			NVolSetErrors(vol);
 			return -EROFS;
 		}
+	} else if (!(sb->s_flags & MS_RDONLY) && (*flags & MS_RDONLY)) {
+		/* Remounting read-only. */
+		if (!NVolErrors(vol)) {
+			if (ntfs_clear_volume_flags(vol, VOLUME_IS_DIRTY))
+				ntfs_warning(sb, "Failed to clear dirty bit "
+						"in volume information "
+						"flags.  Run chkdsk.");
+		}
 	}
 	// TODO:  For now we enforce no atime and dir atime updates as they are
 	// not implemented.
+	if ((sb->s_flags & MS_NOATIME) && !(*flags & MS_NOATIME))
+		ntfs_warning(sb, "Atime updates are not implemented yet.  "
+				"Leaving them disabled.");
+	else if ((sb->s_flags & MS_NODIRATIME) && !(*flags & MS_NODIRATIME))
+		ntfs_warning(sb, "Directory atime updates are not implemented "
+				"yet.  Leaving them disabled.");
 	*flags |= MS_NOATIME | MS_NODIRATIME;
 #endif /* ! NTFS_RW */
 
@@ -1131,7 +1268,7 @@
 			le32_to_cpu(ctx->attr->data.resident.value_length) >
 			(u8*)ctx->attr + le32_to_cpu(ctx->attr->length))
 		goto err_put_vol;
-	/* Setup volume flags and version. */
+	/* Copy the volume flags and version to the ntfs_volume structure. */
 	vol->vol_flags = vi->flags;
 	vol->major_ver = vi->major_ver;
 	vol->minor_ver = vi->minor_ver;
@@ -1142,9 +1279,12 @@
 #ifdef NTFS_RW
 	/* Make sure that no unsupported volume flags are set. */
 	if (vol->vol_flags & VOLUME_MUST_MOUNT_RO_MASK) {
-		static const char *es1 = "Volume has unsupported flags set";
+		static const char *es1a = "Volume is dirty";
+		static const char *es1b = "Volume has unsupported flags set";
 		static const char *es2 = ".  Run chkdsk and mount in Windows.";
-
+		const char *es1;
+		
+		es1 = vol->vol_flags & VOLUME_IS_DIRTY ? es1a : es1b;
 		/* If a read-write mount, convert it to a read-only mount. */
 		if (!(sb->s_flags & MS_RDONLY)) {
 			if (!(vol->on_errors & (ON_ERRORS_REMOUNT_RO |
@@ -1171,10 +1311,12 @@
 	 */
 	if (!load_and_check_logfile(vol) ||
 			!ntfs_is_logfile_clean(vol->logfile_ino)) {
-		static const char *es1 = "Failed to load $LogFile";
-		static const char *es2 = "$LogFile is not clean";
-		static const char *es3 = ".  Mount in Windows.";
+		static const char *es1a = "Failed to load $LogFile";
+		static const char *es1b = "$LogFile is not clean";
+		static const char *es2 = ".  Mount in Windows.";
+		const char *es1;
 
+		es1 = !vol->logfile_ino ? es1a : es1b;
 		/* If a read-write mount, convert it to a read-only mount. */
 		if (!(sb->s_flags & MS_RDONLY)) {
 			if (!(vol->on_errors & (ON_ERRORS_REMOUNT_RO |
@@ -1182,21 +1324,66 @@
 				ntfs_error(sb, "%s and neither on_errors="
 						"continue nor on_errors="
 						"remount-ro was specified%s",
-						!vol->logfile_ino ? es1 : es2,
-						es3);
+						es1, es2);
 				goto iput_logfile_err_out;
 			}
 			sb->s_flags |= MS_RDONLY | MS_NOATIME | MS_NODIRATIME;
-			ntfs_error(sb, "%s.  Mounting read-only%s",
-					!vol->logfile_ino ? es1 : es2, es3);
+			ntfs_error(sb, "%s.  Mounting read-only%s", es1, es2);
 		} else
 			ntfs_warning(sb, "%s.  Will not be able to remount "
-					"read-write%s",
-					!vol->logfile_ino ? es1 : es2, es3);
+					"read-write%s", es1, es2);
 		/* This will prevent a read-write remount. */
 		NVolSetErrors(vol);
-	/* If a read-write mount, empty the logfile. */
-	} else if (!(sb->s_flags & MS_RDONLY) &&
+	}
+	/* If (still) a read-write mount, mark the volume dirty. */
+	if (!(sb->s_flags & MS_RDONLY) &&
+			ntfs_set_volume_flags(vol, VOLUME_IS_DIRTY)) {
+		static const char *es1 = "Failed to set dirty bit in volume "
+				"information flags";
+		static const char *es2 = ".  Run chkdsk.";
+
+		/* Convert to a read-only mount. */
+		if (!(vol->on_errors & (ON_ERRORS_REMOUNT_RO |
+				ON_ERRORS_CONTINUE))) {
+			ntfs_error(sb, "%s and neither on_errors=continue nor "
+					"on_errors=remount-ro was specified%s",
+					es1, es2);
+			goto iput_logfile_err_out;
+		}
+		ntfs_error(sb, "%s.  Mounting read-only%s", es1, es2);
+		sb->s_flags |= MS_RDONLY | MS_NOATIME | MS_NODIRATIME;
+		/*
+		 * Do not set NVolErrors() because ntfs_remount() might manage
+		 * to set the dirty flag in which case all would be well.
+		 */
+	}
+#if 0
+	// TODO: Enable this code once we start modifying anything that is
+	//	 different between NTFS 1.2 and 3.x...
+	/*
+	 * If (still) a read-write mount, set the NT4 compatibility flag on
+	 * newer NTFS version volumes.
+	 */
+	if (!(sb->s_flags & MS_RDONLY) && (vol->major_ver > 1) &&
+			ntfs_set_volume_flags(vol, VOLUME_MOUNTED_ON_NT4)) {
+		static const char *es1 = "Failed to set NT4 compatibility flag";
+		static const char *es2 = ".  Run chkdsk.";
+
+		/* Convert to a read-only mount. */
+		if (!(vol->on_errors & (ON_ERRORS_REMOUNT_RO |
+				ON_ERRORS_CONTINUE))) {
+			ntfs_error(sb, "%s and neither on_errors=continue nor "
+					"on_errors=remount-ro was specified%s",
+					es1, es2);
+			goto iput_logfile_err_out;
+		}
+		ntfs_error(sb, "%s.  Mounting read-only%s", es1, es2);
+		sb->s_flags |= MS_RDONLY | MS_NOATIME | MS_NODIRATIME;
+		NVolSetErrors(vol);
+	}
+#endif
+	/* If (still) a read-write mount, empty the logfile. */
+	if (!(sb->s_flags & MS_RDONLY) &&
 			!ntfs_empty_logfile(vol->logfile_ino)) {
 		static const char *es1 = "Failed to empty $LogFile";
 		static const char *es2 = ".  Mount in Windows.";
@@ -1209,12 +1396,11 @@
 					es1, es2);
 			goto iput_logfile_err_out;
 		}
-		sb->s_flags |= MS_RDONLY | MS_NOATIME | MS_NODIRATIME;
 		ntfs_error(sb, "%s.  Mounting read-only%s", es1, es2);
-		/* This will prevent a read-write remount. */
+		sb->s_flags |= MS_RDONLY | MS_NOATIME | MS_NODIRATIME;
 		NVolSetErrors(vol);
 	}
-#endif
+#endif /* NTFS_RW */
 	/*
 	 * Get the inode for the attribute definitions file and parse the
 	 * attribute definitions.
@@ -1289,18 +1475,69 @@
 
 /**
  * ntfs_put_super - called by the vfs to unmount a volume
- * @vfs_sb:	vfs superblock of volume to unmount
+ * @sb:		vfs superblock of volume to unmount
  *
  * ntfs_put_super() is called by the VFS (from fs/super.c::do_umount()) when
  * the volume is being unmounted (umount system call has been invoked) and it
  * releases all inodes and memory belonging to the NTFS specific part of the
  * super block.
  */
-static void ntfs_put_super(struct super_block *vfs_sb)
+static void ntfs_put_super(struct super_block *sb)
 {
-	ntfs_volume *vol = NTFS_SB(vfs_sb);
+	ntfs_volume *vol = NTFS_SB(sb);
 
 	ntfs_debug("Entering.");
+#ifdef NTFS_RW
+	/*
+	 * Commit all inodes while they are still open in case some of them
+	 * cause others to be dirtied.
+	 */
+	ntfs_commit_inode(vol->vol_ino);
+
+	/* NTFS 3.0+ specific. */
+	if (vol->major_ver >= 3) {
+		if (vol->secure_ino)
+			ntfs_commit_inode(vol->secure_ino);
+	}
+
+	ntfs_commit_inode(vol->root_ino);
+
+	down_write(&vol->lcnbmp_lock);
+	ntfs_commit_inode(vol->lcnbmp_ino);
+	up_write(&vol->lcnbmp_lock);
+
+	down_write(&vol->mftbmp_lock);
+	ntfs_commit_inode(vol->mftbmp_ino);
+	up_write(&vol->mftbmp_lock);
+
+	if (vol->logfile_ino)
+		ntfs_commit_inode(vol->logfile_ino);
+
+	if (vol->mftmirr_ino)
+		ntfs_commit_inode(vol->mftmirr_ino);
+	ntfs_commit_inode(vol->mft_ino);
+
+	/*
+	 * If a read-write mount and no volume errors have occured, mark the
+	 * volume clean.  Also, re-commit all affected inodes.
+	 */
+	if (!(sb->s_flags & MS_RDONLY)) {
+		if (!NVolErrors(vol)) {
+			if (ntfs_clear_volume_flags(vol, VOLUME_IS_DIRTY))
+				ntfs_warning(sb, "Failed to clear dirty bit "
+						"in volume information "
+						"flags.  Run chkdsk.");
+			ntfs_commit_inode(vol->vol_ino);
+			ntfs_commit_inode(vol->root_ino);
+			if (vol->mftmirr_ino)
+				ntfs_commit_inode(vol->mftmirr_ino);
+			ntfs_commit_inode(vol->mft_ino);
+		} else {
+			ntfs_warning(sb, "Volume has errors.  Leaving volume "
+					"marked dirty.  Run chkdsk.");
+		}
+	}
+#endif /* NTFS_RW */
 
 	iput(vol->vol_ino);
 	vol->vol_ino = NULL;
@@ -1331,11 +1568,47 @@
 		iput(vol->logfile_ino);
 		vol->logfile_ino = NULL;
 	}
-
 	if (vol->mftmirr_ino) {
+		/* Re-commit the mft mirror and mft just in case. */
+		ntfs_commit_inode(vol->mftmirr_ino);
+		ntfs_commit_inode(vol->mft_ino);
 		iput(vol->mftmirr_ino);
 		vol->mftmirr_ino = NULL;
 	}
+	/*
+	 * If any dirty inodes are left, throw away all mft data page cache
+	 * pages to allow a clean umount.  This should never happen any more
+	 * due to mft.c::ntfs_mft_writepage() cleaning all the dirty pages as
+	 * the underlying mft records are written out and cleaned.  If it does,
+	 * happen anyway, we want to know...
+	 */
+	ntfs_commit_inode(vol->mft_ino);
+	write_inode_now(vol->mft_ino, 1);
+	if (!list_empty(&sb->s_dirty)) {
+		const char *s1, *s2;
+
+		down(&vol->mft_ino->i_sem);
+		truncate_inode_pages(vol->mft_ino->i_mapping, 0);
+		up(&vol->mft_ino->i_sem);
+		write_inode_now(vol->mft_ino, 1);
+		if (!list_empty(&sb->s_dirty)) {
+			static const char *_s1 = "inodes";
+			static const char *_s2 = "";
+			s1 = _s1;
+			s2 = _s2;
+		} else {
+			static const char *_s1 = "mft pages";
+			static const char *_s2 = "They have been thrown "
+					"away.  ";
+			s1 = _s1;
+			s2 = _s2;
+		}
+		ntfs_error(sb, "Dirty %s found at umount time.  %sYou should "
+				"run chkdsk.  Please email "
+				"linux-ntfs-dev@lists.sourceforge.net and say "
+				"that you saw this message.  Thank you.", s1,
+				s2);
+	}
 #endif /* NTFS_RW */
 
 	iput(vol->mft_ino);
@@ -1344,7 +1617,7 @@
 	vol->upcase_len = 0;
 	/*
 	 * Decrease the number of mounts and destroy the global default upcase
-	 * table if necessary. Also decrease the number of upcase users if we
+	 * table if necessary.  Also decrease the number of upcase users if we
 	 * are a user.
 	 */
 	down(&ntfs_lock);
@@ -1368,7 +1641,7 @@
 		unload_nls(vol->nls_map);
 		vol->nls_map = NULL;
 	}
-	vfs_sb->s_fs_info = NULL;
+	sb->s_fs_info = NULL;
 	kfree(vol);
 	return;
 }
@@ -1629,8 +1902,8 @@
 #ifdef NTFS_RW
 	//.dirty_inode	= NULL,			/* VFS: Called from
 	//					   __mark_inode_dirty(). */
-	//.write_inode	= NULL,			/* VFS: Write dirty inode to
-	//					   disk. */
+	.write_inode	= ntfs_write_inode,	/* VFS: Write dirty inode to
+						   disk. */
 	//.drop_inode	= NULL,			/* VFS: Called just after the
 	//					   inode reference count has
 	//					   been decreased to zero.
@@ -1719,8 +1992,12 @@
 #ifndef NTFS_RW
 	sb->s_flags |= MS_RDONLY | MS_NOATIME | MS_NODIRATIME;
 #else
-	// TODO:  For now we enforce no atime and dir atime updates as they are
-	// not implemented.
+	if (!(sb->s_flags & MS_NOATIME))
+		ntfs_warning(sb, "Atime updates are not implemented yet.  "
+				"Disabling them.");
+	else if (!(sb->s_flags & MS_NODIRATIME))
+		ntfs_warning(sb, "Directory atime updates are not implemented "
+				"yet.  Disabling them.");
 	sb->s_flags |= MS_NOATIME | MS_NODIRATIME;
 #endif
 	/* Allocate a new ntfs_volume and place it in sb->s_fs_info. */
--- diff/fs/partitions/Kconfig	2004-05-19 22:12:31.000000000 +0100
+++ source/fs/partitions/Kconfig	2004-06-11 19:22:06.000000000 +0100
@@ -187,13 +187,6 @@
 
 	  If unsure, say N.
 
-config NEC98_PARTITION
-	bool "NEC PC-9800 partition table support" if PARTITION_ADVANCED
-	default y if !PARTITION_ADVANCED && X86_PC9800
-	help
-	  Say Y here if you would like to be able to read the hard disk
-	  partition table format used by NEC PC-9800 machines.
-
 config SGI_PARTITION
 	bool "SGI partition support" if PARTITION_ADVANCED
 	default y if !PARTITION_ADVANCED && (SGI_IP22 || SGI_IP27)
--- diff/fs/partitions/check.c	2004-06-11 19:17:32.000000000 +0100
+++ source/fs/partitions/check.c	2004-06-11 19:22:05.000000000 +0100
@@ -29,7 +29,6 @@
 #include "ldm.h"
 #include "mac.h"
 #include "msdos.h"
-#include "nec98.h"
 #include "osf.h"
 #include "sgi.h"
 #include "sun.h"
--- diff/fs/proc/generic.c	2004-05-19 22:12:31.000000000 +0100
+++ source/fs/proc/generic.c	2004-06-11 19:22:06.000000000 +0100
@@ -288,18 +288,20 @@
  */
 static unsigned int get_inode_number(void)
 {
-	unsigned int i, inum = 0;
+	int i, inum = 0;
+	int error;
 
 retry:
 	if (idr_pre_get(&proc_inum_idr, GFP_KERNEL) == 0)
 		return 0;
 
 	spin_lock(&proc_inum_lock);
-	i = idr_get_new(&proc_inum_idr, NULL);
+	error = idr_get_new(&proc_inum_idr, NULL, &i);
 	spin_unlock(&proc_inum_lock);
-
-	if (i == -1)
+	if (error == -EAGAIN)
 		goto retry;
+	else if (error)
+		return 0;
 
 	inum = (i & MAX_ID_MASK) + PROC_DYNAMIC_FIRST;
 
@@ -319,21 +321,14 @@
 	spin_unlock(&proc_inum_lock);
 }
 
-static int
-proc_readlink(struct dentry *dentry, char __user *buffer, int buflen)
-{
-	char *s = PDE(dentry->d_inode)->data;
-	return vfs_readlink(dentry, buffer, buflen, s);
-}
-
 static int proc_follow_link(struct dentry *dentry, struct nameidata *nd)
 {
-	char *s = PDE(dentry->d_inode)->data;
-	return vfs_follow_link(nd, s);
+	nd_set_link(nd, PDE(dentry->d_inode)->data);
+	return 0;
 }
 
 static struct inode_operations proc_link_inode_operations = {
-	.readlink	= proc_readlink,
+	.readlink	= generic_readlink,
 	.follow_link	= proc_follow_link,
 };
 
--- diff/fs/proc/kcore.c	2004-06-11 19:17:32.000000000 +0100
+++ source/fs/proc/kcore.c	2004-06-11 19:22:06.000000000 +0100
@@ -18,6 +18,7 @@
 #include <linux/elfcore.h>
 #include <linux/vmalloc.h>
 #include <linux/highmem.h>
+#include <linux/init.h>
 #include <asm/uaccess.h>
 #include <asm/io.h>
 
@@ -84,8 +85,6 @@
 	return 0;
 }
 
-extern char saved_command_line[];
-
 static size_t get_kcore_size(int *nphdr, size_t *elf_buflen)
 {
 	size_t try, size;
--- diff/fs/proc/proc_misc.c	2004-06-11 19:17:32.000000000 +0100
+++ source/fs/proc/proc_misc.c	2004-06-11 19:22:06.000000000 +0100
@@ -47,7 +47,6 @@
 #include <asm/uaccess.h>
 #include <asm/pgtable.h>
 #include <asm/io.h>
-#include <asm/pgalloc.h>
 #include <asm/tlb.h>
 #include <asm/div64.h>
 
@@ -286,6 +285,10 @@
 	.release	= seq_release,
 };
 
+#ifdef CONFIG_SCHEDSTATS
+extern struct file_operations proc_schedstat_operations;
+#endif
+
 #ifdef CONFIG_PROC_HARDWARE
 static int hardware_read_proc(char *page, char **start, off_t off,
 				 int count, int *eof, void *data)
@@ -522,7 +525,6 @@
 static int cmdline_read_proc(char *page, char **start, off_t off,
 				 int count, int *eof, void *data)
 {
-	extern char saved_command_line[];
 	int len;
 
 	len = sprintf(page, "%s\n", saved_command_line);
@@ -651,6 +653,36 @@
 		entry->proc_fops = f;
 }
 
+#ifdef CONFIG_LOCKMETER
+extern ssize_t get_lockmeter_info(char *, size_t, loff_t *);
+extern ssize_t put_lockmeter_info(const char *, size_t);
+extern int get_lockmeter_info_size(void);
+
+/*
+ * This function accesses lock metering information.
+ */
+static ssize_t read_lockmeter(struct file *file, char *buf,
+			      size_t count, loff_t *ppos)
+{
+	return get_lockmeter_info(buf, count, ppos);
+}
+
+/*
+ * Writing to /proc/lockmeter resets the counters
+ */
+static ssize_t write_lockmeter(struct file * file, const char * buf,
+			       size_t count, loff_t *ppos)
+{
+	return put_lockmeter_info(buf, count);
+}
+
+static struct file_operations proc_lockmeter_operations = {
+	NULL,           /* lseek */
+	read:		read_lockmeter,
+	write:		write_lockmeter,
+};
+#endif  /* CONFIG_LOCKMETER */
+
 void __init proc_misc_init(void)
 {
 	struct proc_dir_entry *entry;
@@ -698,6 +730,9 @@
 #ifdef CONFIG_MODULES
 	create_seq_entry("modules", 0, &proc_modules_operations);
 #endif
+#ifdef CONFIG_SCHEDSTATS
+	create_seq_entry("schedstat", 0, &proc_schedstat_operations);
+#endif
 #ifdef CONFIG_PROC_KCORE
 	proc_root_kcore = create_proc_entry("kcore", S_IRUSR, NULL);
 	if (proc_root_kcore) {
@@ -718,6 +753,13 @@
 	if (entry)
 		entry->proc_fops = &proc_sysrq_trigger_operations;
 #endif
+#ifdef CONFIG_LOCKMETER
+	entry = create_proc_entry("lockmeter", S_IWUSR | S_IRUGO, NULL);
+	if (entry) {
+		entry->proc_fops = &proc_lockmeter_operations;
+		entry->size = get_lockmeter_info_size();
+	}
+#endif
 #ifdef CONFIG_PPC32
 	{
 		extern struct file_operations ppc_htab_operations;
--- diff/fs/reiserfs/bitmap.c	2004-06-11 19:17:32.000000000 +0100
+++ source/fs/reiserfs/bitmap.c	2004-06-11 19:22:06.000000000 +0100
@@ -30,6 +30,9 @@
 #define  _ALLOC_hashed_formatted_nodes 7
 #define  _ALLOC_old_way 8
 #define  _ALLOC_hundredth_slices 9
+#define  _ALLOC_dirid_groups 10
+#define  _ALLOC_oid_groups 11
+#define  _ALLOC_packing_groups 12
 
 #define  concentrating_formatted_nodes(s)	test_bit(_ALLOC_concentrating_formatted_nodes, &SB_ALLOC_OPTS(s))
 #define  displacing_large_files(s)		test_bit(_ALLOC_displacing_large_files, &SB_ALLOC_OPTS(s))
@@ -150,11 +153,6 @@
        __wait_on_buffer (bi->bh);
     }
 
-    /* If we know that first zero bit is only one or first zero bit is
-       closer to the end of bitmap than our start pointer */
-    if (bi->first_zero_hint > *beg || bi->free_count == 1)
-	*beg = bi->first_zero_hint;
-
     while (1) {
 	cont:
 	if (bi->free_count < min)
@@ -204,21 +202,12 @@
 		    while (--i >= *beg)
 			reiserfs_test_and_clear_le_bit (i, bi->bh->b_data);
 		    reiserfs_restore_prepared_buffer (s, bi->bh);
-		    *beg = max(org, (int)bi->first_zero_hint);
+		    *beg = org;
 		    /* ... and search again in current block from beginning */
 		    goto cont;	
 		}
 	    }
 	    bi->free_count -= (end - *beg);
-
-	    /* if search started from zero_hint bit, and zero hint have not
-                changed since, then we need to update first_zero_hint */
-	    if ( bi->first_zero_hint >= *beg)
-		/* no point in looking for free bit if there is not any */
-		bi->first_zero_hint = (bi->free_count > 0 ) ?
-			reiserfs_find_next_zero_le_bit
-			((unsigned long*)(bi->bh->b_data), s->s_blocksize << 3, end) : (s->s_blocksize << 3);
-
 	    journal_mark_dirty (th, s, bi->bh);
 
 	    /* free block count calculation */
@@ -231,7 +220,57 @@
 	    *beg = next;
 	}
     }
-  }
+}
+
+static int bmap_hash_id(struct super_block *s, u32 id) {
+    char * hash_in = NULL;
+    unsigned long hash;
+    unsigned bm;
+
+    if (id <= 2) {
+	bm = 1;
+    } else {
+        hash_in = (char *)(&id);
+        hash = keyed_hash(hash_in, 4);
+	bm = hash % SB_BMAP_NR(s);
+	if (!bm)
+	    bm = 1;
+    }
+    return bm;
+}
+
+/*
+ * hashes the id and then returns > 0 if the block group for the
+ * corresponding hash is full
+ */
+static inline int block_group_used(struct super_block *s, u32 id) {
+    int bm;
+    bm = bmap_hash_id(s, id);
+    if (SB_AP_BITMAP(s)[bm].free_count > ((s->s_blocksize << 3) * 60 / 100) ) {
+        return 0;
+    }
+    return 1;
+}
+
+/*
+ * the packing is returned in disk byte order
+ */
+u32 reiserfs_choose_packing(struct inode *dir) {
+    u32 packing;
+    if (TEST_OPTION(packing_groups, dir->i_sb)) {
+	u32 parent_dir = le32_to_cpu(INODE_PKEY(dir)->k_dir_id);
+	/*
+	 * some versions of reiserfsck expect packing locality 1 to be
+	 * special
+	 */
+	if (parent_dir == 1 || block_group_used(dir->i_sb,parent_dir))
+            packing = INODE_PKEY(dir)->k_objectid;
+        else
+            packing = INODE_PKEY(dir)->k_dir_id;
+    } else
+        packing = INODE_PKEY(dir)->k_objectid;
+    return packing;
+}
   
 /* Tries to find contiguous zero bit window (given size) in given region of
  * bitmap and place new blocks there. Returns number of allocated blocks. */
@@ -255,8 +294,18 @@
     get_bit_address (s, *start, &bm, &off);
     get_bit_address (s, finish, &end_bm, &end_off);
 
-    // With this option set first we try to find a bitmap that is at least 10%
-    // free, and if that fails, then we fall back to old whole bitmap scanning
+    /* When the bitmap is more than 10% free, anyone can allocate.
+     * When it's less than 10% free, only files that already use the
+     * bitmap are allowed. Once we pass 80% full, this restriction
+     * is lifted.
+     *
+     * We do this so that files that grow later still have space close to
+     * their original allocation. This improves locality, and presumably
+     * performance as a result.
+     *
+     * This is only an allocation policy and does not make up for getting a
+     * bad hint. Decent hinting must be implemented for this to work well.
+     */
     if ( TEST_OPTION(skip_busy, s) && SB_FREE_BLOCKS(s) > SB_BLOCK_COUNT(s)/20 ) {
 	for (;bm < end_bm; bm++, off = 0) {
 	    if ( ( off && (!unfm || (file_block != 0))) || SB_AP_BITMAP(s)[bm].free_count > (s->s_blocksize << 3) / 10 )
@@ -314,9 +363,6 @@
 			  "free_block (%s:%lu)[dev:blocknr]: bit already cleared",
 			  reiserfs_bdevname (s), block);
     }
-    if (offset < apbi[nr].first_zero_hint) {
-      apbi[nr].first_zero_hint = offset;
-    }
     apbi[nr].free_count ++;
     journal_mark_dirty (th, s, apbi[nr].bh);
 
@@ -396,6 +442,14 @@
 	__discard_prealloc(th, ei);
     }
 }
+
+void reiserfs_init_alloc_options (struct super_block *s)
+{
+    set_bit (_ALLOC_skip_busy, &SB_ALLOC_OPTS(s));
+    set_bit (_ALLOC_dirid_groups, &SB_ALLOC_OPTS(s));
+    set_bit (_ALLOC_packing_groups, &SB_ALLOC_OPTS(s));
+}
+
 /* block allocator related options are parsed here */
 int reiserfs_parse_alloc_options(struct super_block * s, char * options)
 {
@@ -439,6 +493,18 @@
 	    continue;
 	}
 
+        if (!strcmp(this_char, "dirid_groups")) {
+	    SET_OPTION(dirid_groups);
+	    continue;
+        }
+        if (!strcmp(this_char, "oid_groups")) {
+	    SET_OPTION(oid_groups);
+	    continue;
+        }
+        if (!strcmp(this_char, "packing_groups")) {
+	    SET_OPTION(packing_groups);
+	    continue;
+        }
 	if (!strcmp(this_char, "hashed_formatted_nodes")) {
 	    SET_OPTION(hashed_formatted_nodes);
 	    continue;
@@ -481,6 +547,7 @@
 	return 1;
       }
   
+    reiserfs_warning (s, "allocator options = [%08x]\n", SB_ALLOC_OPTS(s));
     return 0;
 }
   
@@ -503,17 +570,76 @@
     hint->search_start = hint->beg + keyed_hash(hash_in, 4) % (hint->end - hint->beg);
 }
 
-static inline void get_left_neighbor(reiserfs_blocknr_hint_t *hint)
+/*
+ * Relocation based on dirid, hashing them into a given bitmap block
+ * files. Formatted nodes are unaffected, a seperate policy covers them
+ */
+static void
+dirid_groups (reiserfs_blocknr_hint_t *hint)
+{
+    unsigned long hash;
+    __u32 dirid = 0;
+    int bm = 0;
+    struct super_block *sb = hint->th->t_super;
+    if (hint->inode)
+	dirid = le32_to_cpu(INODE_PKEY(hint->inode)->k_dir_id);
+    else if (hint->formatted_node)
+        dirid = hint->key.k_dir_id;
+
+    if (dirid) {
+	bm = bmap_hash_id(sb, dirid);
+	hash = bm * (sb->s_blocksize << 3);
+	/* give a portion of the block group to metadata */
+	if (hint->inode)
+	    hash += sb->s_blocksize/2;
+	hint->search_start = hash;
+    }
+}
+
+/*
+ * Relocation based on oid, hashing them into a given bitmap block
+ * files. Formatted nodes are unaffected, a seperate policy covers them
+ */
+static void
+oid_groups (reiserfs_blocknr_hint_t *hint)
+{
+    if (hint->inode) {
+	unsigned long hash;
+	__u32 oid;
+	__u32 dirid;
+	int bm;
+
+	dirid = le32_to_cpu(INODE_PKEY(hint->inode)->k_dir_id);
+
+	/* keep the root dir and it's first set of subdirs close to
+	 * the start of the disk
+	 */
+	if (dirid <= 2)
+	    hash = (hint->inode->i_sb->s_blocksize << 3);
+	else {
+	    oid = le32_to_cpu(INODE_PKEY(hint->inode)->k_objectid);
+	    bm = bmap_hash_id(hint->inode->i_sb, oid);
+	    hash = bm * (hint->inode->i_sb->s_blocksize << 3);
+	}
+	hint->search_start = hash;
+    }
+}
+
+/* returns 1 if it finds an indirect item and gets valid hint info
+ * from it, otherwise 0
+ */
+static int get_left_neighbor(reiserfs_blocknr_hint_t *hint)
 {
     struct path * path;
     struct buffer_head * bh;
     struct item_head * ih;
     int pos_in_item;
     __u32 * item;
+    int ret = 0;
 
     if (!hint->path)		/* reiserfs code can call this function w/o pointer to path
 				 * structure supplied; then we rely on supplied search_start */
-	return;
+	return 0;
 
     path = hint->path;
     bh = get_last_bh(path);
@@ -534,15 +660,15 @@
 	    int t=get_block_num(item,pos_in_item);
 	    if (t) {
 		hint->search_start = t;
+		ret = 1;
 		break;
 	    }
 	    pos_in_item --;
 	}
-    } else {
-      }
+    }
 
     /* does result value fit into specified region? */
-    return;
+    return ret;
 }
 
 /* should be, if formatted node, then try to put on first part of the device
@@ -639,10 +765,12 @@
     }
 }
   
-static inline void determine_search_start(reiserfs_blocknr_hint_t *hint,
+static void determine_search_start(reiserfs_blocknr_hint_t *hint,
 					  int amount_needed)
 {
     struct super_block *s = hint->th->t_super;
+    int unfm_hint;
+
     hint->beg = 0;
     hint->end = SB_BLOCK_COUNT(s) - 1;
 
@@ -673,19 +801,14 @@
 	return;
     }
 
-    /* attempt to copy a feature from old block allocator code */
-    if (TEST_OPTION(old_hashed_relocation, s) && !hint->formatted_node) {
-	old_hashed_relocation(hint);
-    }
-
     /* if none of our special cases is relevant, use the left neighbor in the
        tree order of the new node we are allocating for */
     if (hint->formatted_node && TEST_OPTION(hashed_formatted_nodes,s)) {
-	hash_formatted_node(hint);
+        hash_formatted_node(hint);
 	return;
-    } 
+    }
 
-    get_left_neighbor(hint);
+    unfm_hint = get_left_neighbor(hint);
 
     /* Mimic old block allocator behaviour, that is if VFS allowed for preallocation,
        new blocks are displaced based on directory ID. Also, if suggested search_start
@@ -710,10 +833,36 @@
 	return;
     }
 
-    if (TEST_OPTION(old_hashed_relocation, s))
+    /* old_hashed_relocation only works on unformatted */
+    if (!unfm_hint && !hint->formatted_node &&
+        TEST_OPTION(old_hashed_relocation, s))
+    {
 	old_hashed_relocation(hint);
-    if (TEST_OPTION(new_hashed_relocation, s))
+    }
+    /* new_hashed_relocation works with both formatted/unformatted nodes */
+    if ((!unfm_hint || hint->formatted_node) &&
+        TEST_OPTION(new_hashed_relocation, s))
+    {
 	new_hashed_relocation(hint);
+    }
+    /* dirid grouping works only on unformatted nodes */
+    if (!unfm_hint && !hint->formatted_node && TEST_OPTION(dirid_groups,s))
+    {
+        dirid_groups(hint);
+    }
+
+#ifdef DISPLACE_NEW_PACKING_LOCALITIES
+    if (hint->formatted_node && TEST_OPTION(dirid_groups,s))
+    {
+        dirid_groups(hint);
+    }
+#endif
+
+    /* oid grouping works only on unformatted nodes */
+    if (!unfm_hint && !hint->formatted_node && TEST_OPTION(oid_groups,s))
+    {
+        oid_groups(hint);
+    }
     return;
 }
 
@@ -738,13 +887,14 @@
 static inline int allocate_without_wrapping_disk (reiserfs_blocknr_hint_t * hint,
 					 b_blocknr_t * new_blocknrs,
 					 b_blocknr_t start, b_blocknr_t finish,
+					 int min,
 					 int amount_needed, int prealloc_size)
 {
     int rest = amount_needed;
     int nr_allocated;
   
     while (rest > 0 && start <= finish) {
-	nr_allocated = scan_bitmap (hint->th, &start, finish, 1,
+	nr_allocated = scan_bitmap (hint->th, &start, finish, min,
 				    rest + prealloc_size, !hint->formatted_node,
 				    hint->block);
 
@@ -777,8 +927,9 @@
     struct super_block *s = hint->th->t_super;
     b_blocknr_t start = hint->search_start;
     b_blocknr_t finish = SB_BLOCK_COUNT(s) - 1;
-    int second_pass = 0;
+    int passno = 0;
     int nr_allocated = 0;
+    int bigalloc = 0;
 
     determine_prealloc_size(hint);
     if (!hint->formatted_node) {
@@ -797,32 +948,64 @@
 	    if (quota_ret)
 		hint->preallocate=hint->prealloc_size=0;
 	}
-    }
-
-    while((nr_allocated
-	  += allocate_without_wrapping_disk(hint, new_blocknrs + nr_allocated, start, finish,
-					  amount_needed - nr_allocated, hint->prealloc_size))
-	  < amount_needed) {
-
-	/* not all blocks were successfully allocated yet*/
-	if (second_pass) {	/* it was a second pass; we must free all blocks */
+	/* for unformatted nodes, force large allocations */
+	bigalloc = amount_needed + hint->prealloc_size;
+	/* try to make things even */
+	if (bigalloc & 1 && hint->prealloc_size)
+	    bigalloc--;
+    }
+
+    do {
+	/* in bigalloc mode, nr_allocated should stay zero until
+	 * the entire allocation is filled
+	 */
+	if (unlikely(bigalloc && nr_allocated)) {
+	    reiserfs_warning(s, "bigalloc is %d, nr_allocated %d\n",
+	    bigalloc, nr_allocated);
+	    /* reset things to a sane value */
+	    bigalloc = amount_needed - nr_allocated;
+	}
+	/*
+	 * try pass 0 and pass 1 looking for a nice big
+	 * contiguous allocation.  Then reset and look
+	 * for anything you can find.
+	 */
+	if (passno == 2 && bigalloc) {
+	    passno = 0;
+	    bigalloc = 0;
+	}
+	switch (passno++) {
+        case 0: /* Search from hint->search_start to end of disk */
+	    start = hint->search_start;
+	    finish = SB_BLOCK_COUNT(s) - 1;
+	    break;
+        case 1: /* Search from hint->beg to hint->search_start */
+	    start = hint->beg;
+	    finish = hint->search_start;
+	    break;
+	case 2: /* Last chance: Search from 0 to hint->beg */
+	    start = 0;
+	    finish = hint->beg;
+	    break;
+	default: /* We've tried searching everywhere, not enough space */
+	    /* Free the blocks */
 	    if (!hint->formatted_node) {
 #ifdef REISERQUOTA_DEBUG
 		reiserfs_debug (s, "reiserquota: freeing (nospace) %d blocks id=%u", amount_needed + hint->prealloc_size - nr_allocated, hint->inode->i_uid);
 #endif
 		DQUOT_FREE_BLOCK_NODIRTY(hint->inode, amount_needed + hint->prealloc_size - nr_allocated);     /* Free not allocated blocks */
 	    }
-	    while (nr_allocated --)
+  	    while (nr_allocated --)
 		reiserfs_free_block(hint->th, hint->inode, new_blocknrs[nr_allocated], !hint->formatted_node);
 
 	    return NO_DISK_SPACE;
-	} else {		/* refine search parameters for next pass */
-	    second_pass = 1;
-	    finish = start;
-	    start = 0;
-	    continue;
 	}
-    }
+    } while ((nr_allocated += allocate_without_wrapping_disk (hint,
+			    new_blocknrs + nr_allocated, start, finish,
+			    bigalloc ? bigalloc : 1,
+			    amount_needed - nr_allocated,
+			    hint->prealloc_size))
+			< amount_needed);
     if ( !hint->formatted_node &&
          amount_needed + hint->prealloc_size >
 	 nr_allocated + REISERFS_I(hint->inode)->i_prealloc_count) {
--- diff/fs/reiserfs/dir.c	2004-06-11 19:17:32.000000000 +0100
+++ source/fs/reiserfs/dir.c	2004-06-11 19:22:06.000000000 +0100
@@ -64,6 +64,7 @@
 
     /*  reiserfs_warning (inode->i_sb, "reiserfs_readdir 1: f_pos = %Ld", filp->f_pos);*/
 
+    path_to_entry.reada = PATH_READA;
     while (1) {
     research:
 	/* search the directory item, containing entry with specified key */
--- diff/fs/reiserfs/file.c	2004-06-11 19:17:32.000000000 +0100
+++ source/fs/reiserfs/file.c	2004-06-11 19:22:06.000000000 +0100
@@ -89,15 +89,16 @@
 			      ) {
   struct inode * p_s_inode = p_s_dentry->d_inode;
   int n_err;
-
-  reiserfs_write_lock(p_s_inode->i_sb);
+  int barrier_done;
 
   if (!S_ISREG(p_s_inode->i_mode))
       BUG ();
-
   n_err = sync_mapping_buffers(p_s_inode->i_mapping) ;
-  reiserfs_commit_for_inode(p_s_inode) ;
+  reiserfs_write_lock(p_s_inode->i_sb);
+  barrier_done = reiserfs_commit_for_inode(p_s_inode);
   reiserfs_write_unlock(p_s_inode->i_sb);
+  if (barrier_done != 1)
+      blkdev_issue_flush(p_s_inode->i_sb->s_bdev, NULL);
   return ( n_err < 0 ) ? -EIO : 0;
 }
 
@@ -176,12 +177,13 @@
     hint.formatted_node = 0; // We are allocating blocks for unformatted node.
 
     /* only preallocate if this is a small write */
-    if (blocks_to_allocate <
-        REISERFS_SB(inode->i_sb)->s_alloc_options.preallocsize)
+    if (REISERFS_I(inode)->i_prealloc_count ||
+       (!(write_bytes & (inode->i_sb->s_blocksize -1)) &&
+        blocks_to_allocate <
+        REISERFS_SB(inode->i_sb)->s_alloc_options.preallocsize))
         hint.preallocate = 1;
     else
         hint.preallocate = 0;
-
     /* Call block allocator to allocate blocks */
     res = reiserfs_allocate_blocknrs(&hint, allocated_blocks, blocks_to_allocate, blocks_to_allocate);
     if ( res != CARRY_ON ) {
@@ -467,6 +469,12 @@
     // the inode.
     //
     pathrelse(&path);
+    /*
+     * cleanup prellocation from previous writes
+     * if this is a partial block write
+     */
+    if (write_bytes & (inode->i_sb->s_blocksize -1))
+        reiserfs_discard_prealloc(th, inode);
     reiserfs_write_unlock(inode->i_sb);
 
     // go through all the pages/buffers and map the buffers to newly allocated
@@ -585,9 +593,19 @@
     struct buffer_head *bh, *head;
     unsigned long i_size_index = inode->i_size >> PAGE_CACHE_SHIFT;
     int new;
+    int logit = reiserfs_file_data_log(inode);
+    struct super_block *s = inode->i_sb;
+    int bh_per_page = PAGE_CACHE_SIZE / s->s_blocksize;
+    struct reiserfs_transaction_handle th;
+    th.t_trans_id = 0;
 
     blocksize = 1 << inode->i_blkbits;
 
+    if (logit) {
+	reiserfs_write_lock(s);
+	journal_begin(&th, s, bh_per_page + 1);
+	reiserfs_update_inode_transaction(inode);
+    }
     for(bh = head = page_buffers(page), block_start = 0;
         bh != head || !block_start;
 	block_start=block_end, bh = bh->b_this_page)
@@ -601,7 +619,10 @@
 		    partial = 1;
 	} else {
 	    set_buffer_uptodate(bh);
-	    if (!buffer_dirty(bh)) {
+	    if (logit) {
+		reiserfs_prepare_for_journal(s, bh, 1);
+		journal_mark_dirty(&th, s, bh);
+	    } else if (!buffer_dirty(bh)) {
 		mark_buffer_dirty(bh);
 		/* do data=ordered on any page past the end
 		 * of file and any buffer marked BH_New.
@@ -613,7 +634,10 @@
 	    }
 	}
     }
-
+    if (logit) {
+	journal_end(&th, s, bh_per_page + 1);
+	reiserfs_write_unlock(s);
+    }
     /*
      * If this is a partial write which happened to make all buffers
      * uptodate then we can optimize away a bogus readpage() for
@@ -1254,6 +1278,7 @@
 	journal_end(&th, th.t_super, th.t_blocks_allocated);
         reiserfs_write_unlock(inode->i_sb);
     }
+
     if ((file->f_flags & O_SYNC) || IS_SYNC(inode))
 	res = generic_osync_inode(inode, file->f_mapping, OSYNC_METADATA|OSYNC_DATA);
 
--- diff/fs/reiserfs/inode.c	2004-06-11 19:17:32.000000000 +0100
+++ source/fs/reiserfs/inode.c	2004-06-11 19:22:06.000000000 +0100
@@ -1660,7 +1660,7 @@
     sb = dir->i_sb;
 
     /* item head of new item */
-    ih.ih_key.k_dir_id = INODE_PKEY (dir)->k_objectid;
+    ih.ih_key.k_dir_id = reiserfs_choose_packing(dir);
     ih.ih_key.k_objectid = cpu_to_le32 (reiserfs_get_unused_objectid (th));
     if (!ih.ih_key.k_objectid) {
 	err = -ENOMEM;
@@ -1729,7 +1729,6 @@
 	err = -EEXIST;
 	goto out_bad_inode;
     }
-
     if (old_format_only (sb)) {
 	if (inode->i_uid & ~0xffff || inode->i_gid & ~0xffff) {
 	    pathrelse (&path_to_key);
@@ -2148,6 +2147,11 @@
     struct buffer_head *head, *bh;
     int partial = 0 ;
     int nr = 0;
+    int checked = PageChecked(page);
+    struct reiserfs_transaction_handle th;
+    struct super_block *s = inode->i_sb;
+    int bh_per_page = PAGE_CACHE_SIZE / s->s_blocksize;
+    th.t_trans_id = 0;
 
     /* The page dirty bit is cleared before writepage is called, which
      * means we have to tell create_empty_buffers to make dirty buffers
@@ -2155,7 +2159,7 @@
      * in the BH_Uptodate is just a sanity check.
      */
     if (!page_has_buffers(page)) {
-	create_empty_buffers(page, inode->i_sb->s_blocksize, 
+	create_empty_buffers(page, s->s_blocksize,
 	                    (1 << BH_Dirty) | (1 << BH_Uptodate));
     }
     head = page_buffers(page) ;
@@ -2179,10 +2183,10 @@
 	kunmap_atomic(kaddr, KM_USER0) ;
     }
     bh = head ;
-    block = page->index << (PAGE_CACHE_SHIFT - inode->i_sb->s_blocksize_bits) ;
+    block = page->index << (PAGE_CACHE_SHIFT - s->s_blocksize_bits) ;
     /* first map all the buffers, logging any direct items we find */
     do {
-	if (buffer_dirty(bh) && (!buffer_mapped(bh) ||
+	if ((checked || buffer_dirty(bh)) && (!buffer_mapped(bh) ||
 	   (buffer_mapped(bh) && bh->b_blocknr == 0))) {
 	    /* not mapped yet, or it points to a direct item, search
 	     * the btree for the mapping info, and log any direct
@@ -2196,6 +2200,18 @@
 	block++;
     } while(bh != head) ;
 
+    /*
+     * we start the transaction after map_block_for_writepage,
+     * because it can create holes in the file (an unbounded operation).
+     * starting it here, we can make a reliable estimate for how many
+     * blocks we're going to log
+     */
+    if (checked) {
+	ClearPageChecked(page);
+	reiserfs_write_lock(s);
+	journal_begin(&th, s, bh_per_page + 1);
+	reiserfs_update_inode_transaction(inode);
+    }
     /* now go through and lock any dirty buffers on the page */
     do {
 	get_bh(bh);
@@ -2204,6 +2220,11 @@
 	if (buffer_mapped(bh) && bh->b_blocknr == 0)
 	    continue;
 
+	if (checked) {
+	    reiserfs_prepare_for_journal(s, bh, 1);
+	    journal_mark_dirty(&th, s, bh);
+	    continue;
+	}
 	/* from this point on, we know the buffer is mapped to a
 	 * real block and not a direct item
 	 */
@@ -2222,6 +2243,10 @@
 	}
     } while((bh = bh->b_this_page) != head);
 
+    if (checked) {
+	journal_end(&th, s, bh_per_page + 1);
+	reiserfs_write_unlock(s);
+    }
     BUG_ON(PageWriteback(page));
     set_page_writeback(page);
     unlock_page(page);
@@ -2481,17 +2506,15 @@
     /* the page is locked, and the only places that log a data buffer
      * also lock the page.
      */
-#if 0
     if (reiserfs_file_data_log(inode)) {
-	/* very conservative, leave the buffer pinned if anyone might need it.
-	** this should be changed to drop the buffer if it is only in the
-	** current transaction
-	*/
+	/*
+	 * very conservative, leave the buffer pinned if
+	 * anyone might need it.
+	 */
         if (buffer_journaled(bh) || buffer_journal_dirty(bh)) {
 	    ret = 0 ;
 	}
     } else
-#endif
     if (buffer_dirty(bh) || buffer_locked(bh)) {
 	struct reiserfs_journal_list *jl;
 	struct reiserfs_jh *jh = bh->b_private;
@@ -2529,6 +2552,10 @@
     int ret = 1;
 
     BUG_ON(!PageLocked(page));
+
+    if (offset == 0)
+	ClearPageChecked(page);
+
     if (!page_has_buffers(page))
 	goto out;
 
@@ -2562,6 +2589,15 @@
     return ret;
 }
 
+static int reiserfs_set_page_dirty(struct page *page) {
+    struct inode *inode = page->mapping->host;
+    if (reiserfs_file_data_log(inode)) {
+	SetPageChecked(page);
+	return __set_page_dirty_nobuffers(page);
+    }
+    return __set_page_dirty_buffers(page);
+}
+
 /*
  * Returns 1 if the page's buffers were dropped.  The page is locked.
  *
@@ -2579,6 +2615,7 @@
     struct buffer_head *bh ;
     int ret = 1 ;
 
+    WARN_ON(PageChecked(page));
     spin_lock(&j->j_dirty_buffers_lock) ;
     head = page_buffers(page) ;
     bh = head ;
@@ -2684,5 +2721,6 @@
     .prepare_write = reiserfs_prepare_write,
     .commit_write = reiserfs_commit_write,
     .bmap = reiserfs_aop_bmap,
-    .direct_IO = reiserfs_direct_IO
+    .direct_IO = reiserfs_direct_IO,
+    .set_page_dirty = reiserfs_set_page_dirty,
 } ;
--- diff/fs/reiserfs/journal.c	2004-06-11 19:17:32.000000000 +0100
+++ source/fs/reiserfs/journal.c	2004-06-11 19:22:06.000000000 +0100
@@ -127,6 +127,12 @@
   return 0 ;
 }
 
+static void disable_barrier(struct super_block *s)
+{
+    REISERFS_SB(s)->s_mount_opt &= ~(1 << REISERFS_BARRIER_FLUSH);
+    printk("reiserfs: disabling flush barriers on %s\n", reiserfs_bdevname(s));
+}
+
 static struct reiserfs_bitmap_node *
 allocate_bitmap_node(struct super_block *p_s_sb) {
   struct reiserfs_bitmap_node *bn ;
@@ -640,6 +646,15 @@
     submit_bh(WRITE, bh) ;
 }
 
+static int submit_barrier_buffer(struct buffer_head *bh) {
+    get_bh(bh) ;
+    bh->b_end_io = reiserfs_end_ordered_io;
+    clear_buffer_dirty(bh) ;
+    if (!buffer_uptodate(bh))
+        BUG();
+    return submit_bh(WRITE_BARRIER, bh) ;
+}
+
 #define CHUNK_SIZE 32
 struct buffer_chunk {
     struct buffer_head *bh[CHUNK_SIZE];
@@ -909,6 +924,7 @@
   int bn ;
   struct buffer_head *tbh = NULL ;
   unsigned long trans_id = jl->j_trans_id;
+  int barrier = 0;
 
   reiserfs_check_lock_depth(s, "flush_commit_list") ;
 
@@ -973,7 +989,20 @@
   }
   atomic_dec(&SB_JOURNAL(s)->j_async_throttle);
 
-  /* wait on everything written so far before writing the commit */
+  /* wait on everything written so far before writing the commit
+   * if we are in barrier mode, send the commit down now
+   */
+  barrier = reiserfs_barrier_flush(s);
+  if (barrier) {
+      int ret;
+      lock_buffer(jl->j_commit_bh);
+      ret = submit_barrier_buffer(jl->j_commit_bh);
+      if (ret == -EOPNOTSUPP) {
+	  set_buffer_uptodate(jl->j_commit_bh);
+          disable_barrier(s);
+	  barrier = 0;
+      }
+  }
   for (i = 0 ;  i < (jl->j_len + 1) ; i++) {
     bn = SB_ONDISK_JOURNAL_1st_BLOCK(s) +
 	 (jl->j_start + i) % SB_ONDISK_JOURNAL_SIZE(s) ;
@@ -995,10 +1024,14 @@
   if (atomic_read(&(jl->j_commit_left)) != 1)
     BUG();
 
-  if (buffer_dirty(jl->j_commit_bh))
-    BUG();
-  mark_buffer_dirty(jl->j_commit_bh) ;
-  sync_dirty_buffer(jl->j_commit_bh) ;
+  if (!barrier) {
+      if (buffer_dirty(jl->j_commit_bh))
+	BUG();
+      mark_buffer_dirty(jl->j_commit_bh) ;
+      sync_dirty_buffer(jl->j_commit_bh) ;
+  } else
+      wait_on_buffer(jl->j_commit_bh);
+
   if (!buffer_uptodate(jl->j_commit_bh)) {
     reiserfs_panic(s, "journal-615: buffer write failed\n") ;
   }
@@ -1024,7 +1057,6 @@
   up(&jl->j_commit_lock);
 put_jl:
   put_journal_list(s, jl);
-
   return 0 ;
 }
 
@@ -1099,8 +1131,22 @@
     jh->j_last_flush_trans_id = cpu_to_le32(trans_id) ;
     jh->j_first_unflushed_offset = cpu_to_le32(offset) ;
     jh->j_mount_id = cpu_to_le32(SB_JOURNAL(p_s_sb)->j_mount_id) ;
-    set_buffer_dirty(SB_JOURNAL(p_s_sb)->j_header_bh) ;
-    sync_dirty_buffer(SB_JOURNAL(p_s_sb)->j_header_bh) ;
+
+    if (reiserfs_barrier_flush(p_s_sb)) {
+	int ret;
+	lock_buffer(SB_JOURNAL(p_s_sb)->j_header_bh);
+	ret = submit_barrier_buffer(SB_JOURNAL(p_s_sb)->j_header_bh);
+	if (ret == -EOPNOTSUPP) {
+	    set_buffer_uptodate(SB_JOURNAL(p_s_sb)->j_header_bh);
+	    disable_barrier(p_s_sb);
+	    goto sync;
+	}
+	wait_on_buffer(SB_JOURNAL(p_s_sb)->j_header_bh);
+    } else {
+sync:
+	set_buffer_dirty(SB_JOURNAL(p_s_sb)->j_header_bh) ;
+	sync_dirty_buffer(SB_JOURNAL(p_s_sb)->j_header_bh) ;
+    }
     if (!buffer_uptodate(SB_JOURNAL(p_s_sb)->j_header_bh)) {
       reiserfs_warning (p_s_sb, "journal-837: IO error during journal replay");
       return -EIO ;
@@ -1544,14 +1590,18 @@
     unsigned long cur_len;
     int ret;
     int i;
+    int limit = 256;
     struct reiserfs_journal_list *tjl;
     struct reiserfs_journal_list *flush_jl;
     unsigned long trans_id;
 
     flush_jl = tjl = jl;
 
-    /* flush for 256 transactions or 256 blocks, whichever comes first */
-    for(i = 0 ; i < 256 && len < 256 ; i++) {
+    /* in data logging mode, try harder to flush a lot of blocks */
+    if (reiserfs_data_log(s))
+	limit = 1024;
+    /* flush for 256 transactions or limit blocks, whichever comes first */
+    for(i = 0 ; i < 256 && len < limit ; i++) {
 	if (atomic_read(&tjl->j_commit_left) ||
 	    tjl->j_trans_id < jl->j_trans_id) {
 	    break;
@@ -3181,11 +3231,16 @@
   REISERFS_I(inode)->i_trans_id = SB_JOURNAL(inode->i_sb)->j_trans_id ;
 }
 
-static void __commit_trans_jl(struct inode *inode, unsigned long id,
+/*
+ * returns -1 on error, 0 if no commits/barriers were done and 1
+ * if a transaction was actually committed and the barrier was done
+ */
+static int __commit_trans_jl(struct inode *inode, unsigned long id,
                                  struct reiserfs_journal_list *jl)
 {
     struct reiserfs_transaction_handle th ;
     struct super_block *sb = inode->i_sb ;
+    int ret = 0;
 
     /* is it from the current transaction, or from an unknown transaction? */
     if (id == SB_JOURNAL(sb)->j_trans_id) {
@@ -3207,6 +3262,7 @@
 	}
 
 	journal_end_sync(&th, sb, 1) ;
+	ret = 1;
 
     } else {
 	/* this gets tricky, we have to make sure the journal list in
@@ -3215,13 +3271,21 @@
 	 */
 flush_commit_only:
 	if (journal_list_still_alive(inode->i_sb, id)) {
+	    /*
+	     * we only set ret to 1 when we know for sure
+	     * the barrier hasn't been started yet on the commit
+	     * block.
+	     */
+	    if (atomic_read(&jl->j_commit_left) > 1)
+	        ret = 1;
 	    flush_commit_list(sb, jl, 1) ;
 	}
     }
     /* otherwise the list is gone, and long since committed */
+    return ret;
 }
 
-void reiserfs_commit_for_inode(struct inode *inode) {
+int reiserfs_commit_for_inode(struct inode *inode) {
     unsigned long id = REISERFS_I(inode)->i_trans_id;
     struct reiserfs_journal_list *jl = REISERFS_I(inode)->i_jl;
 
@@ -3234,7 +3298,7 @@
 	/* jl will be updated in __commit_trans_jl */
     }
 
-    __commit_trans_jl(inode, id, jl);
+   return __commit_trans_jl(inode, id, jl);
 }
 
 void reiserfs_restore_prepared_buffer(struct super_block *p_s_sb, 
@@ -3482,10 +3546,16 @@
     /* copy all the real blocks into log area.  dirty log blocks */
     if (test_bit(BH_JDirty, &cn->bh->b_state)) {
       struct buffer_head *tmp_bh ;
+      char *addr;
+      struct page *page;
       tmp_bh =  journal_getblk(p_s_sb, SB_ONDISK_JOURNAL_1st_BLOCK(p_s_sb) + 
 		       ((cur_write_start + jindex) % SB_ONDISK_JOURNAL_SIZE(p_s_sb))) ;
       set_buffer_uptodate(tmp_bh);
-      memcpy(tmp_bh->b_data, cn->bh->b_data, cn->bh->b_size) ;  
+      page = cn->bh->b_page;
+      addr = kmap(page);
+      memcpy(tmp_bh->b_data, addr + offset_in_page(cn->bh->b_data),
+             cn->bh->b_size);
+      kunmap(page);
       mark_buffer_dirty(tmp_bh);
       jindex++ ;
       set_bit(BH_JDirty_wait, &(cn->bh->b_state)) ; 
--- diff/fs/reiserfs/namei.c	2004-06-11 19:17:32.000000000 +0100
+++ source/fs/reiserfs/namei.c	2004-06-11 19:22:06.000000000 +0100
@@ -1389,8 +1389,9 @@
  * stuff added
  */
 struct inode_operations reiserfs_symlink_inode_operations = {
-    .readlink       = page_readlink,
-    .follow_link    = page_follow_link,
+    .readlink       = generic_readlink,
+    .follow_link    = page_follow_link_light,
+    .put_link       = page_put_link,
     .setattr        = reiserfs_setattr,
     .setxattr       = reiserfs_setxattr,
     .getxattr       = reiserfs_getxattr,
--- diff/fs/reiserfs/stree.c	2004-06-11 19:17:32.000000000 +0100
+++ source/fs/reiserfs/stree.c	2004-06-11 19:22:06.000000000 +0100
@@ -596,26 +596,29 @@
 
 
 
-#ifdef SEARCH_BY_KEY_READA
+#define SEARCH_BY_KEY_READA 16
 
 /* The function is NOT SCHEDULE-SAFE! */
-static void search_by_key_reada (struct super_block * s, int blocknr)
+static void search_by_key_reada (struct super_block * s,
+                                 struct buffer_head **bh,
+				 unsigned long *b, int num)
 {
-    struct buffer_head * bh;
+    int i,j;
   
-    if (blocknr == 0)
-	return;
-
-    bh = sb_getblk (s, blocknr);
-  
-    if (!buffer_uptodate (bh)) {
-	ll_rw_block (READA, 1, &bh);
+    for (i = 0 ; i < num ; i++) {
+	bh[i] = sb_getblk (s, b[i]);
+    }
+    for (j = 0 ; j < i ; j++) {
+	/*
+	 * note, this needs attention if we are getting rid of the BKL
+	 * you have to make sure the prepared bit isn't set on this buffer
+	 */
+	if (!buffer_uptodate(bh[j]))
+	    ll_rw_block(READA, 1, bh + j);
+    	brelse(bh[j]);
     }
-    bh->b_count --;
 }
 
-#endif
-
 /**************************************************************************
  * Algorithm   SearchByKey                                                *
  *             look for item in the Disk S+Tree by its key                *
@@ -657,6 +660,9 @@
     int				n_node_level, n_retval;
     int 			right_neighbor_of_leaf_node;
     int				fs_gen;
+    struct buffer_head *reada_bh[SEARCH_BY_KEY_READA];
+    unsigned long      reada_blocks[SEARCH_BY_KEY_READA];
+    int reada_count = 0;
 
 #ifdef CONFIG_REISERFS_CHECK
     int n_repeat_counter = 0;
@@ -691,19 +697,25 @@
 	p_s_last_element = PATH_OFFSET_PELEMENT(p_s_search_path, ++p_s_search_path->path_length);
 	fs_gen = get_generation (p_s_sb);
 
-#ifdef SEARCH_BY_KEY_READA
-	/* schedule read of right neighbor */
-	search_by_key_reada (p_s_sb, right_neighbor_of_leaf_node);
-#endif
-
 	/* Read the next tree node, and set the last element in the path to
            have a pointer to it. */
-	if ( ! (p_s_bh = p_s_last_element->pe_buffer =
-		sb_bread(p_s_sb, n_block_number)) ) {
+	if ((p_s_bh = p_s_last_element->pe_buffer =
+	     sb_getblk(p_s_sb, n_block_number)) ) {
+	    if (!buffer_uptodate(p_s_bh) && reada_count > 1) {
+		search_by_key_reada (p_s_sb, reada_bh,
+		                     reada_blocks, reada_count);
+	    }
+	    ll_rw_block(READ, 1, &p_s_bh);
+	    wait_on_buffer(p_s_bh);
+	    if (!buffer_uptodate(p_s_bh))
+	        goto io_error;
+	} else {
+io_error:
 	    p_s_search_path->path_length --;
 	    pathrelse(p_s_search_path);
 	    return IO_ERROR;
 	}
+	reada_count = 0;
 	if (expected_level == -1)
 		expected_level = SB_TREE_HEIGHT (p_s_sb);
 	expected_level --;
@@ -784,11 +796,36 @@
 	   position in the node. */
 	n_block_number = B_N_CHILD_NUM(p_s_bh, p_s_last_element->pe_position);
 
-#ifdef SEARCH_BY_KEY_READA
-	/* if we are going to read leaf node, then calculate its right neighbor if possible */
-	if (n_node_level == DISK_LEAF_NODE_LEVEL + 1 && p_s_last_element->pe_position < B_NR_ITEMS (p_s_bh))
-	    right_neighbor_of_leaf_node = B_N_CHILD_NUM(p_s_bh, p_s_last_element->pe_position + 1);
-#endif
+	/* if we are going to read leaf nodes, try for read ahead as well */
+	if ((p_s_search_path->reada & PATH_READA) &&
+	    n_node_level == DISK_LEAF_NODE_LEVEL + 1)
+	{
+	    int pos = p_s_last_element->pe_position;
+	    int limit = B_NR_ITEMS(p_s_bh);
+	    struct key *le_key;
+
+	    if (p_s_search_path->reada & PATH_READA_BACK)
+		limit = 0;
+	    while(reada_count < SEARCH_BY_KEY_READA) {
+		if (pos == limit)
+		    break;
+	        reada_blocks[reada_count++] = B_N_CHILD_NUM(p_s_bh, pos);
+		if (p_s_search_path->reada & PATH_READA_BACK)
+		    pos--;
+		else
+		    pos++;
+
+		/*
+		 * check to make sure we're in the same object
+		 */
+		le_key = B_N_PDELIM_KEY(p_s_bh, pos);
+		if (le32_to_cpu(le_key->k_objectid) !=
+		    p_s_key->on_disk_key.k_objectid)
+		{
+		    break;
+		}
+	    }
+        }
     }
 }
 
@@ -1458,6 +1495,41 @@
     reiserfs_delete_solid_item (th, inode, INODE_PKEY (inode));
 }
 
+static void
+unmap_buffers(struct page *page, loff_t pos) {
+    struct buffer_head *bh ;
+    struct buffer_head *head ;
+    struct buffer_head *next ;
+    unsigned long tail_index ;
+    unsigned long cur_index ;
+
+    if (page) {
+	if (page_has_buffers(page)) {
+	    tail_index = pos & (PAGE_CACHE_SIZE - 1) ;
+	    cur_index = 0 ;
+	    head = page_buffers(page) ;
+	    bh = head ;
+	    do {
+		next = bh->b_this_page ;
+
+		/* we want to unmap the buffers that contain the tail, and
+		** all the buffers after it (since the tail must be at the
+		** end of the file).  We don't want to unmap file data
+		** before the tail, since it might be dirty and waiting to
+		** reach disk
+		*/
+		cur_index += bh->b_size ;
+		if (cur_index > tail_index) {
+		    reiserfs_unmap_buffer(bh) ;
+		}
+		bh = next ;
+	    } while (bh != head) ;
+	    if ( PAGE_SIZE == bh->b_size ) {
+		clear_page_dirty(page);
+	    }
+	}
+    }
+}
 
 static int maybe_indirect_to_direct (struct reiserfs_transaction_handle *th, 
 			      struct inode * p_s_inode,
@@ -1550,7 +1622,7 @@
     char                c_mode;            /* Mode of the balance. */
     int retval2 = -1;
     int quota_cut_bytes;
-    
+    loff_t tail_pos = 0;
     
     init_tb_struct(th, &s_cut_balance, p_s_inode->i_sb, p_s_path, n_cut_size);
 
@@ -1590,6 +1662,7 @@
       	    set_cpu_key_k_type (p_s_item_key, TYPE_INDIRECT);
 	    p_s_item_key->key_length = 4;
 	    n_new_file_size -= (n_new_file_size & (p_s_sb->s_blocksize - 1));
+	    tail_pos = n_new_file_size;
 	    set_cpu_key_k_offset (p_s_item_key, n_new_file_size + 1);
 	    if ( search_for_position_by_key(p_s_sb, p_s_item_key, p_s_path) == POSITION_NOT_FOUND ){
 		print_block (PATH_PLAST_BUFFER (p_s_path), 3, PATH_LAST_POSITION (p_s_path) - 1, PATH_LAST_POSITION (p_s_path) + 1);
@@ -1687,9 +1760,10 @@
     if ( n_is_inode_locked ) {
 	/* we've done an indirect->direct conversion.  when the data block
 	** was freed, it was removed from the list of blocks that must
-	** be flushed before the transaction commits, so we don't need to
-	** deal with it here.
+	** be flushed before the transaction commits, make sure to
+	** unmap and invalidate it
 	*/
+	unmap_buffers(page, tail_pos);
 	REISERFS_I(p_s_inode)->i_flags &= ~i_pack_on_close_mask ;
     }
 #ifdef REISERQUOTA_DEBUG
@@ -1778,6 +1852,12 @@
            space, this file would have this file size */
 	n_file_size = offset + bytes - 1;
     }
+    /*
+     * are we doing a full truncate or delete, if so
+     * kick in the reada code
+     */
+    if (n_new_file_size == 0)
+        s_search_path.reada = PATH_READA | PATH_READA_BACK;
 
     if ( n_file_size == 0 || n_file_size < n_new_file_size ) {
 	goto update_and_out ;
--- diff/fs/reiserfs/super.c	2004-06-11 19:17:32.000000000 +0100
+++ source/fs/reiserfs/super.c	2004-06-11 19:22:06.000000000 +0100
@@ -492,7 +492,6 @@
     REISERFS_I(inode)->i_acl_default = NULL;
 }
 
-
 struct super_operations reiserfs_sops = 
 {
   .alloc_inode = reiserfs_alloc_inode,
@@ -550,6 +549,13 @@
     {NULL, 0}
 };
 
+/* possible values for -o barrier= */
+static const arg_desc_t barrier_mode[] = {
+    {"none", 1<<REISERFS_BARRIER_NONE, 1<<REISERFS_BARRIER_FLUSH},
+    {"flush", 1<<REISERFS_BARRIER_FLUSH, 1<<REISERFS_BARRIER_NONE},
+    {NULL, 0}
+};
+
 /* possible values for "-o block-allocator=" and bits which are to be set in
    s_mount_opt of reiserfs specific part of in-core super block */
 static const arg_desc_t balloc[] = {
@@ -651,7 +657,7 @@
 	reiserfs_warning (s, "head of option \"%s\" is only correct", opt->option_name);
 	return -1;
     }
-	
+
     /* move to the argument, or to next option if argument is not required */
     p ++;
     
@@ -711,6 +717,7 @@
 	{"replayonly", 0, 0, 1<<REPLAYONLY, 0},
 	{"block-allocator", 'a', balloc, 0, 0},
 	{"data", 'd', logging_mode, 0, 0},
+	{"barrier", 'b', barrier_mode, 0, 0},
 	{"resize", 'r', 0, 0, 0},
 	{"jdev", 'j', 0, 0, 0},
 	{"nolargeio", 'w', 0, 0, 0},
@@ -810,6 +817,23 @@
     }
 }
 
+static void handle_barrier_mode(struct super_block *s, unsigned long bits) {
+    int flush = (1 << REISERFS_BARRIER_FLUSH);
+    int none = (1 << REISERFS_BARRIER_NONE);
+    int all_barrier = flush | none;
+
+    if (bits & all_barrier) {
+        REISERFS_SB(s)->s_mount_opt &= ~all_barrier;
+	if (bits & flush) {
+	    REISERFS_SB(s)->s_mount_opt |= flush;
+	    printk("reiserfs: enabling write barrier flush mode\n");
+	} else if (bits & none) {
+	    REISERFS_SB(s)->s_mount_opt |= none;
+	    printk("reiserfs: write barriers turned off\n");
+	}
+   }
+}
+
 static void handle_attrs( struct super_block *s )
 {
 	struct reiserfs_super_block * rs;
@@ -854,6 +878,8 @@
   safe_mask |= 1 << REISERFS_ATTRS;
   safe_mask |= 1 << REISERFS_XATTRS_USER;
   safe_mask |= 1 << REISERFS_POSIXACL;
+  safe_mask |= 1 << REISERFS_BARRIER_FLUSH;
+  safe_mask |= 1 << REISERFS_BARRIER_NONE;
 
   /* Update the bitmask, taking care to keep
    * the bits we're not allowed to change here */
@@ -900,6 +926,7 @@
     }
 
     handle_data_mode(s, mount_options);
+    handle_barrier_mode(s, mount_options);
     REISERFS_SB(s)->s_mount_state = sb_umount_state(rs) ;
     s->s_flags &= ~MS_RDONLY ; /* now it is safe to call journal_begin */
     journal_begin(&th, s, 10) ;
@@ -1345,15 +1372,17 @@
     memset (sbi, 0, sizeof (struct reiserfs_sb_info));
     /* Set default values for options: non-aggressive tails */
     REISERFS_SB(s)->s_mount_opt = ( 1 << REISERFS_SMALLTAIL );
-    /* default block allocator option: skip_busy */
-    REISERFS_SB(s)->s_alloc_options.bits = ( 1 << 5);
-    /* If file grew past 4 blocks, start preallocation blocks for it. */
-    REISERFS_SB(s)->s_alloc_options.preallocmin = 4;
+    /* no preallocation minimum, be smart in
+       reiserfs_file_write instead */
+    REISERFS_SB(s)->s_alloc_options.preallocmin = 0;
     /* Preallocate by 16 blocks (17-1) at once */
     REISERFS_SB(s)->s_alloc_options.preallocsize = 17;
     /* Initialize the rwsem for xattr dir */
     init_rwsem(&REISERFS_SB(s)->xattr_dir_sem);
 
+    /* setup default block allocator options */
+    reiserfs_init_alloc_options(s);
+
     jdev_name = NULL;
     if (reiserfs_parse_options (s, (char *) data, &(sbi->s_mount_opt), &blocks, &jdev_name, &commit_max_age) == 0) {
 	goto error;
@@ -1411,6 +1440,9 @@
     } else {
         reiserfs_info (s, "using writeback data mode\n");
     }
+    if (reiserfs_barrier_flush(s)) {
+    	printk("reiserfs: using flush barriers\n");
+    }
 
     // set_device_ro(s->s_dev, 1) ;
     if( journal_init(s, jdev_name, old_format, commit_max_age) ) {
--- diff/fs/reiserfs/tail_conversion.c	2004-06-11 19:17:32.000000000 +0100
+++ source/fs/reiserfs/tail_conversion.c	2004-06-11 19:22:06.000000000 +0100
@@ -162,42 +162,6 @@
     unlock_buffer(bh) ;
 }
 
-static void
-unmap_buffers(struct page *page, loff_t pos) {
-  struct buffer_head *bh ;
-  struct buffer_head *head ;
-  struct buffer_head *next ;
-  unsigned long tail_index ;
-  unsigned long cur_index ;
-
-  if (page) {
-    if (page_has_buffers(page)) {
-      tail_index = pos & (PAGE_CACHE_SIZE - 1) ;
-      cur_index = 0 ;
-      head = page_buffers(page) ;
-      bh = head ;
-      do {
-	next = bh->b_this_page ;
-
-        /* we want to unmap the buffers that contain the tail, and
-        ** all the buffers after it (since the tail must be at the
-        ** end of the file).  We don't want to unmap file data 
-        ** before the tail, since it might be dirty and waiting to 
-        ** reach disk
-        */
-        cur_index += bh->b_size ;
-        if (cur_index > tail_index) {
-          reiserfs_unmap_buffer(bh) ;
-        }
-	bh = next ;
-      } while (bh != head) ;
-      if ( PAGE_SIZE == bh->b_size ) {
-	clear_page_dirty(page);
-      }
-    }
-  } 
-}
-
 /* this first locks inode (neither reads nor sync are permitted),
    reads tail through page cache, insert direct item. When direct item
    inserted successfully inode is left locked. Return value is always
@@ -287,11 +251,6 @@
     }
     kunmap(page) ;
 
-    /* this will invalidate all the buffers in the page after
-    ** pos1
-    */
-    unmap_buffers(page, pos1) ;
-
     /* make sure to get the i_blocks changes from reiserfs_insert_item */
     reiserfs_update_sd(th, p_s_inode);
 
--- diff/fs/select.c	2004-05-19 22:12:24.000000000 +0100
+++ source/fs/select.c	2004-06-11 19:22:06.000000000 +0100
@@ -291,8 +291,6 @@
  * Update: ERESTARTSYS breaks at least the xview clock binary, so
  * I'm trying ERESTARTNOHAND which restart only when you want to.
  */
-#define MAX_SELECT_SECONDS \
-	((unsigned long) (MAX_SCHEDULE_TIMEOUT / HZ)-1)
 
 asmlinkage long
 sys_select(int n, fd_set __user *inp, fd_set __user *outp, fd_set __user *exp, struct timeval __user *tvp)
@@ -315,9 +313,11 @@
 		if (sec < 0 || usec < 0)
 			goto out_nofds;
 
-		if ((unsigned long) sec < MAX_SELECT_SECONDS) {
+		if ((unsigned long) sec < (MAX_SCHEDULE_TIMEOUT-1) / HZ - 1) {
 			timeout = ROUND_UP(usec, 1000000/HZ);
 			timeout += sec * (unsigned long) HZ;
+		} else {
+			timeout = MAX_SCHEDULE_TIMEOUT-1;
 		}
 	}
 
@@ -469,11 +469,17 @@
 		return -EINVAL;
 
 	if (timeout) {
-		/* Careful about overflow in the intermediate values */
-		if ((unsigned long) timeout < MAX_SCHEDULE_TIMEOUT / HZ)
-			timeout = (unsigned long)(timeout*HZ+999)/1000+1;
-		else /* Negative or overflow */
+                if (timeout < 0) {
 			timeout = MAX_SCHEDULE_TIMEOUT;
+		} else {
+			/* Careful about overflow in the intermediate values */
+			long seconds = timeout/1000;
+			timeout = ((timeout - 1000*seconds)*HZ + 999)/1000 + 1;
+			if (seconds <= (MAX_SCHEDULE_TIMEOUT-2) / HZ - 1)
+				timeout += seconds*HZ;
+			else
+				timeout = MAX_SCHEDULE_TIMEOUT-1;
+		}
 	}
 
 	poll_initwait(&table);
--- diff/fs/smbfs/proto.h	2004-05-19 22:12:31.000000000 +0100
+++ source/fs/smbfs/proto.h	2004-06-11 19:22:06.000000000 +0100
@@ -87,7 +87,5 @@
 extern int smb_request_send_server(struct smb_sb_info *server);
 extern int smb_request_recv(struct smb_sb_info *server);
 /* symlink.c */
-extern int smb_read_link(struct dentry *dentry, char *buffer, int len);
 extern int smb_symlink(struct inode *inode, struct dentry *dentry, const char *oldname);
-extern int smb_follow_link(struct dentry *dentry, struct nameidata *nd);
 extern struct inode_operations smb_link_inode_operations;
--- diff/fs/smbfs/symlink.c	2004-05-19 22:12:31.000000000 +0100
+++ source/fs/smbfs/symlink.c	2004-06-11 19:22:06.000000000 +0100
@@ -26,19 +26,6 @@
 #include "smb_debug.h"
 #include "proto.h"
 
-int smb_read_link(struct dentry *dentry, char *buffer, int len)
-{
-	char link[256];		/* FIXME: pain ... */
-	int r;
-	DEBUG1("read link buffer len = %d\n", len);
-
-	r = smb_proc_read_link(server_from_dentry(dentry), dentry, link,
-			       sizeof(link) - 1);
-	if (r < 0)
-		return -ENOENT;
-	return vfs_readlink(dentry, buffer, len, link);
-}
-
 int smb_symlink(struct inode *inode, struct dentry *dentry, const char *oldname)
 {
 	DEBUG1("create symlink %s -> %s/%s\n", oldname, DENTRY_PATH(dentry));
@@ -46,24 +33,37 @@
 	return smb_proc_symlink(server_from_dentry(dentry), dentry, oldname);
 }
 
-int smb_follow_link(struct dentry *dentry, struct nameidata *nd)
+static int smb_follow_link(struct dentry *dentry, struct nameidata *nd)
 {
-	char link[256];		/* FIXME: pain ... */
-	int len;
+	char *link = __getname();
 	DEBUG1("followlink of %s/%s\n", DENTRY_PATH(dentry));
 
-	len = smb_proc_read_link(server_from_dentry(dentry), dentry, link,
-				 sizeof(link) - 1);
-	if(len < 0)
-		return -ENOENT;
-
-	link[len] = 0;
-	return vfs_follow_link(nd, link);
+	if (!link) {
+		link = ERR_PTR(-ENOMEM);
+	} else {
+		int len = smb_proc_read_link(server_from_dentry(dentry),
+						dentry, link, PATH_MAX - 1);
+		if (len < 0) {
+			kfree(link);
+			link = ERR_PTR(len);
+		} else {
+			link[len] = 0;
+		}
+	}
+	nd_set_link(nd, link);
+	return 0;
 }
 
+static void smb_put_link(struct dentry *dentry, struct nameidata *nd)
+{
+	char *s = nd_get_link(nd);
+	if (!IS_ERR(s))
+		putname(s);
+}
 
 struct inode_operations smb_link_inode_operations =
 {
-	.readlink	= smb_read_link,
+	.readlink	= generic_readlink,
 	.follow_link	= smb_follow_link,
+	.put_link	= smb_put_link,
 };
--- diff/fs/super.c	2004-06-11 19:17:32.000000000 +0100
+++ source/fs/super.c	2004-06-11 19:22:06.000000000 +0100
@@ -68,6 +68,7 @@
 		INIT_LIST_HEAD(&s->s_files);
 		INIT_LIST_HEAD(&s->s_instances);
 		INIT_HLIST_HEAD(&s->s_anon);
+		INIT_LIST_HEAD(&s->s_inodes);
 		init_rwsem(&s->s_umount);
 		sema_init(&s->s_lock, 1);
 		down_write(&s->s_umount);
@@ -569,14 +570,19 @@
 int set_anon_super(struct super_block *s, void *data)
 {
 	int dev;
+	int error;
 
-	spin_lock(&unnamed_dev_lock);
-	if (idr_pre_get(&unnamed_dev_idr, GFP_ATOMIC) == 0) {
-		spin_unlock(&unnamed_dev_lock);
+ retry:
+	if (idr_pre_get(&unnamed_dev_idr, GFP_ATOMIC) == 0)
 		return -ENOMEM;
-	}
-	dev = idr_get_new(&unnamed_dev_idr, NULL);
+	spin_lock(&unnamed_dev_lock);
+	error = idr_get_new(&unnamed_dev_idr, NULL, &dev);
 	spin_unlock(&unnamed_dev_lock);
+	if (error == -EAGAIN)
+		/* We raced and lost with another CPU. */
+		goto retry;
+	else if (error)
+		return -EAGAIN;
 
 	if ((dev & MAX_ID_MASK) == (1 << MINORBITS)) {
 		spin_lock(&unnamed_dev_lock);
--- diff/fs/sysfs/bin.c	2004-06-11 19:17:32.000000000 +0100
+++ source/fs/sysfs/bin.c	2004-06-11 19:22:06.000000000 +0100
@@ -17,8 +17,10 @@
 static int
 fill_read(struct dentry *dentry, char *buffer, loff_t off, size_t count)
 {
-	struct bin_attribute * attr = dentry->d_fsdata;
-	struct kobject * kobj = dentry->d_parent->d_fsdata;
+	struct sysfs_dirent * attr_sd = dentry->d_fsdata;
+	struct bin_attribute * attr = attr_sd->s_element;
+	struct sysfs_dirent * kobj_sd = dentry->d_parent->d_fsdata;
+	struct kobject * kobj = kobj_sd->s_element;
 
 	return attr->read(kobj, buffer, off, count);
 }
@@ -60,8 +62,10 @@
 static int
 flush_write(struct dentry *dentry, char *buffer, loff_t offset, size_t count)
 {
-	struct bin_attribute *attr = dentry->d_fsdata;
-	struct kobject *kobj = dentry->d_parent->d_fsdata;
+	struct sysfs_dirent * attr_sd = dentry->d_fsdata;
+	struct bin_attribute * attr = attr_sd->s_element;
+	struct sysfs_dirent * kobj_sd = dentry->d_parent->d_fsdata;
+	struct kobject * kobj = kobj_sd->s_element;
 
 	return attr->write(kobj, buffer, offset, count);
 }
@@ -95,7 +99,8 @@
 static int open(struct inode * inode, struct file * file)
 {
 	struct kobject *kobj = sysfs_get_kobject(file->f_dentry->d_parent);
-	struct bin_attribute * attr = file->f_dentry->d_fsdata;
+	struct sysfs_dirent * attr_sd = file->f_dentry->d_fsdata;
+	struct bin_attribute * attr = attr_sd->s_element;
 	int error = -EINVAL;
 
 	if (!kobj || !attr)
@@ -130,8 +135,10 @@
 
 static int release(struct inode * inode, struct file * file)
 {
-	struct kobject * kobj = file->f_dentry->d_parent->d_fsdata;
-	struct bin_attribute * attr = file->f_dentry->d_fsdata;
+	struct sysfs_dirent * sd = file->f_dentry->d_parent->d_fsdata;
+	struct kobject * kobj = sd->s_element;
+	struct sysfs_dirent * attr_sd = file->f_dentry->d_fsdata;
+	struct bin_attribute * attr = attr_sd->s_element;
 	u8 * buffer = file->private_data;
 
 	if (kobj) 
@@ -141,7 +148,7 @@
 	return 0;
 }
 
-static struct file_operations bin_fops = {
+struct file_operations bin_fops = {
 	.read		= read,
 	.write		= write,
 	.llseek		= generic_file_llseek,
@@ -158,31 +165,10 @@
 
 int sysfs_create_bin_file(struct kobject * kobj, struct bin_attribute * attr)
 {
-	struct dentry * dentry;
-	struct dentry * parent;
-	int error = 0;
-
-	if (!kobj || !attr)
-		return -EINVAL;
-
-	parent = kobj->dentry;
-
-	down(&parent->d_inode->i_sem);
-	dentry = sysfs_get_dentry(parent,attr->attr.name);
-	if (!IS_ERR(dentry)) {
-		dentry->d_fsdata = (void *)attr;
-		error = sysfs_create(dentry,
-				     (attr->attr.mode & S_IALLUGO) | S_IFREG,
-				     NULL);
-		if (!error) {
-			dentry->d_inode->i_size = attr->size;
-			dentry->d_inode->i_fop = &bin_fops;
-		}
-		dput(dentry);
-	} else
-		error = PTR_ERR(dentry);
-	up(&parent->d_inode->i_sem);
-	return error;
+	if (kobj && kobj->dentry && attr)
+		return sysfs_add_file(kobj->dentry, &attr->attr,
+					SYSFS_KOBJ_BIN_ATTR);
+	return -EINVAL;
 }
 
 
--- diff/fs/sysfs/dir.c	2004-06-11 19:17:32.000000000 +0100
+++ source/fs/sysfs/dir.c	2004-06-11 19:22:06.000000000 +0100
@@ -12,31 +12,181 @@
 
 DECLARE_RWSEM(sysfs_rename_sem);
 
+struct inode_operations sysfs_dir_inode_operations = {
+	.lookup		= sysfs_lookup,
+};
+
+struct file_operations sysfs_dir_operations = {
+	.open		= sysfs_dir_open,
+	.release	= sysfs_dir_close,
+	.llseek		= sysfs_dir_lseek,
+	.read		= generic_read_dir,
+	.readdir	= sysfs_readdir,
+};
+
+static void sysfs_d_iput(struct dentry * dentry, struct inode * inode)
+{
+	struct sysfs_dirent * sd = dentry->d_fsdata;
+
+	if (sd) {
+		BUG_ON(sd->s_dentry != dentry);
+		sd->s_dentry = NULL;
+		sysfs_put(sd);
+	}
+	iput(inode);
+}
+
+static struct dentry_operations sysfs_dentry_ops = {
+	.d_iput		= sysfs_d_iput,
+};
+
+const unsigned char * sysfs_get_name(struct sysfs_dirent *sd)
+{
+	struct attribute * attr;
+	struct bin_attribute * bin_attr;
+	struct sysfs_symlink  * sl;
+
+	if (!sd || !sd->s_element)
+		BUG();
+
+	switch (sd->s_type) {
+		case SYSFS_KOBJECT:
+		case SYSFS_KOBJ_ATTR_GROUP:
+			/* Always have a dentry so use that */
+			return sd->s_dentry->d_name.name;
+
+		case SYSFS_KOBJ_ATTR:
+			attr = sd->s_element;
+			return attr->name;
+
+		case SYSFS_KOBJ_BIN_ATTR:
+			bin_attr = sd->s_element;
+			return bin_attr->attr.name;
+
+		case SYSFS_KOBJ_LINK:
+			sl = sd->s_element;
+			return sl->link_name;
+	}
+	return NULL;
+}
+
+static int init_file(struct inode * inode)
+{
+	inode->i_size = PAGE_SIZE;
+	inode->i_fop = &sysfs_file_operations;
+	return 0;
+}
+
 static int init_dir(struct inode * inode)
 {
-	inode->i_op = &simple_dir_inode_operations;
-	inode->i_fop = &simple_dir_operations;
+	inode->i_op = &sysfs_dir_inode_operations;
+	inode->i_fop = &sysfs_dir_operations;
 
 	/* directory inodes start off with i_nlink == 2 (for "." entry) */
 	inode->i_nlink++;
 	return 0;
 }
 
+/* attaches attribute's sysfs_dirent to the dentry corresponding to the
+ * attribute file
+ */
+static int sysfs_attach_attr(struct sysfs_dirent * sd, struct dentry * dentry)
+{
+	struct attribute * attr = NULL;
+	struct bin_attribute * bin_attr = NULL;
+        int (* init) (struct inode *) = NULL;
+	int error = 0;
+
+        if (sd->s_type & SYSFS_KOBJ_BIN_ATTR) {
+                bin_attr = sd->s_element;
+                attr = &bin_attr->attr;
+        } else {
+                attr = sd->s_element;
+                init = init_file;
+        }
+
+	error = sysfs_create(dentry, (attr->mode & S_IALLUGO) | S_IFREG, init);
+	if (error)
+		return error;
+
+        if (bin_attr) {
+		dentry->d_inode->i_size = bin_attr->size;
+		dentry->d_inode->i_fop = &bin_fops;
+	}
+	dentry->d_op = &sysfs_dentry_ops;
+	dentry->d_fsdata = sysfs_get(sd);
+	sd->s_dentry = dentry;
+	d_rehash(dentry);
+
+	return 0;
+}
+
+static int sysfs_attach_link(struct sysfs_dirent * sd, struct dentry * dentry)
+{
+	int err = 0;
+
+	err = sysfs_create(dentry, S_IFLNK|S_IRWXUGO, init_symlink);
+	if (!err) {
+		dentry->d_op = &sysfs_dentry_ops;
+		dentry->d_fsdata = sysfs_get(sd);
+		sd->s_dentry = dentry;
+		d_rehash(dentry);
+	}
+	return err;
+}
+
+struct dentry * sysfs_lookup(struct inode *dir, struct dentry *dentry,
+				struct nameidata *nd)
+{
+	struct sysfs_dirent * parent_sd = dentry->d_parent->d_fsdata;
+	struct sysfs_dirent * sd;
+	int err = 0;
+
+	list_for_each_entry(sd, &parent_sd->s_children, s_sibling) {
+		if (sd->s_type & SYSFS_NOT_PINNED) {
+			const unsigned char * name = sysfs_get_name(sd);
+
+			if (strcmp(name, dentry->d_name.name))
+				continue;
+
+			if (sd->s_type & SYSFS_KOBJ_LINK)
+				err = sysfs_attach_link(sd, dentry);
+			else
+				err = sysfs_attach_attr(sd, dentry);
+			break;
+		}
+	}
+
+	return ERR_PTR(err);
+}
 
 static int create_dir(struct kobject * k, struct dentry * p,
 		      const char * n, struct dentry ** d)
 {
 	int error;
+	umode_t mode = S_IFDIR| S_IRWXU | S_IRUGO | S_IXUGO;
 
 	down(&p->d_inode->i_sem);
 	*d = sysfs_get_dentry(p,n);
 	if (!IS_ERR(*d)) {
-		error = sysfs_create(*d,
-					 S_IFDIR| S_IRWXU | S_IRUGO | S_IXUGO,
-					 init_dir);
+		error = sysfs_create(*d, mode, init_dir);
 		if (!error) {
-			(*d)->d_fsdata = k;
-			p->d_inode->i_nlink++;
+			struct sysfs_dirent * sd, * parent_sd;
+			parent_sd = p->d_fsdata;
+			sd = sysfs_new_dirent(parent_sd, k,
+						(parent_sd->s_element == k) ?
+						SYSFS_KOBJ_ATTR_GROUP :
+						SYSFS_KOBJECT);
+			if (sd) {
+				(*d)->d_fsdata = sysfs_get(sd);
+				(*d)->d_op = &sysfs_dentry_ops;
+				p->d_inode->i_nlink++;
+				sd->s_element = k;
+				sd->s_dentry = *d;
+				sd->s_mode = mode;
+				d_rehash(*d);
+			} else
+				error = -ENOMEM;
 		}
 		dput(*d);
 	} else
@@ -45,7 +195,6 @@
 	return error;
 }
 
-
 int sysfs_create_subdir(struct kobject * k, const char * n, struct dentry ** d)
 {
 	return create_dir(k,k->dentry,n,d);
@@ -79,12 +228,16 @@
 	return error;
 }
 
-
 static void remove_dir(struct dentry * d)
 {
 	struct dentry * parent = dget(d->d_parent);
+	struct sysfs_dirent * sd;
+
 	down(&parent->d_inode->i_sem);
 	d_delete(d);
+	sd = d->d_fsdata;
+ 	list_del_init(&sd->s_sibling);
+ 	sysfs_put(d->d_fsdata);
 	if (d->d_inode)
 		simple_rmdir(parent->d_inode,d);
 
@@ -106,14 +259,14 @@
  *	@kobj:	object. 
  *
  *	The only thing special about this is that we remove any files in 
- *	the directory before we remove the directory, and we've inlined
- *	what used to be sysfs_rmdir() below, instead of calling separately.
+ *	the directory before we remove the directory
  */
 
 void sysfs_remove_dir(struct kobject * kobj)
 {
-	struct list_head * node;
 	struct dentry * dentry = dget(kobj->dentry);
+	struct sysfs_dirent * parent_sd = dentry->d_fsdata;
+	struct sysfs_dirent * sd, * tmp;
 
 	if (!dentry)
 		return;
@@ -121,38 +274,13 @@
 	pr_debug("sysfs %s: removing dir\n",dentry->d_name.name);
 	down(&dentry->d_inode->i_sem);
 
-	spin_lock(&dcache_lock);
-restart:
-	node = dentry->d_subdirs.next;
-	while (node != &dentry->d_subdirs) {
-		struct dentry * d = list_entry(node,struct dentry,d_child);
-
-		node = node->next;
-		pr_debug(" o %s (%d): ",d->d_name.name,atomic_read(&d->d_count));
-		if (!d_unhashed(d) && (d->d_inode)) {
-			d = dget_locked(d);
-			pr_debug("removing");
-
-			/**
-			 * Unlink and unhash.
-			 */
-			__d_drop(d);
-			spin_unlock(&dcache_lock);
-			/* release the target kobject in case of 
-			 * a symlink
-			 */
-			if (S_ISLNK(d->d_inode->i_mode))
-				kobject_put(d->d_fsdata);
-			
-			simple_unlink(dentry->d_inode,d);
-			dput(d);
-			pr_debug(" done\n");
-			spin_lock(&dcache_lock);
-			/* re-acquired dcache_lock, need to restart */
-			goto restart;
-		}
-	}
-	spin_unlock(&dcache_lock);
+	list_for_each_entry_safe(sd, tmp, &parent_sd->s_children, s_sibling) {
+		if (!sd->s_element)
+			continue;
+		list_del_init(&sd->s_sibling);
+		sysfs_drop_dentry(sd, dentry);
+		sysfs_put(sd);
+  	}
 	up(&dentry->d_inode->i_sem);
 
 	remove_dir(dentry);
@@ -182,8 +310,10 @@
 	if (!IS_ERR(new_dentry)) {
   		if (!new_dentry->d_inode) {
 			error = kobject_set_name(kobj,new_name);
-			if (!error)
+			if (!error) {
+				d_add(new_dentry, NULL);
 				d_move(kobj->dentry, new_dentry);
+			}
 		}
 		dput(new_dentry);
 	}
@@ -193,6 +323,137 @@
 	return error;
 }
 
+int sysfs_dir_open(struct inode *inode, struct file *file)
+{
+	struct dentry * dentry = file->f_dentry;
+	struct sysfs_dirent * parent_sd = dentry->d_fsdata;
+
+	down(&dentry->d_inode->i_sem);
+	file->private_data = sysfs_new_dirent(parent_sd, NULL, 0);
+	up(&dentry->d_inode->i_sem);
+
+	return file->private_data ? 0 : -ENOMEM;
+
+}
+
+int sysfs_dir_close(struct inode *inode, struct file *file)
+{
+	struct dentry * dentry = file->f_dentry;
+	struct sysfs_dirent * cursor = file->private_data;
+
+	down(&dentry->d_inode->i_sem);
+	list_del_init(&cursor->s_sibling);
+	up(&dentry->d_inode->i_sem);
+	sysfs_put(file->private_data);
+
+	return 0;
+}
+
+/* Relationship between s_mode and the DT_xxx types */
+static inline unsigned char dt_type(struct sysfs_dirent *sd)
+{
+	return (sd->s_mode >> 12) & 15;
+}
+
+int sysfs_readdir(struct file * filp, void * dirent, filldir_t filldir)
+{
+	struct dentry *dentry = filp->f_dentry;
+	struct sysfs_dirent * parent_sd = dentry->d_fsdata;
+	struct sysfs_dirent *cursor = filp->private_data;
+	struct list_head *p, *q = &cursor->s_sibling;
+	ino_t ino;
+	int i = filp->f_pos;
+
+	switch (i) {
+		case 0:
+			ino = dentry->d_inode->i_ino;
+			if (filldir(dirent, ".", 1, i, ino, DT_DIR) < 0)
+				break;
+			filp->f_pos++;
+			i++;
+			/* fallthrough */
+		case 1:
+			ino = parent_ino(dentry);
+			if (filldir(dirent, "..", 2, i, ino, DT_DIR) < 0)
+				break;
+			filp->f_pos++;
+			i++;
+			/* fallthrough */
+		default:
+			if (filp->f_pos == 2) {
+				list_del(q);
+				list_add(q, &parent_sd->s_children);
+			}
+			for (p=q->next; p!= &parent_sd->s_children; p=p->next) {
+				struct sysfs_dirent *next;
+				const char * name;
+				int len;
+
+				next = list_entry(p, struct sysfs_dirent,
+						   s_sibling);
+				if (!next->s_element)
+					continue;
+
+				name = sysfs_get_name(next);
+				len = strlen(name);
+				if (next->s_dentry)
+					ino = next->s_dentry->d_inode->i_ino;
+				else
+					ino = iunique(sysfs_sb, 2);
+
+				if (filldir(dirent, name, len, filp->f_pos, ino,
+						 dt_type(next)) < 0)
+					return 0;
+
+				list_del(q);
+				list_add(q, p);
+				p = q;
+				filp->f_pos++;
+			}
+	}
+	return 0;
+}
+
+loff_t sysfs_dir_lseek(struct file * file, loff_t offset, int origin)
+{
+	struct dentry * dentry = file->f_dentry;
+
+	down(&dentry->d_inode->i_sem);
+	switch (origin) {
+		case 1:
+			offset += file->f_pos;
+		case 0:
+			if (offset >= 0)
+				break;
+		default:
+			up(&file->f_dentry->d_inode->i_sem);
+			return -EINVAL;
+	}
+	if (offset != file->f_pos) {
+		file->f_pos = offset;
+		if (file->f_pos >= 2) {
+			struct sysfs_dirent *sd = dentry->d_fsdata;
+			struct sysfs_dirent *cursor = file->private_data;
+			struct list_head *p;
+			loff_t n = file->f_pos - 2;
+
+			list_del(&cursor->s_sibling);
+			p = sd->s_children.next;
+			while (n && p != &sd->s_children) {
+				struct sysfs_dirent *next;
+				next = list_entry(p, struct sysfs_dirent,
+						   s_sibling);
+				if (next->s_element)
+					n--;
+				p = p->next;
+			}
+			list_add_tail(&cursor->s_sibling, p);
+		}
+	}
+	up(&dentry->d_inode->i_sem);
+	return offset;
+}
+
 EXPORT_SYMBOL(sysfs_create_dir);
 EXPORT_SYMBOL(sysfs_remove_dir);
 EXPORT_SYMBOL(sysfs_rename_dir);
--- diff/fs/sysfs/file.c	2004-06-11 19:17:32.000000000 +0100
+++ source/fs/sysfs/file.c	2004-06-11 19:22:06.000000000 +0100
@@ -9,14 +9,6 @@
 
 #include "sysfs.h"
 
-static struct file_operations sysfs_file_operations;
-
-static int init_file(struct inode * inode)
-{
-	inode->i_size = PAGE_SIZE;
-	inode->i_fop = &sysfs_file_operations;
-	return 0;
-}
 
 #define to_subsys(k) container_of(k,struct subsystem,kset.kobj)
 #define to_sattr(a) container_of(a,struct subsys_attribute,attr)
@@ -77,8 +69,10 @@
  */
 static int fill_read_buffer(struct file * file, struct sysfs_buffer * buffer)
 {
-	struct attribute * attr = file->f_dentry->d_fsdata;
-	struct kobject * kobj = file->f_dentry->d_parent->d_fsdata;
+	struct sysfs_dirent * attr_sd = file->f_dentry->d_fsdata;
+	struct attribute * attr = attr_sd->s_element;
+	struct sysfs_dirent * kobj_sd = file->f_dentry->d_parent->d_fsdata;
+	struct kobject * kobj = kobj_sd->s_element;
 	struct sysfs_ops * ops = buffer->ops;
 	int ret = 0;
 	ssize_t count;
@@ -135,6 +129,9 @@
  *	is in the file's ->d_fsdata. The target object is in the directory's
  *	->d_fsdata.
  *
+ *	It is safe to use ->d_parent->d_fsdata as both dentry and the kobject
+ *	are pinned in ->open().
+ *
  *	We call fill_read_buffer() to allocate and fill the buffer from the
  *	object's show() method exactly once (if the read is happening from
  *	the beginning of the file). That should fill the entire buffer with
@@ -199,8 +196,10 @@
 static int 
 flush_write_buffer(struct file * file, struct sysfs_buffer * buffer, size_t count)
 {
-	struct attribute * attr = file->f_dentry->d_fsdata;
-	struct kobject * kobj = file->f_dentry->d_parent->d_fsdata;
+	struct sysfs_dirent * attr_sd = file->f_dentry->d_fsdata;
+	struct attribute * attr = attr_sd->s_element;
+	struct sysfs_dirent * kobj_sd = file->f_dentry->d_parent->d_fsdata;
+	struct kobject * kobj = kobj_sd->s_element;
 	struct sysfs_ops * ops = buffer->ops;
 
 	return ops->store(kobj,attr,buffer->page,count);
@@ -240,7 +239,8 @@
 static int check_perm(struct inode * inode, struct file * file)
 {
 	struct kobject *kobj = sysfs_get_kobject(file->f_dentry->d_parent);
-	struct attribute * attr = file->f_dentry->d_fsdata;
+	struct sysfs_dirent * attr_sd = file->f_dentry->d_fsdata;
+	struct attribute * attr = attr_sd->s_element;
 	struct sysfs_buffer * buffer;
 	struct sysfs_ops * ops = NULL;
 	int error = 0;
@@ -321,8 +321,10 @@
 
 static int sysfs_release(struct inode * inode, struct file * filp)
 {
-	struct kobject * kobj = filp->f_dentry->d_parent->d_fsdata;
-	struct attribute * attr = filp->f_dentry->d_fsdata;
+	struct sysfs_dirent * attr_sd = filp->f_dentry->d_fsdata;
+	struct attribute * attr = attr_sd->s_element;
+	struct sysfs_dirent * kobj_sd = filp->f_dentry->d_parent->d_fsdata;
+	struct kobject * kobj = kobj_sd->s_element;
 	struct sysfs_buffer * buffer = filp->private_data;
 
 	if (kobj) 
@@ -337,7 +339,7 @@
 	return 0;
 }
 
-static struct file_operations sysfs_file_operations = {
+struct file_operations sysfs_file_operations = {
 	.read		= sysfs_read_file,
 	.write		= sysfs_write_file,
 	.llseek		= generic_file_llseek,
@@ -346,23 +348,20 @@
 };
 
 
-int sysfs_add_file(struct dentry * dir, const struct attribute * attr)
+int sysfs_add_file(struct dentry * parent, const struct attribute * attr, int t)
 {
-	struct dentry * dentry;
-	int error;
+	struct sysfs_dirent * sd;
+	struct sysfs_dirent * parent_sd = parent->d_fsdata;
+	int error = 0;
+
+	down(&parent->d_inode->i_sem);
+	sd = sysfs_new_dirent(parent_sd, (void *) attr, t);
+	if (!sd)
+		error =  -ENOMEM;
+	else
+		sd->s_mode =  (attr->mode & S_IALLUGO) | S_IFREG ;
+	up(&parent->d_inode->i_sem);
 
-	down(&dir->d_inode->i_sem);
-	dentry = sysfs_get_dentry(dir,attr->name);
-	if (!IS_ERR(dentry)) {
-		error = sysfs_create(dentry,
-				     (attr->mode & S_IALLUGO) | S_IFREG,
-				     init_file);
-		if (!error)
-			dentry->d_fsdata = (void *)attr;
-		dput(dentry);
-	} else
-		error = PTR_ERR(dentry);
-	up(&dir->d_inode->i_sem);
 	return error;
 }
 
@@ -375,8 +374,8 @@
 
 int sysfs_create_file(struct kobject * kobj, const struct attribute * attr)
 {
-	if (kobj && attr)
-		return sysfs_add_file(kobj->dentry,attr);
+	if (kobj && kobj->dentry && attr)
+		return sysfs_add_file(kobj->dentry, attr, SYSFS_KOBJ_ATTR);
 	return -EINVAL;
 }
 
--- diff/fs/sysfs/group.c	2004-05-19 22:12:31.000000000 +0100
+++ source/fs/sysfs/group.c	2004-06-11 19:22:06.000000000 +0100
@@ -10,7 +10,7 @@
 
 #include <linux/kobject.h>
 #include <linux/module.h>
-#include <linux/dcache.h>
+#include <linux/fs.h>
 #include <linux/err.h>
 #include "sysfs.h"
 
@@ -31,7 +31,7 @@
 	int error = 0;
 
 	for (attr = grp->attrs; *attr && !error; attr++) {
-		error = sysfs_add_file(dir,*attr);
+		error = sysfs_add_file(dir, *attr, SYSFS_KOBJ_ATTR);
 	}
 	if (error)
 		remove_files(dir,grp);
@@ -70,11 +70,15 @@
 	else
 		dir = dget(kobj->dentry);
 
-	remove_files(dir,grp);
-	if (grp->name)
-		sysfs_remove_subdir(dir);
-	/* release the ref. taken in this routine */
-	dput(dir);
+	if (!IS_ERR(dir)) {
+		if (dir && dir->d_inode) {
+			remove_files(dir,grp);
+			if (grp->name)
+				sysfs_remove_subdir(dir);
+			/* release the ref. taken in this routine */
+			dput(dir);
+		}
+	}
 }
 
 
--- diff/fs/sysfs/inode.c	2004-06-11 19:17:32.000000000 +0100
+++ source/fs/sysfs/inode.c	2004-06-11 19:22:06.000000000 +0100
@@ -11,6 +11,8 @@
 #include <linux/pagemap.h>
 #include <linux/namei.h>
 #include <linux/backing-dev.h>
+#include "sysfs.h"
+
 extern struct super_block * sysfs_sb;
 
 static struct address_space_operations sysfs_aops = {
@@ -61,7 +63,8 @@
 		error = init(inode);
 	if (!error) {
 		d_instantiate(dentry, inode);
-		dget(dentry); /* Extra count - pin the dentry in core */
+		if (S_ISDIR(mode))
+			dget(dentry);  /* pin only directory dentry in core */
 	} else
 		iput(inode);
  Done:
@@ -83,31 +86,51 @@
 	return lookup_hash(&qstr,parent);
 }
 
+static struct sysfs_dirent * sysfs_find_dirent(struct sysfs_dirent * parent_sd,
+					  const char * name)
+{
+	struct sysfs_dirent *sd;
+
+	list_for_each_entry(sd, &parent_sd->s_children, s_sibling) {
+			if (sd->s_element) {
+				if (!strcmp(sysfs_get_name(sd), name))
+					return sd;
+			}
+	}
+	return NULL;
+}
+
+/* Unhashes the dentry corresponding to given sysfs_dirent
+ * Called with parent inode's i_sem held.
+ */
+void sysfs_drop_dentry(struct sysfs_dirent * sd, struct dentry * parent)
+{
+	struct dentry * dentry = sd->s_dentry;
+
+	if (dentry) {
+		spin_lock(&dcache_lock);
+		dget_locked(dentry);
+		if (!(d_unhashed(dentry) && dentry->d_inode)) {
+			__d_drop(dentry);
+			spin_unlock(&dcache_lock);
+			simple_unlink(parent->d_inode, dentry);
+		} else {
+			spin_unlock(&dcache_lock);
+			dput(dentry);
+		}
+	}
+}
+
 void sysfs_hash_and_remove(struct dentry * dir, const char * name)
 {
-	struct dentry * victim;
+	struct sysfs_dirent * sd;
 
 	down(&dir->d_inode->i_sem);
-	victim = sysfs_get_dentry(dir,name);
-	if (!IS_ERR(victim)) {
-		/* make sure dentry is really there */
-		if (victim->d_inode && 
-		    (victim->d_parent->d_inode == dir->d_inode)) {
-			pr_debug("sysfs: Removing %s (%d)\n", victim->d_name.name,
-				 atomic_read(&victim->d_count));
-
-			d_drop(victim);
-			/* release the target kobject in case of 
-			 * a symlink
-			 */
-			if (S_ISLNK(victim->d_inode->i_mode))
-				kobject_put(victim->d_fsdata);
-			simple_unlink(dir->d_inode,victim);
-		}
-		/*
-		 * Drop reference from sysfs_get_dentry() above.
-		 */
-		dput(victim);
+	sd = sysfs_find_dirent(dir->d_fsdata, name);
+	if (sd) {
+		list_del_init(&sd->s_sibling);
+		sysfs_drop_dentry(sd, dir);
+		sysfs_put(sd);
 	}
 	up(&dir->d_inode->i_sem);
 }
--- diff/fs/sysfs/mount.c	2004-05-19 22:12:31.000000000 +0100
+++ source/fs/sysfs/mount.c	2004-06-11 19:22:06.000000000 +0100
@@ -22,6 +22,13 @@
 	.drop_inode	= generic_delete_inode,
 };
 
+struct sysfs_dirent sysfs_root = {
+	.s_sibling	= LIST_HEAD_INIT(sysfs_root.s_sibling),
+	.s_children	= LIST_HEAD_INIT(sysfs_root.s_children),
+	.s_element	= NULL,
+	.s_type		= SYSFS_ROOT,
+};
+
 static int sysfs_fill_super(struct super_block *sb, void *data, int silent)
 {
 	struct inode *inode;
@@ -35,8 +42,8 @@
 
 	inode = sysfs_new_inode(S_IFDIR | S_IRWXU | S_IRUGO | S_IXUGO);
 	if (inode) {
-		inode->i_op = &simple_dir_inode_operations;
-		inode->i_fop = &simple_dir_operations;
+		inode->i_op = &sysfs_dir_inode_operations;
+		inode->i_fop = &sysfs_dir_operations;
 		/* directory inodes start off with i_nlink == 2 (for "." entry) */
 		inode->i_nlink++;	
 	} else {
@@ -50,6 +57,7 @@
 		iput(inode);
 		return -ENOMEM;
 	}
+	root->d_fsdata = &sysfs_root;
 	sb->s_root = root;
 	return 0;
 }
--- diff/fs/sysfs/symlink.c	2004-06-11 19:17:32.000000000 +0100
+++ source/fs/sysfs/symlink.c	2004-06-11 19:22:06.000000000 +0100
@@ -13,7 +13,7 @@
 	.follow_link = sysfs_follow_link,
 };
 
-static int init_symlink(struct inode * inode)
+int init_symlink(struct inode * inode)
 {
 	inode->i_op = &sysfs_symlink_inode_operations;
 	return 0;
@@ -53,6 +53,30 @@
 	}
 }
 
+static int sysfs_add_link(struct sysfs_dirent * parent_sd, char * name,
+			    struct kobject * target)
+{
+	struct sysfs_dirent * sd;
+	struct sysfs_symlink * sl;
+
+	sl = kmalloc(sizeof(*sl), GFP_KERNEL);
+	if (!sl)
+		return -ENOMEM;
+
+	sl->link_name = kmalloc(strlen(name) + 1, GFP_KERNEL);
+	strcpy(sl->link_name, name);
+	sl->target_kobj = kobject_get(target);
+
+	sd = sysfs_new_dirent(parent_sd, sl, SYSFS_KOBJ_LINK);
+	if (sd) {
+		sd->s_mode = S_IFLNK|S_IRWXUGO;
+		return 0;
+	}
+
+	kfree(sl);
+	return -ENOMEM;
+}
+
 /**
  *	sysfs_create_link - create symlink between two objects.
  *	@kobj:	object whose directory we're creating the link in.
@@ -62,21 +86,13 @@
 int sysfs_create_link(struct kobject * kobj, struct kobject * target, char * name)
 {
 	struct dentry * dentry = kobj->dentry;
-	struct dentry * d;
 	int error = 0;
 
+	if (!name)
+		return -EINVAL;
+
 	down(&dentry->d_inode->i_sem);
-	d = sysfs_get_dentry(dentry,name);
-	if (!IS_ERR(d)) {
-		error = sysfs_create(d, S_IFLNK|S_IRWXUGO, init_symlink);
-		if (!error)
-			/* 
-			 * associate the link dentry with the target kobject 
-			 */
-			d->d_fsdata = kobject_get(target);
-		dput(d);
-	} else 
-		error = PTR_ERR(d);
+	error = sysfs_add_link(dentry->d_fsdata, name, target);
 	up(&dentry->d_inode->i_sem);
 	return error;
 }
--- diff/fs/sysfs/sysfs.h	2004-06-11 19:17:32.000000000 +0100
+++ source/fs/sysfs/sysfs.h	2004-06-11 19:22:06.000000000 +0100
@@ -1,28 +1,96 @@
 
+#include <linux/fs.h>
 extern struct vfsmount * sysfs_mount;
+extern struct super_block * sysfs_sb;
 
 extern struct inode * sysfs_new_inode(mode_t mode);
 extern int sysfs_create(struct dentry *, int mode, int (*init)(struct inode *));
 
 extern struct dentry * sysfs_get_dentry(struct dentry *, const char *);
+extern int sysfs_add_file(struct dentry *, const struct attribute *, int);
 
-extern int sysfs_add_file(struct dentry * dir, const struct attribute * attr);
 extern void sysfs_hash_and_remove(struct dentry * dir, const char * name);
 
 extern int sysfs_create_subdir(struct kobject *, const char *, struct dentry **);
 extern void sysfs_remove_subdir(struct dentry *);
+extern int sysfs_dir_open(struct inode *inode, struct file *file);
+extern int sysfs_dir_close(struct inode *inode, struct file *file);
+extern loff_t sysfs_dir_lseek(struct file *, loff_t, int);
+extern int sysfs_readdir(struct file *, void *, filldir_t);
+extern void sysfs_umount_begin(struct super_block *);
+extern const unsigned char * sysfs_get_name(struct sysfs_dirent *);
+extern struct dentry * sysfs_lookup(struct inode *, struct dentry *, struct nameidata *);
+extern void sysfs_drop_dentry(struct sysfs_dirent *, struct dentry *);
+extern int sysfs_symlink(struct inode *, struct dentry *, const char *);
+extern int init_symlink(struct inode *);
 
 extern int sysfs_readlink(struct dentry *, char __user *, int );
 extern int sysfs_follow_link(struct dentry *, struct nameidata *);
 extern struct rw_semaphore sysfs_rename_sem;
+extern struct file_operations sysfs_file_operations;
+extern struct file_operations bin_fops;
+extern struct inode_operations sysfs_dir_inode_operations;
+extern struct file_operations sysfs_dir_operations;
+
+struct sysfs_symlink {
+	char * link_name;
+	struct kobject * target_kobj;
+};
+
+static inline
+struct sysfs_dirent * sysfs_new_dirent(struct sysfs_dirent * p, void * e, int t)
+{
+	struct sysfs_dirent * sd;
+
+	sd = kmalloc(sizeof(*sd), GFP_KERNEL);
+	if (!sd)
+		return NULL;
+	memset(sd, 0, sizeof(*sd));
+	atomic_set(&sd->s_count, 1);
+	sd->s_element = e;
+	sd->s_type = t;
+	sd->s_dentry = NULL;
+	INIT_LIST_HEAD(&sd->s_children);
+	list_add(&sd->s_sibling, &p->s_children);
+
+	return sd;
+}
+
+static inline struct sysfs_dirent * sysfs_get(struct sysfs_dirent * sd)
+{
+	if (sd) {
+		WARN_ON(!atomic_read(&sd->s_count));
+		atomic_inc(&sd->s_count);
+	}
+	return sd;
+}
+
+static inline void sysfs_put(struct sysfs_dirent * sd)
+{
+	if (atomic_dec_and_test(&sd->s_count)) {
+		if (sd->s_type & SYSFS_KOBJ_LINK) {
+			struct sysfs_symlink * sl = sd->s_element;
+			kfree(sl->link_name);
+			kobject_put(sl->target_kobj);
+			kfree(sl);
+		}
+		kfree(sd);
+	}
+}
 
 static inline struct kobject *sysfs_get_kobject(struct dentry *dentry)
 {
 	struct kobject * kobj = NULL;
 
 	spin_lock(&dcache_lock);
-	if (!d_unhashed(dentry))
-		kobj = kobject_get(dentry->d_fsdata);
+	if (!d_unhashed(dentry)) {
+		struct sysfs_dirent * sd = dentry->d_fsdata;
+		if (sd->s_type & SYSFS_KOBJ_LINK) {
+			struct sysfs_symlink * sl = sd->s_element;
+			kobj = kobject_get(sl->target_kobj);
+		} else
+			kobj = kobject_get(sd->s_element);
+	}
 	spin_unlock(&dcache_lock);
 
 	return kobj;
--- diff/fs/sysv/inode.c	2004-05-19 22:12:31.000000000 +0100
+++ source/fs/sysv/inode.c	2004-06-11 19:22:06.000000000 +0100
@@ -142,8 +142,9 @@
 }
 
 static struct inode_operations sysv_symlink_inode_operations = {
-	.readlink	= page_readlink,
-	.follow_link	= page_follow_link,
+	.readlink	= generic_readlink,
+	.follow_link	= page_follow_link_light,
+	.put_link	= page_put_link,
 	.getattr	= sysv_getattr,
 };
 
--- diff/fs/sysv/symlink.c	2004-05-19 22:12:31.000000000 +0100
+++ source/fs/sysv/symlink.c	2004-06-11 19:22:06.000000000 +0100
@@ -7,19 +7,13 @@
 
 #include "sysv.h"
 
-static int sysv_readlink(struct dentry *dentry, char *buffer, int buflen)
-{
-	char *s = (char *)SYSV_I(dentry->d_inode)->i_data;
-	return vfs_readlink(dentry, buffer, buflen, s);
-}
-
 static int sysv_follow_link(struct dentry *dentry, struct nameidata *nd)
 {
-	char *s = (char *)SYSV_I(dentry->d_inode)->i_data;
-	return vfs_follow_link(nd, s);
+	nd_set_link(nd, (char *)SYSV_I(dentry->d_inode)->i_data);
+	return 0;
 }
 
 struct inode_operations sysv_fast_symlink_inode_operations = {
-	.readlink	= sysv_readlink,
+	.readlink	= generic_readlink,
 	.follow_link	= sysv_follow_link,
 };
--- diff/fs/ufs/symlink.c	2004-05-19 22:12:32.000000000 +0100
+++ source/fs/ufs/symlink.c	2004-06-11 19:22:06.000000000 +0100
@@ -28,19 +28,14 @@
 #include <linux/fs.h>
 #include <linux/ufs_fs.h>
 
-static int ufs_readlink(struct dentry *dentry, char *buffer, int buflen)
-{
-	struct ufs_inode_info *p = UFS_I(dentry->d_inode);
-	return vfs_readlink(dentry, buffer, buflen, (char*)p->i_u1.i_symlink);
-}
-
 static int ufs_follow_link(struct dentry *dentry, struct nameidata *nd)
 {
 	struct ufs_inode_info *p = UFS_I(dentry->d_inode);
-	return vfs_follow_link(nd, (char*)p->i_u1.i_symlink);
+	nd_set_link(nd, (char*)p->i_u1.i_symlink);
+	return 0;
 }
 
 struct inode_operations ufs_fast_symlink_inode_operations = {
-	.readlink	= ufs_readlink,
+	.readlink	= generic_readlink,
 	.follow_link	= ufs_follow_link,
 };
--- diff/fs/xfs/linux-2.6/xfs_iops.c	2004-06-11 19:17:33.000000000 +0100
+++ source/fs/xfs/linux-2.6/xfs_iops.c	2004-06-11 19:22:06.000000000 +0100
@@ -419,13 +419,16 @@
 	ASSERT(nd);
 
 	link = (char *)kmalloc(MAXNAMELEN+1, GFP_KERNEL);
-	if (!link)
-		return -ENOMEM;
+	if (!link) {
+		nd_set_link(nd, ERR_PTR(-ENOMEM));
+		return 0;
+	}
 
 	uio = (uio_t *)kmalloc(sizeof(uio_t), GFP_KERNEL);
 	if (!uio) {
 		kfree(link);
-		return -ENOMEM;
+		nd_set_link(nd, ERR_PTR(-ENOMEM));
+		return 0;
 	}
 
 	vp = LINVFS_GET_VP(dentry->d_inode);
@@ -441,18 +444,22 @@
 
 	VOP_READLINK(vp, uio, 0, NULL, error);
 	if (error) {
-		kfree(uio);
 		kfree(link);
-		return -error;
+		link = ERR_PTR(-error);
+	} else {
+		link[MAXNAMELEN - uio->uio_resid] = '\0';
 	}
-
-	link[MAXNAMELEN - uio->uio_resid] = '\0';
 	kfree(uio);
 
-	/* vfs_follow_link returns (-) errors */
-	error = vfs_follow_link(nd, link);
-	kfree(link);
-	return error;
+	nd_set_link(nd, link);
+	return 0;
+}
+
+static void linvfs_put_link(struct dentry *dentry, struct nameidata *nd)
+{
+	char *s = nd_get_link(nd);
+	if (!IS_ERR(s))
+		kfree(s);
 }
 
 #ifdef CONFIG_XFS_POSIX_ACL
@@ -692,6 +699,7 @@
 struct inode_operations linvfs_symlink_inode_operations = {
 	.readlink		= linvfs_readlink,
 	.follow_link		= linvfs_follow_link,
+	.put_link		= linvfs_put_link,
 	.permission		= linvfs_permission,
 	.getattr		= linvfs_getattr,
 	.setattr		= linvfs_setattr,
--- diff/include/acpi/acpi_drivers.h	2004-05-19 22:12:33.000000000 +0100
+++ source/include/acpi/acpi_drivers.h	2004-06-11 19:22:06.000000000 +0100
@@ -55,7 +55,7 @@
 
 /* ACPI PCI Interrupt Link (pci_link.c) */
 
-int acpi_pci_link_check (void);
+int acpi_irq_penalty_init (void);
 int acpi_pci_link_get_irq (acpi_handle handle, int index, int* edge_level, int* active_high_low);
 
 /* ACPI PCI Interrupt Routing (pci_irq.c) */
--- diff/include/asm-alpha/resource.h	2004-05-19 22:12:34.000000000 +0100
+++ source/include/asm-alpha/resource.h	2004-06-11 19:22:06.000000000 +0100
@@ -15,9 +15,11 @@
 #define RLIMIT_AS	7		/* address space limit(?) */
 #define RLIMIT_NPROC	8		/* max number of processes */
 #define RLIMIT_MEMLOCK	9		/* max locked-in-memory address space */
-#define RLIMIT_LOCKS   10              /* maximum file locks held */
+#define RLIMIT_LOCKS	10		/* maximum file locks held */
+#define RLIMIT_SIGPENDING 11		/* max number of pending signals */
+#define RLIMIT_MSGQUEUE 12		/* maximum bytes in POSIX mqueues */
 
-#define RLIM_NLIMITS	11
+#define RLIM_NLIMITS	13
 
 /*
  * SuS says limits have to be unsigned.  Fine, it's unsigned, but
@@ -40,7 +42,9 @@
     {LONG_MAX, LONG_MAX},			/* RLIMIT_AS */		\
     {LONG_MAX, LONG_MAX},			/* RLIMIT_NPROC */	\
     {LONG_MAX, LONG_MAX},			/* RLIMIT_MEMLOCK */	\
-    {LONG_MAX, LONG_MAX},                       /* RLIMIT_LOCKS */      \
+    {LONG_MAX, LONG_MAX},			/* RLIMIT_LOCKS */	\
+    {MAX_SIGPENDING, MAX_SIGPENDING},		/* RLIMIT_SIGPENDING */ \
+    {MQ_BYTES_MAX, MQ_BYTES_MAX},		/* RLIMIT_MSGQUEUE */	\
 }
 
 #endif /* __KERNEL__ */
--- diff/include/asm-alpha/spinlock.h	2004-06-11 19:17:33.000000000 +0100
+++ source/include/asm-alpha/spinlock.h	2004-06-11 19:22:06.000000000 +0100
@@ -6,6 +6,10 @@
 #include <linux/kernel.h>
 #include <asm/current.h>
 
+#ifdef CONFIG_LOCKMETER
+#undef DEBUG_SPINLOCK
+#undef DEBUG_RWLOCK
+#endif
 
 /*
  * Simple spin lock operations.  There are two variants, one clears IRQ's
@@ -96,9 +100,18 @@
 
 typedef struct {
 	volatile int write_lock:1, read_counter:31;
+#ifdef CONFIG_LOCKMETER
+	/* required for LOCKMETER since all bits in lock are used */
+	/* need this storage for CPU and lock INDEX ............. */
+	unsigned magic;
+#endif
 } /*__attribute__((aligned(32)))*/ rwlock_t;
 
+#ifdef CONFIG_LOCKMETER
+#define RW_LOCK_UNLOCKED (rwlock_t) { 0, 0, 0 }
+#else
 #define RW_LOCK_UNLOCKED (rwlock_t) { 0, 0 }
+#endif
 
 #define rwlock_init(x)	do { *(x) = RW_LOCK_UNLOCKED; } while(0)
 #define rwlock_is_locked(x)	(*(volatile int *)(x) != 0)
@@ -170,4 +183,41 @@
 	: "m" (*lock) : "memory");
 }
 
+#ifdef CONFIG_LOCKMETER
+static inline int _raw_write_trylock(rwlock_t *lock)
+{
+	long temp,result;
+
+	__asm__ __volatile__(
+	"	ldl_l %1,%0\n"
+	"	mov $31,%2\n"
+	"	bne %1,1f\n"
+	"	or $31,1,%2\n"
+	"	stl_c %2,%0\n"
+	"1:	mb\n"
+	: "=m" (*(volatile int *)lock), "=&r" (temp), "=&r" (result)
+	: "m" (*(volatile int *)lock)
+	);
+
+	return (result);
+}
+
+static inline int _raw_read_trylock(rwlock_t *lock)
+{
+	unsigned long temp,result;
+
+	__asm__ __volatile__(
+	"	ldl_l %1,%0\n"
+	"	mov $31,%2\n"
+	"	blbs %1,1f\n"
+	"	subl %1,2,%2\n"
+	"	stl_c %2,%0\n"
+	"1:	mb\n"
+	: "=m" (*(volatile int *)lock), "=&r" (temp), "=&r" (result)
+	: "m" (*(volatile int *)lock)
+	);
+	return (result);
+}
+#endif /* CONFIG_LOCKMETER */
+
 #endif /* _ALPHA_SPINLOCK_H */
--- diff/include/asm-alpha/system.h	2004-05-19 22:12:34.000000000 +0100
+++ source/include/asm-alpha/system.h	2004-06-11 19:22:06.000000000 +0100
@@ -43,7 +43,6 @@
  */
 #define PARAM			ZERO_PGE
 #define COMMAND_LINE		((char*)(PARAM + 0x0000))
-#define COMMAND_LINE_SIZE	256
 #define INITRD_START		(*(unsigned long *) (PARAM+0x100))
 #define INITRD_SIZE		(*(unsigned long *) (PARAM+0x108))
 
--- diff/include/asm-arm/cacheflush.h	2004-06-11 19:17:33.000000000 +0100
+++ source/include/asm-arm/cacheflush.h	2004-06-11 19:22:06.000000000 +0100
@@ -294,9 +294,9 @@
 extern void flush_dcache_page(struct page *);
 
 #define flush_dcache_mmap_lock(mapping) \
-	spin_lock_irq(&(mapping)->tree_lock)
+	write_lock_irq(&(mapping)->tree_lock)
 #define flush_dcache_mmap_unlock(mapping) \
-	spin_unlock_irq(&(mapping)->tree_lock)
+	write_unlock_irq(&(mapping)->tree_lock)
 
 #define flush_icache_user_range(vma,page,addr,len) \
 	flush_dcache_page(page)
--- diff/include/asm-arm/resource.h	2004-05-19 22:12:34.000000000 +0100
+++ source/include/asm-arm/resource.h	2004-06-11 19:22:06.000000000 +0100
@@ -16,8 +16,10 @@
 #define RLIMIT_MEMLOCK	8		/* max locked-in-memory address space */
 #define RLIMIT_AS	9		/* address space limit */
 #define RLIMIT_LOCKS	10		/* maximum file locks held */
+#define RLIMIT_SIGPENDING 11		/* max number of pending signals */
+#define RLIMIT_MSGQUEUE 12		/* maximum bytes in POSIX mqueues */
 
-#define RLIM_NLIMITS	11
+#define RLIM_NLIMITS	13
 
 #ifdef __KERNEL__
 
@@ -40,6 +42,8 @@
 	{ RLIM_INFINITY, RLIM_INFINITY },	\
 	{ RLIM_INFINITY, RLIM_INFINITY },	\
 	{ RLIM_INFINITY, RLIM_INFINITY },	\
+	{ MAX_SIGPENDING, MAX_SIGPENDING},	\
+	{ MQ_BYTES_MAX, MQ_BYTES_MAX},		\
 }
 
 #endif /* __KERNEL__ */
--- diff/include/asm-arm/unistd.h	2004-06-11 19:17:33.000000000 +0100
+++ source/include/asm-arm/unistd.h	2004-06-11 19:22:06.000000000 +0100
@@ -466,6 +466,7 @@
 #define __ARCH_WANT_SYS_OLDUMOUNT
 #define __ARCH_WANT_SYS_SIGPENDING
 #define __ARCH_WANT_SYS_SIGPROCMASK
+#define __ARCH_WANT_SYS_RT_SIGACTION
 #endif
 
 #ifdef __KERNEL_SYSCALLS__
--- diff/include/asm-arm26/resource.h	2004-05-19 22:12:38.000000000 +0100
+++ source/include/asm-arm26/resource.h	2004-06-11 19:22:06.000000000 +0100
@@ -16,8 +16,10 @@
 #define RLIMIT_MEMLOCK	8		/* max locked-in-memory address space */
 #define RLIMIT_AS	9		/* address space limit */
 #define RLIMIT_LOCKS	10		/* maximum file locks held */
+#define RLIMIT_SIGPENDING 11		/* max number of pending signals */
+#define RLIMIT_MSGQUEUE 12		/* maximum bytes in POSIX mqueues */
 
-#define RLIM_NLIMITS	11
+#define RLIM_NLIMITS	13
 
 #ifdef __KERNEL__
 
@@ -40,6 +42,8 @@
 	{ RLIM_INFINITY, RLIM_INFINITY },	\
 	{ RLIM_INFINITY, RLIM_INFINITY },	\
 	{ RLIM_INFINITY, RLIM_INFINITY },	\
+	{ MAX_SIGPENDING, MAX_SIGPENDING},	\
+	{ MQ_BYTES_MAX, MQ_BYTES_MAX},		\
 }
 
 #endif /* __KERNEL__ */
--- diff/include/asm-arm26/tlb.h	2004-05-19 22:12:38.000000000 +0100
+++ source/include/asm-arm26/tlb.h	2004-06-11 19:22:06.000000000 +0100
@@ -1,6 +1,7 @@
 #ifndef __ASMARM_TLB_H
 #define __ASMARM_TLB_H
 
+#include <asm/pgalloc.h>
 #include <asm/tlbflush.h>
 
 /*
--- diff/include/asm-arm26/unistd.h	2004-06-11 19:17:33.000000000 +0100
+++ source/include/asm-arm26/unistd.h	2004-06-11 19:22:06.000000000 +0100
@@ -397,6 +397,7 @@
 #define __ARCH_WANT_SYS_OLDUMOUNT
 #define __ARCH_WANT_SYS_SIGPENDING
 #define __ARCH_WANT_SYS_SIGPROCMASK
+#define __ARCH_WANT_SYS_RT_SIGACTION
 #endif
 
 #ifdef __KERNEL_SYSCALLS__
--- diff/include/asm-cris/resource.h	2004-05-19 22:12:38.000000000 +0100
+++ source/include/asm-cris/resource.h	2004-06-11 19:22:06.000000000 +0100
@@ -15,9 +15,11 @@
 #define RLIMIT_NOFILE	7		/* max number of open files */
 #define RLIMIT_MEMLOCK	8		/* max locked-in-memory address space */
 #define RLIMIT_AS	9		/* address space limit */
-#define RLIMIT_LOCKS   10              /* maximum file locks held */
+#define RLIMIT_LOCKS	10		/* maximum file locks held */
+#define RLIMIT_SIGPENDING 11		/* max number of pending signals */
+#define RLIMIT_MSGQUEUE 12		/* maximum bytes in POSIX mqueues */
 
-#define RLIM_NLIMITS	11
+#define RLIM_NLIMITS	13
 
 /*
  * SuS says limits have to be unsigned.
@@ -38,8 +40,10 @@
 	{             0,             0 },		\
 	{      INR_OPEN,     INR_OPEN  },		\
 	{ RLIM_INFINITY, RLIM_INFINITY },               \
-        { RLIM_INFINITY, RLIM_INFINITY },		\
 	{ RLIM_INFINITY, RLIM_INFINITY },		\
+	{ RLIM_INFINITY, RLIM_INFINITY },		\
+	{ MAX_SIGPENDING, MAX_SIGPENDING },		\
+	{ MQ_BYTES_MAX, MQ_BYTES_MAX },			\
 }
 
 #endif /* __KERNEL__ */
--- diff/include/asm-cris/setup.h	2004-05-19 22:12:39.000000000 +0100
+++ source/include/asm-cris/setup.h	2004-06-11 19:22:06.000000000 +0100
@@ -1,3 +1,6 @@
 #ifndef _CRIS_SETUP_H
 #define _CRIS_SETUP_H
+
+#define COMMAND_LINE_SIZE	256
+
 #endif
--- diff/include/asm-cris/unistd.h	2004-06-11 19:17:33.000000000 +0100
+++ source/include/asm-cris/unistd.h	2004-06-11 19:22:06.000000000 +0100
@@ -314,6 +314,7 @@
 #define __ARCH_WANT_SYS_OLDUMOUNT
 #define __ARCH_WANT_SYS_SIGPENDING
 #define __ARCH_WANT_SYS_SIGPROCMASK
+#define __ARCH_WANT_SYS_RT_SIGACTION
 #endif
 
 #ifdef __KERNEL_SYSCALLS__
--- diff/include/asm-generic/bitops.h	2004-05-19 22:12:39.000000000 +0100
+++ source/include/asm-generic/bitops.h	2004-06-11 19:22:06.000000000 +0100
@@ -42,7 +42,7 @@
 	return retval;
 }
 
-extern __inline__ int test_bit(int nr, long * addr)
+extern __inline__ int test_bit(int nr, const unsigned long * addr)
 {
 	int	mask;
 
--- diff/include/asm-generic/tlb.h	2004-05-19 22:12:39.000000000 +0100
+++ source/include/asm-generic/tlb.h	2004-06-11 19:22:06.000000000 +0100
@@ -15,6 +15,7 @@
 
 #include <linux/config.h>
 #include <linux/swap.h>
+#include <asm/pgalloc.h>
 #include <asm/tlbflush.h>
 
 /*
@@ -146,4 +147,10 @@
 		__pmd_free_tlb(tlb, pmdp);			\
 	} while (0)
 
+#define tlb_migrate_finish(mm)					\
+	do {							\
+		if (likely(mm))					\
+			flush_tlb_mm(mm);			\
+	} while (0)
+
 #endif /* _ASM_GENERIC__TLB_H */
--- diff/include/asm-h8300/resource.h	2004-05-19 22:12:39.000000000 +0100
+++ source/include/asm-h8300/resource.h	2004-06-11 19:22:06.000000000 +0100
@@ -16,8 +16,10 @@
 #define RLIMIT_MEMLOCK	8		/* max locked-in-memory address space */
 #define RLIMIT_AS	9		/* address space limit */
 #define RLIMIT_LOCKS	10		/* maximum file locks held */
+#define RLIMIT_SIGPENDING 11		/* max number of pending signals */
+#define RLIMIT_MSGQUEUE 12		/* maximum bytes in POSIX mqueues */
 
-#define RLIM_NLIMITS	11
+#define RLIM_NLIMITS	13
 
 /*
  * SuS says limits have to be unsigned.
@@ -39,7 +41,9 @@
 	{      INR_OPEN,     INR_OPEN  },		\
 	{ RLIM_INFINITY, RLIM_INFINITY },		\
 	{ RLIM_INFINITY, RLIM_INFINITY },		\
-        { RLIM_INFINITY, RLIM_INFINITY },		\
+	{ RLIM_INFINITY, RLIM_INFINITY },		\
+	{ MAX_SIGPENDING, MAX_SIGPENDING },		\
+	{ MQ_BYTES_MAX, MQ_BYTES_MAX },			\
 }
 
 #endif /* __KERNEL__ */
--- diff/include/asm-h8300/setup.h	2004-05-19 22:12:39.000000000 +0100
+++ source/include/asm-h8300/setup.h	2004-06-11 19:22:06.000000000 +0100
@@ -1 +1,6 @@
-/* Nothing do */
+#ifndef __H8300_SETUP_H
+#define __H8300_SETUP_H
+
+#define COMMAND_LINE_SIZE	512
+
+#endif
--- diff/include/asm-h8300/unistd.h	2004-06-11 19:17:33.000000000 +0100
+++ source/include/asm-h8300/unistd.h	2004-06-11 19:22:06.000000000 +0100
@@ -468,6 +468,7 @@
 #define __ARCH_WANT_SYS_OLDUMOUNT
 #define __ARCH_WANT_SYS_SIGPENDING
 #define __ARCH_WANT_SYS_SIGPROCMASK
+#define __ARCH_WANT_SYS_RT_SIGACTION
 #endif
 
 #ifdef __KERNEL_SYSCALLS__
--- diff/include/asm-i386/bitops.h	2004-06-11 19:17:33.000000000 +0100
+++ source/include/asm-i386/bitops.h	2004-06-11 19:22:06.000000000 +0100
@@ -34,7 +34,7 @@
  * Note that @nr may be almost arbitrarily large; this function is not
  * restricted to acting on a single-word quantity.
  */
-static __inline__ void set_bit(int nr, volatile unsigned long * addr)
+static inline void set_bit(int nr, volatile unsigned long * addr)
 {
 	__asm__ __volatile__( LOCK_PREFIX
 		"btsl %1,%0"
@@ -51,7 +51,7 @@
  * If it's called on the same region of memory simultaneously, the effect
  * may be that only one operation succeeds.
  */
-static __inline__ void __set_bit(int nr, volatile unsigned long * addr)
+static inline void __set_bit(int nr, volatile unsigned long * addr)
 {
 	__asm__(
 		"btsl %1,%0"
@@ -69,7 +69,7 @@
  * you should call smp_mb__before_clear_bit() and/or smp_mb__after_clear_bit()
  * in order to ensure changes are visible on other processors.
  */
-static __inline__ void clear_bit(int nr, volatile unsigned long * addr)
+static inline void clear_bit(int nr, volatile unsigned long * addr)
 {
 	__asm__ __volatile__( LOCK_PREFIX
 		"btrl %1,%0"
@@ -77,7 +77,7 @@
 		:"Ir" (nr));
 }
 
-static __inline__ void __clear_bit(int nr, volatile unsigned long * addr)
+static inline void __clear_bit(int nr, volatile unsigned long * addr)
 {
 	__asm__ __volatile__(
 		"btrl %1,%0"
@@ -96,7 +96,7 @@
  * If it's called on the same region of memory simultaneously, the effect
  * may be that only one operation succeeds.
  */
-static __inline__ void __change_bit(int nr, volatile unsigned long * addr)
+static inline void __change_bit(int nr, volatile unsigned long * addr)
 {
 	__asm__ __volatile__(
 		"btcl %1,%0"
@@ -113,7 +113,7 @@
  * Note that @nr may be almost arbitrarily large; this function is not
  * restricted to acting on a single-word quantity.
  */
-static __inline__ void change_bit(int nr, volatile unsigned long * addr)
+static inline void change_bit(int nr, volatile unsigned long * addr)
 {
 	__asm__ __volatile__( LOCK_PREFIX
 		"btcl %1,%0"
@@ -129,7 +129,7 @@
  * This operation is atomic and cannot be reordered.  
  * It also implies a memory barrier.
  */
-static __inline__ int test_and_set_bit(int nr, volatile unsigned long * addr)
+static inline int test_and_set_bit(int nr, volatile unsigned long * addr)
 {
 	int oldbit;
 
@@ -149,7 +149,7 @@
  * If two examples of this operation race, one can appear to succeed
  * but actually fail.  You must protect multiple accesses with a lock.
  */
-static __inline__ int __test_and_set_bit(int nr, volatile unsigned long * addr)
+static inline int __test_and_set_bit(int nr, volatile unsigned long * addr)
 {
 	int oldbit;
 
@@ -168,7 +168,7 @@
  * This operation is atomic and cannot be reordered.  
  * It also implies a memory barrier.
  */
-static __inline__ int test_and_clear_bit(int nr, volatile unsigned long * addr)
+static inline int test_and_clear_bit(int nr, volatile unsigned long * addr)
 {
 	int oldbit;
 
@@ -188,7 +188,7 @@
  * If two examples of this operation race, one can appear to succeed
  * but actually fail.  You must protect multiple accesses with a lock.
  */
-static __inline__ int __test_and_clear_bit(int nr, volatile unsigned long *addr)
+static inline int __test_and_clear_bit(int nr, volatile unsigned long *addr)
 {
 	int oldbit;
 
@@ -200,7 +200,7 @@
 }
 
 /* WARNING: non atomic and it can be reordered! */
-static __inline__ int __test_and_change_bit(int nr, volatile unsigned long *addr)
+static inline int __test_and_change_bit(int nr, volatile unsigned long *addr)
 {
 	int oldbit;
 
@@ -219,7 +219,7 @@
  * This operation is atomic and cannot be reordered.  
  * It also implies a memory barrier.
  */
-static __inline__ int test_and_change_bit(int nr, volatile unsigned long* addr)
+static inline int test_and_change_bit(int nr, volatile unsigned long* addr)
 {
 	int oldbit;
 
@@ -244,7 +244,7 @@
 	return ((1UL << (nr & 31)) & (addr[nr >> 5])) != 0;
 }
 
-static __inline__ int variable_test_bit(int nr, const volatile unsigned long * addr)
+static inline int variable_test_bit(int nr, const volatile unsigned long * addr)
 {
 	int oldbit;
 
@@ -270,7 +270,7 @@
  * Returns the bit-number of the first zero bit, not the number of the byte
  * containing a bit.
  */
-static __inline__ int find_first_zero_bit(const unsigned long *addr, unsigned size)
+static inline int find_first_zero_bit(const unsigned long *addr, unsigned size)
 {
 	int d0, d1, d2;
 	int res;
@@ -295,6 +295,14 @@
 }
 
 /**
+ * find_next_zero_bit - find the first zero bit in a memory region
+ * @addr: The address to base the search on
+ * @offset: The bitnumber to start searching at
+ * @size: The maximum size to search
+ */
+int find_next_zero_bit(const unsigned long *addr, int size, int offset);
+
+/**
  * find_first_bit - find the first set bit in a memory region
  * @addr: The address to start the search at
  * @size: The maximum size to search
@@ -302,7 +310,7 @@
  * Returns the bit-number of the first set bit, not the number of the byte
  * containing a bit.
  */
-static __inline__ int find_first_bit(const unsigned long *addr, unsigned size)
+static inline int find_first_bit(const unsigned long *addr, unsigned size)
 {
 	int d0, d1;
 	int res;
@@ -323,70 +331,12 @@
 }
 
 /**
- * find_next_zero_bit - find the first zero bit in a memory region
- * @addr: The address to base the search on
- * @offset: The bitnumber to start searching at
- * @size: The maximum size to search
- */
-static __inline__ int find_next_zero_bit(const unsigned long *addr, int size, int offset)
-{
-	unsigned long * p = ((unsigned long *) addr) + (offset >> 5);
-	int set = 0, bit = offset & 31, res;
-	
-	if (bit) {
-		/*
-		 * Look for zero in the first 32 bits.
-		 */
-		__asm__("bsfl %1,%0\n\t"
-			"jne 1f\n\t"
-			"movl $32, %0\n"
-			"1:"
-			: "=r" (set)
-			: "r" (~(*p >> bit)));
-		if (set < (32 - bit))
-			return set + offset;
-		set = 32 - bit;
-		p++;
-	}
-	/*
-	 * No zero yet, search remaining full bytes for a zero
-	 */
-	res = find_first_zero_bit (p, size - 32 * (p - (unsigned long *) addr));
-	return (offset + set + res);
-}
-
-/**
  * find_next_bit - find the first set bit in a memory region
  * @addr: The address to base the search on
  * @offset: The bitnumber to start searching at
  * @size: The maximum size to search
  */
-static __inline__ int find_next_bit(const unsigned long *addr, int size, int offset)
-{
-	const unsigned long *p = addr + (offset >> 5);
-	int set = 0, bit = offset & 31, res;
-
-	if (bit) {
-		/*
-		 * Look for nonzero in the first 32 bits:
-		 */
-		__asm__("bsfl %1,%0\n\t"
-			"jne 1f\n\t"
-			"movl $32, %0\n"
-			"1:"
-			: "=r" (set)
-			: "r" (*p >> bit));
-		if (set < (32 - bit))
-			return set + offset;
-		set = 32 - bit;
-		p++;
-	}
-	/*
-	 * No set bit yet, search remaining full words for a bit
-	 */
-	res = find_first_bit (p, size - 32 * (p - addr));
-	return (offset + set + res);
-}
+int find_next_bit(const unsigned long *addr, int size, int offset);
 
 /**
  * ffz - find first zero in word.
@@ -394,7 +344,7 @@
  *
  * Undefined if no zero exists, so code should check against ~0UL first.
  */
-static __inline__ unsigned long ffz(unsigned long word)
+static inline unsigned long ffz(unsigned long word)
 {
 	__asm__("bsfl %1,%0"
 		:"=r" (word)
@@ -408,7 +358,7 @@
  *
  * Undefined if no bit exists, so code should check against 0 first.
  */
-static __inline__ unsigned long __ffs(unsigned long word)
+static inline unsigned long __ffs(unsigned long word)
 {
 	__asm__("bsfl %1,%0"
 		:"=r" (word)
@@ -451,7 +401,7 @@
  * the libc and compiler builtin ffs routines, therefore
  * differs in spirit from the above ffz (man ffs).
  */
-static __inline__ int ffs(int x)
+static inline int ffs(int x)
 {
 	int r;
 
--- diff/include/asm-i386/bugs.h	2004-05-19 22:12:40.000000000 +0100
+++ source/include/asm-i386/bugs.h	2004-06-11 19:22:06.000000000 +0100
@@ -1,11 +1,11 @@
 /*
  *  include/asm-i386/bugs.h
  *
- *  Copyright (C) 1994  Linus Torvalds
+ *  Copyright (C) 1994	Linus Torvalds
  *
  *  Cyrix stuff, June 1998 by:
  *	- Rafael R. Reilova (moved everything from head.S),
- *        <rreilova@ececs.uc.edu>
+ *	  <rreilova@ececs.uc.edu>
  *	- Channing Corn (tests & fixes),
  *	- Andrew D. Balsa (code cleanup).
  *
@@ -25,7 +25,20 @@
 #include <asm/processor.h>
 #include <asm/i387.h>
 #include <asm/msr.h>
-
+#ifdef CONFIG_KGDB
+/*
+ * Provied the command line "gdb" initial break
+ */
+int __init kgdb_initial_break(char * str)
+{
+	if (*str == '\0'){
+		breakpoint();
+		return 1;
+	}
+	return 0;
+}
+__setup("gdb",kgdb_initial_break);
+#endif
 static int __init no_halt(char *s)
 {
 	boot_cpu_data.hlt_works_ok = 0;
@@ -140,7 +153,7 @@
 	  : "ecx", "edi" );
 	/* If this fails, it means that any user program may lock the CPU hard. Too bad. */
 	if (res != 12345678) printk( "Buggy.\n" );
-		        else printk( "OK.\n" );
+			else printk( "OK.\n" );
 #endif
 }
 
--- diff/include/asm-i386/cpufeature.h	2004-05-19 22:12:40.000000000 +0100
+++ source/include/asm-i386/cpufeature.h	2004-06-11 19:22:06.000000000 +0100
@@ -47,6 +47,7 @@
 /* Don't duplicate feature flags which are redundant with Intel! */
 #define X86_FEATURE_SYSCALL	(1*32+11) /* SYSCALL/SYSRET */
 #define X86_FEATURE_MP		(1*32+19) /* MP Capable. */
+#define X86_FEATURE_NX		(1*32+20) /* Execute Disable */
 #define X86_FEATURE_MMXEXT	(1*32+22) /* AMD MMX extensions */
 #define X86_FEATURE_LM		(1*32+29) /* Long Mode (x86-64) */
 #define X86_FEATURE_3DNOWEXT	(1*32+30) /* AMD 3DNow! extensions */
@@ -100,6 +101,7 @@
 #define cpu_has_xmm		boot_cpu_has(X86_FEATURE_XMM)
 #define cpu_has_ht		boot_cpu_has(X86_FEATURE_HT)
 #define cpu_has_mp		boot_cpu_has(X86_FEATURE_MP)
+#define cpu_has_nx		boot_cpu_has(X86_FEATURE_NX)
 #define cpu_has_k6_mtrr		boot_cpu_has(X86_FEATURE_K6_MTRR)
 #define cpu_has_cyrix_arr	boot_cpu_has(X86_FEATURE_CYRIX_ARR)
 #define cpu_has_centaur_mcr	boot_cpu_has(X86_FEATURE_CENTAUR_MCR)
--- diff/include/asm-i386/genapic.h	2004-06-11 19:17:33.000000000 +0100
+++ source/include/asm-i386/genapic.h	2004-06-11 19:22:06.000000000 +0100
@@ -25,7 +25,6 @@
 	cpumask_t (*target_cpus)(void);
 	int int_delivery_mode;
 	int int_dest_mode; 
-	int apic_broadcast_id; 
 	int ESR_DISABLE;
 	int apic_destination_logical;
 	unsigned long (*check_apicid_used)(physid_mask_t bitmap, int apicid);
@@ -63,7 +62,7 @@
 
 	unsigned (*get_apic_id)(unsigned long x);
 	unsigned long apic_id_mask;
-	unsigned int (*cpu_mask_to_apicid)(cpumask_const_t cpumask);
+	unsigned int (*cpu_mask_to_apicid)(cpumask_t cpumask);
 	
 	/* ipi */
 	void (*send_IPI_mask)(cpumask_t mask, int vector);
@@ -78,7 +77,6 @@
 	.probe = aprobe, \
 	.int_delivery_mode = INT_DELIVERY_MODE, \
 	.int_dest_mode = INT_DEST_MODE, \
-	.apic_broadcast_id = APIC_BROADCAST_ID, \
 	.no_balance_irq = NO_BALANCE_IRQ, \
 	.no_ioapic_check = NO_IOAPIC_CHECK, \
 	.ESR_DISABLE = esr_disable, \
--- diff/include/asm-i386/hpet.h	2004-05-19 22:12:40.000000000 +0100
+++ source/include/asm-i386/hpet.h	2004-06-11 19:22:06.000000000 +0100
@@ -57,9 +57,12 @@
 #define HPET_ID_LEGSUP	0x00008000
 #define HPET_ID_NUMBER	0x00001f00
 #define HPET_ID_REV	0x000000ff
+#define	HPET_ID_NUMBER_SHIFT	8
 
 #define HPET_CFG_ENABLE	0x001
 #define HPET_CFG_LEGACY	0x002
+#define	HPET_LEGACY_8254	2
+#define	HPET_LEGACY_RTC		8
 
 #define HPET_TN_ENABLE		0x004
 #define HPET_TN_PERIODIC	0x008
--- diff/include/asm-i386/ide.h	2004-06-11 19:17:33.000000000 +0100
+++ source/include/asm-i386/ide.h	2004-06-11 19:22:06.000000000 +0100
@@ -28,9 +28,6 @@
 static __inline__ int ide_default_irq(unsigned long base)
 {
 	switch (base) {
-#ifdef CONFIG_X86_PC9800
-		case 0x640: return 9;
-#endif
 		case 0x1f0: return 14;
 		case 0x170: return 15;
 		case 0x1e8: return 11;
@@ -45,48 +42,17 @@
 static __inline__ unsigned long ide_default_io_base(int index)
 {
 	switch (index) {
-#ifdef CONFIG_X86_PC9800
-		case 0:
-		case 1:	return 0x640;
-#else
 		case 0:	return 0x1f0;
 		case 1:	return 0x170;
 		case 2: return 0x1e8;
 		case 3: return 0x168;
 		case 4: return 0x1e0;
 		case 5: return 0x160;
-#endif
 		default:
 			return 0;
 	}
 }
 
-#ifdef CONFIG_X86_PC9800
-static __inline__ void ide_init_hwif_ports(hw_regs_t *hw, unsigned long data_port,
-	 unsigned long ctrl_port, int *irq)
-{
-	unsigned long reg = data_port;
-	int i;
-
-	unsigned long increment = data_port == 0x640 ? 2 : 1;
-
-	for (i = IDE_DATA_OFFSET; i <= IDE_STATUS_OFFSET; i++) {
-		hw->io_ports[i] = reg;
-		reg += increment;
-	}
-	if (ctrl_port) {
-		hw->io_ports[IDE_CONTROL_OFFSET] = ctrl_port;
-	} else if (data_port == 0x640) {
-		hw->io_ports[IDE_CONTROL_OFFSET] = 0x74c;
-	} else {
-		hw->io_ports[IDE_CONTROL_OFFSET] = hw->io_ports[IDE_DATA_OFFSET] + 0x206;
-	}
-	if (irq != NULL)
-		*irq = 0;
-	hw->io_ports[IDE_IRQ_OFFSET] = 0;
-}
-#endif
-
 #define IDE_ARCH_OBSOLETE_INIT
 #define ide_default_io_ctl(base)	((base) + 0x206) /* obsolete */
 
--- diff/include/asm-i386/io.h	2004-05-19 22:12:40.000000000 +0100
+++ source/include/asm-i386/io.h	2004-06-11 19:22:06.000000000 +0100
@@ -364,4 +364,19 @@
 BUILDIO(w,w,short)
 BUILDIO(l,,int)
 
+static inline u64 readq(void *addr)
+{
+	return readl(addr) | (((u64)readl(addr + 4)) << 32);
+}
+
+static inline void writeq(u64 v, void *addr)
+{
+	u32 v32;
+
+	v32 = v;
+	writel(v32, addr);
+	v32 = v >> 32;
+	writel(v32, addr + 4);
+}
+
 #endif
--- diff/include/asm-i386/io_apic.h	2004-05-19 22:12:40.000000000 +0100
+++ source/include/asm-i386/io_apic.h	2004-06-11 19:22:06.000000000 +0100
@@ -188,15 +188,6 @@
 	*(IO_APIC_BASE(apic)+4) = value;
 }
 
-/*
- * Synchronize the IO-APIC and the CPU by doing
- * a dummy read from the IO-APIC
- */
-static inline void io_apic_sync(unsigned int apic)
-{
-	(void) *(IO_APIC_BASE(apic)+4);
-}
-
 /* 1 if "noapic" boot option passed */
 extern int skip_ioapic_setup;
 
--- diff/include/asm-i386/mach-bigsmp/mach_apic.h	2004-06-11 19:17:33.000000000 +0100
+++ source/include/asm-i386/mach-bigsmp/mach_apic.h	2004-06-11 19:22:06.000000000 +0100
@@ -28,18 +28,17 @@
 	static unsigned long cpu = NR_CPUS;
 	do {
 		if (cpu >= NR_CPUS)
-			cpu = first_cpu_const(cpu_online_map);
+			cpu = first_cpu(cpu_online_map);
 		else
-			cpu = next_cpu_const(cpu, cpu_online_map);
+			cpu = next_cpu(cpu, cpu_online_map);
 	} while (cpu >= NR_CPUS);
-	return mk_cpumask_const(cpumask_of_cpu(cpu));
+	return cpumask_of_cpu(cpu);
 }
 #define TARGET_CPUS	(target_cpus())
 
 #define INT_DELIVERY_MODE dest_Fixed
 #define INT_DEST_MODE 1     /* logical delivery broadcast to all procs */
 
-#define APIC_BROADCAST_ID     (0xff)
 static inline unsigned long check_apicid_used(physid_mask_t bitmap, int apicid)
 {
 	return 0;
@@ -150,12 +149,12 @@
 }
 
 /* As we are using single CPU as destination, pick only one CPU here */
-static inline unsigned int cpu_mask_to_apicid(cpumask_const_t cpumask)
+static inline unsigned int cpu_mask_to_apicid(cpumask_t cpumask)
 {
 	int cpu;
 	int apicid;	
 
-	cpu = first_cpu_const(cpumask);
+	cpu = first_cpu(cpumask);
 	apicid = cpu_to_logical_apicid(cpu);
 	return apicid;
 }
--- diff/include/asm-i386/mach-bigsmp/mach_mpspec.h	2004-05-19 22:12:41.000000000 +0100
+++ source/include/asm-i386/mach-bigsmp/mach_mpspec.h	2004-06-11 19:22:06.000000000 +0100
@@ -1,11 +1,6 @@
 #ifndef __ASM_MACH_MPSPEC_H
 #define __ASM_MACH_MPSPEC_H
 
-/*
- * a maximum of 16 APICs with the current APIC ID architecture.
- */
-#define MAX_APICS 16
-
 #define MAX_IRQ_SOURCES 256
 
 #define MAX_MP_BUSSES 32
--- diff/include/asm-i386/mach-default/irq_vectors.h	2004-05-19 22:12:41.000000000 +0100
+++ source/include/asm-i386/mach-default/irq_vectors.h	2004-06-11 19:22:06.000000000 +0100
@@ -56,14 +56,15 @@
  * sources per level' errata.
  */
 #define LOCAL_TIMER_VECTOR	0xef
+#define LOCAL_PERFCTR_VECTOR	0xee
 
 /*
- * First APIC vector available to drivers: (vectors 0x30-0xee)
+ * First APIC vector available to drivers: (vectors 0x30-0xed)
  * we start at 0x31 to spread out vectors evenly between priority
  * levels. (0x80 is the syscall vector)
  */
 #define FIRST_DEVICE_VECTOR	0x31
-#define FIRST_SYSTEM_VECTOR	0xef
+#define FIRST_SYSTEM_VECTOR	0xee
 
 #define TIMER_IRQ 0
 
--- diff/include/asm-i386/mach-default/mach_apic.h	2004-05-19 22:12:41.000000000 +0100
+++ source/include/asm-i386/mach-default/mach_apic.h	2004-06-11 19:22:06.000000000 +0100
@@ -5,12 +5,12 @@
 
 #define APIC_DFR_VALUE	(APIC_DFR_FLAT)
 
-static inline cpumask_const_t target_cpus(void)
+static inline cpumask_t target_cpus(void)
 { 
 #ifdef CONFIG_SMP
-	return mk_cpumask_const(cpu_online_map);
+	return cpu_online_map;
 #else
-	return mk_cpumask_const(cpumask_of_cpu(0));
+	return cpumask_of_cpu(0);
 #endif
 } 
 #define TARGET_CPUS (target_cpus())
@@ -23,12 +23,6 @@
 #define INT_DELIVERY_MODE dest_LowestPrio
 #define INT_DEST_MODE 1     /* logical delivery broadcast to all procs */
 
-/*
- * this isn't really broadcast, just a (potentially inaccurate) upper
- * bound for valid physical APIC id's
- */
-#define APIC_BROADCAST_ID      0x0F
-
 static inline unsigned long check_apicid_used(physid_mask_t bitmap, int apicid)
 {
 	return physid_isset(apicid, bitmap);
@@ -118,9 +112,9 @@
 	return physid_isset(GET_APIC_ID(apic_read(APIC_ID)), phys_cpu_present_map);
 }
 
-static inline unsigned int cpu_mask_to_apicid(cpumask_const_t cpumask)
+static inline unsigned int cpu_mask_to_apicid(cpumask_t cpumask)
 {
-	return cpus_coerce_const(cpumask);
+	return cpus_addr(cpumask)[0];
 }
 
 static inline void enable_apic_mode(void)
--- diff/include/asm-i386/mach-default/mach_mpspec.h	2004-05-19 22:12:41.000000000 +0100
+++ source/include/asm-i386/mach-default/mach_mpspec.h	2004-06-11 19:22:06.000000000 +0100
@@ -1,11 +1,6 @@
 #ifndef __ASM_MACH_MPSPEC_H
 #define __ASM_MACH_MPSPEC_H
 
-/*
- * a maximum of 16 APICs with the current APIC ID architecture.
- */
-#define MAX_APICS 16
-
 #define MAX_IRQ_SOURCES 256
 
 #define MAX_MP_BUSSES 32
--- diff/include/asm-i386/mach-es7000/mach_apic.h	2004-06-11 19:17:33.000000000 +0100
+++ source/include/asm-i386/mach-es7000/mach_apic.h	2004-06-11 19:22:06.000000000 +0100
@@ -38,7 +38,6 @@
 #define WAKE_SECONDARY_VIA_INIT
 #endif
 
-#define APIC_BROADCAST_ID	(0xff)
 #define NO_IOAPIC_CHECK (1)
 
 static inline unsigned long check_apicid_used(physid_mask_t bitmap, int apicid)
@@ -89,7 +88,7 @@
 	int apic = bios_cpu_apicid[smp_processor_id()];
 	printk("Enabling APIC mode:  %s.  Using %d I/O APICs, target cpus %lx\n",
 		(apic_version[apic] == 0x14) ? 
-		"Physical Cluster" : "Logical Cluster", nr_ioapics, cpus_coerce(TARGET_CPUS));
+		"Physical Cluster" : "Logical Cluster", nr_ioapics, cpus_addr(TARGET_CPUS)[0]);
 }
 
 static inline int multi_timer_check(int apic, int irq)
@@ -159,14 +158,14 @@
 	return (1);
 }
 
-static inline unsigned int cpu_mask_to_apicid(cpumask_const_t cpumask)
+static inline unsigned int cpu_mask_to_apicid(cpumask_t cpumask)
 {
 	int num_bits_set;
 	int cpus_found = 0;
 	int cpu;
 	int apicid;	
 
-	num_bits_set = cpus_weight_const(cpumask);
+	num_bits_set = cpus_weight(cpumask);
 	/* Return id to all */
 	if (num_bits_set == NR_CPUS)
 #if defined CONFIG_ES7000_CLUSTERED_APIC
@@ -178,10 +177,10 @@
 	 * The cpus in the mask must all be on the apic cluster.  If are not 
 	 * on the same apicid cluster return default value of TARGET_CPUS. 
 	 */
-	cpu = first_cpu_const(cpumask);
+	cpu = first_cpu(cpumask);
 	apicid = cpu_to_logical_apicid(cpu);
 	while (cpus_found < num_bits_set) {
-		if (cpu_isset_const(cpu, cpumask)) {
+		if (cpu_isset(cpu, cpumask)) {
 			int new_apicid = cpu_to_logical_apicid(cpu);
 			if (apicid_cluster(apicid) != 
 					apicid_cluster(new_apicid)){
--- diff/include/asm-i386/mach-es7000/mach_ipi.h	2004-06-11 19:17:33.000000000 +0100
+++ source/include/asm-i386/mach-es7000/mach_ipi.h	2004-06-11 19:22:06.000000000 +0100
@@ -10,9 +10,8 @@
 
 static inline void send_IPI_allbutself(int vector)
 {
-	cpumask_t mask = cpumask_of_cpu(smp_processor_id());
-	cpus_complement(mask);
-	cpus_and(mask, mask, cpu_online_map);
+	cpumask_t mask = cpu_online_map;
+	cpu_clear(smp_processor_id(), mask);
 	if (!cpus_empty(mask))
 		send_IPI_mask(mask, vector);
 }
--- diff/include/asm-i386/mach-es7000/mach_mpspec.h	2004-05-19 22:12:41.000000000 +0100
+++ source/include/asm-i386/mach-es7000/mach_mpspec.h	2004-06-11 19:22:06.000000000 +0100
@@ -1,11 +1,6 @@
 #ifndef __ASM_MACH_MPSPEC_H
 #define __ASM_MACH_MPSPEC_H
 
-/*
- * a maximum of 256 APICs with the current APIC ID architecture.
- */
-#define MAX_APICS 256
-
 #define MAX_IRQ_SOURCES 256
 
 #define MAX_MP_BUSSES 32
--- diff/include/asm-i386/mach-generic/mach_apic.h	2004-06-11 19:17:33.000000000 +0100
+++ source/include/asm-i386/mach-generic/mach_apic.h	2004-06-11 19:22:06.000000000 +0100
@@ -6,7 +6,6 @@
 #define esr_disable (genapic->ESR_DISABLE)
 #define NO_BALANCE_IRQ (genapic->no_balance_irq)
 #define NO_IOAPIC_CHECK	(genapic->no_ioapic_check)
-#define APIC_BROADCAST_ID (genapic->apic_broadcast_id)
 #define INT_DELIVERY_MODE (genapic->int_delivery_mode)
 #define INT_DEST_MODE (genapic->int_dest_mode)
 #undef APIC_DEST_LOGICAL
--- diff/include/asm-i386/mach-generic/mach_mpspec.h	2004-05-19 22:12:41.000000000 +0100
+++ source/include/asm-i386/mach-generic/mach_mpspec.h	2004-06-11 19:22:06.000000000 +0100
@@ -1,11 +1,6 @@
 #ifndef __ASM_MACH_MPSPEC_H
 #define __ASM_MACH_MPSPEC_H
 
-/*
- * a maximum of 256 APICs with the current APIC ID architecture.
- */
-#define MAX_APICS 256
-
 #define MAX_IRQ_SOURCES 256
 
 /* Summit or generic (i.e. installer) kernels need lots of bus entries. */
--- diff/include/asm-i386/mach-numaq/mach_apic.h	2004-05-19 22:12:41.000000000 +0100
+++ source/include/asm-i386/mach-numaq/mach_apic.h	2004-06-11 19:22:06.000000000 +0100
@@ -8,8 +8,7 @@
 
 static inline cpumask_t target_cpus(void)
 {
-	cpumask_t tmp = CPU_MASK_ALL;
-	return tmp;
+	return CPU_MASK_ALL;
 }
 
 #define TARGET_CPUS (target_cpus())
@@ -22,7 +21,6 @@
 #define INT_DELIVERY_MODE dest_LowestPrio
 #define INT_DEST_MODE 0     /* physical delivery on LOCAL quad */
  
-#define APIC_BROADCAST_ID      0x0F
 #define check_apicid_used(bitmap, apicid) physid_isset(apicid, bitmap)
 #define check_apicid_present(bit) physid_isset(bit, phys_cpu_present_map)
 #define apicid_cluster(apicid) (apicid & 0xF0)
@@ -136,7 +134,7 @@
  * We use physical apicids here, not logical, so just return the default
  * physical broadcast to stop people from breaking us
  */
-static inline unsigned int cpu_mask_to_apicid(cpumask_const_t cpumask)
+static inline unsigned int cpu_mask_to_apicid(cpumask_t cpumask)
 {
 	return (int) 0xF;
 }
--- diff/include/asm-i386/mach-numaq/mach_mpspec.h	2004-05-19 22:12:41.000000000 +0100
+++ source/include/asm-i386/mach-numaq/mach_mpspec.h	2004-06-11 19:22:06.000000000 +0100
@@ -1,11 +1,6 @@
 #ifndef __ASM_MACH_MPSPEC_H
 #define __ASM_MACH_MPSPEC_H
 
-/*
- * a maximum of 256 APICs with the current APIC ID architecture.
- */
-#define MAX_APICS 256
-
 #define MAX_IRQ_SOURCES 512
 
 #define MAX_MP_BUSSES 32
--- diff/include/asm-i386/mach-pc9800/irq_vectors.h	2004-05-19 22:12:41.000000000 +0100
+++ source/include/asm-i386/mach-pc9800/irq_vectors.h	2004-06-11 19:22:06.000000000 +0100
@@ -59,14 +59,15 @@
  * sources per level' errata.
  */
 #define LOCAL_TIMER_VECTOR	0xef
+#define LOCAL_PERFCTR_VECTOR	0xee
 
 /*
- * First APIC vector available to drivers: (vectors 0x30-0xee)
+ * First APIC vector available to drivers: (vectors 0x30-0xed)
  * we start at 0x31 to spread out vectors evenly between priority
  * levels. (0x80 is the syscall vector)
  */
 #define FIRST_DEVICE_VECTOR	0x31
-#define FIRST_SYSTEM_VECTOR	0xef
+#define FIRST_SYSTEM_VECTOR	0xee
 
 #define TIMER_IRQ 0
 
--- diff/include/asm-i386/mach-summit/mach_apic.h	2004-05-19 22:12:41.000000000 +0100
+++ source/include/asm-i386/mach-summit/mach_apic.h	2004-06-11 19:22:06.000000000 +0100
@@ -19,15 +19,13 @@
 
 static inline cpumask_t target_cpus(void)
 {
-	cpumask_t tmp = CPU_MASK_ALL;
-	return tmp;
+	return CPU_MASK_ALL;
 } 
 #define TARGET_CPUS	(target_cpus())
 
 #define INT_DELIVERY_MODE (dest_Fixed)
 #define INT_DEST_MODE 1     /* logical delivery broadcast to all procs */
 
-#define APIC_BROADCAST_ID     (0xFF)
 static inline unsigned long check_apicid_used(physid_mask_t bitmap, int apicid)
 {
 	return 0;
@@ -140,14 +138,14 @@
 {
 }
 
-static inline unsigned int cpu_mask_to_apicid(cpumask_const_t cpumask)
+static inline unsigned int cpu_mask_to_apicid(cpumask_t cpumask)
 {
 	int num_bits_set;
 	int cpus_found = 0;
 	int cpu;
 	int apicid;	
 
-	num_bits_set = cpus_weight_const(cpumask);
+	num_bits_set = cpus_weight(cpumask);
 	/* Return id to all */
 	if (num_bits_set == NR_CPUS)
 		return (int) 0xFF;
@@ -155,10 +153,10 @@
 	 * The cpus in the mask must all be on the apic cluster.  If are not 
 	 * on the same apicid cluster return default value of TARGET_CPUS. 
 	 */
-	cpu = first_cpu_const(cpumask);
+	cpu = first_cpu(cpumask);
 	apicid = cpu_to_logical_apicid(cpu);
 	while (cpus_found < num_bits_set) {
-		if (cpu_isset_const(cpu, cpumask)) {
+		if (cpu_isset(cpu, cpumask)) {
 			int new_apicid = cpu_to_logical_apicid(cpu);
 			if (apicid_cluster(apicid) != 
 					apicid_cluster(new_apicid)){
--- diff/include/asm-i386/mach-summit/mach_mpspec.h	2004-05-19 22:12:41.000000000 +0100
+++ source/include/asm-i386/mach-summit/mach_mpspec.h	2004-06-11 19:22:06.000000000 +0100
@@ -1,11 +1,6 @@
 #ifndef __ASM_MACH_MPSPEC_H
 #define __ASM_MACH_MPSPEC_H
 
-/*
- * a maximum of 256 APICs with the current APIC ID architecture.
- */
-#define MAX_APICS 256
-
 #define MAX_IRQ_SOURCES 256
 
 /* Maximum 256 PCI busses, plus 1 ISA bus in each of 4 cabinets. */
--- diff/include/asm-i386/mach-visws/irq_vectors.h	2004-05-19 22:12:41.000000000 +0100
+++ source/include/asm-i386/mach-visws/irq_vectors.h	2004-06-11 19:22:06.000000000 +0100
@@ -35,14 +35,15 @@
  * sources per level' errata.
  */
 #define LOCAL_TIMER_VECTOR	0xef
+#define LOCAL_PERFCTR_VECTOR	0xee
 
 /*
- * First APIC vector available to drivers: (vectors 0x30-0xee)
+ * First APIC vector available to drivers: (vectors 0x30-0xed)
  * we start at 0x31 to spread out vectors evenly between priority
  * levels. (0x80 is the syscall vector)
  */
 #define FIRST_DEVICE_VECTOR	0x31
-#define FIRST_SYSTEM_VECTOR	0xef
+#define FIRST_SYSTEM_VECTOR	0xee
 
 #define TIMER_IRQ 0
 
--- diff/include/asm-i386/mach-visws/mach_apic.h	2004-05-19 22:12:41.000000000 +0100
+++ source/include/asm-i386/mach-visws/mach_apic.h	2004-06-11 19:22:06.000000000 +0100
@@ -19,7 +19,6 @@
  #define TARGET_CPUS cpumask_of_cpu(0)
 #endif
 
-#define APIC_BROADCAST_ID      0x0F
 #define check_apicid_used(bitmap, apicid)	physid_isset(apicid, bitmap)
 #define check_apicid_present(bit)		physid_isset(bit, phys_cpu_present_map)
 
@@ -84,9 +83,9 @@
 	return physid_isset(boot_cpu_physical_apicid, phys_cpu_present_map);
 }
 
-static inline unsigned int cpu_mask_to_apicid(cpumask_const_t cpumask)
+static inline unsigned int cpu_mask_to_apicid(cpumask_t cpumask)
 {
-	return cpus_coerce_const(cpumask);
+	return cpus_addr(cpumask)[0];
 }
 
 static inline u32 phys_pkg_id(u32 cpuid_apic, int index_msb)
--- diff/include/asm-i386/mpspec.h	2004-05-19 22:12:40.000000000 +0100
+++ source/include/asm-i386/mpspec.h	2004-06-11 19:22:06.000000000 +0100
@@ -33,7 +33,7 @@
 extern void mp_register_ioapic (u8 id, u32 address, u32 gsi_base);
 extern void mp_override_legacy_irq (u8 bus_irq, u8 polarity, u8 trigger, u32 gsi);
 extern void mp_config_acpi_legacy_irqs (void);
-extern void mp_parse_prt (void);
+extern void mp_register_gsi (u32 gsi, int edge_level, int active_high_low);
 #endif /*CONFIG_ACPI_BOOT*/
 
 #define PHYSID_ARRAY_SIZE	BITS_TO_LONGS(MAX_APICS)
@@ -53,7 +53,7 @@
 #define physids_and(dst, src1, src2)		bitmap_and((dst).mask, (src1).mask, (src2).mask, MAX_APICS)
 #define physids_or(dst, src1, src2)		bitmap_or((dst).mask, (src1).mask, (src2).mask, MAX_APICS)
 #define physids_clear(map)			bitmap_zero((map).mask, MAX_APICS)
-#define physids_complement(map)			bitmap_complement((map).mask, MAX_APICS)
+#define physids_complement(dst, src)		bitmap_complement((dst).mask,(src).mask, MAX_APICS)
 #define physids_empty(map)			bitmap_empty((map).mask, MAX_APICS)
 #define physids_equal(map1, map2)		bitmap_equal((map1).mask, (map2).mask, MAX_APICS)
 #define physids_weight(map)			bitmap_weight((map).mask, MAX_APICS)
--- diff/include/asm-i386/mpspec_def.h	2004-05-19 22:12:40.000000000 +0100
+++ source/include/asm-i386/mpspec_def.h	2004-06-11 19:22:06.000000000 +0100
@@ -14,6 +14,7 @@
 #define SMP_MAGIC_IDENT	(('_'<<24)|('P'<<16)|('M'<<8)|'_')
 
 #define MAX_MPC_ENTRY 1024
+#define MAX_APICS      256
 
 struct intel_mp_floating
 {
--- diff/include/asm-i386/msr.h	2004-05-19 22:12:40.000000000 +0100
+++ source/include/asm-i386/msr.h	2004-06-11 19:22:06.000000000 +0100
@@ -217,6 +217,15 @@
 #define MSR_K7_FID_VID_CTL		0xC0010041
 #define MSR_K7_FID_VID_STATUS		0xC0010042
 
+/* extended feature register */
+#define MSR_EFER 			0xc0000080
+
+/* EFER bits: */
+
+/* Execute Disable enable */
+#define _EFER_NX			11
+#define EFER_NX				(1<<_EFER_NX)
+
 /* Centaur-Hauls/IDT defined MSRs. */
 #define MSR_IDT_FCR1			0x107
 #define MSR_IDT_FCR2			0x108
--- diff/include/asm-i386/page.h	2004-05-19 22:12:40.000000000 +0100
+++ source/include/asm-i386/page.h	2004-06-11 19:22:06.000000000 +0100
@@ -40,15 +40,18 @@
  * These are used to make use of C type-checking..
  */
 #ifdef CONFIG_X86_PAE
+extern unsigned long long __supported_pte_mask;
 typedef struct { unsigned long pte_low, pte_high; } pte_t;
 typedef struct { unsigned long long pmd; } pmd_t;
 typedef struct { unsigned long long pgd; } pgd_t;
+typedef struct { unsigned long long pgprot; } pgprot_t;
 #define pte_val(x)	((x).pte_low | ((unsigned long long)(x).pte_high << 32))
 #define HPAGE_SHIFT	21
 #else
 typedef struct { unsigned long pte_low; } pte_t;
 typedef struct { unsigned long pmd; } pmd_t;
 typedef struct { unsigned long pgd; } pgd_t;
+typedef struct { unsigned long pgprot; } pgprot_t;
 #define boot_pte_t pte_t /* or would you rather have a typedef */
 #define pte_val(x)	((x).pte_low)
 #define HPAGE_SHIFT	22
@@ -61,7 +64,6 @@
 #define HUGETLB_PAGE_ORDER	(HPAGE_SHIFT - PAGE_SHIFT)
 #endif
 
-typedef struct { unsigned long pgprot; } pgprot_t;
 
 #define pmd_val(x)	((x).pmd)
 #define pgd_val(x)	((x).pgd)
--- diff/include/asm-i386/param.h	2004-06-11 19:17:33.000000000 +0100
+++ source/include/asm-i386/param.h	2004-06-11 19:22:06.000000000 +0100
@@ -18,5 +18,6 @@
 #endif
 
 #define MAXHOSTNAMELEN	64	/* max length of hostname */
+#define COMMAND_LINE_SIZE 256
 
 #endif
--- diff/include/asm-i386/pgtable-3level.h	2004-05-19 22:12:40.000000000 +0100
+++ source/include/asm-i386/pgtable-3level.h	2004-06-11 19:22:06.000000000 +0100
@@ -101,18 +101,24 @@
 		(pte.pte_high << (32 - PAGE_SHIFT));
 }
 
+extern unsigned long long __supported_pte_mask;
+
 static inline pte_t pfn_pte(unsigned long page_nr, pgprot_t pgprot)
 {
 	pte_t pte;
 
-	pte.pte_high = page_nr >> (32 - PAGE_SHIFT);
-	pte.pte_low = (page_nr << PAGE_SHIFT) | pgprot_val(pgprot);
+	pte.pte_high = (page_nr >> (32 - PAGE_SHIFT)) | \
+					(pgprot_val(pgprot) >> 32);
+	pte.pte_high &= (__supported_pte_mask >> 32);
+	pte.pte_low = ((page_nr << PAGE_SHIFT) | pgprot_val(pgprot)) & \
+							__supported_pte_mask;
 	return pte;
 }
 
 static inline pmd_t pfn_pmd(unsigned long page_nr, pgprot_t pgprot)
 {
-	return __pmd(((unsigned long long)page_nr << PAGE_SHIFT) | pgprot_val(pgprot));
+	return __pmd((((unsigned long long)page_nr << PAGE_SHIFT) | \
+			pgprot_val(pgprot)) & __supported_pte_mask);
 }
 
 /*
--- diff/include/asm-i386/pgtable.h	2004-06-11 19:17:33.000000000 +0100
+++ source/include/asm-i386/pgtable.h	2004-06-11 19:22:06.000000000 +0100
@@ -110,6 +110,7 @@
 #define _PAGE_BIT_UNUSED1	9	/* available for programmer */
 #define _PAGE_BIT_UNUSED2	10
 #define _PAGE_BIT_UNUSED3	11
+#define _PAGE_BIT_NX		63
 
 #define _PAGE_PRESENT	0x001
 #define _PAGE_RW	0x002
@@ -126,28 +127,51 @@
 
 #define _PAGE_FILE	0x040	/* set:pagecache unset:swap */
 #define _PAGE_PROTNONE	0x080	/* If not present */
+#ifdef CONFIG_X86_PAE
+#define _PAGE_NX	(1ULL<<_PAGE_BIT_NX)
+#else
+#define _PAGE_NX	0
+#endif
 
 #define _PAGE_TABLE	(_PAGE_PRESENT | _PAGE_RW | _PAGE_USER | _PAGE_ACCESSED | _PAGE_DIRTY)
 #define _KERNPG_TABLE	(_PAGE_PRESENT | _PAGE_RW | _PAGE_ACCESSED | _PAGE_DIRTY)
 #define _PAGE_CHG_MASK	(PTE_MASK | _PAGE_ACCESSED | _PAGE_DIRTY)
 
-#define PAGE_NONE	__pgprot(_PAGE_PROTNONE | _PAGE_ACCESSED)
-#define PAGE_SHARED	__pgprot(_PAGE_PRESENT | _PAGE_RW | _PAGE_USER | _PAGE_ACCESSED)
-#define PAGE_COPY	__pgprot(_PAGE_PRESENT | _PAGE_USER | _PAGE_ACCESSED)
-#define PAGE_READONLY	__pgprot(_PAGE_PRESENT | _PAGE_USER | _PAGE_ACCESSED)
+#define PAGE_NONE \
+	__pgprot(_PAGE_PROTNONE | _PAGE_ACCESSED)
+#define PAGE_SHARED \
+	__pgprot(_PAGE_PRESENT | _PAGE_RW | _PAGE_USER | _PAGE_ACCESSED)
+
+#define PAGE_SHARED_EXEC \
+	__pgprot(_PAGE_PRESENT | _PAGE_RW | _PAGE_USER | _PAGE_ACCESSED)
+#define PAGE_COPY_NOEXEC \
+	__pgprot(_PAGE_PRESENT | _PAGE_USER | _PAGE_ACCESSED | _PAGE_NX)
+#define PAGE_COPY_EXEC \
+	__pgprot(_PAGE_PRESENT | _PAGE_USER | _PAGE_ACCESSED)
+#define PAGE_COPY \
+	PAGE_COPY_NOEXEC
+#define PAGE_READONLY \
+	__pgprot(_PAGE_PRESENT | _PAGE_USER | _PAGE_ACCESSED | _PAGE_NX)
+#define PAGE_READONLY_EXEC \
+	__pgprot(_PAGE_PRESENT | _PAGE_USER | _PAGE_ACCESSED)
 
 #define _PAGE_KERNEL \
+	(_PAGE_PRESENT | _PAGE_RW | _PAGE_DIRTY | _PAGE_ACCESSED | _PAGE_NX)
+#define _PAGE_KERNEL_EXEC \
 	(_PAGE_PRESENT | _PAGE_RW | _PAGE_DIRTY | _PAGE_ACCESSED)
 
-extern unsigned long __PAGE_KERNEL;
-#define __PAGE_KERNEL_RO	(__PAGE_KERNEL & ~_PAGE_RW)
-#define __PAGE_KERNEL_NOCACHE	(__PAGE_KERNEL | _PAGE_PCD)
-#define __PAGE_KERNEL_LARGE	(__PAGE_KERNEL | _PAGE_PSE)
+extern unsigned long long __PAGE_KERNEL, __PAGE_KERNEL_EXEC;
+#define __PAGE_KERNEL_RO		(__PAGE_KERNEL & ~_PAGE_RW)
+#define __PAGE_KERNEL_NOCACHE		(__PAGE_KERNEL | _PAGE_PCD)
+#define __PAGE_KERNEL_LARGE		(__PAGE_KERNEL | _PAGE_PSE)
+#define __PAGE_KERNEL_LARGE_EXEC	(__PAGE_KERNEL_EXEC | _PAGE_PSE)
 
 #define PAGE_KERNEL		__pgprot(__PAGE_KERNEL)
 #define PAGE_KERNEL_RO		__pgprot(__PAGE_KERNEL_RO)
+#define PAGE_KERNEL_EXEC	__pgprot(__PAGE_KERNEL_EXEC)
 #define PAGE_KERNEL_NOCACHE	__pgprot(__PAGE_KERNEL_NOCACHE)
 #define PAGE_KERNEL_LARGE	__pgprot(__PAGE_KERNEL_LARGE)
+#define PAGE_KERNEL_LARGE_EXEC	__pgprot(__PAGE_KERNEL_LARGE_EXEC)
 
 /*
  * The i386 can't do page protection for execute, and considers that
@@ -158,19 +182,19 @@
 #define __P001	PAGE_READONLY
 #define __P010	PAGE_COPY
 #define __P011	PAGE_COPY
-#define __P100	PAGE_READONLY
-#define __P101	PAGE_READONLY
-#define __P110	PAGE_COPY
-#define __P111	PAGE_COPY
+#define __P100	PAGE_READONLY_EXEC
+#define __P101	PAGE_READONLY_EXEC
+#define __P110	PAGE_COPY_EXEC
+#define __P111	PAGE_COPY_EXEC
 
 #define __S000	PAGE_NONE
 #define __S001	PAGE_READONLY
 #define __S010	PAGE_SHARED
 #define __S011	PAGE_SHARED
-#define __S100	PAGE_READONLY
-#define __S101	PAGE_READONLY
-#define __S110	PAGE_SHARED
-#define __S111	PAGE_SHARED
+#define __S100	PAGE_READONLY_EXEC
+#define __S101	PAGE_READONLY_EXEC
+#define __S110	PAGE_SHARED_EXEC
+#define __S111	PAGE_SHARED_EXEC
 
 /*
  * Define this if things work differently on an i386 and an i486:
@@ -220,8 +244,20 @@
 static inline pte_t pte_mkyoung(pte_t pte)	{ (pte).pte_low |= _PAGE_ACCESSED; return pte; }
 static inline pte_t pte_mkwrite(pte_t pte)	{ (pte).pte_low |= _PAGE_RW; return pte; }
 
-static inline  int ptep_test_and_clear_dirty(pte_t *ptep)	{ return test_and_clear_bit(_PAGE_BIT_DIRTY, &ptep->pte_low); }
-static inline  int ptep_test_and_clear_young(pte_t *ptep)	{ return test_and_clear_bit(_PAGE_BIT_ACCESSED, &ptep->pte_low); }
+static inline int ptep_test_and_clear_dirty(pte_t *ptep)
+{
+	if (!pte_dirty(*ptep))
+		return 0;
+	return test_and_clear_bit(_PAGE_BIT_DIRTY, &ptep->pte_low);
+}
+
+static inline int ptep_test_and_clear_young(pte_t *ptep)
+{
+	if (!pte_young(*ptep))
+		return 0;
+	return test_and_clear_bit(_PAGE_BIT_ACCESSED, &ptep->pte_low);
+}
+
 static inline void ptep_set_wrprotect(pte_t *ptep)		{ clear_bit(_PAGE_BIT_RW, &ptep->pte_low); }
 static inline void ptep_mkdirty(pte_t *ptep)			{ set_bit(_PAGE_BIT_DIRTY, &ptep->pte_low); }
 
@@ -244,6 +280,15 @@
 {
 	pte.pte_low &= _PAGE_CHG_MASK;
 	pte.pte_low |= pgprot_val(newprot);
+#ifdef CONFIG_X86_PAE
+	/*
+	 * Chop off the NX bit (if present), and add the NX portion of
+	 * the newprot (if present):
+	 */
+	pte.pte_high &= -1 ^ (1 << (_PAGE_BIT_NX - 32));
+	pte.pte_high |= (pgprot_val(newprot) >> 32) & \
+					(__supported_pte_mask >> 32);
+#endif
 	return pte;
 }
 
--- diff/include/asm-i386/processor.h	2004-06-11 19:17:33.000000000 +0100
+++ source/include/asm-i386/processor.h	2004-06-11 19:22:06.000000000 +0100
@@ -259,14 +259,8 @@
 
 /*
  * Bus types (default is ISA, but people can check others with these..)
- * pc98 indicates PC98 systems (CBUS)
  */
 extern int MCA_bus;
-#ifdef CONFIG_X86_PC9800
-#define pc98 1
-#else
-#define pc98 0
-#endif
 
 static inline void __monitor(const void *eax, unsigned long ecx,
 		unsigned long edx)
@@ -428,6 +422,8 @@
 	unsigned int		saved_fs, saved_gs;
 /* IO permissions */
 	unsigned long	*io_bitmap_ptr;
+/* performance counters */
+	struct vperfctr *perfctr;
 };
 
 #define INIT_THREAD  {							\
--- diff/include/asm-i386/resource.h	2004-05-19 22:12:40.000000000 +0100
+++ source/include/asm-i386/resource.h	2004-06-11 19:22:06.000000000 +0100
@@ -16,8 +16,11 @@
 #define RLIMIT_MEMLOCK	8		/* max locked-in-memory address space */
 #define RLIMIT_AS	9		/* address space limit */
 #define RLIMIT_LOCKS	10		/* maximum file locks held */
+#define RLIMIT_SIGPENDING 11		/* max number of pending signals */
+#define RLIMIT_MSGQUEUE 12		/* maximum bytes in POSIX mqueues */
+
+#define RLIM_NLIMITS	13
 
-#define RLIM_NLIMITS	11
 
 /*
  * SuS says limits have to be unsigned.
@@ -39,7 +42,9 @@
 	{      INR_OPEN,     INR_OPEN  },		\
 	{ RLIM_INFINITY, RLIM_INFINITY },		\
 	{ RLIM_INFINITY, RLIM_INFINITY },		\
-        { RLIM_INFINITY, RLIM_INFINITY },		\
+	{ RLIM_INFINITY, RLIM_INFINITY },		\
+	{ MAX_SIGPENDING, MAX_SIGPENDING },		\
+	{ MQ_BYTES_MAX, MQ_BYTES_MAX },			\
 }
 
 #endif /* __KERNEL__ */
--- diff/include/asm-i386/rwlock.h	2004-05-19 22:12:40.000000000 +0100
+++ source/include/asm-i386/rwlock.h	2004-06-11 19:22:06.000000000 +0100
@@ -20,28 +20,52 @@
 #define RW_LOCK_BIAS		 0x01000000
 #define RW_LOCK_BIAS_STR	"0x01000000"
 
-#define __build_read_lock_ptr(rw, helper)   \
-	asm volatile(LOCK "subl $1,(%0)\n\t" \
-		     "js 2f\n" \
-		     "1:\n" \
-		     LOCK_SECTION_START("") \
-		     "2:\tcall " helper "\n\t" \
-		     "jmp 1b\n" \
-		     LOCK_SECTION_END \
-		     ::"a" (rw) : "memory")
-
-#define __build_read_lock_const(rw, helper)   \
-	asm volatile(LOCK "subl $1,%0\n\t" \
-		     "js 2f\n" \
-		     "1:\n" \
-		     LOCK_SECTION_START("") \
-		     "2:\tpushl %%eax\n\t" \
-		     "leal %0,%%eax\n\t" \
-		     "call " helper "\n\t" \
-		     "popl %%eax\n\t" \
-		     "jmp 1b\n" \
-		     LOCK_SECTION_END \
-		     :"=m" (*(volatile int *)rw) : : "memory")
+#ifdef CONFIG_SPINLINE
+
+	#define __build_read_lock_ptr(rw, helper)   \
+		asm volatile(LOCK "subl $1,(%0)\n\t" \
+			     "jns 1f\n\t" \
+			     "call " helper "\n\t" \
+			     "1:\t" \
+			     ::"a" (rw) : "memory")
+
+	#define __build_read_lock_const(rw, helper)   \
+		asm volatile(LOCK "subl $1,%0\n\t" \
+			     "jns 1f\n\t" \
+			     "pushl %%eax\n\t" \
+			     "leal %0,%%eax\n\t" \
+			     "call " helper "\n\t" \
+			     "popl %%eax\n\t" \
+			     "1:\t" \
+			     :"=m" (*(volatile int *)rw) : : "memory")
+
+#else /* !CONFIG_SPINLINE */
+
+	#define __build_read_lock_ptr(rw, helper)   \
+		asm volatile(LOCK "subl $1,(%0)\n\t" \
+			     "js 2f\n" \
+			     "1:\n" \
+			     LOCK_SECTION_START("") \
+			     "2:\tcall " helper "\n\t" \
+			     "jmp 1b\n" \
+			     LOCK_SECTION_END \
+			     ::"a" (rw) : "memory")
+
+	#define __build_read_lock_const(rw, helper)   \
+		asm volatile(LOCK "subl $1,%0\n\t" \
+			     "js 2f\n" \
+			     "1:\n" \
+			     LOCK_SECTION_START("") \
+			     "2:\tpushl %%eax\n\t" \
+			     "leal %0,%%eax\n\t" \
+			     "call " helper "\n\t" \
+			     "popl %%eax\n\t" \
+			     "jmp 1b\n" \
+			     LOCK_SECTION_END \
+			     :"=m" (*(volatile int *)rw) : : "memory")
+
+#endif /* CONFIG_SPINLINE */
+
 
 #define __build_read_lock(rw, helper)	do { \
 						if (__builtin_constant_p(rw)) \
@@ -50,28 +74,51 @@
 							__build_read_lock_ptr(rw, helper); \
 					} while (0)
 
-#define __build_write_lock_ptr(rw, helper) \
-	asm volatile(LOCK "subl $" RW_LOCK_BIAS_STR ",(%0)\n\t" \
-		     "jnz 2f\n" \
-		     "1:\n" \
-		     LOCK_SECTION_START("") \
-		     "2:\tcall " helper "\n\t" \
-		     "jmp 1b\n" \
-		     LOCK_SECTION_END \
-		     ::"a" (rw) : "memory")
-
-#define __build_write_lock_const(rw, helper) \
-	asm volatile(LOCK "subl $" RW_LOCK_BIAS_STR ",%0\n\t" \
-		     "jnz 2f\n" \
-		     "1:\n" \
-		     LOCK_SECTION_START("") \
-		     "2:\tpushl %%eax\n\t" \
-		     "leal %0,%%eax\n\t" \
-		     "call " helper "\n\t" \
-		     "popl %%eax\n\t" \
-		     "jmp 1b\n" \
-		     LOCK_SECTION_END \
-		     :"=m" (*(volatile int *)rw) : : "memory")
+#ifdef CONFIG_SPINLINE
+
+	#define __build_write_lock_ptr(rw, helper) \
+		asm volatile(LOCK "subl $" RW_LOCK_BIAS_STR ",(%0)\n\t" \
+			     "jz 1f\n\t" \
+			     "call " helper "\n\t" \
+			     "1:\n" \
+			     ::"a" (rw) : "memory")
+
+	#define __build_write_lock_const(rw, helper) \
+		asm volatile(LOCK "subl $" RW_LOCK_BIAS_STR ",%0\n\t" \
+			     "jz 1f\n\t" \
+			     "pushl %%eax\n\t" \
+			     "leal %0,%%eax\n\t" \
+			     "call " helper "\n\t" \
+			     "popl %%eax\n\t" \
+			     "1:\n" \
+			     :"=m" (*(volatile int *)rw) : : "memory")
+
+#else /* !CONFIG_SPINLINE */
+
+	#define __build_write_lock_ptr(rw, helper) \
+		asm volatile(LOCK "subl $" RW_LOCK_BIAS_STR ",(%0)\n\t" \
+			     "jnz 2f\n" \
+			     "1:\n" \
+			     LOCK_SECTION_START("") \
+			     "2:\tcall " helper "\n\t" \
+			     "jmp 1b\n" \
+			     LOCK_SECTION_END \
+			     ::"a" (rw) : "memory")
+
+	#define __build_write_lock_const(rw, helper) \
+		asm volatile(LOCK "subl $" RW_LOCK_BIAS_STR ",%0\n\t" \
+			     "jnz 2f\n" \
+			     "1:\n" \
+			     LOCK_SECTION_START("") \
+			     "2:\tpushl %%eax\n\t" \
+			     "leal %0,%%eax\n\t" \
+			     "call " helper "\n\t" \
+			     "popl %%eax\n\t" \
+			     "jmp 1b\n" \
+			     LOCK_SECTION_END \
+			     :"=m" (*(volatile int *)rw) : : "memory")
+
+#endif /* CONFIG_SPINLINE */
 
 #define __build_write_lock(rw, helper)	do { \
 						if (__builtin_constant_p(rw)) \
--- diff/include/asm-i386/serial.h	2004-05-19 22:12:40.000000000 +0100
+++ source/include/asm-i386/serial.h	2004-06-11 19:22:06.000000000 +0100
@@ -47,19 +47,12 @@
 
 #define C_P(card,port) (((card)<<6|(port)<<3) + 1)
 
-#ifndef CONFIG_X86_PC9800
 #define STD_SERIAL_PORT_DEFNS			\
 	/* UART CLK   PORT IRQ     FLAGS        */			\
 	{ 0, BASE_BAUD, 0x3F8, 4, STD_COM_FLAGS },	/* ttyS0 */	\
 	{ 0, BASE_BAUD, 0x2F8, 3, STD_COM_FLAGS },	/* ttyS1 */	\
 	{ 0, BASE_BAUD, 0x3E8, 4, STD_COM_FLAGS },	/* ttyS2 */	\
 	{ 0, BASE_BAUD, 0x2E8, 3, STD_COM4_FLAGS },	/* ttyS3 */
-#else
-#define STD_SERIAL_PORT_DEFNS			\
-	/* UART CLK   PORT IRQ     FLAGS        */			\
-	{ 0, BASE_BAUD, 0x30, 4, STD_COM_FLAGS },	/* ttyS0 */	\
-	{ 0, BASE_BAUD, 0x238, 5, STD_COM_FLAGS },	/* ttyS1 */
-#endif /* CONFIG_X86_PC9800 */
 
 
 #ifdef CONFIG_SERIAL_MANY_PORTS
--- diff/include/asm-i386/spinlock.h	2004-06-11 19:17:33.000000000 +0100
+++ source/include/asm-i386/spinlock.h	2004-06-11 19:22:06.000000000 +0100
@@ -42,20 +42,68 @@
 
 #define spin_is_locked(x)	(*(volatile signed char *)(&(x)->lock) <= 0)
 #define spin_unlock_wait(x)	do { barrier(); } while(spin_is_locked(x))
-#define _raw_spin_lock_flags(lock, flags) _raw_spin_lock(lock)
 
-#define spin_lock_string \
-	"\n1:\t" \
-	"lock ; decb %0\n\t" \
-	"js 2f\n" \
-	LOCK_SECTION_START("") \
-	"2:\t" \
-	"rep;nop\n\t" \
-	"cmpb $0,%0\n\t" \
-	"jle 2b\n\t" \
-	"jmp 1b\n" \
-	LOCK_SECTION_END
+#ifdef CONFIG_SPINLINE
 
+	#define spin_lock_string \
+		"\n1:\t" \
+		"lock ; decb %0\n\t" \
+		"js 2f\n" \
+		"jmp 3f\n" \
+		"2:\t" \
+		"rep;nop\n\t" \
+		"cmpb $0,%0\n\t" \
+		"jle 2b\n\t" \
+		"jmp 1b\n" \
+		"3:\t"
+
+	#define spin_lock_string_flags \
+		"\n1:\t" \
+		"lock ; decb %0\n\t" \
+		"jns 3f\n" \
+		"testl $0x200, %1\n\t" \
+		"jz 2f\n\t" \
+		"sti\n\t" \
+		"2:\t" \
+		"rep;nop\n\t" \
+		"cmpb $0, %0\n\t" \
+		"jle 2b\n\t" \
+		"cli\n\t" \
+		"jmp 1b\n" \
+		"3:\t"
+
+#else /* !CONFIG_SPINLINE */
+
+	#define spin_lock_string \
+		"\n1:\t" \
+		"lock ; decb %0\n\t" \
+		"js 2f\n" \
+		LOCK_SECTION_START("") \
+		"2:\t" \
+		"rep;nop\n\t" \
+		"cmpb $0,%0\n\t" \
+		"jle 2b\n\t" \
+		"jmp 1b\n" \
+		LOCK_SECTION_END
+
+	#define spin_lock_string_flags \
+		"\n1:\t" \
+		"lock ; decb %0\n\t" \
+		"js 2f\n\t" \
+		LOCK_SECTION_START("") \
+		"2:\t" \
+		"testl $0x200, %1\n\t" \
+		"jz 3f\n\t" \
+		"sti\n\t" \
+		"3:\t" \
+		"rep;nop\n\t" \
+		"cmpb $0, %0\n\t" \
+		"jle 3b\n\t" \
+		"cli\n\t" \
+		"jmp 1b\n" \
+		LOCK_SECTION_END
+
+#endif /* CONFIG_SPINLINE */
 /*
  * This works. Despite all the confusion.
  * (except on PPro SMP or if we are using OOSTORE)
@@ -126,6 +174,20 @@
 		:"=m" (lock->lock) : : "memory");
 }
 
+static inline void _raw_spin_lock_flags (spinlock_t *lock, unsigned long flags)
+{
+#ifdef CONFIG_DEBUG_SPINLOCK
+	__label__ here;
+here:
+	if (unlikely(lock->magic != SPINLOCK_MAGIC)) {
+		printk("eip: %p\n", &&here);
+		BUG();
+	}
+#endif
+	__asm__ __volatile__(
+		spin_lock_string_flags
+		:"=m" (lock->lock) : "r" (flags) : "memory");
+}
 
 /*
  * Read-write spinlocks, allowing multiple readers
@@ -139,6 +201,11 @@
  */
 typedef struct {
 	volatile unsigned int lock;
+#ifdef CONFIG_LOCKMETER
+	/* required for LOCKMETER since all bits in lock are used */
+	/* and we need this storage for CPU and lock INDEX        */
+	unsigned lockmeter_magic;
+#endif
 #ifdef CONFIG_DEBUG_SPINLOCK
 	unsigned magic;
 #endif
@@ -146,11 +213,19 @@
 
 #define RWLOCK_MAGIC	0xdeaf1eed
 
+#ifdef CONFIG_LOCKMETER
+#ifdef CONFIG_DEBUG_SPINLOCK
+#define RWLOCK_MAGIC_INIT	, 0, RWLOCK_MAGIC
+#else
+#define RWLOCK_MAGIC_INIT	, 0
+#endif
+#else /* !CONFIG_LOCKMETER */
 #ifdef CONFIG_DEBUG_SPINLOCK
 #define RWLOCK_MAGIC_INIT	, RWLOCK_MAGIC
 #else
 #define RWLOCK_MAGIC_INIT	/* */
 #endif
+#endif /* !CONFIG_LOCKMETER */
 
 #define RW_LOCK_UNLOCKED (rwlock_t) { RW_LOCK_BIAS RWLOCK_MAGIC_INIT }
 
@@ -197,4 +272,60 @@
 	return 0;
 }
 
+#ifdef CONFIG_LOCKMETER
+static inline int _raw_read_trylock(rwlock_t *lock)
+{
+/* FIXME -- replace with assembler */
+	atomic_t *count = (atomic_t *)lock;
+	atomic_dec(count);
+	if (count->counter > 0)
+		return 1;
+	atomic_inc(count);
+	return 0;
+}
+#endif
+
+#if defined(CONFIG_LOCKMETER) && defined(CONFIG_HAVE_DEC_LOCK)
+extern void _metered_spin_lock  (spinlock_t *lock);
+extern void _metered_spin_unlock(spinlock_t *lock);
+
+/*
+ *  Matches what is in arch/i386/lib/dec_and_lock.c, except this one is
+ *  "static inline" so that the spin_lock(), if actually invoked, is charged
+ *  against the real caller, not against the catch-all atomic_dec_and_lock
+ */
+static inline int atomic_dec_and_lock(atomic_t *atomic, spinlock_t *lock)
+{
+	int counter;
+	int newcount;
+
+repeat:
+	counter = atomic_read(atomic);
+	newcount = counter-1;
+
+	if (!newcount)
+		goto slow_path;
+
+	asm volatile("lock; cmpxchgl %1,%2"
+		:"=a" (newcount)
+		:"r" (newcount), "m" (atomic->counter), "0" (counter));
+
+	/* If the above failed, "eax" will have changed */
+	if (newcount != counter)
+		goto repeat;
+	return 0;
+
+slow_path:
+	preempt_disable();
+	_metered_spin_lock(lock);
+	if (atomic_dec_and_test(atomic))
+		return 1;
+	_metered_spin_unlock(lock);
+	preempt_enable();
+	return 0;
+}
+
+#define ATOMIC_DEC_AND_LOCK
+#endif
+
 #endif /* __ASM_SPINLOCK_H */
--- diff/include/asm-i386/thread_info.h	2004-06-11 19:17:33.000000000 +0100
+++ source/include/asm-i386/thread_info.h	2004-06-11 19:22:06.000000000 +0100
@@ -157,7 +157,7 @@
 
 /* work to do on interrupt/exception return */
 #define _TIF_WORK_MASK \
-  (0x0000FFFF & ~(_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT))
+  (0x0000FFFF & ~(_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT|_TIF_SINGLESTEP))
 #define _TIF_ALLWORK_MASK	0x0000FFFF	/* work to do on any return to u-space */
 
 /*
--- diff/include/asm-i386/timex.h	2004-05-19 22:12:41.000000000 +0100
+++ source/include/asm-i386/timex.h	2004-06-11 19:22:06.000000000 +0100
@@ -9,15 +9,11 @@
 #include <linux/config.h>
 #include <asm/msr.h>
 
-#ifdef CONFIG_X86_PC9800
-   extern int CLOCK_TICK_RATE;
-#else
 #ifdef CONFIG_X86_ELAN
 #  define CLOCK_TICK_RATE 1189200 /* AMD Elan has different frequency! */
 #else
 #  define CLOCK_TICK_RATE 1193182 /* Underlying HZ */
 #endif
-#endif
 
 #define CLOCK_TICK_FACTOR	20	/* Factor of both 1000000 and CLOCK_TICK_RATE */
 #define FINETUNE ((((((long)LATCH * HZ - CLOCK_TICK_RATE) << SHIFT_HZ) * \
--- diff/include/asm-i386/unistd.h	2004-06-11 19:17:33.000000000 +0100
+++ source/include/asm-i386/unistd.h	2004-06-11 19:22:06.000000000 +0100
@@ -289,8 +289,14 @@
 #define __NR_mq_notify		(__NR_mq_open+4)
 #define __NR_mq_getsetattr	(__NR_mq_open+5)
 #define __NR_sys_kexec_load	283
+#define __NR_perfctr_info	284
+#define __NR_vperfctr_open	(__NR_perfctr_info+1)
+#define __NR_vperfctr_control	(__NR_perfctr_info+2)
+#define __NR_vperfctr_unlink	(__NR_perfctr_info+3)
+#define __NR_vperfctr_iresume	(__NR_perfctr_info+4)
+#define __NR_vperfctr_read	(__NR_perfctr_info+5)
 
-#define NR_syscalls 284
+#define NR_syscalls 290
 
 /* user-visible error numbers are in the range -1 - -124: see <asm-i386/errno.h> */
 
@@ -403,6 +409,7 @@
 #define __ARCH_WANT_SYS_OLDUMOUNT
 #define __ARCH_WANT_SYS_SIGPENDING
 #define __ARCH_WANT_SYS_SIGPROCMASK
+#define __ARCH_WANT_SYS_RT_SIGACTION
 #endif
 
 #ifdef __KERNEL_SYSCALLS__
--- diff/include/asm-ia64/iosapic.h	2004-05-19 22:12:41.000000000 +0100
+++ source/include/asm-ia64/iosapic.h	2004-06-11 19:22:06.000000000 +0100
@@ -60,7 +60,6 @@
 				    unsigned int gsi_base);
 extern int gsi_to_vector (unsigned int gsi);
 extern int gsi_to_irq (unsigned int gsi);
-extern void __init iosapic_parse_prt (void);
 extern void iosapic_enable_intr (unsigned int vector);
 extern int iosapic_register_intr (unsigned int gsi, unsigned long polarity,
 				  unsigned long trigger);
--- diff/include/asm-ia64/machvec.h	2004-05-19 22:12:41.000000000 +0100
+++ source/include/asm-ia64/machvec.h	2004-06-11 19:22:06.000000000 +0100
@@ -19,6 +19,7 @@
 struct scatterlist;
 struct irq_desc;
 struct page;
+struct mm_struct;
 
 typedef void ia64_mv_setup_t (char **);
 typedef void ia64_mv_cpu_init_t (void);
@@ -26,6 +27,7 @@
 typedef void ia64_mv_send_ipi_t (int, int, int, int);
 typedef void ia64_mv_timer_interrupt_t (int, void *, struct pt_regs *);
 typedef void ia64_mv_global_tlb_purge_t (unsigned long, unsigned long, unsigned long);
+typedef void ia64_mv_tlb_migrate_finish_t (struct mm_struct *);
 typedef struct irq_desc *ia64_mv_irq_desc (unsigned int);
 typedef u8 ia64_mv_irq_to_vector (u8);
 typedef unsigned int ia64_mv_local_vector_to_irq (u8 vector);
@@ -72,6 +74,7 @@
 extern void machvec_noop (void);
 extern void machvec_setup (char **);
 extern void machvec_timer_interrupt (int, void *, struct pt_regs *);
+extern void machvec_tlb_migrate_finish (struct mm_struct *);
 extern void machvec_dma_sync_single (struct device *, dma_addr_t, size_t, int);
 extern void machvec_dma_sync_sg (struct device *, struct scatterlist *, int, int);
 
@@ -95,6 +98,7 @@
 #  define platform_send_ipi	ia64_mv.send_ipi
 #  define platform_timer_interrupt	ia64_mv.timer_interrupt
 #  define platform_global_tlb_purge	ia64_mv.global_tlb_purge
+#  define platform_tlb_migrate_finish	ia64_mv.tlb_migrate_finish
 #  define platform_dma_init		ia64_mv.dma_init
 #  define platform_dma_alloc_coherent	ia64_mv.dma_alloc_coherent
 #  define platform_dma_free_coherent	ia64_mv.dma_free_coherent
@@ -140,6 +144,7 @@
 	ia64_mv_send_ipi_t *send_ipi;
 	ia64_mv_timer_interrupt_t *timer_interrupt;
 	ia64_mv_global_tlb_purge_t *global_tlb_purge;
+	ia64_mv_tlb_migrate_finish_t *tlb_migrate_finish;
 	ia64_mv_dma_init *dma_init;
 	ia64_mv_dma_alloc_coherent *dma_alloc_coherent;
 	ia64_mv_dma_free_coherent *dma_free_coherent;
@@ -181,6 +186,7 @@
 	platform_send_ipi,			\
 	platform_timer_interrupt,		\
 	platform_global_tlb_purge,		\
+	platform_tlb_migrate_finish,		\
 	platform_dma_init,			\
 	platform_dma_alloc_coherent,		\
 	platform_dma_free_coherent,		\
@@ -260,6 +266,9 @@
 #ifndef platform_global_tlb_purge
 # define platform_global_tlb_purge	ia64_global_tlb_purge /* default to architected version */
 #endif
+#ifndef platform_tlb_migrate_finish
+# define platform_tlb_migrate_finish machvec_tlb_migrate_finish
+#endif
 #ifndef platform_dma_init
 # define platform_dma_init		swiotlb_init
 #endif
--- diff/include/asm-ia64/machvec_sn2.h	2004-05-19 22:12:41.000000000 +0100
+++ source/include/asm-ia64/machvec_sn2.h	2004-06-11 19:22:06.000000000 +0100
@@ -39,6 +39,7 @@
 extern ia64_mv_send_ipi_t sn2_send_IPI;
 extern ia64_mv_timer_interrupt_t sn_timer_interrupt;
 extern ia64_mv_global_tlb_purge_t sn2_global_tlb_purge;
+extern ia64_mv_tlb_migrate_finish_t	sn_tlb_migrate_finish;
 extern ia64_mv_irq_desc sn_irq_desc;
 extern ia64_mv_irq_to_vector sn_irq_to_vector;
 extern ia64_mv_local_vector_to_irq sn_local_vector_to_irq;
@@ -83,6 +84,7 @@
 #define platform_send_ipi		sn2_send_IPI
 #define platform_timer_interrupt	sn_timer_interrupt
 #define platform_global_tlb_purge       sn2_global_tlb_purge
+#define platform_tlb_migrate_finish	sn_tlb_migrate_finish
 #define platform_pci_fixup		sn_pci_fixup
 #define platform_inb			__sn_inb
 #define platform_inw			__sn_inw
--- diff/include/asm-ia64/pgtable.h	2004-06-11 19:17:33.000000000 +0100
+++ source/include/asm-ia64/pgtable.h	2004-06-11 19:22:06.000000000 +0100
@@ -346,6 +346,8 @@
 ptep_test_and_clear_young (pte_t *ptep)
 {
 #ifdef CONFIG_SMP
+	if (!pte_young(*ptep))
+		return 0;
 	return test_and_clear_bit(_PAGE_A_BIT, ptep);
 #else
 	pte_t pte = *ptep;
@@ -360,6 +362,8 @@
 ptep_test_and_clear_dirty (pte_t *ptep)
 {
 #ifdef CONFIG_SMP
+	if (!pte_dirty(*ptep))
+		return 0;
 	return test_and_clear_bit(_PAGE_D_BIT, ptep);
 #else
 	pte_t pte = *ptep;
--- diff/include/asm-ia64/resource.h	2004-05-19 22:12:42.000000000 +0100
+++ source/include/asm-ia64/resource.h	2004-06-11 19:22:06.000000000 +0100
@@ -23,8 +23,10 @@
 #define RLIMIT_MEMLOCK	8		/* max locked-in-memory address space */
 #define RLIMIT_AS	9		/* address space limit */
 #define RLIMIT_LOCKS	10		/* maximum file locks held */
+#define RLIMIT_SIGPENDING 11		/* max number of pending signals */
+#define RLIMIT_MSGQUEUE 12		/* maximum bytes in POSIX mqueues */
 
-#define RLIM_NLIMITS	11
+#define RLIM_NLIMITS	13
 
 /*
  * SuS says limits have to be unsigned.
@@ -47,6 +49,8 @@
 	{ RLIM_INFINITY, RLIM_INFINITY },		\
 	{ RLIM_INFINITY, RLIM_INFINITY },		\
 	{ RLIM_INFINITY, RLIM_INFINITY },		\
+	{ MAX_SIGPENDING, MAX_SIGPENDING },		\
+	{ MQ_BYTES_MAX, MQ_BYTES_MAX },			\
 }
 
 # endif /* __KERNEL__ */
--- diff/include/asm-ia64/spinlock.h	2004-06-11 19:17:33.000000000 +0100
+++ source/include/asm-ia64/spinlock.h	2004-06-11 19:22:06.000000000 +0100
@@ -116,8 +116,18 @@
 typedef struct {
 	volatile int read_counter	: 31;
 	volatile int write_lock		:  1;
+#ifdef CONFIG_LOCKMETER
+	/* required for LOCKMETER since all bits in lock are used */
+	/* and we need this storage for CPU and lock INDEX        */
+	unsigned lockmeter_magic;
+#endif
 } rwlock_t;
+
+#ifdef CONFIG_LOCKMETER
+#define RW_LOCK_UNLOCKED (rwlock_t) { 0, 0, 0 }
+#else
 #define RW_LOCK_UNLOCKED (rwlock_t) { 0, 0 }
+#endif
 
 #define rwlock_init(x)		do { *(x) = RW_LOCK_UNLOCKED; } while(0)
 #define rwlock_is_locked(x)	(*(volatile int *) (x) != 0)
@@ -133,6 +143,48 @@
 	}										\
 } while (0)
 
+#ifdef CONFIG_LOCKMETER
+/*
+ * HACK: This works, but still have a timing window that affects performance:
+ * we see that no one owns the Write lock, then someone * else grabs for Write
+ * lock before we do a read_lock().
+ * This means that on rare occasions our read_lock() will stall and spin-wait
+ * until we acquire for Read, instead of simply returning a trylock failure.
+ */
+static inline int _raw_read_trylock(rwlock_t *rw)
+{
+	if (rw->write_lock) {
+		return 0;
+	} else {
+		_raw_read_lock(rw);
+		return 1;
+	}
+}
+
+static inline int _raw_write_trylock(rwlock_t *rw)
+{
+	if (!(rw->write_lock)) {
+	    /* isn't currently write-locked... that looks promising... */
+	    if (test_and_set_bit(31, rw) == 0) {
+		/* now it is write-locked by me... */
+		if (rw->read_counter) {
+		    /* really read-locked, so release write-lock and fail */
+		    clear_bit(31, rw);
+		} else {
+		    /* we've the the write-lock, no read-lockers... success! */
+		    barrier();
+		    return 1;
+		}
+
+	    }
+	}
+
+	/* falls through ... fails to write-lock */
+	barrier();
+	return 0;
+}
+#endif
+
 #define _raw_read_unlock(rw)					\
 do {								\
 	rwlock_t *__read_lock_ptr = (rw);			\
@@ -196,4 +248,25 @@
 	clear_bit(31, (x));								\
 })
 
+#ifdef CONFIG_LOCKMETER
+extern void _metered_spin_lock  (spinlock_t *lock);
+extern void _metered_spin_unlock(spinlock_t *lock);
+
+/*
+ *  Use a less efficient, and inline, atomic_dec_and_lock() if lockmetering
+ *  so we can see the callerPC of who is actually doing the spin_lock().
+ *  Otherwise, all we see is the generic rollup of all locks done by
+ *  atomic_dec_and_lock().
+ */
+static inline int atomic_dec_and_lock(atomic_t *atomic, spinlock_t *lock)
+{
+	_metered_spin_lock(lock);
+	if (atomic_dec_and_test(atomic))
+		return 1;
+	_metered_spin_unlock(lock);
+	return 0;
+}
+#define ATOMIC_DEC_AND_LOCK
+#endif
+
 #endif /*  _ASM_IA64_SPINLOCK_H */
--- diff/include/asm-ia64/tlb.h	2004-05-19 22:12:42.000000000 +0100
+++ source/include/asm-ia64/tlb.h	2004-06-11 19:22:06.000000000 +0100
@@ -44,6 +44,7 @@
 #include <asm/pgalloc.h>
 #include <asm/processor.h>
 #include <asm/tlbflush.h>
+#include <asm/machvec.h>
 
 #ifdef CONFIG_SMP
 # define FREE_PTE_NR		2048
@@ -211,6 +212,8 @@
 	tlb->end_addr = address + PAGE_SIZE;
 }
 
+#define tlb_migrate_finish(mm)	platform_tlb_migrate_finish(mm)
+
 #define tlb_start_vma(tlb, vma)			do { } while (0)
 #define tlb_end_vma(tlb, vma)			do { } while (0)
 
--- diff/include/asm-ia64/unistd.h	2004-06-11 19:17:33.000000000 +0100
+++ source/include/asm-ia64/unistd.h	2004-06-11 19:22:06.000000000 +0100
@@ -275,6 +275,7 @@
 # define __ARCH_WANT_SYS_OLDUMOUNT
 # define __ARCH_WANT_SYS_SIGPENDING
 # define __ARCH_WANT_SYS_SIGPROCMASK
+# define __ARCH_WANT_SYS_RT_SIGACTION
 #endif
 
 #if !defined(__ASSEMBLY__) && !defined(ASSEMBLER)
--- diff/include/asm-m68k/resource.h	2004-05-19 22:12:44.000000000 +0100
+++ source/include/asm-m68k/resource.h	2004-06-11 19:22:06.000000000 +0100
@@ -16,8 +16,10 @@
 #define RLIMIT_MEMLOCK	8		/* max locked-in-memory address space */
 #define RLIMIT_AS	9		/* address space limit */
 #define RLIMIT_LOCKS	10		/* maximum file locks held */
+#define RLIMIT_SIGPENDING 11		/* max number of pending signals */
+#define RLIMIT_MSGQUEUE 12		/* maximum bytes in POSIX mqueues */
 
-#define RLIM_NLIMITS	11
+#define RLIM_NLIMITS	13
 
 /*
  * SuS says limits have to be unsigned.
@@ -39,7 +41,9 @@
 	{      INR_OPEN,     INR_OPEN  },		\
 	{ RLIM_INFINITY, RLIM_INFINITY },		\
 	{ RLIM_INFINITY, RLIM_INFINITY },		\
-        { RLIM_INFINITY, RLIM_INFINITY },		\
+	{ RLIM_INFINITY, RLIM_INFINITY },		\
+	{ MAX_SIGPENDING, MAX_SIGPENDING },		\
+	{ MQ_BYTES_MAX, MQ_BYTES_MAX },			\
 }
 
 #endif /* __KERNEL__ */
--- diff/include/asm-m68k/setup.h	2004-06-11 19:17:33.000000000 +0100
+++ source/include/asm-m68k/setup.h	2004-06-11 19:22:06.000000000 +0100
@@ -357,6 +357,7 @@
 
 #define NUM_MEMINFO	4
 #define CL_SIZE		256
+#define COMMAND_LINE_SIZE	CL_SIZE
 
 #ifndef __ASSEMBLY__
 extern int m68k_num_memory;		/* # of memory blocks found (and used) */
--- diff/include/asm-m68k/unistd.h	2004-06-11 19:17:34.000000000 +0100
+++ source/include/asm-m68k/unistd.h	2004-06-11 19:22:06.000000000 +0100
@@ -359,6 +359,7 @@
 #define __ARCH_WANT_SYS_OLDUMOUNT
 #define __ARCH_WANT_SYS_SIGPENDING
 #define __ARCH_WANT_SYS_SIGPROCMASK
+#define __ARCH_WANT_SYS_RT_SIGACTION
 #endif
 
 #ifdef __KERNEL_SYSCALLS__
--- diff/include/asm-m68knommu/setup.h	2004-05-19 22:12:45.000000000 +0100
+++ source/include/asm-m68knommu/setup.h	2004-06-11 19:22:06.000000000 +0100
@@ -1 +1,5 @@
 #include <asm-m68k/setup.h>
+
+/* We have a bigger command line buffer. */
+#undef COMMAND_LINE_SIZE
+#define COMMAND_LINE_SIZE	512
--- diff/include/asm-m68knommu/unistd.h	2004-06-11 19:17:34.000000000 +0100
+++ source/include/asm-m68knommu/unistd.h	2004-06-11 19:22:06.000000000 +0100
@@ -394,6 +394,7 @@
 #define __ARCH_WANT_SYS_OLDUMOUNT
 #define __ARCH_WANT_SYS_SIGPENDING
 #define __ARCH_WANT_SYS_SIGPROCMASK
+#define __ARCH_WANT_SYS_RT_SIGACTION
 #endif
 
 #ifdef __KERNEL_SYSCALLS__
--- diff/include/asm-mips/bootinfo.h	2004-05-19 22:12:45.000000000 +0100
+++ source/include/asm-mips/bootinfo.h	2004-06-11 19:22:06.000000000 +0100
@@ -12,6 +12,7 @@
 #define _ASM_BOOTINFO_H
 
 #include <linux/types.h>
+#include <asm/setup.h>
 
 /*
  * The MACH_GROUP_ IDs are the equivalent to PCI vendor IDs; the remaining
@@ -209,7 +210,7 @@
 #define MACH_GROUP_TITAN       22	/* PMC-Sierra Titan		*/
 #define  MACH_TITAN_YOSEMITE	1	/* PMC-Sierra Yosemite		*/
 
-#define CL_SIZE			(256)
+#define CL_SIZE			COMMAND_LINE_SIZE
 
 const char *get_system_type(void);
 
--- diff/include/asm-mips/resource.h	2004-05-19 22:12:46.000000000 +0100
+++ source/include/asm-mips/resource.h	2004-06-11 19:22:06.000000000 +0100
@@ -23,8 +23,10 @@
 #define RLIMIT_NPROC 8			/* max number of processes */
 #define RLIMIT_MEMLOCK 9		/* max locked-in-memory address space */
 #define RLIMIT_LOCKS 10			/* maximum file locks held */
+#define RLIMIT_SIGPENDING 11		/* max number of pending signals */
+#define RLIMIT_MSGQUEUE 12		/* maximum bytes in POSIX mqueues */
 
-#define RLIM_NLIMITS 11			/* Number of limit flavors.  */
+#define RLIM_NLIMITS 13			/* Number of limit flavors.  */
 
 #ifdef __KERNEL__
 
@@ -54,6 +56,8 @@
 	{ 0,             0             },		\
 	{ RLIM_INFINITY, RLIM_INFINITY },		\
 	{ RLIM_INFINITY, RLIM_INFINITY },		\
+	{ MAX_SIGPENDING, MAX_SIGPENDING },		\
+	{ MQ_BYTES_MAX, MQ_BYTES_MAX },			\
 }
 
 #endif /* __KERNEL__ */
--- diff/include/asm-mips/spinlock.h	2004-06-11 19:17:34.000000000 +0100
+++ source/include/asm-mips/spinlock.h	2004-06-11 19:22:06.000000000 +0100
@@ -92,9 +92,18 @@
 
 typedef struct {
 	volatile unsigned int lock;
+#ifdef CONFIG_LOCKMETER
+	/* required for LOCKMETER since all bits in lock are used */
+	/* and we need this storage for CPU and lock INDEX        */
+	unsigned lockmeter_magic;
+#endif
 } rwlock_t;
 
+#ifdef CONFIG_LOCKMETER
+#define RW_LOCK_UNLOCKED (rwlock_t) { 0, 0 }
+#else
 #define RW_LOCK_UNLOCKED (rwlock_t) { 0 }
+#endif
 
 #define rwlock_init(x)  do { *(x) = RW_LOCK_UNLOCKED; } while(0)
 
--- diff/include/asm-mips/unistd.h	2004-06-11 19:17:34.000000000 +0100
+++ source/include/asm-mips/unistd.h	2004-06-11 19:22:06.000000000 +0100
@@ -1091,6 +1091,7 @@
 #define __ARCH_WANT_SYS_OLDUMOUNT
 #define __ARCH_WANT_SYS_SIGPENDING
 #define __ARCH_WANT_SYS_SIGPROCMASK
+#define __ARCH_WANT_SYS_RT_SIGACTION
 # ifndef __mips64
 #  define __ARCH_WANT_STAT64
 # endif
--- diff/include/asm-parisc/cacheflush.h	2004-06-11 19:17:34.000000000 +0100
+++ source/include/asm-parisc/cacheflush.h	2004-06-11 19:22:06.000000000 +0100
@@ -79,9 +79,9 @@
 }
 
 #define flush_dcache_mmap_lock(mapping) \
-	spin_lock_irq(&(mapping)->tree_lock)
+	write_lock_irq(&(mapping)->tree_lock)
 #define flush_dcache_mmap_unlock(mapping) \
-	spin_unlock_irq(&(mapping)->tree_lock)
+	write_unlock_irq(&(mapping)->tree_lock)
 
 #define flush_icache_page(vma,page)	do { flush_kernel_dcache_page(page_address(page)); flush_kernel_icache_page(page_address(page)); } while (0)
 
--- diff/include/asm-parisc/pgtable.h	2004-06-11 19:17:34.000000000 +0100
+++ source/include/asm-parisc/pgtable.h	2004-06-11 19:22:06.000000000 +0100
@@ -417,6 +417,8 @@
 static inline int ptep_test_and_clear_young(pte_t *ptep)
 {
 #ifdef CONFIG_SMP
+	if (!pte_young(*ptep))
+		return 0;
 	return test_and_clear_bit(xlate_pabit(_PAGE_ACCESSED_BIT), ptep);
 #else
 	pte_t pte = *ptep;
@@ -430,6 +432,8 @@
 static inline int ptep_test_and_clear_dirty(pte_t *ptep)
 {
 #ifdef CONFIG_SMP
+	if (!pte_dirty(*ptep))
+		return 0;
 	return test_and_clear_bit(xlate_pabit(_PAGE_DIRTY_BIT), ptep);
 #else
 	pte_t pte = *ptep;
--- diff/include/asm-parisc/resource.h	2004-05-19 22:12:49.000000000 +0100
+++ source/include/asm-parisc/resource.h	2004-06-11 19:22:06.000000000 +0100
@@ -16,8 +16,10 @@
 #define RLIMIT_MEMLOCK	8		/* max locked-in-memory address space */
 #define RLIMIT_AS	9		/* address space limit */
 #define RLIMIT_LOCKS	10		/* maximum file locks held */
+#define RLIMIT_SIGPENDING 11		/* max number of pending signals */
+#define RLIMIT_MSGQUEUE 12		/* maximum bytes in POSIX mqueues */
 
-#define RLIM_NLIMITS	11
+#define RLIM_NLIMITS	13
 
 /*
  * SuS says limits have to be unsigned.
@@ -40,6 +42,8 @@
 	{ RLIM_INFINITY, RLIM_INFINITY },		\
 	{ RLIM_INFINITY, RLIM_INFINITY },		\
 	{ RLIM_INFINITY, RLIM_INFINITY },		\
+	{ MAX_SIGPENDING, MAX_SIGPENDING },		\
+	{ MQ_BYTES_MAX, MQ_BYTES_MAX },			\
 }
 
 #endif /* __KERNEL__ */
--- diff/include/asm-parisc/setup.h	2004-05-19 22:12:49.000000000 +0100
+++ source/include/asm-parisc/setup.h	2004-06-11 19:22:06.000000000 +0100
@@ -1,10 +1,6 @@
-/*
- *	Just a place holder. We don't want to have to test x86 before
- *	we include stuff
- */
+#ifndef _PARISC_SETUP_H
+#define _PARISC_SETUP_H
 
-#ifndef _i386_SETUP_H
-#define _i386_SETUP_H
+#define COMMAND_LINE_SIZE	1024
 
-
-#endif /* _i386_SETUP_H */
+#endif /* _PARISC_SETUP_H */
--- diff/include/asm-parisc/unistd.h	2004-06-11 19:17:34.000000000 +0100
+++ source/include/asm-parisc/unistd.h	2004-06-11 19:22:06.000000000 +0100
@@ -899,6 +899,7 @@
 #define __ARCH_WANT_SYS_OLDUMOUNT
 #define __ARCH_WANT_SYS_SIGPENDING
 #define __ARCH_WANT_SYS_SIGPROCMASK
+#define __ARCH_WANT_SYS_RT_SIGACTION
 #endif
 
 /* mmap & mmap2 take 6 arguments */
--- diff/include/asm-ppc/elf.h	2004-05-19 22:12:50.000000000 +0100
+++ source/include/asm-ppc/elf.h	2004-06-11 19:22:06.000000000 +0100
@@ -52,6 +52,7 @@
 #define ELF_NGREG	48	/* includes nip, msr, lr, etc. */
 #define ELF_NFPREG	33	/* includes fpscr */
 #define ELF_NVRREG	33	/* includes vscr */
+#define ELF_NEVRREG	34	/* includes acc (as 2) */
 
 /*
  * These are used to set parameters in the core dumps.
--- diff/include/asm-ppc/io.h	2004-06-11 19:17:34.000000000 +0100
+++ source/include/asm-ppc/io.h	2004-06-11 19:22:06.000000000 +0100
@@ -30,6 +30,8 @@
 #include <asm/mpc8xx.h>
 #elif defined(CONFIG_8260)
 #include <asm/mpc8260.h>
+#elif defined(CONFIG_85xx)
+#include <asm/mpc85xx.h>
 #elif defined(CONFIG_APUS)
 #define _IO_BASE	0
 #define _ISA_MEM_BASE	0
--- diff/include/asm-ppc/machdep.h	2004-05-19 22:12:50.000000000 +0100
+++ source/include/asm-ppc/machdep.h	2004-06-11 19:22:06.000000000 +0100
@@ -106,7 +106,6 @@
 };
 
 extern struct machdep_calls ppc_md;
-#define COMMAND_LINE_SIZE 512
 extern char cmd_line[COMMAND_LINE_SIZE];
 
 extern void setup_pci_ptrs(void);
--- diff/include/asm-ppc/mmu.h	2004-05-19 22:12:50.000000000 +0100
+++ source/include/asm-ppc/mmu.h	2004-06-11 19:22:06.000000000 +0100
@@ -379,6 +379,74 @@
 #define PPC44x_TLB_SW		0x00000002      /* Super write */
 #define PPC44x_TLB_SR		0x00000001      /* Super read */
 
+/* Book-E defined page sizes */
+#define BOOKE_PAGESZ_1K		0
+#define BOOKE_PAGESZ_4K		1
+#define BOOKE_PAGESZ_16K	2
+#define BOOKE_PAGESZ_64K	3
+#define BOOKE_PAGESZ_256K	4
+#define BOOKE_PAGESZ_1M		5
+#define BOOKE_PAGESZ_4M		6
+#define BOOKE_PAGESZ_16M	7
+#define BOOKE_PAGESZ_64M	8
+#define BOOKE_PAGESZ_256M	9
+#define BOOKE_PAGESZ_1GB	10
+#define BOOKE_PAGESZ_4GB	11
+#define BOOKE_PAGESZ_16GB	12
+#define BOOKE_PAGESZ_64GB	13
+#define BOOKE_PAGESZ_256GB	14
+#define BOOKE_PAGESZ_1TB	15
+
+/*
+ * Freescale Book-E MMU support
+ */
+
+#define MAS0_TLBSEL	0x10000000
+#define MAS0_ESEL	0x000F0000
+#define MAS0_NV		0x00000001
+
+#define MAS1_VALID 	0x80000000
+#define MAS1_IPROT	0x40000000
+#define MAS1_TID 	0x03FF0000
+#define MAS1_TS		0x00001000
+#define MAS1_TSIZE(x)	(x << 8)
+
+#define MAS2_EPN	0xFFFFF000
+#define MAS2_SHAREN	0x00000200
+#define MAS2_X0		0x00000040
+#define MAS2_X1		0x00000020
+#define MAS2_W		0x00000010
+#define MAS2_I		0x00000008
+#define MAS2_M		0x00000004
+#define MAS2_G		0x00000002
+#define MAS2_E		0x00000001
+
+#define MAS3_RPN	0xFFFFF000
+#define MAS3_U0		0x00000200
+#define MAS3_U1		0x00000100
+#define MAS3_U2		0x00000080
+#define MAS3_U3		0x00000040
+#define MAS3_UX		0x00000020
+#define MAS3_SX		0x00000010
+#define MAS3_UW		0x00000008
+#define MAS3_SW		0x00000004
+#define MAS3_UR		0x00000002
+#define MAS3_SR		0x00000001
+
+#define MAS4_TLBSELD	0x10000000
+#define MAS4_TIDDSEL	0x00030000
+#define MAS4_DSHAREN	0x00001000
+#define MAS4_TSIZED(x)	(x << 8)
+#define MAS4_X0D	0x00000040
+#define MAS4_X1D	0x00000020
+#define MAS4_WD		0x00000010
+#define MAS4_ID		0x00000008
+#define MAS4_MD		0x00000004
+#define MAS4_GD		0x00000002
+#define MAS4_ED		0x00000001
+
+#define MAS6_SPID	0x00FF0000
+#define MAS6_SAS	0x00000001
 
 #endif /* _PPC_MMU_H_ */
 #endif /* __KERNEL__ */
--- diff/include/asm-ppc/mmu_context.h	2004-05-19 22:12:50.000000000 +0100
+++ source/include/asm-ppc/mmu_context.h	2004-06-11 19:22:06.000000000 +0100
@@ -63,6 +63,11 @@
 #define LAST_CONTEXT    	255
 #define FIRST_CONTEXT    	1
 
+#elif CONFIG_E500
+#define NO_CONTEXT      	256
+#define LAST_CONTEXT    	255
+#define FIRST_CONTEXT    	1
+
 #else
 
 /* PPC 6xx, 7xx CPUs */
--- diff/include/asm-ppc/mpc8260.h	2004-05-19 22:12:50.000000000 +0100
+++ source/include/asm-ppc/mpc8260.h	2004-06-11 19:22:06.000000000 +0100
@@ -16,6 +16,10 @@
 #include <platforms/est8260.h>
 #endif
 
+#ifdef CONFIG_SBC82xx
+#include <platforms/sbc82xx.h>
+#endif
+
 #ifdef CONFIG_SBS8260
 #include <platforms/sbs8260.h>
 #endif
--- diff/include/asm-ppc/ocp.h	2004-06-11 19:17:34.000000000 +0100
+++ source/include/asm-ppc/ocp.h	2004-06-11 19:22:06.000000000 +0100
@@ -202,6 +202,10 @@
 #include <asm/ibm_ocp.h>
 #endif
 
+#ifdef CONFIG_FSL_OCP
+#include <asm/fsl_ocp.h>
+#endif
+
 #endif				/* CONFIG_PPC_OCP */
 #endif				/* __OCP_H__ */
 #endif				/* __KERNEL__ */
--- diff/include/asm-ppc/ocp_ids.h	2004-06-11 19:17:34.000000000 +0100
+++ source/include/asm-ppc/ocp_ids.h	2004-06-11 19:22:06.000000000 +0100
@@ -45,6 +45,7 @@
 
 /* Memory devices 0x0090 - 0x009F */
 #define OCP_FUNC_MAL		0x0090
+#define OCP_FUNC_DMA		0x0091
 
 /* Display 0x00A0 - 0x00AF */
 
@@ -62,7 +63,7 @@
 
 /* Network 0x0200 - 0x02FF */
 #define OCP_FUNC_EMAC		0x0200
-#define OCP_FUNC_ENET		0x0201	/* TSEC & FEC */
+#define OCP_FUNC_GFAR		0x0201	/* TSEC & FEC */
 
 /* Bridge devices 0xE00 - 0xEFF */
 #define OCP_FUNC_OPB		0x0E00
--- diff/include/asm-ppc/pgtable.h	2004-06-11 19:17:34.000000000 +0100
+++ source/include/asm-ppc/pgtable.h	2004-06-11 19:22:06.000000000 +0100
@@ -222,6 +222,43 @@
 /* ERPN in a PTE never gets cleared, ignore it */
 #define _PTE_NONE_MASK	0xffffffff00000000ULL
 
+#elif defined(CONFIG_E500)
+
+/*
+   MMU Assist Register 3:
+
+   32 33 34 35 36  ... 50 51 52 53 54 55 56 57 58 59 60 61 62 63
+   RPN......................  0  0 U0 U1 U2 U3 UX SX UW SW UR SR
+
+   - PRESENT *must* be in the bottom three bits because swap cache
+     entries use the top 29 bits.
+
+   - FILE *must* be in the bottom three bits because swap cache
+     entries use the top 29 bits.
+*/
+
+/* Definitions for e500 core */
+#define _PAGE_PRESENT	0x001	/* S: PTE contains a translation */
+#define _PAGE_USER	0x002	/* S: User page (maps to UR) */
+#define _PAGE_FILE	0x002	/* S: when !present: nonlinear file mapping */
+#define _PAGE_ACCESSED	0x004	/* S: Page referenced */
+#define _PAGE_HWWRITE	0x008	/* H: Dirty & RW, set in exception */
+#define _PAGE_RW	0x010	/* S: Write permission */
+#define _PAGE_HWEXEC	0x020	/* H: UX permission */
+
+#define _PAGE_ENDIAN	0x040	/* H: E bit */
+#define _PAGE_GUARDED	0x080	/* H: G bit */
+#define _PAGE_COHERENT	0x100	/* H: M bit */
+#define _PAGE_NO_CACHE	0x200	/* H: I bit */
+#define _PAGE_WRITETHRU	0x400	/* H: W bit */
+#define _PAGE_DIRTY	0x800	/* S: Page dirty */
+
+#define _PMD_PRESENT	0
+#define _PMD_PRESENT_MASK (PAGE_MASK)
+#define _PMD_BAD	(~PAGE_MASK)
+
+#define NUM_TLBCAMS	(16)
+
 #elif defined(CONFIG_8xx)
 /* Definitions for 8xx embedded chips. */
 #define _PAGE_PRESENT	0x0001	/* Page is valid */
--- diff/include/asm-ppc/ppc_asm.h	2004-06-11 19:17:34.000000000 +0100
+++ source/include/asm-ppc/ppc_asm.h	2004-06-11 19:22:06.000000000 +0100
@@ -59,6 +59,20 @@
 #define REST_16VR(n,b,base)	REST_8VR(n,b,base); REST_8VR(n+8,b,base)
 #define REST_32VR(n,b,base)	REST_16VR(n,b,base); REST_16VR(n+16,b,base)
 
+#define SAVE_EVR(n,s,base)	evmergehi s,s,n; stw s,THREAD_EVR0+4*(n)(base)
+#define SAVE_2EVR(n,s,base)	SAVE_EVR(n,s,base); SAVE_EVR(n+1,s,base)
+#define SAVE_4EVR(n,s,base)	SAVE_2EVR(n,s,base); SAVE_2EVR(n+2,s,base)
+#define SAVE_8EVR(n,s,base)	SAVE_4EVR(n,s,base); SAVE_4EVR(n+4,s,base)
+#define SAVE_16EVR(n,s,base)	SAVE_8EVR(n,s,base); SAVE_8EVR(n+8,s,base)
+#define SAVE_32EVR(n,s,base)	SAVE_16EVR(n,s,base); SAVE_16EVR(n+16,s,base)
+
+#define REST_EVR(n,s,base)	lwz s,THREAD_EVR0+4*(n)(base); evmergelo n,s,n
+#define REST_2EVR(n,s,base)	REST_EVR(n,s,base); REST_EVR(n+1,s,base)
+#define REST_4EVR(n,s,base)	REST_2EVR(n,s,base); REST_2EVR(n+2,s,base)
+#define REST_8EVR(n,s,base)	REST_4EVR(n,s,base); REST_4EVR(n+4,s,base)
+#define REST_16EVR(n,s,base)	REST_8EVR(n,s,base); REST_8EVR(n+8,s,base)
+#define REST_32EVR(n,s,base)	REST_16EVR(n,s,base); REST_16EVR(n+16,s,base)
+
 #ifdef CONFIG_PPC601_SYNC_FIX
 #define SYNC				\
 BEGIN_FTR_SECTION			\
@@ -107,7 +121,14 @@
 	bdnz	0b
 #endif
 
-#if !defined(CONFIG_44x)
+#ifdef CONFIG_BOOKE
+#define tophys(rd,rs)				\
+	addis	rd,rs,0
+
+#define tovirt(rd,rs)				\
+	addis	rd,rs,0
+
+#else  /* CONFIG_BOOKE */
 /*
  * On APUS (Amiga PowerPC cpu upgrade board), we don't know the
  * physical base address of RAM at compile time.
@@ -125,15 +146,7 @@
 	.align  1;				\
 	.long   0b;				\
 	.previous
-#else  /* CONFIG_44x */
-
-#define tophys(rd,rs)				\
-	mr	rd,rs
-
-#define tovirt(rd,rs)				\
-	mr	rd,rs
-
-#endif /* CONFIG_44x */
+#endif  /* CONFIG_BOOKE */
 
 /*
  * On 64-bit cpus, we use the rfid instruction instead of rfi, but
@@ -289,6 +302,39 @@
 #define	vr30	30
 #define	vr31	31
 
+#define	evr0	0
+#define	evr1	1
+#define	evr2	2
+#define	evr3	3
+#define	evr4	4
+#define	evr5	5
+#define	evr6	6
+#define	evr7	7
+#define	evr8	8
+#define	evr9	9
+#define	evr10	10
+#define	evr11	11
+#define	evr12	12
+#define	evr13	13
+#define	evr14	14
+#define	evr15	15
+#define	evr16	16
+#define	evr17	17
+#define	evr18	18
+#define	evr19	19
+#define	evr20	20
+#define	evr21	21
+#define	evr22	22
+#define	evr23	23
+#define	evr24	24
+#define	evr25	25
+#define	evr26	26
+#define	evr27	27
+#define	evr28	28
+#define	evr29	29
+#define	evr30	30
+#define	evr31	31
+
 /* some stab codes */
 #define N_FUN	36
 #define N_RSYM	64
--- diff/include/asm-ppc/ppcboot.h	2004-05-19 22:12:50.000000000 +0100
+++ source/include/asm-ppc/ppcboot.h	2004-06-11 19:22:06.000000000 +0100
@@ -52,7 +52,7 @@
 	unsigned long	bi_flashoffset; /* reserved area for startup monitor */
 	unsigned long	bi_sramstart;	/* start of SRAM memory */
 	unsigned long	bi_sramsize;	/* size	 of SRAM memory */
-#if defined(CONFIG_8xx) || defined(CONFIG_8260)
+#if defined(CONFIG_8xx) || defined(CONFIG_8260) || defined(CONFIG_85xx)
 	unsigned long	bi_immr_base;	/* base of IMMR register */
 #endif
 	unsigned long	bi_bootflags;	/* boot / reboot flag (for LynxOS) */
@@ -79,7 +79,7 @@
 #if defined(CONFIG_HYMOD)
 	hymod_conf_t	bi_hymod_conf;	/* hymod configuration information */
 #endif
-#if defined(CONFIG_EVB64260)
+#if defined(CONFIG_EVB64260) || defined(CONFIG_85xx)
 	/* the board has three onboard ethernet ports */
 	unsigned char	bi_enet1addr[6];
 	unsigned char	bi_enet2addr[6];
--- diff/include/asm-ppc/processor.h	2004-05-19 22:12:50.000000000 +0100
+++ source/include/asm-ppc/processor.h	2004-06-11 19:22:06.000000000 +0100
@@ -40,6 +40,14 @@
 	.globl n;\
 n:
 
+/*
+ * this is the minimum allowable io space due to the location
+ * of the io areas on prep (first one at 0x80000000) but
+ * as soon as I get around to remapping the io areas with the BATs
+ * to match the mac we can raise this. -- Cort
+ */
+#define TASK_SIZE	(CONFIG_TASK_SIZE)
+
 #ifndef __ASSEMBLY__
 #ifdef CONFIG_PPC_MULTIPLATFORM
 extern int _machine;
@@ -79,14 +87,7 @@
 /* Lazy FPU handling on uni-processor */
 extern struct task_struct *last_task_used_math;
 extern struct task_struct *last_task_used_altivec;
-
-/*
- * this is the minimum allowable io space due to the location
- * of the io areas on prep (first one at 0x80000000) but
- * as soon as I get around to remapping the io areas with the BATs
- * to match the mac we can raise this. -- Cort
- */
-#define TASK_SIZE	(CONFIG_TASK_SIZE)
+extern struct task_struct *last_task_used_spe;
 
 /* This decides where the kernel will search for a free chunk of vm
  * space during mmap's.
@@ -104,7 +105,7 @@
 	void		*pgdir;		/* root of page-table tree */
 	int		fpexc_mode;	/* floating-point exception mode */
 	signed long	last_syscall;
-#ifdef CONFIG_4xx
+#if defined(CONFIG_4xx) || defined (CONFIG_BOOKE)
 	unsigned long	dbcr0;		/* debug control register values */
 	unsigned long	dbcr1;
 #endif
@@ -119,6 +120,13 @@
 	unsigned long	vrsave;
 	int		used_vr;	/* set if process has used altivec */
 #endif /* CONFIG_ALTIVEC */
+#ifdef CONFIG_SPE
+	unsigned long	evr[32];	/* upper 32-bits of SPE regs */
+	u64		acc;		/* Accumulator */
+	unsigned long	spefscr;	/* SPE & eFP status */
+	int		used_spe;	/* set if process has used spe */
+#endif /* CONFIG_SPE */
+	struct vperfctr *perfctr;	/* performance counters */
 };
 
 #define ARCH_MIN_TASKALIGN 16
--- diff/include/asm-ppc/ptrace.h	2004-05-19 22:12:50.000000000 +0100
+++ source/include/asm-ppc/ptrace.h	2004-06-11 19:22:06.000000000 +0100
@@ -131,4 +131,9 @@
 #define PTRACE_GETVRREGS	18
 #define PTRACE_SETVRREGS	19
 
+/* Get/set all the upper 32-bits of the SPE registers, accumulator, and
+ * spefscr, in one go */
+#define PTRACE_GETEVRREGS	20
+#define PTRACE_SETEVRREGS	21
+
 #endif
--- diff/include/asm-ppc/reg.h	2004-06-11 19:17:34.000000000 +0100
+++ source/include/asm-ppc/reg.h	2004-06-11 19:22:06.000000000 +0100
@@ -268,22 +268,14 @@
 #define SPRN_LDSTCR	0x3f8	/* Load/Store control register */
 #define SPRN_LDSTDB	0x3f4	/* */
 #define SPRN_LR		0x008	/* Link Register */
-#define SPRN_MMCR0	0x3B8	/* Monitor Mode Control Register 0 */
-#define SPRN_MMCR1	0x3BC	/* Monitor Mode Control Register 1 */
 #ifndef SPRN_PIR
 #define SPRN_PIR	0x3FF	/* Processor Identification Register */
 #endif
-#define SPRN_PMC1	0x3B9	/* Performance Counter Register 1 */
-#define SPRN_PMC2	0x3BA	/* Performance Counter Register 2 */
-#define SPRN_PMC3	0x3BD	/* Performance Counter Register 3 */
-#define SPRN_PMC4	0x3BE	/* Performance Counter Register 4 */
 #define SPRN_PTEHI	0x3D5	/* 981 7450 PTE HI word (S/W TLB load) */
 #define SPRN_PTELO	0x3D6	/* 982 7450 PTE LO word (S/W TLB load) */
 #define SPRN_PVR	0x11F	/* Processor Version Register */
 #define SPRN_RPA	0x3D6	/* Required Physical Address Register */
-#define SPRN_SDA	0x3BF	/* Sampled Data Address Register */
 #define SPRN_SDR1	0x019	/* MMU Hash Base Register */
-#define SPRN_SIA	0x3BB	/* Sampled Instruction Address Register */
 #define SPRN_SPRG0	0x110	/* Special Purpose Register General 0 */
 #define SPRN_SPRG1	0x111	/* Special Purpose Register General 1 */
 #define SPRN_SPRG2	0x112	/* Special Purpose Register General 2 */
@@ -294,6 +286,9 @@
 #define SPRN_SPRG7	0x117	/* Special Purpose Register General 7 */
 #define SPRN_SRR0	0x01A	/* Save/Restore Register 0 */
 #define SPRN_SRR1	0x01B	/* Save/Restore Register 1 */
+#ifndef SPRN_SVR
+#define SPRN_SVR	0x11E	/* System Version Register */
+#endif
 #define SPRN_THRM1	0x3FC		/* Thermal Management Register 1 */
 /* these bits were defined in inverted endian sense originally, ugh, confusing */
 #define THRM1_TIN	(1 << 31)
@@ -307,16 +302,79 @@
 #define SPRN_THRM3	0x3FE		/* Thermal Management Register 3 */
 #define THRM3_E		(1<<0)
 #define SPRN_TLBMISS	0x3D4		/* 980 7450 TLB Miss Register */
-#define SPRN_UMMCR0	0x3A8	/* User Monitor Mode Control Register 0 */
-#define SPRN_UMMCR1	0x3AC	/* User Monitor Mode Control Register 0 */
-#define SPRN_UPMC1	0x3A9	/* User Performance Counter Register 1 */
-#define SPRN_UPMC2	0x3AA	/* User Performance Counter Register 2 */
-#define SPRN_UPMC3	0x3AD	/* User Performance Counter Register 3 */
-#define SPRN_UPMC4	0x3AE	/* User Performance Counter Register 4 */
-#define SPRN_USIA	0x3AB	/* User Sampled Instruction Address Register */
 #define SPRN_VRSAVE	0x100	/* Vector Register Save Register */
 #define SPRN_XER	0x001	/* Fixed Point Exception Register */
 
+/* Performance-monitoring control and counter registers */
+#define SPRN_MMCR0	0x3B8	/* Monitor Mode Control Register 0 (604 and up) */
+#define SPRN_MMCR1	0x3BC	/* Monitor Mode Control Register 1 (604e and up) */
+#define SPRN_MMCR2	0x3B0	/* Monitor Mode Control Register 2 (7400 and up) */
+#define SPRN_PMC1	0x3B9	/* Performance Counter Register 1 (604 and up) */
+#define SPRN_PMC2	0x3BA	/* Performance Counter Register 2 (604 and up) */
+#define SPRN_PMC3	0x3BD	/* Performance Counter Register 3 (604e and up) */
+#define SPRN_PMC4	0x3BE	/* Performance Counter Register 4 (604e and up) */
+#define SPRN_PMC5	0x3B1	/* Performance Counter Register 5 (7450 and up) */
+#define SPRN_PMC6	0x3B2	/* Performance Counter Register 6 (7450 and up) */
+#define SPRN_SIA	0x3BB	/* Sampled Instruction Address Register (604 and up) */
+#define SPRN_SDA	0x3BF	/* Sampled Data Address Register (604/604e only) */
+#define SPRN_BAMR	0x3B7	/* Breakpoint Address Mask Register (7400 and up) */
+
+#define SPRN_UMMCR0	0x3A8	/* User Monitor Mode Control Register 0 (750 and up) */
+#define SPRN_UMMCR1	0x3AC	/* User Monitor Mode Control Register 0 (750 and up) */
+#define SPRN_UMMCR2	0x3A0	/* User Monitor Mode Control Register 0 (7400 and up) */
+#define SPRN_UPMC1	0x3A9	/* User Performance Counter Register 1 (750 and up) */
+#define SPRN_UPMC2	0x3AA	/* User Performance Counter Register 2 (750 and up) */
+#define SPRN_UPMC3	0x3AD	/* User Performance Counter Register 3 (750 and up) */
+#define SPRN_UPMC4	0x3AE	/* User Performance Counter Register 4 (750 and up) */
+#define SPRN_UPMC5	0x3A1	/* User Performance Counter Register 5 (7450 and up) */
+#define SPRN_UPMC6	0x3A2	/* User Performance Counter Register 5 (7450 and up) */
+#define SPRN_USIA	0x3AB	/* User Sampled Instruction Address Register (750 and up) */
+#define SPRN_UBAMR	0x3A7	/* User Breakpoint Address Mask Register (7400 and up) */
+
+/* MMCR0 layout (74xx terminology) */
+#define MMCR0_FC		0x80000000 /* Freeze counters unconditionally. */
+#define MMCR0_FCS		0x40000000 /* Freeze counters while MSR[PR]=0 (supervisor mode). */
+#define MMCR0_FCP		0x20000000 /* Freeze counters while MSR[PR]=1 (user mode). */
+#define MMCR0_FCM1		0x10000000 /* Freeze counters while MSR[PM]=1. */
+#define MMCR0_FCM0		0x08000000 /* Freeze counters while MSR[PM]=0. */
+#define MMCR0_PMXE		0x04000000 /* Enable performance monitor exceptions.
+					    * Cleared by hardware when a PM exception occurs.
+					    * 604: PMXE is not cleared by hardware.
+					    */
+#define MMCR0_FCECE		0x02000000 /* Freeze counters on enabled condition or event.
+					    * FCECE is treated as 0 if TRIGGER is 1.
+					    * 74xx: FC is set when the event occurs.
+					    * 604/750: ineffective when PMXE=0.
+					    */
+#define MMCR0_TBSEL		0x01800000 /* Time base lower (TBL) bit selector.
+					    * 00: bit 31, 01: bit 23, 10: bit 19, 11: bit 15.
+					    */
+#define MMCR0_TBEE		0x00400000 /* Enable event on TBL bit transition from 0 to 1. */
+#define MMCR0_THRESHOLD		0x003F0000 /* Threshold value for certain events. */
+#define MMCR0_PMC1CE		0x00008000 /* Enable event on PMC1 overflow. */
+#define MMCR0_PMCjCE		0x00004000 /* Enable event on PMC2-PMC6 overflow.
+					    * 604/750: Overrides FCECE (DISCOUNT).
+					    */
+#define MMCR0_TRIGGER		0x00002000 /* Disable PMC2-PMC6 until PMC1 overflow or other event.
+					    * 74xx: cleared by hardware when the event occurs.
+					    */
+#define MMCR0_PMC1SEL		0x00001FB0 /* PMC1 event selector, 7 bits. */
+#define MMCR0_PMC2SEL		0x0000003F /* PMC2 event selector, 6 bits. */
+
+/* MMCR1 layout (604e-7457) */
+#define MMCR1_PMC3SEL		0xF8000000 /* PMC3 event selector, 5 bits. */
+#define MMCR1_PMC4SEL		0x07B00000 /* PMC4 event selector, 5 bits. */
+#define MMCR1_PMC5SEL		0x003E0000 /* PMC5 event selector, 5 bits. (745x only) */
+#define MMCR1_PMC6SEL		0x0001F800 /* PMC6 event selector, 6 bits. (745x only) */
+#define MMCR1__RESERVED		0x000007FF /* should be zero */
+
+/* MMCR2 layout (7400-7457) */
+#define MMCR2_THRESHMULT	0x80000000 /* MMCR0[THRESHOLD] multiplier. */
+#define MMCR2_SMCNTEN		0x40000000 /* 7400/7410 only, should be zero. */
+#define MMCR2_SMINTEN		0x20000000 /* 7400/7410 only, should be zero. */
+#define MMCR2__RESERVED		0x1FFFFFFF /* should be zero */
+#define MMCR2_RESERVED		(MMCR2_SMCNTEN | MMCR2_SMINTEN | MMCR2__RESERVED)
+
 /* Bit definitions for MMCR0 and PMC1 / PMC2. */
 #define MMCR0_PMC1_CYCLES	(1 << 7)
 #define MMCR0_PMC1_ICACHEMISS	(5 << 7)
@@ -400,6 +458,7 @@
 #define SRR1	SPRN_SRR1	/* Save and Restore Register 1 */
 #define SRR2	SPRN_SRR2	/* Save and Restore Register 2 */
 #define SRR3	SPRN_SRR3	/* Save and Restore Register 3 */
+#define SVR	SPRN_SVR	/* System Version Register */
 #define ICTC	SPRN_ICTC	/* Instruction Cache Throttling Control Reg */
 #define THRM1	SPRN_THRM1	/* Thermal Management Register 1 */
 #define THRM2	SPRN_THRM2	/* Thermal Management Register 2 */
@@ -462,6 +521,8 @@
 #define PVR_7400	0x000C0000
 #define PVR_7410	0x800C0000
 #define PVR_7450	0x80000000
+#define PVR_8540	0x80200000
+#define PVR_8560	0x80200000
 /*
  * For the 8xx processors, all of them report the same PVR family for
  * the PowerPC core. The various versions of these processors must be
@@ -476,6 +537,12 @@
 #define PVR_8245	0x80811014
 #define PVR_8260	PVR_8240
 
+/* System Version Numbers */
+#define SVR_8540	0x80300000
+#define SVR_8541E	0x807A0000
+#define SVR_8555E	0x80790000
+#define SVR_8560	0x80700000
+
 /* Segment Registers */
 #define SR0	0
 #define SR1	1
--- diff/include/asm-ppc/reg_booke.h	2004-06-11 19:17:34.000000000 +0100
+++ source/include/asm-ppc/reg_booke.h	2004-06-11 19:22:06.000000000 +0100
@@ -43,13 +43,23 @@
 	mtdcr(base ## _CFGADDR, base ## _ ## reg);	\
 	mtdcr(base ## _CFGDATA, data);		\
 } while (0)
+
+/* Performance Monitor Registers */
+#define mfpmr(rn)	({unsigned int rval; \
+			asm volatile("mfpmr %0," __stringify(rn) \
+				     : "=r" (rval)); rval;})
+#define mtpmr(rn, v)	asm volatile("mtpmr " __stringify(rn) ",%0" : : "r" (v))
 #endif /* __ASSEMBLY__ */
 
 
 /* Machine State Register (MSR) Fields */
+#define MSR_UCLE	(1<<26)	/* User-mode cache lock enable */
+#define MSR_SPE		(1<<25)	/* Enable SPE */
 #define MSR_DWE		(1<<10)	/* Debug Wait Enable */
+#define MSR_UBLE	(1<<10)	/* BTB lock enable (e500) */
 #define MSR_IS		MSR_IR	/* Instruction Space */
 #define MSR_DS		MSR_DR	/* Data Space */
+#define MSR_PMM		(1<<2)	/* Performance monitor mark bit */
 
 /* Default MSR for kernel mode. */
 #if defined (CONFIG_40x)
@@ -91,20 +101,28 @@
 #define SPRN_IVOR13	0x19D	/* Interrupt Vector Offset Register 13 */
 #define SPRN_IVOR14	0x19E	/* Interrupt Vector Offset Register 14 */
 #define SPRN_IVOR15	0x19F	/* Interrupt Vector Offset Register 15 */
+#define SPRN_SPEFSCR	0x200	/* SPE & Embedded FP Status & Control */
+#define SPRN_BBEAR	0x201	/* Branch Buffer Entry Address Register */
+#define SPRN_BBTAR	0x202	/* Branch Buffer Target Address Register */
+#define SPRN_IVOR32	0x210	/* Interrupt Vector Offset Register 32 */
+#define SPRN_IVOR33	0x211	/* Interrupt Vector Offset Register 33 */
+#define SPRN_IVOR34	0x212	/* Interrupt Vector Offset Register 34 */
+#define SPRN_IVOR35	0x213	/* Interrupt Vector Offset Register 35 */
 #define SPRN_MCSRR0	0x23A	/* Machine Check Save and Restore Register 0 */
 #define SPRN_MCSRR1	0x23B	/* Machine Check Save and Restore Register 1 */
 #define SPRN_MCSR	0x23C	/* Machine Check Status Register */
-#ifdef CONFIG_440A
-#define  MCSR_MCS	0x80000000 /* Machine Check Summary */
-#define  MCSR_IB	0x40000000 /* Instruction PLB Error */
-#define  MCSR_DRB	0x20000000 /* Data Read PLB Error */
-#define  MCSR_DWB	0x10000000 /* Data Write PLB Error */
-#define  MCSR_TLBP	0x08000000 /* TLB Parity Error */
-#define  MCSR_ICP	0x04000000 /* I-Cache Parity Error */
-#define  MCSR_DCSP	0x02000000 /* D-Cache Search Parity Error */
-#define  MCSR_DCFP	0x01000000 /* D-Cache Flush Parity Error */
-#define  MCSR_IMPE	0x00800000 /* Imprecise Machine Check Exception */
-#endif
+#define SPRN_MCAR	0x23D	/* Machine Check Address Register */
+#define SPRN_MAS0	0x270	/* MMU Assist Register 0 */
+#define SPRN_MAS1	0x271	/* MMU Assist Register 1 */
+#define SPRN_MAS2	0x272	/* MMU Assist Register 2 */
+#define SPRN_MAS3	0x273	/* MMU Assist Register 3 */
+#define SPRN_MAS4	0x274	/* MMU Assist Register 4 */
+#define SPRN_MAS5	0x275	/* MMU Assist Register 5 */
+#define SPRN_MAS6	0x276	/* MMU Assist Register 6 */
+#define SPRN_PID1	0x279	/* Process ID Register 1 */
+#define SPRN_PID2	0x27A	/* Process ID Register 2 */
+#define SPRN_TLB0CFG	0x2B0	/* TLB 0 Config Register */
+#define SPRN_TLB1CFG	0x2B1	/* TLB 1 Config Register */
 #define SPRN_ZPR	0x3B0	/* Zone Protection Register (40x) */
 #define SPRN_MMUCR	0x3B2	/* MMU Control Register */
 #define SPRN_CCR0	0x3B3	/* Core Configuration Register */
@@ -115,9 +133,12 @@
 #define SPRN_DCMP	0x3D1	/* Data TLB Compare Register */
 #define SPRN_ICDBDR	0x3D3	/* Instruction Cache Debug Data Register */
 #define SPRN_EVPR	0x3D6	/* Exception Vector Prefix Register */
+#define SPRN_L1CSR0	0x3F2	/* L1 Cache Control and Status Register 0 */
+#define SPRN_L1CSR1	0x3F3	/* L1 Cache Control and Status Register 1 */
 #define SPRN_PIT	0x3DB	/* Programmable Interval Timer */
 #define SPRN_DCCR	0x3FA	/* Data Cache Cacheability Register */
 #define SPRN_ICCR	0x3FB	/* Instruction Cache Cacheability Register */
+#define SPRN_SVR	0x3FF	/* System Version Register */
 
 /*
  * SPRs which have conflicting definitions on true Book E versus classic,
@@ -125,6 +146,7 @@
  */
 #ifdef CONFIG_BOOKE
 #define SPRN_PID	0x030	/* Process ID */
+#define SPRN_PID0	SPRN_PID/* Process ID Register 0 */
 #define SPRN_CSRR0	0x03A	/* Critical Save and Restore Register 0 */
 #define SPRN_CSRR1	0x03B	/* Critical Save and Restore Register 1 */
 #define SPRN_DEAR	0x03D	/* Data Error Address Register */
@@ -157,6 +179,34 @@
 #define SPRN_CSRR1	SPRN_SRR3 /* Critical Save and Restore Register 1 */
 #endif
 
+/* Bit definitions for the MCSR. */
+#ifdef CONFIG_440A
+#define MCSR_MCS	0x80000000 /* Machine Check Summary */
+#define MCSR_IB		0x40000000 /* Instruction PLB Error */
+#define MCSR_DRB	0x20000000 /* Data Read PLB Error */
+#define MCSR_DWB	0x10000000 /* Data Write PLB Error */
+#define MCSR_TLBP	0x08000000 /* TLB Parity Error */
+#define MCSR_ICP	0x04000000 /* I-Cache Parity Error */
+#define MCSR_DCSP	0x02000000 /* D-Cache Search Parity Error */
+#define MCSR_DCFP	0x01000000 /* D-Cache Flush Parity Error */
+#define MCSR_IMPE	0x00800000 /* Imprecise Machine Check Exception */
+#endif
+#ifdef CONFIG_E500
+#define MCSR_MCP 	0x80000000UL /* Machine Check Input Pin */
+#define MCSR_ICPERR 	0x40000000UL /* I-Cache Parity Error */
+#define MCSR_DCP_PERR 	0x20000000UL /* D-Cache Push Parity Error */
+#define MCSR_DCPERR 	0x10000000UL /* D-Cache Parity Error */
+#define MCSR_GL_CI 	0x00010000UL /* Guarded Load or Cache-Inhibited stwcx. */
+#define MCSR_BUS_IAERR 	0x00000080UL /* Instruction Address Error */
+#define MCSR_BUS_RAERR 	0x00000040UL /* Read Address Error */
+#define MCSR_BUS_WAERR 	0x00000020UL /* Write Address Error */
+#define MCSR_BUS_IBERR 	0x00000010UL /* Instruction Data Error */
+#define MCSR_BUS_RBERR 	0x00000008UL /* Read Data Bus Error */
+#define MCSR_BUS_WBERR 	0x00000004UL /* Write Data Bus Error */
+#define MCSR_BUS_IPERR 	0x00000002UL /* Instruction parity Error */
+#define MCSR_BUS_RPERR 	0x00000001UL /* Read parity Error */
+#endif
+
 /* Bit definitions for the DBSR. */
 /*
  * DBSR bits which have conflicting definitions on true Book E versus IBM 40x.
@@ -165,11 +215,27 @@
 #define DBSR_IC		0x08000000	/* Instruction Completion */
 #define DBSR_BT		0x04000000	/* Branch Taken */
 #define DBSR_TIE	0x01000000	/* Trap Instruction Event */
+#define DBSR_IAC1	0x00800000	/* Instr Address Compare 1 Event */
+#define DBSR_IAC2	0x00400000	/* Instr Address Compare 2 Event */
+#define DBSR_IAC3	0x00200000	/* Instr Address Compare 3 Event */
+#define DBSR_IAC4	0x00100000	/* Instr Address Compare 4 Event */
+#define DBSR_DAC1R	0x00080000	/* Data Addr Compare 1 Read Event */
+#define DBSR_DAC1W	0x00040000	/* Data Addr Compare 1 Write Event */
+#define DBSR_DAC2R	0x00020000	/* Data Addr Compare 2 Read Event */
+#define DBSR_DAC2W	0x00010000	/* Data Addr Compare 2 Write Event */
 #endif
 #ifdef CONFIG_40x
 #define DBSR_IC		0x80000000	/* Instruction Completion */
 #define DBSR_BT		0x40000000	/* Branch taken */
 #define DBSR_TIE	0x10000000	/* Trap Instruction debug Event */
+#define DBSR_IAC1	0x00800000	/* Instruction Address Compare 1 Event */
+#define DBSR_IAC2	0x00400000	/* Instruction Address Compare 2 Event */
+#define DBSR_IAC3	0x00200000	/* Instruction Address Compare 3 Event */
+#define DBSR_IAC4	0x00100000	/* Instruction Address Compare 4 Event */
+#define DBSR_DAC1R	0x00080000	/* Data Address Compare 1 Read Event */
+#define DBSR_DAC1W	0x00040000	/* Data Address Compare 1 Write Event */
+#define DBSR_DAC2R	0x00020000	/* Data Address Compare 2 Read Event */
+#define DBSR_DAC2W	0x00010000	/* Data Address Compare 2 Write Event */
 #endif
 
 /* Bit definitions related to the ESR. */
@@ -184,6 +250,9 @@
 #define ESR_DST		0x00800000	/* Storage Exception - Data miss */
 #define ESR_DIZ		0x00400000	/* Storage Exception - Zone fault */
 #define ESR_ST		0x00800000	/* Store Operation */
+#define ESR_DLK		0x00200000	/* Data Cache Locking */
+#define ESR_ILK		0x00100000	/* Instr. Cache Locking */
+#define ESR_BO		0x00020000	/* Byte Ordering */
 
 /* Bit definitions related to the DBCR0. */
 #define DBCR0_EDM	0x80000000	/* External Debug Mode */
@@ -258,10 +327,49 @@
 #define ICCR_NOCACHE	0		/* Noncacheable */
 #define ICCR_CACHE	1		/* Cacheable */
 
+/* Bit definitions for L1CSR0. */
+#define L1CSR0_DCFI	0x00000002	/* Data Cache Flash Invalidate */
+#define L1CSR0_DCE	0x00000001	/* Data Cache Enable */
+
+/* Bit definitions for L1CSR0. */
+#define L1CSR1_ICLFR	0x00000100	/* Instr Cache Lock Bits Flash Reset */
+#define L1CSR1_ICFI	0x00000002	/* Instr Cache Flash Invalidate */
+#define L1CSR1_ICE	0x00000001	/* Instr Cache Enable */
+
 /* Bit definitions for SGR. */
 #define SGR_NORMAL	0		/* Speculative fetching allowed. */
 #define SGR_GUARDED	1		/* Speculative fetching disallowed. */
 
+/* Bit definitions for SPEFSCR. */
+#define SPEFSCR_SOVH	0x80000000	/* Summary integer overflow high */
+#define SPEFSCR_OVH	0x40000000	/* Integer overflow high */
+#define SPEFSCR_FGH	0x20000000	/* Embedded FP guard bit high */
+#define SPEFSCR_FXH	0x10000000	/* Embedded FP sticky bit high */
+#define SPEFSCR_FINVH	0x08000000	/* Embedded FP invalid operation high */
+#define SPEFSCR_FDBZH	0x04000000	/* Embedded FP div by zero high */
+#define SPEFSCR_FUNFH	0x02000000	/* Embedded FP underflow high */
+#define SPEFSCR_FOVFH	0x01000000	/* Embedded FP overflow high */
+#define SPEFSCR_FINXS	0x00200000	/* Embedded FP inexact sticky */
+#define SPEFSCR_FINVS	0x00100000	/* Embedded FP invalid op. sticky */
+#define SPEFSCR_FDBZS	0x00080000	/* Embedded FP div by zero sticky */
+#define SPEFSCR_FUNFS	0x00040000	/* Embedded FP underflow sticky */
+#define SPEFSCR_FOVFS	0x00020000	/* Embedded FP overflow sticky */
+#define SPEFSCR_MODE	0x00010000	/* Embedded FP mode */
+#define SPEFSCR_SOV	0x00008000	/* Integer summary overflow */
+#define SPEFSCR_OV	0x00004000	/* Integer overflow */
+#define SPEFSCR_FG	0x00002000	/* Embedded FP guard bit */
+#define SPEFSCR_FX	0x00001000	/* Embedded FP sticky bit */
+#define SPEFSCR_FINV	0x00000800	/* Embedded FP invalid operation */
+#define SPEFSCR_FDBZ	0x00000400	/* Embedded FP div by zero */
+#define SPEFSCR_FUNF	0x00000200	/* Embedded FP underflow */
+#define SPEFSCR_FOVF	0x00000100	/* Embedded FP overflow */
+#define SPEFSCR_FINXE	0x00000040	/* Embedded FP inexact enable */
+#define SPEFSCR_FINVE	0x00000020	/* Embedded FP invalid op. enable */
+#define SPEFSCR_FDBZE	0x00000010	/* Embedded FP div by zero enable */
+#define SPEFSCR_FUNFE	0x00000008	/* Embedded FP underflow enable */
+#define SPEFSCR_FOVFE	0x00000004	/* Embedded FP overflow enable */
+#define SPEFSCR_FRMC 	0x00000003	/* Embedded FP rounding mode control */
+
 /* Short-hand for various SPRs. */
 #ifdef CONFIG_BOOKE
 #define CSRR0	SPRN_CSRR0	/* Critical Save and Restore Register 0 */
--- diff/include/asm-ppc/resource.h	2004-05-19 22:12:50.000000000 +0100
+++ source/include/asm-ppc/resource.h	2004-06-11 19:22:06.000000000 +0100
@@ -12,8 +12,10 @@
 #define RLIMIT_MEMLOCK	8		/* max locked-in-memory address space */
 #define RLIMIT_AS	9		/* address space limit(?) */
 #define RLIMIT_LOCKS	10		/* maximum file locks held */
+#define RLIMIT_SIGPENDING 11		/* max number of pending signals */
+#define RLIMIT_MSGQUEUE 12		/* maximum bytes in POSIX mqueues */
 
-#define RLIM_NLIMITS	11
+#define RLIM_NLIMITS	13
 
 #ifdef __KERNEL__
 
@@ -37,6 +39,8 @@
 	{ RLIM_INFINITY, RLIM_INFINITY },		\
 	{ RLIM_INFINITY, RLIM_INFINITY },		\
 	{ RLIM_INFINITY, RLIM_INFINITY },		\
+	{ MAX_SIGPENDING, MAX_SIGPENDING },		\
+	{ MQ_BYTES_MAX, MQ_BYTES_MAX },			\
 }
 
 #endif /* __KERNEL__ */
--- diff/include/asm-ppc/serial.h	2004-05-19 22:12:50.000000000 +0100
+++ source/include/asm-ppc/serial.h	2004-06-11 19:22:06.000000000 +0100
@@ -30,6 +30,8 @@
 #include <platforms/spruce.h>
 #elif defined(CONFIG_4xx)
 #include <asm/ibm4xx.h>
+#elif defined(CONFIG_85xx)
+#include <asm/mpc85xx.h>
 #else
 
 /*
--- diff/include/asm-ppc/setup.h	2004-05-19 22:12:50.000000000 +0100
+++ source/include/asm-ppc/setup.h	2004-06-11 19:22:06.000000000 +0100
@@ -6,6 +6,9 @@
 #define m68k_memory memory
 
 #include <asm-m68k/setup.h>
+/* We have a bigger command line buffer. */
+#undef COMMAND_LINE_SIZE
+#define COMMAND_LINE_SIZE	512
 
 #endif /* _PPC_SETUP_H */
 #endif /* __KERNEL__ */
--- diff/include/asm-ppc/system.h	2004-06-11 19:17:34.000000000 +0100
+++ source/include/asm-ppc/system.h	2004-06-11 19:22:06.000000000 +0100
@@ -76,6 +76,8 @@
 extern void enable_kernel_fp(void);
 extern void giveup_altivec(struct task_struct *);
 extern void load_up_altivec(struct task_struct *);
+extern void giveup_spe(struct task_struct *);
+extern void load_up_spe(struct task_struct *);
 extern int fix_alignment(struct pt_regs *);
 extern void cvt_fd(float *from, double *to, unsigned long *fpscr);
 extern void cvt_df(double *from, float *to, unsigned long *fpscr);
--- diff/include/asm-ppc/tlbflush.h	2004-06-11 19:17:34.000000000 +0100
+++ source/include/asm-ppc/tlbflush.h	2004-06-11 19:22:06.000000000 +0100
@@ -39,6 +39,28 @@
 				unsigned long end)
 	{ __tlbia(); }
 
+#elif defined(CONFIG_FSL_BOOKE)
+
+/* TODO: determine if flush_tlb_range & flush_tlb_kernel_range
+ * are best implemented as tlbia vs specific tlbie's */
+
+#define __tlbia()	_tlbia()
+
+static inline void flush_tlb_mm(struct mm_struct *mm)
+	{ __tlbia(); }
+static inline void flush_tlb_page(struct vm_area_struct *vma,
+				unsigned long vmaddr)
+	{ _tlbie(vmaddr); }
+static inline void flush_tlb_page_nohash(struct vm_area_struct *vma,
+					 unsigned long vmaddr)
+	{ _tlbie(vmaddr); }
+static inline void flush_tlb_range(struct vm_area_struct *vma,
+				unsigned long start, unsigned long end)
+	{ __tlbia(); }
+static inline void flush_tlb_kernel_range(unsigned long start,
+				unsigned long end)
+	{ __tlbia(); }
+
 #elif defined(CONFIG_8xx)
 #define __tlbia()	asm volatile ("tlbia; sync" : : : "memory")
 
--- diff/include/asm-ppc/unistd.h	2004-06-11 19:17:34.000000000 +0100
+++ source/include/asm-ppc/unistd.h	2004-06-11 19:22:06.000000000 +0100
@@ -273,8 +273,14 @@
 #define __NR_mq_notify		266
 #define __NR_mq_getsetattr	267
 #define __NR_kexec_load		268
+#define __NR_perfctr_info	269
+#define __NR_vperfctr_open	(__NR_perfctr_info+1)
+#define __NR_vperfctr_control	(__NR_perfctr_info+2)
+#define __NR_vperfctr_unlink	(__NR_perfctr_info+3)
+#define __NR_vperfctr_iresume	(__NR_perfctr_info+4)
+#define __NR_vperfctr_read	(__NR_perfctr_info+5)
 
-#define __NR_syscalls		269
+#define __NR_syscalls		275
 
 #define __NR(n)	#n
 
@@ -402,6 +408,7 @@
 #define __ARCH_WANT_SYS_OLDUMOUNT
 #define __ARCH_WANT_SYS_SIGPENDING
 #define __ARCH_WANT_SYS_SIGPROCMASK
+#define __ARCH_WANT_SYS_RT_SIGACTION
 
 /*
  * Forking from kernel space will result in the child getting a new,
--- diff/include/asm-ppc64/current.h	2004-05-19 22:12:51.000000000 +0100
+++ source/include/asm-ppc64/current.h	2004-06-11 19:22:06.000000000 +0100
@@ -8,13 +8,11 @@
  * 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.
- *
- * Use r13 for current since the ppc64 ABI reserves it - Anton
  */
 
 #include <asm/thread_info.h>
 
-#define get_current()   ((struct task_struct *)(get_paca()->xCurrent))
+#define get_current()   (get_paca()->xCurrent)
 #define current         get_current()
 
 #endif /* !(_PPC64_CURRENT_H) */
--- diff/include/asm-ppc64/machdep.h	2004-05-19 22:12:51.000000000 +0100
+++ source/include/asm-ppc64/machdep.h	2004-06-11 19:22:06.000000000 +0100
@@ -11,6 +11,7 @@
 
 #include <linux/config.h>
 #include <linux/seq_file.h>
+#include <linux/init.h>
 #include <linux/dma-mapping.h>
 
 struct pt_regs;
@@ -112,9 +113,7 @@
 };
 
 extern struct machdep_calls ppc_md;
-#define COMMAND_LINE_SIZE 512
 extern char cmd_line[COMMAND_LINE_SIZE];
-extern char saved_command_line[COMMAND_LINE_SIZE];
 
 /* Functions to produce codes on the leds.
  * The SRC code should be unique for the message category and should
--- diff/include/asm-ppc64/paca.h	2004-06-11 19:17:34.000000000 +0100
+++ source/include/asm-ppc64/paca.h	2004-06-11 19:22:06.000000000 +0100
@@ -37,6 +37,8 @@
 register struct paca_struct *local_paca asm("r13");
 #define get_paca()	local_paca
 
+struct task_struct;
+
 /*============================================================================
  * Name_______:	paca
  *
@@ -59,7 +61,7 @@
  */
 	struct ItLpPaca *xLpPacaPtr;	/* Pointer to LpPaca for PLIC		0x00 */
 	struct ItLpRegSave *xLpRegSavePtr; /* Pointer to LpRegSave for PLIC	0x08 */
-	u64 xCurrent;  		        /* Pointer to current			0x10 */
+	struct task_struct *xCurrent;	/* Pointer to current			0x10 */
 	/* Note: the spinlock functions in arch/ppc64/lib/locks.c load lock_token and
 	   xPacaIndex with a single lwz instruction, using the constant offset 24.
 	   If you move either field, fix the spinlocks and rwlocks. */
--- diff/include/asm-ppc64/pgalloc.h	2004-06-11 19:17:34.000000000 +0100
+++ source/include/asm-ppc64/pgalloc.h	2004-06-11 19:22:06.000000000 +0100
@@ -101,33 +101,7 @@
 
 DECLARE_PER_CPU(struct pte_freelist_batch *, pte_freelist_cur);
 
-static inline void __pte_free_tlb(struct mmu_gather *tlb, struct page *ptepage)
-{
-	/* This is safe as we are holding page_table_lock */
-        cpumask_t local_cpumask = cpumask_of_cpu(smp_processor_id());
-	struct pte_freelist_batch **batchp = &__get_cpu_var(pte_freelist_cur);
-
-	if (atomic_read(&tlb->mm->mm_users) < 2 ||
-	    cpus_equal(tlb->mm->cpu_vm_mask, local_cpumask)) {
-		pte_free(ptepage);
-		return;
-	}
-
-	if (*batchp == NULL) {
-		*batchp = (struct pte_freelist_batch *)__get_free_page(GFP_ATOMIC);
-		if (*batchp == NULL) {
-			pte_free_now(ptepage);
-			return;
-		}
-		(*batchp)->index = 0;
-	}
-	(*batchp)->pages[(*batchp)->index++] = ptepage;
-	if ((*batchp)->index == PTE_FREELIST_SIZE) {
-		pte_free_submit(*batchp);
-		*batchp = NULL;
-	}
-}
-
+void __pte_free_tlb(struct mmu_gather *tlb, struct page *ptepage);
 #define __pmd_free_tlb(tlb, pmd)	__pte_free_tlb(tlb, virt_to_page(pmd))
 
 #define check_pgt_cache()	do { } while (0)
--- diff/include/asm-ppc64/resource.h	2004-05-19 22:12:51.000000000 +0100
+++ source/include/asm-ppc64/resource.h	2004-06-11 19:22:06.000000000 +0100
@@ -21,8 +21,10 @@
 #define RLIMIT_MEMLOCK	8		/* max locked-in-memory address space */
 #define RLIMIT_AS	9		/* address space limit(?) */
 #define RLIMIT_LOCKS	10		/* maximum file locks held */
+#define RLIMIT_SIGPENDING 11		/* max number of pending signals */
+#define RLIMIT_MSGQUEUE 12		/* maximum bytes in POSIX mqueues */
 
-#define RLIM_NLIMITS	11
+#define RLIM_NLIMITS	13
 
 #ifdef __KERNEL__
 
@@ -46,6 +48,8 @@
 	{ RLIM_INFINITY, RLIM_INFINITY },		\
 	{ RLIM_INFINITY, RLIM_INFINITY },		\
 	{ RLIM_INFINITY, RLIM_INFINITY },		\
+	{ MAX_SIGPENDING, MAX_SIGPENDING },		\
+	{ MQ_BYTES_MAX, MQ_BYTES_MAX },			\
 }
 
 #endif /* __KERNEL__ */
--- diff/include/asm-ppc64/setup.h	2004-05-19 22:12:51.000000000 +0100
+++ source/include/asm-ppc64/setup.h	2004-06-11 19:22:06.000000000 +0100
@@ -1,6 +1,6 @@
 #ifndef _PPC_SETUP_H
 #define _PPC_SETUP_H
 
-/* This is a place holder include */
+#define COMMAND_LINE_SIZE 512
 
 #endif /* _PPC_SETUP_H */
--- diff/include/asm-ppc64/smp.h	2004-05-19 22:12:51.000000000 +0100
+++ source/include/asm-ppc64/smp.h	2004-06-11 19:22:06.000000000 +0100
@@ -51,8 +51,6 @@
 extern cpumask_t cpu_available_map;
 
 #define cpu_present_at_boot(cpu) cpu_isset(cpu, cpu_present_at_boot)
-#define cpu_online(cpu)          cpu_isset(cpu, cpu_online_map) 
-#define cpu_possible(cpu)        cpu_isset(cpu, cpu_possible_map) 
 #define cpu_available(cpu)       cpu_isset(cpu, cpu_available_map) 
 
 /* Since OpenPIC has only 4 IPIs, we use slightly different message numbers.
--- diff/include/asm-ppc64/unistd.h	2004-06-11 19:17:34.000000000 +0100
+++ source/include/asm-ppc64/unistd.h	2004-06-11 19:22:06.000000000 +0100
@@ -439,6 +439,7 @@
 #define __ARCH_WANT_SYS_OLDUMOUNT
 #define __ARCH_WANT_SYS_SIGPENDING
 #define __ARCH_WANT_SYS_SIGPROCMASK
+#define __ARCH_WANT_SYS_RT_SIGACTION
 
 unsigned long sys_mmap(unsigned long addr, size_t len, unsigned long prot,
 		       unsigned long flags, unsigned long fd, off_t offset);
--- diff/include/asm-ppc64/vio.h	2004-05-19 22:12:52.000000000 +0100
+++ source/include/asm-ppc64/vio.h	2004-06-11 19:22:06.000000000 +0100
@@ -43,8 +43,6 @@
 
 int vio_register_driver(struct vio_driver *drv);
 void vio_unregister_driver(struct vio_driver *drv);
-const struct vio_device_id * vio_match_device(const struct vio_device_id *ids, 
-						const struct vio_dev *dev);
 
 struct vio_dev * __devinit vio_register_device(struct device_node *node_vdev);
 void __devinit vio_unregister_device(struct vio_dev *dev);
@@ -52,7 +50,6 @@
 
 const void * vio_get_attribute(struct vio_dev *vdev, void* which, int* length);
 int vio_get_irq(struct vio_dev *dev);
-struct iommu_table * vio_build_iommu_table(struct vio_dev *dev);
 int vio_enable_interrupts(struct vio_dev *dev);
 int vio_disable_interrupts(struct vio_dev *dev);
 
@@ -110,8 +107,6 @@
  * The vio_dev structure is used to describe virtual I/O devices.
  */
 struct vio_dev {
-	struct device_node *archdata;   /* Open Firmware node */
-	void *driver_data;              /* data private to the driver */
 	struct iommu_table *iommu_table;     /* vio_map_* uses this */
 	uint32_t unit_address;	
 	unsigned int irq;
--- diff/include/asm-s390/ptrace.h	2004-05-19 22:12:52.000000000 +0100
+++ source/include/asm-s390/ptrace.h	2004-06-11 19:22:06.000000000 +0100
@@ -303,6 +303,7 @@
  */
 struct pt_regs 
 {
+	unsigned long args[1];
 	psw_t psw;
 	unsigned long gprs[NUM_GPRS];
 	unsigned long orig_gpr2;
--- diff/include/asm-s390/resource.h	2004-05-19 22:12:52.000000000 +0100
+++ source/include/asm-s390/resource.h	2004-06-11 19:22:06.000000000 +0100
@@ -24,8 +24,10 @@
 #define RLIMIT_MEMLOCK	8		/* max locked-in-memory address space */
 #define RLIMIT_AS	9		/* address space limit */
 #define RLIMIT_LOCKS	10		/* maximum file locks held */
-  
-#define RLIM_NLIMITS	11
+#define RLIMIT_SIGPENDING 11		/* max number of pending signals */
+#define RLIMIT_MSGQUEUE 12		/* maximum bytes in POSIX mqueues */
+
+#define RLIM_NLIMITS	13
 
 /*
  * SuS says limits have to be unsigned.
@@ -48,6 +50,8 @@
 	{ RLIM_INFINITY, RLIM_INFINITY },		\
 	{ RLIM_INFINITY, RLIM_INFINITY },		\
 	{ RLIM_INFINITY, RLIM_INFINITY },		\
+	{ MAX_SIGPENDING, MAX_SIGPENDING },		\
+	{ MQ_BYTES_MAX, MQ_BYTES_MAX },			\
 }
 
 #endif /* __KERNEL__ */
--- diff/include/asm-s390/unistd.h	2004-06-11 19:17:34.000000000 +0100
+++ source/include/asm-s390/unistd.h	2004-06-11 19:22:06.000000000 +0100
@@ -530,6 +530,7 @@
 #define __ARCH_WANT_SYS_OLDUMOUNT
 #define __ARCH_WANT_SYS_SIGPENDING
 #define __ARCH_WANT_SYS_SIGPROCMASK
+#define __ARCH_WANT_SYS_RT_SIGACTION
 # ifndef CONFIG_ARCH_S390X
 #   define __ARCH_WANT_STAT64
 # endif
--- diff/include/asm-sh/resource.h	2004-05-19 22:12:53.000000000 +0100
+++ source/include/asm-sh/resource.h	2004-06-11 19:22:06.000000000 +0100
@@ -16,8 +16,10 @@
 #define RLIMIT_MEMLOCK	8		/* max locked-in-memory address space */
 #define RLIMIT_AS	9		/* address space limit */
 #define RLIMIT_LOCKS	10		/* maximum file locks held */
+#define RLIMIT_SIGPENDING 11		/* max number of pending signals */
+#define RLIMIT_MSGQUEUE 12		/* maximum bytes in POSIX mqueues */
 
-#define RLIM_NLIMITS	11
+#define RLIM_NLIMITS	13
 
 #ifdef __KERNEL__
 
@@ -40,6 +42,8 @@
 	{ RLIM_INFINITY, RLIM_INFINITY },		\
 	{ RLIM_INFINITY, RLIM_INFINITY },		\
 	{ RLIM_INFINITY, RLIM_INFINITY },		\
+	{ MAX_SIGPENDING, MAX_SIGPENDING },		\
+	{ MQ_BYTES_MAX, MQ_BYTES_MAX },			\
 }
 
 #endif /* __KERNEL__ */
--- diff/include/asm-sh/unistd.h	2004-06-11 19:17:35.000000000 +0100
+++ source/include/asm-sh/unistd.h	2004-06-11 19:22:06.000000000 +0100
@@ -422,6 +422,7 @@
 #define __ARCH_WANT_SYS_OLDUMOUNT
 #define __ARCH_WANT_SYS_SIGPENDING
 #define __ARCH_WANT_SYS_SIGPROCMASK
+#define __ARCH_WANT_SYS_RT_SIGACTION
 #endif
 
 #ifdef __KERNEL_SYSCALLS__
--- diff/include/asm-sparc/resource.h	2004-05-19 22:12:55.000000000 +0100
+++ source/include/asm-sparc/resource.h	2004-06-11 19:22:06.000000000 +0100
@@ -19,11 +19,13 @@
 #define RLIMIT_RSS	5		/* max resident set size */
 #define RLIMIT_NOFILE	6		/* max number of open files */
 #define RLIMIT_NPROC	7		/* max number of processes */
-#define RLIMIT_MEMLOCK  8               /* max locked-in-memory address space */
-#define RLIMIT_AS       9               /* address space limit */
+#define RLIMIT_MEMLOCK	8		/* max locked-in-memory address space */
+#define RLIMIT_AS	9		/* address space limit */
 #define RLIMIT_LOCKS	10		/* maximum file locks held */
+#define RLIMIT_SIGPENDING 11		/* max number of pending signals */
+#define RLIMIT_MSGQUEUE 12		/* maximum bytes in POSIX mqueues */
 
-#define RLIM_NLIMITS	11
+#define RLIM_NLIMITS	13
 
 /*
  * SuS says limits have to be unsigned.
@@ -44,7 +46,9 @@
     {INR_OPEN, INR_OPEN}, {0, 0},	\
     {RLIM_INFINITY, RLIM_INFINITY},	\
     {RLIM_INFINITY, RLIM_INFINITY},	\
-    {RLIM_INFINITY, RLIM_INFINITY}	\
+    {RLIM_INFINITY, RLIM_INFINITY},	\
+    {MAX_SIGPENDING, MAX_SIGPENDING},	\
+    {MQ_BYTES_MAX, MQ_BYTES_MAX},	\
 }
 
 #endif /* __KERNEL__ */
--- diff/include/asm-sparc/setup.h	2004-05-19 22:12:55.000000000 +0100
+++ source/include/asm-sparc/setup.h	2004-06-11 19:22:06.000000000 +0100
@@ -5,5 +5,6 @@
 #ifndef _SPARC_SETUP_H
 #define _SPARC_SETUP_H
 
+#define COMMAND_LINE_SIZE	256
 
 #endif /* _SPARC_SETUP_H */
--- diff/include/asm-sparc64/resource.h	2004-05-19 22:12:56.000000000 +0100
+++ source/include/asm-sparc64/resource.h	2004-06-11 19:22:06.000000000 +0100
@@ -19,11 +19,13 @@
 #define RLIMIT_RSS	5		/* max resident set size */
 #define RLIMIT_NOFILE	6		/* max number of open files */
 #define RLIMIT_NPROC	7		/* max number of processes */
-#define RLIMIT_MEMLOCK  8               /* max locked-in-memory address space */
-#define RLIMIT_AS       9               /* address space limit */
+#define RLIMIT_MEMLOCK	8		/* max locked-in-memory address space */
+#define RLIMIT_AS	9		/* address space limit */
 #define RLIMIT_LOCKS	10		/* maximum file locks held */
+#define RLIMIT_SIGPENDING 11		/* max number of pending signals */
+#define RLIMIT_MSGQUEUE 12		/* maximum bytes in POSIX mqueues */
 
-#define RLIM_NLIMITS	11
+#define RLIM_NLIMITS	13
 
 /*
  * SuS says limits have to be unsigned.
@@ -43,7 +45,9 @@
     {INR_OPEN, INR_OPEN}, {0, 0},	\
     {RLIM_INFINITY, RLIM_INFINITY},	\
     {RLIM_INFINITY, RLIM_INFINITY},	\
-    {RLIM_INFINITY, RLIM_INFINITY}	\
+    {RLIM_INFINITY, RLIM_INFINITY},	\
+    {MAX_SIGPENDING, MAX_SIGPENDING},	\
+    {MQ_BYTES_MAX, MQ_BYTES_MAX},	\
 }
 
 #endif /* __KERNEL__ */
--- diff/include/asm-sparc64/setup.h	2004-05-19 22:12:56.000000000 +0100
+++ source/include/asm-sparc64/setup.h	2004-06-11 19:22:06.000000000 +0100
@@ -5,5 +5,6 @@
 #ifndef _SPARC64_SETUP_H
 #define _SPARC64_SETUP_H
 
+#define COMMAND_LINE_SIZE	256
 
 #endif /* _SPARC64_SETUP_H */
--- diff/include/asm-sparc64/spinlock.h	2004-06-11 19:17:35.000000000 +0100
+++ source/include/asm-sparc64/spinlock.h	2004-06-11 19:22:06.000000000 +0100
@@ -31,15 +31,23 @@
 
 #ifndef CONFIG_DEBUG_SPINLOCK
 
-typedef unsigned char spinlock_t;
-#define SPIN_LOCK_UNLOCKED	0
+typedef struct {
+	unsigned char lock;
+	unsigned int  index;
+} spinlock_t;
 
-#define spin_lock_init(lock)	(*((unsigned char *)(lock)) = 0)
-#define spin_is_locked(lock)	(*((volatile unsigned char *)(lock)) != 0)
+#ifdef CONFIG_LOCKMETER
+#define SPIN_LOCK_UNLOCKED	(spinlock_t) {0, 0}
+#else
+#define SPIN_LOCK_UNLOCKED	(spinlock_t) { 0 }
+#endif
 
-#define spin_unlock_wait(lock)	\
+#define spin_lock_init(__lock)	do { *(__lock) = SPIN_LOCK_UNLOCKED; } while(0)
+#define spin_is_locked(__lock)	(*((volatile unsigned char *)(&((__lock)->lock))) != 0)
+
+#define spin_unlock_wait(__lock)	\
 do {	membar("#LoadLoad");	\
-} while(*((volatile unsigned char *)lock))
+} while(*((volatile unsigned char *)(&(((spinlock_t *)__lock)->lock))))
 
 static __inline__ void _raw_spin_lock(spinlock_t *lock)
 {
@@ -113,17 +121,31 @@
 
 #ifndef CONFIG_DEBUG_SPINLOCK
 
-typedef unsigned int rwlock_t;
-#define RW_LOCK_UNLOCKED	0
-#define rwlock_init(lp) do { *(lp) = RW_LOCK_UNLOCKED; } while(0)
-#define rwlock_is_locked(x) (*(x) != RW_LOCK_UNLOCKED)
+#ifdef CONFIG_LOCKMETER
+typedef struct {
+	unsigned int lock;
+	unsigned int index;
+	unsigned int cpu;
+} rwlock_t;
+#define RW_LOCK_UNLOCKED       (rwlock_t) { 0, 0, 0xff }
+#else
+typedef struct {
+	unsigned int lock;
+} rwlock_t;
+#define RW_LOCK_UNLOCKED        (rwlock_t) { 0 }
+#endif
+
+#define rwlock_init(lp)		do { *(lp) = RW_LOCK_UNLOCKED; } while(0)
+#define rwlock_is_locked(x)	((x)->lock != 0)
 
+extern int __read_trylock(rwlock_t *);
 extern void __read_lock(rwlock_t *);
 extern void __read_unlock(rwlock_t *);
 extern void __write_lock(rwlock_t *);
 extern void __write_unlock(rwlock_t *);
 extern int __write_trylock(rwlock_t *);
 
+#define _raw_read_trylock(p)	__read_trylock(p)
 #define _raw_read_lock(p)	__read_lock(p)
 #define _raw_read_unlock(p)	__read_unlock(p)
 #define _raw_write_lock(p)	__write_lock(p)
--- diff/include/asm-um/unistd.h	2004-06-11 19:17:35.000000000 +0100
+++ source/include/asm-um/unistd.h	2004-06-11 19:22:06.000000000 +0100
@@ -34,6 +34,7 @@
 #define __ARCH_WANT_SYS_OLDUMOUNT
 #define __ARCH_WANT_SYS_SIGPENDING
 #define __ARCH_WANT_SYS_SIGPROCMASK
+#define __ARCH_WANT_SYS_RT_SIGACTION
 #endif
 
 #ifdef __KERNEL_SYSCALLS__
--- diff/include/asm-v850/resource.h	2004-05-19 22:12:57.000000000 +0100
+++ source/include/asm-v850/resource.h	2004-06-11 19:22:06.000000000 +0100
@@ -16,8 +16,10 @@
 #define RLIMIT_MEMLOCK	8		/* max locked-in-memory address space */
 #define RLIMIT_AS	9		/* address space limit */
 #define RLIMIT_LOCKS	10		/* maximum file locks held */
+#define RLIMIT_SIGPENDING 11		/* max number of pending signals */
+#define RLIMIT_MSGQUEUE 12		/* maximum bytes in POSIX mqueues */
 
-#define RLIM_NLIMITS	11
+#define RLIM_NLIMITS	13
 
 /*
  * SuS says limits have to be unsigned.
@@ -39,7 +41,9 @@
 	{      INR_OPEN,     INR_OPEN  },		\
 	{ RLIM_INFINITY, RLIM_INFINITY },		\
 	{ RLIM_INFINITY, RLIM_INFINITY },		\
-        { RLIM_INFINITY, RLIM_INFINITY },		\
+	{ RLIM_INFINITY, RLIM_INFINITY },		\
+	{ MAX_SIGPENDING, MAX_SIGPENDING },		\
+	{ MQ_BYTES_MAX, MQ_BYTES_MAX },			\
 }
 
 #endif /* __KERNEL__ */
--- diff/include/asm-v850/unistd.h	2004-06-11 19:17:35.000000000 +0100
+++ source/include/asm-v850/unistd.h	2004-06-11 19:22:06.000000000 +0100
@@ -408,6 +408,7 @@
 #define __ARCH_WANT_SYS_OLDUMOUNT
 #define __ARCH_WANT_SYS_SIGPENDING
 #define __ARCH_WANT_SYS_SIGPROCMASK
+#define __ARCH_WANT_SYS_RT_SIGACTION
 #endif
 
 #ifdef __KERNEL_SYSCALLS__
--- diff/include/asm-x86_64/bootsetup.h	2004-05-19 22:12:57.000000000 +0100
+++ source/include/asm-x86_64/bootsetup.h	2004-06-11 19:22:06.000000000 +0100
@@ -30,7 +30,6 @@
 #define EDD_NR     (*(unsigned char *) (PARAM+EDDNR))
 #define EDD_BUF     ((struct edd_info *) (PARAM+EDDBUF))
 #define COMMAND_LINE saved_command_line
-#define COMMAND_LINE_SIZE 256
 
 #define RAMDISK_IMAGE_START_MASK  	0x07FF
 #define RAMDISK_PROMPT_FLAG		0x8000
--- diff/include/asm-x86_64/hw_irq.h	2004-05-19 22:12:57.000000000 +0100
+++ source/include/asm-x86_64/hw_irq.h	2004-06-11 19:22:06.000000000 +0100
@@ -65,19 +65,21 @@
  * sources per level' errata.
  */
 #define LOCAL_TIMER_VECTOR	0xef
+#define LOCAL_PERFCTR_VECTOR	0xee
 
 /*
- * First APIC vector available to drivers: (vectors 0x30-0xee)
+ * First APIC vector available to drivers: (vectors 0x30-0xed)
  * we start at 0x31 to spread out vectors evenly between priority
  * levels. (0x80 is the syscall vector)
  */
 #define FIRST_DEVICE_VECTOR	0x31
-#define FIRST_SYSTEM_VECTOR	0xef   /* duplicated in irq.h */
+#define FIRST_SYSTEM_VECTOR	0xee   /* duplicated in irq.h */
 
 
 #ifndef __ASSEMBLY__
 extern u8 irq_vector[NR_IRQ_VECTORS];
 #define IO_APIC_VECTOR(irq)	(irq_vector[irq])
+#define AUTO_ASSIGN		-1
 
 /*
  * Various low-level irq details needed by irq.c, process.c,
--- diff/include/asm-x86_64/ia32_unistd.h	2004-06-11 19:17:35.000000000 +0100
+++ source/include/asm-x86_64/ia32_unistd.h	2004-06-11 19:22:06.000000000 +0100
@@ -289,7 +289,13 @@
 #define __NR_ia32_mq_notify		(__NR_ia32_mq_open+4)
 #define __NR_ia32_mq_getsetattr	(__NR_ia32_mq_open+5)
 #define __NR_ia32_kexec		283
+#define __NR_ia32_perfctr_info		284
+#define __NR_ia32_vperfctr_open		(__NR_ia32_perfctr_info+1)
+#define __NR_ia32_vperfctr_control	(__NR_ia32_perfctr_info+2)
+#define __NR_ia32_vperfctr_unlink	(__NR_ia32_perfctr_info+3)
+#define __NR_ia32_vperfctr_iresume	(__NR_ia32_perfctr_info+4)
+#define __NR_ia32_vperfctr_read		(__NR_ia32_perfctr_info+5)
 
-#define IA32_NR_syscalls 287	/* must be > than biggest syscall! */
+#define IA32_NR_syscalls 290	/* must be > than biggest syscall! */
 
 #endif /* _ASM_X86_64_IA32_UNISTD_H_ */
--- diff/include/asm-x86_64/irq.h	2004-05-19 22:12:57.000000000 +0100
+++ source/include/asm-x86_64/irq.h	2004-06-11 19:22:06.000000000 +0100
@@ -29,7 +29,7 @@
  */
 #define NR_VECTORS 256
 
-#define FIRST_SYSTEM_VECTOR	0xef   /* duplicated in hw_irq.h */
+#define FIRST_SYSTEM_VECTOR	0xee   /* duplicated in hw_irq.h */
 
 #ifdef CONFIG_PCI_USE_VECTOR
 #define NR_IRQS FIRST_SYSTEM_VECTOR
--- diff/include/asm-x86_64/mpspec.h	2004-05-19 22:12:58.000000000 +0100
+++ source/include/asm-x86_64/mpspec.h	2004-06-11 19:22:06.000000000 +0100
@@ -189,7 +189,7 @@
 extern void mp_register_ioapic (u8 id, u32 address, u32 gsi_base);
 extern void mp_override_legacy_irq (u8 bus_irq, u8 polarity, u8 trigger, u32 gsi);
 extern void mp_config_acpi_legacy_irqs (void);
-extern void mp_parse_prt (void);
+extern void mp_register_gsi (u32 gsi, int edge_level, int active_high_low);
 #endif /*CONFIG_X86_IO_APIC*/
 #endif
 
@@ -212,7 +212,7 @@
 #define physids_and(dst, src1, src2)		bitmap_and((dst).mask, (src1).mask, (src2).mask, MAX_APICS)
 #define physids_or(dst, src1, src2)		bitmap_or((dst).mask, (src1).mask, (src2).mask, MAX_APICS)
 #define physids_clear(map)			bitmap_zero((map).mask, MAX_APICS)
-#define physids_complement(map)			bitmap_complement((map).mask, MAX_APICS)
+#define physids_complement(dst, src)		bitmap_complement((dst).mask, (src).mask, MAX_APICS)
 #define physids_empty(map)			bitmap_empty((map).mask, MAX_APICS)
 #define physids_equal(map1, map2)		bitmap_equal((map1).mask, (map2).mask, MAX_APICS)
 #define physids_weight(map)			bitmap_weight((map).mask, MAX_APICS)
--- diff/include/asm-x86_64/msi.h	2004-05-19 22:12:58.000000000 +0100
+++ source/include/asm-x86_64/msi.h	2004-06-11 19:22:06.000000000 +0100
@@ -11,11 +11,6 @@
 #define LAST_DEVICE_VECTOR		232
 #define MSI_DEST_MODE			MSI_LOGICAL_MODE
 #define MSI_TARGET_CPU_SHIFT		12
-
-#ifdef CONFIG_SMP
-#define MSI_TARGET_CPU		logical_smp_processor_id()
-#else
-#define MSI_TARGET_CPU		TARGET_CPUS
-#endif
+#define MSI_TARGET_CPU			TARGET_CPUS
 
 #endif /* ASM_MSI_H */
--- diff/include/asm-x86_64/pgtable.h	2004-06-11 19:17:35.000000000 +0100
+++ source/include/asm-x86_64/pgtable.h	2004-06-11 19:22:06.000000000 +0100
@@ -172,7 +172,7 @@
 #define PAGE_READONLY_EXEC __pgprot(_PAGE_PRESENT | _PAGE_USER | _PAGE_ACCESSED)
 #define __PAGE_KERNEL \
 	(_PAGE_PRESENT | _PAGE_RW | _PAGE_DIRTY | _PAGE_ACCESSED | _PAGE_NX)
-#define __PAGE_KERNEL_EXECUTABLE \
+#define __PAGE_KERNEL_EXEC \
 	(_PAGE_PRESENT | _PAGE_RW | _PAGE_DIRTY | _PAGE_ACCESSED)
 #define __PAGE_KERNEL_NOCACHE \
 	(_PAGE_PRESENT | _PAGE_RW | _PAGE_DIRTY | _PAGE_PCD | _PAGE_ACCESSED | _PAGE_NX)
@@ -188,7 +188,7 @@
 #define MAKE_GLOBAL(x) __pgprot((x) | _PAGE_GLOBAL)
 
 #define PAGE_KERNEL MAKE_GLOBAL(__PAGE_KERNEL)
-#define PAGE_KERNEL_EXECUTABLE MAKE_GLOBAL(__PAGE_KERNEL_EXECUTABLE)
+#define PAGE_KERNEL_EXEC MAKE_GLOBAL(__PAGE_KERNEL_EXEC)
 #define PAGE_KERNEL_RO MAKE_GLOBAL(__PAGE_KERNEL_RO)
 #define PAGE_KERNEL_NOCACHE MAKE_GLOBAL(__PAGE_KERNEL_NOCACHE)
 #define PAGE_KERNEL_VSYSCALL MAKE_GLOBAL(__PAGE_KERNEL_VSYSCALL)
@@ -262,8 +262,21 @@
 extern inline pte_t pte_mkdirty(pte_t pte)	{ set_pte(&pte, __pte(pte_val(pte) | _PAGE_DIRTY)); return pte; }
 extern inline pte_t pte_mkyoung(pte_t pte)	{ set_pte(&pte, __pte(pte_val(pte) | _PAGE_ACCESSED)); return pte; }
 extern inline pte_t pte_mkwrite(pte_t pte)	{ set_pte(&pte, __pte(pte_val(pte) | _PAGE_RW)); return pte; }
-static inline  int ptep_test_and_clear_dirty(pte_t *ptep)	{ return test_and_clear_bit(_PAGE_BIT_DIRTY, ptep); }
-static inline  int ptep_test_and_clear_young(pte_t *ptep)	{ return test_and_clear_bit(_PAGE_BIT_ACCESSED, ptep); }
+
+static inline int ptep_test_and_clear_dirty(pte_t *ptep)
+{
+	if (!pte_dirty(*ptep))
+		return 0;
+	return test_and_clear_bit(_PAGE_BIT_DIRTY, ptep);
+}
+
+static inline int ptep_test_and_clear_young(pte_t *ptep)
+{
+	if (!pte_young(*ptep))
+		return 0;
+	return test_and_clear_bit(_PAGE_BIT_ACCESSED, ptep);
+}
+
 static inline void ptep_set_wrprotect(pte_t *ptep)		{ clear_bit(_PAGE_BIT_RW, ptep); }
 static inline void ptep_mkdirty(pte_t *ptep)			{ set_bit(_PAGE_BIT_DIRTY, ptep); }
 
--- diff/include/asm-x86_64/processor.h	2004-06-11 19:17:35.000000000 +0100
+++ source/include/asm-x86_64/processor.h	2004-06-11 19:22:06.000000000 +0100
@@ -253,6 +253,8 @@
 	unsigned long	*io_bitmap_ptr;
 /* cached TLS descriptors. */
 	u64 tls_array[GDT_ENTRY_TLS_ENTRIES];
+/* performance counters */
+	struct vperfctr *perfctr;
 } __attribute__((aligned(16)));
 
 #define INIT_THREAD  {}
--- diff/include/asm-x86_64/resource.h	2004-05-19 22:12:58.000000000 +0100
+++ source/include/asm-x86_64/resource.h	2004-06-11 19:22:06.000000000 +0100
@@ -16,8 +16,10 @@
 #define RLIMIT_MEMLOCK	8		/* max locked-in-memory address space */
 #define RLIMIT_AS	9		/* address space limit */
 #define RLIMIT_LOCKS	10		/* maximum file locks held */
+#define RLIMIT_SIGPENDING 11		/* max number of pending signals */
+#define RLIMIT_MSGQUEUE 12		/* maximum bytes in POSIX mqueues */
 
-#define RLIM_NLIMITS	11
+#define RLIM_NLIMITS	13
 
 /*
  * SuS says limits have to be unsigned.
@@ -39,7 +41,9 @@
 	{      INR_OPEN,     INR_OPEN  },		\
 	{ RLIM_INFINITY, RLIM_INFINITY },		\
 	{ RLIM_INFINITY, RLIM_INFINITY },		\
-        { RLIM_INFINITY, RLIM_INFINITY },		\
+	{ RLIM_INFINITY, RLIM_INFINITY },		\
+	{ MAX_SIGPENDING, MAX_SIGPENDING },		\
+	{ MQ_BYTES_MAX, MQ_BYTES_MAX },			\
 }
 
 #endif /* __KERNEL__ */
--- diff/include/asm-x86_64/setup.h	2004-05-19 22:12:58.000000000 +0100
+++ source/include/asm-x86_64/setup.h	2004-06-11 19:22:06.000000000 +0100
@@ -1,10 +1,6 @@
-/*
- *	Just a place holder. We don't want to have to test x86 before
- *	we include stuff
- */
-
 #ifndef _x8664_SETUP_H
 #define _x8664_SETUP_H
 
+#define COMMAND_LINE_SIZE	256
 
 #endif
--- diff/include/asm-x86_64/smp.h	2004-06-11 19:17:35.000000000 +0100
+++ source/include/asm-x86_64/smp.h	2004-06-11 19:22:06.000000000 +0100
@@ -60,7 +60,6 @@
 
 extern cpumask_t cpu_callout_map;
 #define cpu_possible_map cpu_callout_map
-#define cpu_online(cpu) cpu_isset(cpu, cpu_online_map)
 
 static inline int num_booting_cpus(void)
 {
@@ -105,7 +104,6 @@
 		return BAD_APICID;
 }
 
-#define cpu_online(cpu) cpu_isset(cpu, cpu_online_map)
 #endif /* !ASSEMBLY */
 
 #define NO_PROC_ID		0xFF		/* No processor magic marker */
@@ -115,9 +113,9 @@
 #define TARGET_CPUS 1
 
 #ifndef ASSEMBLY
-static inline unsigned int cpu_mask_to_apicid(cpumask_const_t cpumask)
+static inline unsigned int cpu_mask_to_apicid(cpumask_t cpumask)
 {
-	return cpus_coerce_const(cpumask);
+	return cpus_addr(cpumask)[0];
 }
 #endif
 
--- diff/include/asm-x86_64/topology.h	2004-05-19 22:12:58.000000000 +0100
+++ source/include/asm-x86_64/topology.h	2004-06-11 19:22:06.000000000 +0100
@@ -20,9 +20,11 @@
 #define node_to_first_cpu(node) 	(__ffs(node_to_cpumask[node]))
 #define node_to_cpumask(node)		(node_to_cpumask[node])
 
-static inline unsigned long pcibus_to_cpumask(int bus)
+static inline cpumask_t pcibus_to_cpumask(int bus)
 {
-	return mp_bus_to_cpumask[bus] & cpu_online_map; 
+	cpumask_t tmp;
+	cpus_and(tmp, mp_bus_to_cpumask[bus], cpu_online_map);
+	return tmp;
 }
 
 #define NODE_BALANCE_RATE 30	/* CHECKME */ 
--- diff/include/asm-x86_64/unistd.h	2004-06-11 19:17:35.000000000 +0100
+++ source/include/asm-x86_64/unistd.h	2004-06-11 19:22:06.000000000 +0100
@@ -554,8 +554,20 @@
 __SYSCALL(__NR_mq_getsetattr, sys_mq_getsetattr)
 #define __NR_kexec_load 	246
 __SYSCALL(__NR_kexec_load, sys_ni_syscall)
+#define __NR_perfctr_info	247
+__SYSCALL(__NR_perfctr_info, sys_perfctr_info)
+#define __NR_vperfctr_open	(__NR_perfctr_info+1)
+__SYSCALL(__NR_vperfctr_open, sys_vperfctr_open)
+#define __NR_vperfctr_control	(__NR_perfctr_info+2)
+__SYSCALL(__NR_vperfctr_control, sys_vperfctr_control)
+#define __NR_vperfctr_unlink	(__NR_perfctr_info+3)
+__SYSCALL(__NR_vperfctr_unlink, sys_vperfctr_unlink)
+#define __NR_vperfctr_iresume	(__NR_perfctr_info+4)
+__SYSCALL(__NR_vperfctr_iresume, sys_vperfctr_iresume)
+#define __NR_vperfctr_read	(__NR_perfctr_info+5)
+__SYSCALL(__NR_vperfctr_read, sys_vperfctr_read)
 
-#define __NR_syscall_max __NR_kexec_load
+#define __NR_syscall_max __NR_vperfctr_read
 #ifndef __NO_STUBS
 
 /* user-visible error numbers are in the range -1 - -4095 */
@@ -591,6 +603,7 @@
 #define __ARCH_WANT_SYS_OLDUMOUNT
 #define __ARCH_WANT_SYS_SIGPENDING
 #define __ARCH_WANT_SYS_SIGPROCMASK
+#define __ARCH_WANT_SYS_RT_SIGACTION
 #endif
 
 #ifndef __KERNEL_SYSCALLS__
--- diff/include/linux/acct.h	2004-05-19 22:12:58.000000000 +0100
+++ source/include/linux/acct.h	2004-06-11 19:22:06.000000000 +0100
@@ -16,14 +16,18 @@
 #define _LINUX_ACCT_H
 
 #include <linux/types.h>
+#include <asm/param.h>
 
 /* 
  *  comp_t is a 16-bit "floating" point number with a 3-bit base 8
- *  exponent and a 13-bit fraction. See linux/kernel/acct.c for the
- *  specific encoding system used.
+ *  exponent and a 13-bit fraction.
+ *  comp2_t is 24-bit with 5-bit base 2 exponent and 20 bit fraction
+ *  (leading 1 not stored).
+ *  See linux/kernel/acct.c for the specific encoding systems used.
  */
 
 typedef __u16	comp_t;
+typedef __u32	comp2_t;
 
 /*
  *   accounting file record
@@ -36,27 +40,59 @@
 
 struct acct
 {
-	char		ac_flag;		/* Accounting Flags */
-/*
- *	No binary format break with 2.0 - but when we hit 32bit uid we'll
- *	have to bite one
- */
-	__u16		ac_uid;			/* Accounting Real User ID */
-	__u16		ac_gid;			/* Accounting Real Group ID */
-	__u16		ac_tty;			/* Accounting Control Terminal */
-	__u32		ac_btime;		/* Accounting Process Creation Time */
-	comp_t		ac_utime;		/* Accounting User Time */
-	comp_t		ac_stime;		/* Accounting System Time */
-	comp_t		ac_etime;		/* Accounting Elapsed Time */
-	comp_t		ac_mem;			/* Accounting Average Memory Usage */
-	comp_t		ac_io;			/* Accounting Chars Transferred */
-	comp_t		ac_rw;			/* Accounting Blocks Read or Written */
-	comp_t		ac_minflt;		/* Accounting Minor Pagefaults */
-	comp_t		ac_majflt;		/* Accounting Major Pagefaults */
-	comp_t		ac_swaps;		/* Accounting Number of Swaps */
-	__u32		ac_exitcode;		/* Accounting Exitcode */
-	char		ac_comm[ACCT_COMM + 1];	/* Accounting Command Name */
-	char		ac_pad[10];		/* Accounting Padding Bytes */
+	char		ac_flag;		/* Flags */
+	char		ac_version;		/* Always set to ACCT_VERSION */
+	/* for binary compatibility back until 2.0 */
+	__u16		ac_uid16;		/* LSB of Real User ID */
+	__u16		ac_gid16;		/* LSB of Real Group ID */
+	__u16		ac_tty;			/* Control Terminal */
+	__u32		ac_btime;		/* Process Creation Time */
+	comp_t		ac_utime;		/* User Time */
+	comp_t		ac_stime;		/* System Time */
+	comp_t		ac_etime;		/* Elapsed Time */
+	comp_t		ac_mem;			/* Average Memory Usage */
+	comp_t		ac_io;			/* Chars Transferred */
+	comp_t		ac_rw;			/* Blocks Read or Written */
+	comp_t		ac_minflt;		/* Minor Pagefaults */
+	comp_t		ac_majflt;		/* Major Pagefaults */
+	comp_t		ac_swaps;		/* Number of Swaps */
+/* m68k had no padding here. */
+#if !defined(CONFIG_M68K) || !defined(__KERNEL__)
+	__u16		ac_ahz;			/* AHZ */
+#endif
+	__u32		ac_exitcode;		/* Exitcode */
+	char		ac_comm[ACCT_COMM + 1];	/* Command Name */
+	__u8		ac_etime_hi;		/* Elapsed Time MSB */
+	__u16		ac_etime_lo;		/* Elapsed Time LSB */
+	__u32		ac_uid;			/* Real User ID */
+	__u32		ac_gid;			/* Real Group ID */
+};
+
+struct acct_v3
+{
+	char		ac_flag;		/* Flags */
+	char		ac_version;		/* Always set to ACCT_VERSION */
+	__u16		ac_tty;			/* Control Terminal */
+	__u32		ac_exitcode;		/* Exitcode */
+	__u32		ac_uid;			/* Real User ID */
+	__u32		ac_gid;			/* Real Group ID */
+	__u32		ac_pid;			/* Process ID */
+	__u32		ac_ppid;		/* Parent Process ID */
+	__u32		ac_btime;		/* Process Creation Time */
+#ifdef __KERNEL__
+	__u32		ac_etime;		/* Elapsed Time */
+#else
+	float		ac_etime;		/* Elapsed Time */
+#endif
+	comp_t		ac_utime;		/* User Time */
+	comp_t		ac_stime;		/* System Time */
+	comp_t		ac_mem;			/* Average Memory Usage */
+	comp_t		ac_io;			/* Chars Transferred */
+	comp_t		ac_rw;			/* Blocks Read or Written */
+	comp_t		ac_minflt;		/* Minor Pagefaults */
+	comp_t		ac_majflt;		/* Major Pagefaults */
+	comp_t		ac_swaps;		/* Number of Swaps */
+	char		ac_comm[ACCT_COMM];	/* Command Name */
 };
 
 /*
@@ -68,8 +104,7 @@
 #define ACOMPAT		0x04	/* ... used compatibility mode (VAX only not used) */
 #define ACORE		0x08	/* ... dumped core */
 #define AXSIG		0x10	/* ... was killed by a signal */
-
-#define AHZ		100
+#define ABYTESEX	0x80	/* always set, allows to detect byteorder */
 
 #ifdef __KERNEL__
 
@@ -84,6 +119,60 @@
 #define acct_process(x)		do { } while (0)
 #endif
 
+/*
+ * ACCT_VERSION numbers as yet defined:
+ * 0: old format (until 2.6.7) with 16 bit uid/gid
+ * 1: extended variant (binary compatible on M68K)
+ * 2: extended variant (binary compatible on everything except M68K)
+ * 3: new binary incompatible format (64 bytes)
+ * 4: new binary incompatible format (128 bytes)
+ * 5: new binary incompatible format (128 bytes, second half)
+ *
+ */
+
+#ifdef CONFIG_BSD_PROCESS_ACCT_V3
+#define ACCT_VERSION	3
+#define AHZ		100
+typedef struct acct_v3 acct_t;
+#else
+#ifdef CONFIG_M68K
+#define ACCT_VERSION	1
+#else
+#define ACCT_VERSION	2
+#endif
+#define AHZ		(USER_HZ)
+typedef struct acct acct_t;
+#endif
+
+#else
+#define ACCT_VERSION	2
+#define AHZ		(USER_HZ)
 #endif	/* __KERNEL */
 
+#ifdef __KERNEL__
+/*
+ * Yet another HZ to *HZ helper function.
+ * See <linux/times.h> for the original.
+ * TODO: Not exactly precise on i386.
+ */
+#if (HZ % AHZ)==0
+# define jiffies_to_AHZ(x) ((x) / (HZ / AHZ))
+#else
+# define jiffies_to_AHZ(x) ((clock_t) jiffies_64_to_AHZ((u64) x))
+#endif
+
+static inline u64 jiffies_64_to_AHZ(u64 x)
+{
+#if HZ == AHZ
+	/* do nothing */
+#elif (HZ % AHZ) == 0
+	do_div(x, HZ / AHZ);
+#else
+	x *= AHZ;
+	do_div(x, HZ);
+#endif
+       return x;
+}
+#endif  /* __KERNEL */
+
 #endif	/* _LINUX_ACCT_H */
--- diff/include/linux/acpi.h	2004-06-11 19:17:35.000000000 +0100
+++ source/include/linux/acpi.h	2004-06-11 19:22:06.000000000 +0100
@@ -413,6 +413,8 @@
 
 #endif 	/*!CONFIG_ACPI_BOOT*/
 
+unsigned int acpi_register_gsi (u32 gsi, int edge_level, int active_high_low);
+int acpi_gsi_to_irq (u32 gsi, unsigned int *irq);
 
 #ifdef CONFIG_ACPI_PCI
 
@@ -437,8 +439,6 @@
 struct pci_dev;
 
 int acpi_pci_irq_enable (struct pci_dev *dev);
-int acpi_pci_irq_init (void);
-int acpi_gsi_to_irq (u32 gsi, unsigned int *irq);
 
 struct acpi_pci_driver {
 	struct acpi_pci_driver *next;
--- diff/include/linux/binfmts.h	2004-05-19 22:12:58.000000000 +0100
+++ source/include/linux/binfmts.h	2004-06-11 19:22:06.000000000 +0100
@@ -35,9 +35,13 @@
 	char * interp;		/* Name of the binary really executed. Most
 				   of the time same as filename, but could be
 				   different for binfmt_{misc,script} */
+	unsigned long interp_flags;
 	unsigned long loader, exec;
 };
 
+#define BINPRM_FLAGS_ENFORCE_NONDUMP_BIT 0
+#define BINPRM_FLAGS_ENFORCE_NONDUMP (1 << BINPRM_FLAGS_ENFORCE_NONDUMP_BIT)
+
 /*
  * This structure defines the functions that are used to load the binary formats that
  * linux accepts.
--- diff/include/linux/bio.h	2004-05-19 22:12:58.000000000 +0100
+++ source/include/linux/bio.h	2004-06-11 19:22:06.000000000 +0100
@@ -102,6 +102,7 @@
 #define BIO_SEG_VALID	3	/* nr_hw_seg valid */
 #define BIO_CLONED	4	/* doesn't own data */
 #define BIO_BOUNCED	5	/* bio is a bounce bio */
+#define BIO_EOPNOTSUPP	6	/* not supported */
 #define bio_flagged(bio, flag)	((bio)->bi_flags & (1 << (flag)))
 
 /*
@@ -141,6 +142,8 @@
 #define bio_data(bio)		(page_address(bio_page((bio))) + bio_offset((bio)))
 #define bio_barrier(bio)	((bio)->bi_rw & (1 << BIO_RW_BARRIER))
 #define bio_sync(bio)		((bio)->bi_rw & (1 << BIO_RW_SYNC))
+#define bio_failfast(bio)	((bio)->bi_rw & (1 << BIO_RW_FAILFAST))
+#define bio_rw_ahead(bio)	((bio)->bi_rw & (1 << BIO_RW_AHEAD))
 
 /*
  * will die
--- diff/include/linux/bitmap.h	2004-06-11 19:17:35.000000000 +0100
+++ source/include/linux/bitmap.h	2004-06-11 19:22:06.000000000 +0100
@@ -3,49 +3,249 @@
 
 #ifndef __ASSEMBLY__
 
-#include <linux/config.h>
-#include <linux/compiler.h>
 #include <linux/types.h>
-#include <linux/kernel.h>
 #include <linux/bitops.h>
 #include <linux/string.h>
 
-int bitmap_empty(const unsigned long *bitmap, int bits);
-int bitmap_full(const unsigned long *bitmap, int bits);
-int bitmap_equal(const unsigned long *bitmap1,
-			unsigned long *bitmap2, int bits);
-void bitmap_complement(unsigned long *bitmap, int bits);
+/*
+ * bitmaps provide bit arrays that consume one or more unsigned
+ * longs.  The bitmap interface and available operations are listed
+ * here, in bitmap.h
+ *
+ * Function implementations generic to all architectures are in
+ * lib/bitmap.c.  Functions implementations that are architecture
+ * specific are in various include/asm-<arch>/bitops.h headers
+ * and other arch/<arch> specific files.
+ *
+ * See lib/bitmap.c for more details.
+ */
+
+/*
+ * The available bitmap operations and their rough meaning in the
+ * case that the bitmap is a single unsigned long are thus:
+ *
+ * bitmap_zero(dst, nbits)			*dst = 0UL
+ * bitmap_fill(dst, nbits)			*dst = ~0UL
+ * bitmap_copy(dst, src, nbits)			*dst = *src
+ * bitmap_and(dst, src1, src2, nbits)		*dst = *src1 & *src2
+ * bitmap_or(dst, src1, src2, nbits)		*dst = *src1 | *src2
+ * bitmap_xor(dst, src1, src2, nbits)		*dst = *src1 ^ *src2
+ * bitmap_andnot(dst, src1, src2, nbits)	*dst = *src1 & ~(*src2)
+ * bitmap_complement(dst, src, nbits)		*dst = ~(*src)
+ * bitmap_equal(src1, src2, nbits)		Are *src1 and *src2 equal?
+ * bitmap_intersects(src1, src2, nbits) 	Do *src1 and *src2 overlap?
+ * bitmap_subset(src1, src2, nbits)		Is *src1 a subset of *src2?
+ * bitmap_empty(src, nbits)			Are all bits zero in *src?
+ * bitmap_full(src, nbits)			Are all bits set in *src?
+ * bitmap_weight(src, nbits)			Hamming Weight: number set bits
+ * bitmap_shift_right(dst, src, n, nbits)	*dst = *src >> n
+ * bitmap_shift_left(dst, src, n, nbits)	*dst = *src << n
+ * bitmap_scnprintf(buf, len, src, nbits)	Print bitmap src to buf
+ * bitmap_parse(ubuf, ulen, dst, nbits)		Parse bitmap dst from buf
+ */
+
+/*
+ * Also the following operations in asm/bitops.h apply to bitmaps.
+ *
+ * set_bit(bit, addr)			*addr |= bit
+ * clear_bit(bit, addr)			*addr &= ~bit
+ * change_bit(bit, addr)		*addr ^= bit
+ * test_bit(bit, addr)			Is bit set in *addr?
+ * test_and_set_bit(bit, addr)		Set bit and return old value
+ * test_and_clear_bit(bit, addr)	Clear bit and return old value
+ * test_and_change_bit(bit, addr)	Change bit and return old value
+ * find_first_zero_bit(addr, nbits)	Position first zero bit in *addr
+ * find_first_bit(addr, nbits)		Position first set bit in *addr
+ * find_next_zero_bit(addr, nbits, bit)	Position next zero bit in *addr >= bit
+ * find_next_bit(addr, nbits, bit)	Position next set bit in *addr >= bit
+ */
+
+/*
+ * The DECLARE_BITMAP(name,bits) macro, in linux/types.h, can be used
+ * to declare an array named 'name' of just enough unsigned longs to
+ * contain all bit positions from 0 to 'bits' - 1.
+ */
+
+/*
+ * lib/bitmap.c provides these functions:
+ */
+
+extern int __bitmap_empty(const unsigned long *bitmap, int bits);
+extern int __bitmap_full(const unsigned long *bitmap, int bits);
+extern int __bitmap_equal(const unsigned long *bitmap1,
+                	const unsigned long *bitmap2, int bits);
+extern void __bitmap_complement(unsigned long *dst, const unsigned long *src,
+			int bits);
+extern void __bitmap_shift_right(unsigned long *dst,
+                        const unsigned long *src, int shift, int bits);
+extern void __bitmap_shift_left(unsigned long *dst,
+                        const unsigned long *src, int shift, int bits);
+extern void __bitmap_and(unsigned long *dst, const unsigned long *bitmap1,
+			const unsigned long *bitmap2, int bits);
+extern void __bitmap_or(unsigned long *dst, const unsigned long *bitmap1,
+			const unsigned long *bitmap2, int bits);
+extern void __bitmap_xor(unsigned long *dst, const unsigned long *bitmap1,
+			const unsigned long *bitmap2, int bits);
+extern void __bitmap_andnot(unsigned long *dst, const unsigned long *bitmap1,
+			const unsigned long *bitmap2, int bits);
+extern int __bitmap_intersects(const unsigned long *bitmap1,
+			const unsigned long *bitmap2, int bits);
+extern int __bitmap_subset(const unsigned long *bitmap1,
+			const unsigned long *bitmap2, int bits);
+extern int __bitmap_weight(const unsigned long *bitmap, int bits);
 
-static inline void bitmap_zero(unsigned long *bitmap, int bits)
+extern int bitmap_scnprintf(char *buf, unsigned int len,
+			const unsigned long *src, int nbits);
+extern int bitmap_parse(const char __user *ubuf, unsigned int ulen,
+			unsigned long *dst, int nbits);
+
+#define BITMAP_LAST_WORD_MASK(nbits)					\
+(									\
+	((nbits) % BITS_PER_LONG) ?					\
+		(1UL<<((nbits) % BITS_PER_LONG))-1 : ~0UL		\
+)
+
+static inline void bitmap_zero(unsigned long *dst, int nbits)
 {
-	memset(bitmap, 0, BITS_TO_LONGS(bits)*sizeof(unsigned long));
+	if (nbits <= BITS_PER_LONG)
+		*dst = 0UL;
+	else {
+		int len = BITS_TO_LONGS(nbits) * sizeof(unsigned long);
+		memset(dst, 0, len);
+	}
 }
 
-static inline void bitmap_fill(unsigned long *bitmap, int bits)
+static inline void bitmap_fill(unsigned long *dst, int nbits)
 {
-	memset(bitmap, 0xff, BITS_TO_LONGS(bits)*sizeof(unsigned long));
+	size_t nlongs = BITS_TO_LONGS(nbits);
+	if (nlongs > 1) {
+		int len = (nlongs - 1) * sizeof(unsigned long);
+		memset(dst, 0xff,  len);
+	}
+	dst[nlongs - 1] = BITMAP_LAST_WORD_MASK(nbits);
 }
 
-static inline void bitmap_copy(unsigned long *dst,
-			const unsigned long *src, int bits)
+static inline void bitmap_copy(unsigned long *dst, const unsigned long *src,
+			int nbits)
 {
-	int len = BITS_TO_LONGS(bits)*sizeof(unsigned long);
-	memcpy(dst, src, len);
+	if (nbits <= BITS_PER_LONG)
+		*dst = *src;
+	else {
+		int len = BITS_TO_LONGS(nbits) * sizeof(unsigned long);
+		memcpy(dst, src, len);
+	}
 }
 
-void bitmap_shift_right(unsigned long *dst,
-			const unsigned long *src, int shift, int bits);
-void bitmap_shift_left(unsigned long *dst,
-			const unsigned long *src, int shift, int bits);
-void bitmap_and(unsigned long *dst, const unsigned long *bitmap1,
-			const unsigned long *bitmap2, int bits);
-void bitmap_or(unsigned long *dst, const unsigned long *bitmap1,
-			const unsigned long *bitmap2, int bits);
-int bitmap_weight(const unsigned long *bitmap, int bits);
-int bitmap_scnprintf(char *buf, unsigned int buflen,
-			const unsigned long *maskp, int bits);
-int bitmap_parse(const char __user *ubuf, unsigned int ubuflen,
-			unsigned long *maskp, int bits);
+static inline void bitmap_and(unsigned long *dst, const unsigned long *src1,
+			const unsigned long *src2, int nbits)
+{
+	if (nbits <= BITS_PER_LONG)
+		*dst = *src1 & *src2;
+	else
+		__bitmap_and(dst, src1, src2, nbits);
+}
+
+static inline void bitmap_or(unsigned long *dst, const unsigned long *src1,
+			const unsigned long *src2, int nbits)
+{
+	if (nbits <= BITS_PER_LONG)
+		*dst = *src1 | *src2;
+	else
+		__bitmap_or(dst, src1, src2, nbits);
+}
+
+static inline void bitmap_xor(unsigned long *dst, const unsigned long *src1,
+			const unsigned long *src2, int nbits)
+{
+	if (nbits <= BITS_PER_LONG)
+		*dst = *src1 ^ *src2;
+	else
+		__bitmap_xor(dst, src1, src2, nbits);
+}
+
+static inline void bitmap_andnot(unsigned long *dst, const unsigned long *src1,
+			const unsigned long *src2, int nbits)
+{
+	if (nbits <= BITS_PER_LONG)
+		*dst = *src1 & ~(*src2);
+	else
+		__bitmap_andnot(dst, src1, src2, nbits);
+}
+
+static inline void bitmap_complement(unsigned long *dst, const unsigned long *src,
+			int nbits)
+{
+	if (nbits <= BITS_PER_LONG)
+		*dst = ~(*src) & BITMAP_LAST_WORD_MASK(nbits);
+	else
+		__bitmap_complement(dst, src, nbits);
+}
+
+static inline int bitmap_equal(const unsigned long *src1,
+			const unsigned long *src2, int nbits)
+{
+	if (nbits <= BITS_PER_LONG)
+		return ! ((*src1 ^ *src2) & BITMAP_LAST_WORD_MASK(nbits));
+	else
+		return __bitmap_equal(src1, src2, nbits);
+}
+
+static inline int bitmap_intersects(const unsigned long *src1,
+			const unsigned long *src2, int nbits)
+{
+	if (nbits <= BITS_PER_LONG)
+		return ((*src1 & *src2) & BITMAP_LAST_WORD_MASK(nbits)) != 0;
+	else
+		return __bitmap_intersects(src1, src2, nbits);
+}
+
+static inline int bitmap_subset(const unsigned long *src1,
+			const unsigned long *src2, int nbits)
+{
+	if (nbits <= BITS_PER_LONG)
+		return ! ((*src1 & ~(*src2)) & BITMAP_LAST_WORD_MASK(nbits));
+	else
+		return __bitmap_subset(src1, src2, nbits);
+}
+
+static inline int bitmap_empty(const unsigned long *src, int nbits)
+{
+	if (nbits <= BITS_PER_LONG)
+		return ! (*src & BITMAP_LAST_WORD_MASK(nbits));
+	else
+		return __bitmap_empty(src, nbits);
+}
+
+static inline int bitmap_full(const unsigned long *src, int nbits)
+{
+	if (nbits <= BITS_PER_LONG)
+		return ! (~(*src) & BITMAP_LAST_WORD_MASK(nbits));
+	else
+		return __bitmap_full(src, nbits);
+}
+
+static inline int bitmap_weight(const unsigned long *src, int nbits)
+{
+	return __bitmap_weight(src, nbits);
+}
+
+static inline void bitmap_shift_right(unsigned long *dst,
+			const unsigned long *src, int n, int nbits)
+{
+	if (nbits <= BITS_PER_LONG)
+		*dst = *src >> n;
+	else
+		__bitmap_shift_right(dst, src, n, nbits);
+}
+
+static inline void bitmap_shift_left(unsigned long *dst,
+			const unsigned long *src, int n, int nbits)
+{
+	if (nbits <= BITS_PER_LONG)
+		*dst = (*src << n) & BITMAP_LAST_WORD_MASK(nbits);
+	else
+		__bitmap_shift_left(dst, src, n, nbits);
+}
 
 #endif /* __ASSEMBLY__ */
 
--- diff/include/linux/blkdev.h	2004-06-11 19:17:35.000000000 +0100
+++ source/include/linux/blkdev.h	2004-06-11 19:22:06.000000000 +0100
@@ -195,6 +195,8 @@
 	__REQ_PM_SUSPEND,	/* suspend request */
 	__REQ_PM_RESUME,	/* resume request */
 	__REQ_PM_SHUTDOWN,	/* shutdown request */
+	__REQ_BAR_PREFLUSH,	/* barrier pre-flush done */
+	__REQ_BAR_POSTFLUSH,	/* barrier post-flush */
 	__REQ_NR_BITS,		/* stops here */
 };
 
@@ -220,6 +222,8 @@
 #define REQ_PM_SUSPEND	(1 << __REQ_PM_SUSPEND)
 #define REQ_PM_RESUME	(1 << __REQ_PM_RESUME)
 #define REQ_PM_SHUTDOWN	(1 << __REQ_PM_SHUTDOWN)
+#define REQ_BAR_PREFLUSH	(1 << __REQ_BAR_PREFLUSH)
+#define REQ_BAR_POSTFLUSH	(1 << __REQ_BAR_POSTFLUSH)
 
 /*
  * State information carried for REQ_PM_SUSPEND and REQ_PM_RESUME
@@ -248,6 +252,7 @@
 struct bio_vec;
 typedef int (merge_bvec_fn) (request_queue_t *, struct bio *, struct bio_vec *);
 typedef void (activity_fn) (void *data, int rw);
+typedef int (issue_flush_fn) (request_queue_t *, struct gendisk *, sector_t *);
 
 enum blk_queue_state {
 	Queue_down,
@@ -290,6 +295,7 @@
 	unplug_fn		*unplug_fn;
 	merge_bvec_fn		*merge_bvec_fn;
 	activity_fn		*activity_fn;
+	issue_flush_fn		*issue_flush_fn;
 
 	/*
 	 * Auto-unplugging state
@@ -373,6 +379,7 @@
 #define QUEUE_FLAG_DEAD		5	/* queue being torn down */
 #define QUEUE_FLAG_REENTER	6	/* Re-entrancy avoidance */
 #define QUEUE_FLAG_PLUGGED	7	/* queue is plugged */
+#define QUEUE_FLAG_ORDERED	8	/* supports ordered writes */
 
 #define blk_queue_plugged(q)	test_bit(QUEUE_FLAG_PLUGGED, &(q)->queue_flags)
 #define blk_queue_tagged(q)	test_bit(QUEUE_FLAG_QUEUED, &(q)->queue_flags)
@@ -390,6 +397,10 @@
 #define blk_pm_request(rq)	\
 	((rq)->flags & (REQ_PM_SUSPEND | REQ_PM_RESUME))
 
+#define blk_barrier_rq(rq)	((rq)->flags & REQ_HARDBARRIER)
+#define blk_barrier_preflush(rq)	((rq)->flags & REQ_BAR_PREFLUSH)
+#define blk_barrier_postflush(rq)	((rq)->flags & REQ_BAR_POSTFLUSH)
+
 #define list_entry_rq(ptr)	list_entry((ptr), struct request, queuelist)
 
 #define rq_data_dir(rq)		((rq)->flags & 1)
@@ -560,6 +571,14 @@
 extern int process_that_request_first(struct request *, unsigned int);
 extern void end_request(struct request *req, int uptodate);
 
+/*
+ * end_that_request_first/chunk() takes an uptodate argument. we account
+ * any value <= as an io error. 0 means -EIO for compatability reasons,
+ * any other < 0 value is the direct error type. An uptodate value of
+ * 1 indicates successful io completion
+ */
+#define end_io_error(uptodate)	(unlikely((uptodate) <= 0))
+
 static inline void blkdev_dequeue_request(struct request *req)
 {
 	BUG_ON(list_empty(&req->queuelist));
@@ -588,6 +607,9 @@
 extern void blk_queue_merge_bvec(request_queue_t *, merge_bvec_fn *);
 extern void blk_queue_dma_alignment(request_queue_t *, int);
 extern struct backing_dev_info *blk_get_backing_dev_info(struct block_device *bdev);
+extern void blk_queue_ordered(request_queue_t *, int);
+extern void blk_queue_issue_flush_fn(request_queue_t *, issue_flush_fn *);
+extern int blkdev_scsi_issue_flush_fn(request_queue_t *, struct gendisk *, sector_t *);
 
 extern int blk_rq_map_sg(request_queue_t *, struct request *, struct scatterlist *);
 extern void blk_dump_rq_flags(struct request *, char *);
@@ -615,6 +637,7 @@
 
 extern void blk_rq_bio_prep(request_queue_t *, struct request *, struct bio *);
 extern void blk_rq_prep_restart(struct request *);
+extern int blkdev_issue_flush(struct block_device *, sector_t *);
 
 #define MAX_PHYS_SEGMENTS 128
 #define MAX_HW_SEGMENTS 128
--- diff/include/linux/buffer_head.h	2004-06-11 19:17:35.000000000 +0100
+++ source/include/linux/buffer_head.h	2004-06-11 19:22:06.000000000 +0100
@@ -26,6 +26,7 @@
 	BH_Delay,	/* Buffer is not yet allocated on disk */
 	BH_Boundary,	/* Block is followed by a discontiguity */
 	BH_Write_EIO,	/* I/O error on write */
+	BH_Ordered,	/* ordered write */
 
 	BH_PrivateStart,/* not a state bit, but the first bit available
 			 * for private allocation by other entities
@@ -110,7 +111,8 @@
 BUFFER_FNS(Async_Write, async_write)
 BUFFER_FNS(Delay, delay)
 BUFFER_FNS(Boundary, boundary)
-BUFFER_FNS(Write_EIO,write_io_error)
+BUFFER_FNS(Write_EIO, write_io_error)
+BUFFER_FNS(Ordered, ordered)
 
 #define bh_offset(bh)		((unsigned long)(bh)->b_data & ~PAGE_MASK)
 #define touch_buffer(bh)	mark_page_accessed(bh->b_page)
@@ -172,8 +174,8 @@
 void FASTCALL(unlock_buffer(struct buffer_head *bh));
 void FASTCALL(__lock_buffer(struct buffer_head *bh));
 void ll_rw_block(int, int, struct buffer_head * bh[]);
-void sync_dirty_buffer(struct buffer_head *bh);
-void submit_bh(int, struct buffer_head *);
+int sync_dirty_buffer(struct buffer_head *bh);
+int submit_bh(int, struct buffer_head *);
 void write_boundary_block(struct block_device *bdev,
 			sector_t bblock, unsigned blocksize);
 
--- diff/include/linux/cciss_ioctl.h	2004-06-11 19:17:35.000000000 +0100
+++ source/include/linux/cciss_ioctl.h	2004-06-11 19:22:06.000000000 +0100
@@ -206,7 +206,35 @@
 #define CCISS_REGNEWDISK  _IOW(CCISS_IOC_MAGIC, 13, int)
 
 #define CCISS_REGNEWD	   _IO(CCISS_IOC_MAGIC, 14)
+#define CCISS_RESCANDISK   _IO(CCISS_IOC_MAGIC, 16)
 #define CCISS_GETLUNINFO   _IOR(CCISS_IOC_MAGIC, 17, LogvolInfo_struct)
 #define CCISS_BIG_PASSTHRU _IOWR(CCISS_IOC_MAGIC, 18, BIG_IOCTL_Command_struct)
 
+#ifdef __KERNEL__
+#ifdef CONFIG_COMPAT
+
+/* 32 bit compatible ioctl structs */
+typedef struct _IOCTL32_Command_struct {
+  LUNAddr_struct	   LUN_info;
+  RequestBlock_struct      Request;
+  ErrorInfo_struct  	   error_info;
+  WORD			   buf_size;  /* size in bytes of the buf */
+  __u32			   buf; /* 32 bit pointer to data buffer */
+} IOCTL32_Command_struct;
+
+typedef struct _BIG_IOCTL32_Command_struct {
+  LUNAddr_struct	   LUN_info;
+  RequestBlock_struct      Request;
+  ErrorInfo_struct  	   error_info;
+  DWORD			   malloc_size; /* < MAX_KMALLOC_SIZE in cciss.c */
+  DWORD			   buf_size;    /* size in bytes of the buf */
+  				        /* < malloc_size * MAXSGENTRIES */
+  __u32 		buf;	/* 32 bit pointer to data buffer */
+} BIG_IOCTL32_Command_struct;
+
+#define CCISS_PASSTHRU32   _IOWR(CCISS_IOC_MAGIC, 11, IOCTL32_Command_struct)
+#define CCISS_BIG_PASSTHRU32 _IOWR(CCISS_IOC_MAGIC, 18, BIG_IOCTL32_Command_struct)
+
+#endif /* CONFIG_COMPAT */
+#endif /* __KERNEL__ */
 #endif  
--- diff/include/linux/compat_ioctl.h	2004-06-11 19:17:35.000000000 +0100
+++ source/include/linux/compat_ioctl.h	2004-06-11 19:22:06.000000000 +0100
@@ -728,3 +728,20 @@
 COMPATIBLE_IOCTL(SIOCGIWRETRY)
 COMPATIBLE_IOCTL(SIOCSIWPOWER)
 COMPATIBLE_IOCTL(SIOCGIWPOWER)
+/* hiddev */
+COMPATIBLE_IOCTL(HIDIOCGVERSION)
+COMPATIBLE_IOCTL(HIDIOCAPPLICATION)
+COMPATIBLE_IOCTL(HIDIOCGDEVINFO)
+COMPATIBLE_IOCTL(HIDIOCGSTRING)
+COMPATIBLE_IOCTL(HIDIOCINITREPORT)
+COMPATIBLE_IOCTL(HIDIOCGREPORT)
+COMPATIBLE_IOCTL(HIDIOCSREPORT)
+COMPATIBLE_IOCTL(HIDIOCGREPORTINFO)
+COMPATIBLE_IOCTL(HIDIOCGFIELDINFO)
+COMPATIBLE_IOCTL(HIDIOCGUSAGE)
+COMPATIBLE_IOCTL(HIDIOCSUSAGE)
+COMPATIBLE_IOCTL(HIDIOCGUCODE)
+COMPATIBLE_IOCTL(HIDIOCGFLAG)
+COMPATIBLE_IOCTL(HIDIOCSFLAG)
+COMPATIBLE_IOCTL(HIDIOCGCOLLECTIONINDEX)
+COMPATIBLE_IOCTL(HIDIOCGCOLLECTIONINFO)
--- diff/include/linux/compiler-gcc.h	2004-05-19 22:12:58.000000000 +0100
+++ source/include/linux/compiler-gcc.h	2004-06-11 19:22:06.000000000 +0100
@@ -13,5 +13,5 @@
    shouldn't recognize the original var, and make assumptions about it */
 #define RELOC_HIDE(ptr, off)					\
   ({ unsigned long __ptr;					\
-    __asm__ ("" : "=g"(__ptr) : "0"(ptr));		\
+	__asm__ ("" : "=r"(__ptr) : "0"(ptr));			\
     (typeof(ptr)) (__ptr + (off)); })
--- diff/include/linux/config.h	2004-05-19 22:12:58.000000000 +0100
+++ source/include/linux/config.h	2004-06-11 19:22:06.000000000 +0100
@@ -2,5 +2,8 @@
 #define _LINUX_CONFIG_H
 
 #include <linux/autoconf.h>
+#ifdef CONFIG_X86
+#include <asm/kgdb.h>
+#endif
 
 #endif
--- diff/include/linux/cpumask.h	2004-06-11 19:17:35.000000000 +0100
+++ source/include/linux/cpumask.h	2004-06-11 19:22:06.000000000 +0100
@@ -1,55 +1,371 @@
 #ifndef __LINUX_CPUMASK_H
 #define __LINUX_CPUMASK_H
 
+/*
+ * Cpumasks provide a bitmap suitable for representing the
+ * set of CPU's in a system, one bit position per CPU number.
+ *
+ * See detailed comments in the file linux/bitmap.h describing the
+ * data type on which these cpumasks are based.
+ *
+ * For details of cpumask_scnprintf() and cpumask_parse(),
+ * see bitmap_scnprintf() and bitmap_parse() in lib/bitmap.c.
+ *
+ * The available cpumask operations are:
+ *
+ * void cpu_set(cpu, mask)		turn on bit 'cpu' in mask
+ * void cpu_clear(cpu, mask)		turn off bit 'cpu' in mask
+ * void cpus_setall(mask)		set all bits
+ * void cpus_clear(mask)		clear all bits
+ * int cpu_isset(cpu, mask)		true iff bit 'cpu' set in mask
+ * int cpu_test_and_set(cpu, mask)	test and set bit 'cpu' in mask
+ *
+ * void cpus_and(dst, src1, src2)	dst = src1 & src2  [intersection]
+ * void cpus_or(dst, src1, src2)	dst = src1 | src2  [union]
+ * void cpus_xor(dst, src1, src2)	dst = src1 ^ src2
+ * void cpus_andnot(dst, src1, src2)	dst = src1 & ~src2
+ * void cpus_complement(dst, src)	dst = ~src
+ *
+ * int cpus_equal(mask1, mask2)		Does mask1 == mask2?
+ * int cpus_intersects(mask1, mask2)	Do mask1 and mask2 intersect?
+ * int cpus_subset(mask1, mask2)	Is mask1 a subset of mask2?
+ * int cpus_empty(mask)			Is mask empty (no bits sets)?
+ * int cpus_full(mask)			Is mask full (all bits sets)?
+ * int cpus_weight(mask)		Hamming weigh - number of set bits
+ *
+ * void cpus_shift_right(dst, src, n)	Shift right
+ * void cpus_shift_left(dst, src, n)	Shift left
+ *
+ * int first_cpu(mask)			Number lowest set bit, or NR_CPUS
+ * int next_cpu(cpu, mask)		Next cpu past 'cpu', or NR_CPUS
+ *
+ * cpumask_t cpumask_of_cpu(cpu)	Return cpumask with bit 'cpu' set
+ * CPU_MASK_ALL				Initializer - all bits set
+ * CPU_MASK_NONE			Initializer - no bits set
+ * unsigned long *cpus_addr(mask)	Array of unsigned long's in mask
+ *
+ * int cpumask_scnprintf(buf, len, mask) Format cpumask for printing
+ * int cpumask_parse(ubuf, ulen, mask)	Parse ascii string as cpumask
+ *
+ * for_each_cpu_mask(cpu, mask)		for-loop cpu over mask
+ *
+ * int num_online_cpus()		Number of online CPUs
+ * int num_possible_cpus()		Number of all possible CPUs
+ * int num_present_cpus()		Number of present CPUs
+ *
+ * int cpu_online(cpu)			Is some cpu online?
+ * int cpu_possible(cpu)		Is some cpu possible?
+ * int cpu_present(cpu)			Is some cpu present (can schedule)?
+ *
+ * int any_online_cpu(mask)		First online cpu in mask
+ *
+ * for_each_cpu(cpu)			for-loop cpu over cpu_possible_map
+ * for_each_online_cpu(cpu)		for-loop cpu over cpu_online_map
+ * for_each_present_cpu(cpu)		for-loop cpu over cpu_present_map
+ *
+ * Subtlety:
+ * 1) The 'type-checked' form of cpu_isset() causes gcc (3.3.2, anyway)
+ *    to generate slightly worse code.  Note for example the additional
+ *    40 lines of assembly code compiling the "for each possible cpu"
+ *    loops buried in the disk_stat_read() macros calls when compiling
+ *    drivers/block/genhd.c (arch i386, CONFIG_SMP=y).  So use a simple
+ *    one-line #define for cpu_isset(), instead of wrapping an inline
+ *    inside a macro, the way we do the other calls.
+ */
+
 #include <linux/threads.h>
 #include <linux/bitmap.h>
-#include <asm/cpumask.h>
 #include <asm/bug.h>
 
-#ifdef CONFIG_SMP
+typedef struct { DECLARE_BITMAP(bits, NR_CPUS); } cpumask_t;
+extern cpumask_t _unused_cpumask_arg_;
+
+#define cpu_set(cpu, dst) __cpu_set((cpu), &(dst))
+static inline void __cpu_set(int cpu, volatile cpumask_t *dstp)
+{
+	set_bit(cpu, dstp->bits);
+}
+
+#define cpu_clear(cpu, dst) __cpu_clear((cpu), &(dst))
+static inline void __cpu_clear(int cpu, volatile cpumask_t *dstp)
+{
+	clear_bit(cpu, dstp->bits);
+}
+
+#define cpus_setall(dst) __cpus_setall(&(dst), NR_CPUS)
+static inline void __cpus_setall(cpumask_t *dstp, int nbits)
+{
+	bitmap_fill(dstp->bits, nbits);
+}
+
+#define cpus_clear(dst) __cpus_clear(&(dst), NR_CPUS)
+static inline void __cpus_clear(cpumask_t *dstp, int nbits)
+{
+	bitmap_zero(dstp->bits, nbits);
+}
+
+/* No static inline type checking - see Subtlety (1) above. */
+#define cpu_isset(cpu, cpumask) test_bit((cpu), (cpumask).bits)
+
+#define cpu_test_and_set(cpu, cpumask) __cpu_test_and_set((cpu), &(cpumask))
+static inline int __cpu_test_and_set(int cpu, cpumask_t *addr)
+{
+	return test_and_set_bit(cpu, addr->bits);
+}
+
+#define cpus_and(dst, src1, src2) __cpus_and(&(dst), &(src1), &(src2), NR_CPUS)
+static inline void __cpus_and(cpumask_t *dstp, cpumask_t *src1p,
+					cpumask_t *src2p, int nbits)
+{
+	bitmap_and(dstp->bits, src1p->bits, src2p->bits, nbits);
+}
+
+#define cpus_or(dst, src1, src2) __cpus_or(&(dst), &(src1), &(src2), NR_CPUS)
+static inline void __cpus_or(cpumask_t *dstp, cpumask_t *src1p,
+					cpumask_t *src2p, int nbits)
+{
+	bitmap_or(dstp->bits, src1p->bits, src2p->bits, nbits);
+}
+
+#define cpus_xor(dst, src1, src2) __cpus_xor(&(dst), &(src1), &(src2), NR_CPUS)
+static inline void __cpus_xor(cpumask_t *dstp, cpumask_t *src1p,
+					cpumask_t *src2p, int nbits)
+{
+	bitmap_xor(dstp->bits, src1p->bits, src2p->bits, nbits);
+}
+
+#define cpus_andnot(dst, src1, src2) \
+				__cpus_andnot(&(dst), &(src1), &(src2), NR_CPUS)
+static inline void __cpus_andnot(cpumask_t *dstp, cpumask_t *src1p,
+					cpumask_t *src2p, int nbits)
+{
+	bitmap_andnot(dstp->bits, src1p->bits, src2p->bits, nbits);
+}
+
+#define cpus_complement(dst, src) __cpus_complement(&(dst), &(src), NR_CPUS)
+static inline void __cpus_complement(cpumask_t *dstp,
+					cpumask_t *srcp, int nbits)
+{
+	bitmap_complement(dstp->bits, srcp->bits, nbits);
+}
+
+#define cpus_equal(src1, src2) __cpus_equal(&(src1), &(src2), NR_CPUS)
+static inline int __cpus_equal(cpumask_t *src1p,
+					cpumask_t *src2p, int nbits)
+{
+	return bitmap_equal(src1p->bits, src2p->bits, nbits);
+}
+
+#define cpus_intersects(src1, src2) __cpus_intersects(&(src1), &(src2), NR_CPUS)
+static inline int __cpus_intersects(cpumask_t *src1p,
+					cpumask_t *src2p, int nbits)
+{
+	return bitmap_intersects(src1p->bits, src2p->bits, nbits);
+}
+
+#define cpus_subset(src1, src2) __cpus_subset(&(src1), &(src2), NR_CPUS)
+static inline int __cpus_subset(cpumask_t *src1p,
+					cpumask_t *src2p, int nbits)
+{
+	return bitmap_subset(src1p->bits, src2p->bits, nbits);
+}
+
+#define cpus_empty(src) __cpus_empty(&(src), NR_CPUS)
+static inline int __cpus_empty(cpumask_t *srcp, int nbits)
+{
+	return bitmap_empty(srcp->bits, nbits);
+}
+
+#define cpus_full(cpumask) __cpus_full(&(cpumask), NR_CPUS)
+static inline int __cpus_full(cpumask_t *srcp, int nbits)
+{
+	return bitmap_full(srcp->bits, nbits);
+}
+
+#define cpus_weight(cpumask) __cpus_weight(&(cpumask), NR_CPUS)
+static inline int __cpus_weight(cpumask_t *srcp, int nbits)
+{
+	return bitmap_weight(srcp->bits, nbits);
+}
+
+#define cpus_shift_right(dst, src, n) \
+			__cpus_shift_right(&(dst), &(src), (n), NR_CPUS)
+static inline void __cpus_shift_right(cpumask_t *dstp,
+					cpumask_t *srcp, int n, int nbits)
+{
+	bitmap_shift_right(dstp->bits, srcp->bits, n, nbits);
+}
+
+#define cpus_shift_left(dst, src, n) \
+			__cpus_shift_left(&(dst), &(src), (n), NR_CPUS)
+static inline void __cpus_shift_left(cpumask_t *dstp,
+					cpumask_t *srcp, int n, int nbits)
+{
+	bitmap_shift_left(dstp->bits, srcp->bits, n, nbits);
+}
+
+#define first_cpu(src) __first_cpu(&(src), NR_CPUS)
+static inline int __first_cpu(cpumask_t *srcp, int nbits)
+{
+	return find_first_bit(srcp->bits, nbits);
+}
+
+#define next_cpu(n, src) __next_cpu((n), &(src), NR_CPUS)
+static inline int __next_cpu(int n, cpumask_t *srcp, int nbits)
+{
+	return find_next_bit(srcp->bits, nbits, n+1);
+}
+
+#define cpumask_of_cpu(cpu)						\
+({									\
+	typeof(_unused_cpumask_arg_) m;					\
+	if (sizeof(m) == sizeof(unsigned long)) {			\
+		m.bits[0] = 1UL<<(cpu);					\
+	} else {							\
+		cpus_clear(m);						\
+		cpu_set((cpu), m);					\
+	}								\
+	m;								\
+})
+
+#define CPU_MASK_LAST_WORD BITMAP_LAST_WORD_MASK(NR_CPUS)
+
+#if NR_CPUS <= BITS_PER_LONG
+
+#define CPU_MASK_ALL							\
+((cpumask_t) { {							\
+	[BITS_TO_LONGS(NR_CPUS)-1] = CPU_MASK_LAST_WORD			\
+} })
+
+#else
+
+#define CPU_MASK_ALL							\
+((cpumask_t) { {							\
+	[0 ... BITS_TO_LONGS(NR_CPUS)-2] = ~0UL,			\
+	[BITS_TO_LONGS(NR_CPUS)-1] = CPU_MASK_LAST_WORD			\
+} })
+
+#endif
+
+#define CPU_MASK_NONE							\
+{ {									\
+	[0 ... BITS_TO_LONGS(NR_CPUS)-1] =  0UL				\
+} }
+
+#define cpus_addr(src) ((src).bits)
+
+#define cpumask_scnprintf(buf, len, src) \
+			__cpumask_scnprintf((buf), (len), &(src), NR_CPUS)
+static inline int __cpumask_scnprintf(char *buf, int len,
+					cpumask_t *srcp, int nbits)
+{
+	return bitmap_scnprintf(buf, len, srcp->bits, nbits);
+}
+
+#define cpumask_parse(ubuf, ulen, src) \
+			__cpumask_parse((ubuf), (ulen), &(src), NR_CPUS)
+static inline int __cpumask_parse(const char __user *buf, int len,
+					cpumask_t *srcp, int nbits)
+{
+	return bitmap_parse(buf, len, srcp->bits, nbits);
+}
+
+#if NR_CPUS > 1
+#define for_each_cpu_mask(cpu, mask)		\
+	for ((cpu) = first_cpu(mask);		\
+		(cpu) < NR_CPUS;		\
+		(cpu) = next_cpu((cpu), (mask)))
+#else /* NR_CPUS == 1 */
+#define for_each_cpu_mask(cpu, mask) for ((cpu) = 0; (cpu) < 1; (cpu)++)
+#endif /* NR_CPUS */
+
+/*
+ * The following particular system cpumasks and operations manage
+ * possible, present and online cpus.  Each of them is a fixed size
+ * bitmap of size NR_CPUS.
+ *
+ *  #ifdef CONFIG_HOTPLUG_CPU
+ *     cpu_possible_map - all NR_CPUS bits set
+ *     cpu_present_map  - has bit 'cpu' set iff cpu is populated
+ *     cpu_online_map   - has bit 'cpu' set iff cpu available to scheduler
+ *  #else
+ *     cpu_possible_map - has bit 'cpu' set iff cpu is populated
+ *     cpu_present_map  - copy of cpu_possible_map
+ *     cpu_online_map   - has bit 'cpu' set iff cpu available to scheduler
+ *  #endif
+ *
+ *  In either case, NR_CPUS is fixed at compile time, as the static
+ *  size of these bitmaps.  The cpu_possible_map is fixed at boot
+ *  time, as the set of CPU id's that it is possible might ever
+ *  be plugged in at anytime during the life of that system boot.
+ *  The cpu_present_map is dynamic(*), representing which CPUs
+ *  are currently plugged in.  And cpu_online_map is the dynamic
+ *  subset of cpu_present_map, indicating those CPUs available
+ *  for scheduling.
+ *
+ *  If HOTPLUG is enabled, then cpu_possible_map is forced to have
+ *  all NR_CPUS bits set, otherwise it is just the set of CPUs that
+ *  ACPI reports present at boot.
+ *
+ *  If HOTPLUG is enabled, then cpu_present_map varies dynamically,
+ *  depending on what ACPI reports as currently plugged in, otherwise
+ *  cpu_present_map is just a copy of cpu_possible_map.
+ *
+ *  (*) Well, cpu_present_map is dynamic in the hotplug case.  If not
+ *      hotplug, it's a copy of cpu_possible_map, hence fixed at boot.
+ *
+ * Subtleties:
+ * 1) UP arch's (NR_CPUS == 1, CONFIG_SMP not defined) hardcode
+ *    assumption that their single CPU is online.  The UP
+ *    cpu_{online,possible,present}_maps are placebos.  Changing them
+ *    will have no useful affect on the following num_*_cpus()
+ *    and cpu_*() macros in the UP case.  This ugliness is a UP
+ *    optimization - don't waste any instructions or memory references
+ *    asking if you're online or how many CPUs there are if there is
+ *    only one CPU.
+ * 2) Most SMP arch's #define some of these maps to be some
+ *    other map specific to that arch.  Therefore, the following
+ *    must be #define macros, not inlines.  To see why, examine
+ *    the assembly code produced by the following.  Note that
+ *    set1() writes phys_x_map, but set2() writes x_map:
+ *        int x_map, phys_x_map;
+ *        #define set1(a) x_map = a
+ *        inline void set2(int a) { x_map = a; }
+ *        #define x_map phys_x_map
+ *        main(){ set1(3); set2(5); }
+ */
 
-extern cpumask_t cpu_online_map;
 extern cpumask_t cpu_possible_map;
+extern cpumask_t cpu_online_map;
 extern cpumask_t cpu_present_map;
 
-#define num_online_cpus()		cpus_weight(cpu_online_map)
-#define num_possible_cpus()		cpus_weight(cpu_possible_map)
-#define num_present_cpus()		cpus_weight(cpu_present_map)
-
-#define cpu_online(cpu)			cpu_isset(cpu, cpu_online_map)
-#define cpu_possible(cpu)		cpu_isset(cpu, cpu_possible_map)
-#define cpu_present(cpu)		cpu_isset(cpu, cpu_present_map)
-
-#define for_each_cpu_mask(cpu, mask)					\
-	for (cpu = first_cpu_const(mk_cpumask_const(mask));		\
-		cpu < NR_CPUS;						\
-		cpu = next_cpu_const(cpu, mk_cpumask_const(mask)))
-
-#define for_each_cpu(cpu) for_each_cpu_mask(cpu, cpu_possible_map)
-#define for_each_online_cpu(cpu) for_each_cpu_mask(cpu, cpu_online_map)
-#define for_each_present_cpu(cpu) for_each_cpu_mask(cpu, cpu_present_map)
+#if NR_CPUS > 1
+#define num_online_cpus()	cpus_weight(cpu_online_map)
+#define num_possible_cpus()	cpus_weight(cpu_possible_map)
+#define num_present_cpus()	cpus_weight(cpu_present_map)
+#define cpu_online(cpu)		cpu_isset((cpu), cpu_online_map)
+#define cpu_possible(cpu)	cpu_isset((cpu), cpu_possible_map)
+#define cpu_present(cpu)	cpu_isset((cpu), cpu_present_map)
 #else
-#define	cpu_online_map			cpumask_of_cpu(0)
-#define	cpu_possible_map		cpumask_of_cpu(0)
-#define	cpu_present_map			cpumask_of_cpu(0)
-
-#define num_online_cpus()		1
-#define num_possible_cpus()		1
-#define num_present_cpus()		1
-
-#define cpu_online(cpu)			({ BUG_ON((cpu) != 0); 1; })
-#define cpu_possible(cpu)		({ BUG_ON((cpu) != 0); 1; })
-#define cpu_present(cpu)		({ BUG_ON((cpu) != 0); 1; })
-
-#define for_each_cpu(cpu) for (cpu = 0; cpu < 1; cpu++)
-#define for_each_online_cpu(cpu) for (cpu = 0; cpu < 1; cpu++)
-#define for_each_present_cpu(cpu) for (cpu = 0; cpu < 1; cpu++)
+#define num_online_cpus()	1
+#define num_possible_cpus()	1
+#define num_present_cpus()	1
+#define cpu_online(cpu)		((cpu) == 0)
+#define cpu_possible(cpu)	((cpu) == 0)
+#define cpu_present(cpu)	((cpu) == 0)
 #endif
 
-#define cpumask_scnprintf(buf, buflen, map)				\
-	bitmap_scnprintf(buf, buflen, cpus_addr(map), NR_CPUS)
-
-#define cpumask_parse(buf, buflen, map)					\
-	bitmap_parse(buf, buflen, cpus_addr(map), NR_CPUS)
+#define any_online_cpu(mask)			\
+({						\
+	int cpu;				\
+	for_each_cpu_mask(cpu, (mask))		\
+		if (cpu_online(cpu))		\
+			break;			\
+	cpu;					\
+})
+
+#define for_each_cpu(cpu)	  for_each_cpu_mask((cpu), cpu_possible_map)
+#define for_each_online_cpu(cpu)  for_each_cpu_mask((cpu), cpu_online_map)
+#define for_each_present_cpu(cpu) for_each_cpu_mask((cpu), cpu_present_map)
 
 #endif /* __LINUX_CPUMASK_H */
--- diff/include/linux/device.h	2004-06-11 19:17:35.000000000 +0100
+++ source/include/linux/device.h	2004-06-11 19:22:06.000000000 +0100
@@ -54,6 +54,9 @@
 	struct kset		drivers;
 	struct kset		devices;
 
+	struct bus_attribute	* bus_attrs;
+	struct device_attribute	* dev_attrs;
+
 	int		(*match)(struct device * dev, struct device_driver * drv);
 	struct device * (*add)	(struct device * parent, char * bus_id);
 	int		(*hotplug) (struct device *dev, char **envp, 
@@ -90,11 +93,7 @@
 };
 
 #define BUS_ATTR(_name,_mode,_show,_store)	\
-struct bus_attribute bus_attr_##_name = { 		\
-	.attr = {.name = __stringify(_name), .mode = _mode, .owner = THIS_MODULE },	\
-	.show	= _show,				\
-	.store	= _store,				\
-};
+struct bus_attribute bus_attr_##_name = __ATTR(_name,_mode,_show,_store)
 
 extern int bus_create_file(struct bus_type *, struct bus_attribute *);
 extern void bus_remove_file(struct bus_type *, struct bus_attribute *);
@@ -131,11 +130,7 @@
 };
 
 #define DRIVER_ATTR(_name,_mode,_show,_store)	\
-struct driver_attribute driver_attr_##_name = { 		\
-	.attr = {.name = __stringify(_name), .mode = _mode, .owner = THIS_MODULE },	\
-	.show	= _show,				\
-	.store	= _store,				\
-};
+struct driver_attribute driver_attr_##_name = __ATTR(_name,_mode,_show,_store)
 
 extern int driver_create_file(struct device_driver *, struct driver_attribute *);
 extern void driver_remove_file(struct device_driver *, struct driver_attribute *);
@@ -151,6 +146,9 @@
 	struct list_head	children;
 	struct list_head	interfaces;
 
+	struct class_attribute		* class_attrs;
+	struct class_device_attribute	* class_dev_attrs;
+
 	int	(*hotplug)(struct class_device *dev, char **envp, 
 			   int num_envp, char *buffer, int buffer_size);
 
@@ -172,11 +170,7 @@
 };
 
 #define CLASS_ATTR(_name,_mode,_show,_store)			\
-struct class_attribute class_attr_##_name = { 			\
-	.attr = {.name = __stringify(_name), .mode = _mode, .owner = THIS_MODULE },	\
-	.show	= _show,					\
-	.store	= _store,					\
-};
+struct class_attribute class_attr_##_name = __ATTR(_name,_mode,_show,_store) 
 
 extern int class_create_file(struct class *, const struct class_attribute *);
 extern void class_remove_file(struct class *, const struct class_attribute *);
@@ -224,11 +218,8 @@
 };
 
 #define CLASS_DEVICE_ATTR(_name,_mode,_show,_store)		\
-struct class_device_attribute class_device_attr_##_name = { 	\
-	.attr = {.name = __stringify(_name), .mode = _mode, .owner = THIS_MODULE },	\
-	.show	= _show,					\
-	.store	= _store,					\
-};
+struct class_device_attribute class_device_attr_##_name = 	\
+	__ATTR(_name,_mode,_show,_store)
 
 extern int class_device_create_file(struct class_device *, 
 				    const struct class_device_attribute *);
@@ -342,11 +333,7 @@
 };
 
 #define DEVICE_ATTR(_name,_mode,_show,_store) \
-struct device_attribute dev_attr_##_name = { 		\
-	.attr = {.name = __stringify(_name), .mode = _mode, .owner = THIS_MODULE },	\
-	.show	= _show,				\
-	.store	= _store,				\
-};
+struct device_attribute dev_attr_##_name = __ATTR(_name,_mode,_show,_store)
 
 
 extern int device_create_file(struct device *device, struct device_attribute * entry);
@@ -390,6 +377,11 @@
 extern struct bus_type platform_bus_type;
 extern struct device platform_bus;
 
+extern struct resource *platform_get_resource(struct platform_device *, unsigned int, unsigned int);
+extern int platform_get_irq(struct platform_device *, unsigned int);
+extern int platform_add_device(struct platform_device *);
+extern int platform_add_devices(struct platform_device **, int);
+
 /* drivers/base/power.c */
 extern void device_shutdown(void);
 
--- diff/include/linux/ethtool.h	2004-05-19 22:12:59.000000000 +0100
+++ source/include/linux/ethtool.h	2004-06-11 19:22:06.000000000 +0100
@@ -351,6 +351,8 @@
 	int	(*phys_id)(struct net_device *, u32);
 	int	(*get_stats_count)(struct net_device *);
 	void	(*get_ethtool_stats)(struct net_device *, struct ethtool_stats *, u64 *);
+	int	(*begin)(struct net_device *);
+	void	(*complete)(struct net_device *);
 };
 
 /* CMDs currently supported */
--- diff/include/linux/ext3_fs.h	2004-05-19 22:12:59.000000000 +0100
+++ source/include/linux/ext3_fs.h	2004-06-11 19:22:06.000000000 +0100
@@ -33,11 +33,10 @@
 #undef EXT3FS_DEBUG
 
 /*
- * Define EXT3_PREALLOCATE to preallocate data blocks for expanding files
+ * Define EXT3_RESERVATION to reserve data blocks for expanding files
  */
-#undef  EXT3_PREALLOCATE /* @@@ Fix this! */
-#define EXT3_DEFAULT_PREALLOC_BLOCKS	8
-
+#define EXT3_DEFAULT_RESERVE_BLOCKS     8
+#define EXT3_MAX_RESERVE_BLOCKS         1024
 /*
  * Always enable hashed directories
  */
@@ -208,6 +207,8 @@
 #ifdef CONFIG_JBD_DEBUG
 #define EXT3_IOC_WAIT_FOR_READONLY	_IOR('f', 99, long)
 #endif
+#define EXT3_IOC_GETRSVSZ		_IOR('r', 1, long)
+#define EXT3_IOC_SETRSVSZ		_IOW('r', 2, long)
 
 /*
  * Structure of an inode on the disk
@@ -306,24 +307,26 @@
 /*
  * Mount flags
  */
-#define EXT3_MOUNT_CHECK		0x0001	/* Do mount-time checks */
-#define EXT3_MOUNT_OLDALLOC		0x0002  /* Don't use the new Orlov allocator */
-#define EXT3_MOUNT_GRPID		0x0004	/* Create files with directory's group */
-#define EXT3_MOUNT_DEBUG		0x0008	/* Some debugging messages */
-#define EXT3_MOUNT_ERRORS_CONT		0x0010	/* Continue on errors */
-#define EXT3_MOUNT_ERRORS_RO		0x0020	/* Remount fs ro on errors */
-#define EXT3_MOUNT_ERRORS_PANIC		0x0040	/* Panic on errors */
-#define EXT3_MOUNT_MINIX_DF		0x0080	/* Mimics the Minix statfs */
-#define EXT3_MOUNT_NOLOAD		0x0100	/* Don't use existing journal*/
-#define EXT3_MOUNT_ABORT		0x0200	/* Fatal error detected */
-#define EXT3_MOUNT_DATA_FLAGS		0x0C00	/* Mode for data writes: */
-  #define EXT3_MOUNT_JOURNAL_DATA	0x0400	/* Write data to journal */
-  #define EXT3_MOUNT_ORDERED_DATA	0x0800	/* Flush data before commit */
-  #define EXT3_MOUNT_WRITEBACK_DATA	0x0C00	/* No data ordering */
-#define EXT3_MOUNT_UPDATE_JOURNAL	0x1000	/* Update the journal format */
-#define EXT3_MOUNT_NO_UID32		0x2000  /* Disable 32-bit UIDs */
-#define EXT3_MOUNT_XATTR_USER		0x4000	/* Extended user attributes */
-#define EXT3_MOUNT_POSIX_ACL		0x8000	/* POSIX Access Control Lists */
+#define EXT3_MOUNT_CHECK		0x00001	/* Do mount-time checks */
+#define EXT3_MOUNT_OLDALLOC		0x00002  /* Don't use the new Orlov allocator */
+#define EXT3_MOUNT_GRPID		0x00004	/* Create files with directory's group */
+#define EXT3_MOUNT_DEBUG		0x00008	/* Some debugging messages */
+#define EXT3_MOUNT_ERRORS_CONT		0x00010	/* Continue on errors */
+#define EXT3_MOUNT_ERRORS_RO		0x00020	/* Remount fs ro on errors */
+#define EXT3_MOUNT_ERRORS_PANIC		0x00040	/* Panic on errors */
+#define EXT3_MOUNT_MINIX_DF		0x00080	/* Mimics the Minix statfs */
+#define EXT3_MOUNT_NOLOAD		0x00100	/* Don't use existing journal*/
+#define EXT3_MOUNT_ABORT		0x00200	/* Fatal error detected */
+#define EXT3_MOUNT_DATA_FLAGS		0x00C00	/* Mode for data writes: */
+#define EXT3_MOUNT_JOURNAL_DATA		0x00400	/* Write data to journal */
+#define EXT3_MOUNT_ORDERED_DATA		0x00800	/* Flush data before commit */
+#define EXT3_MOUNT_WRITEBACK_DATA	0x00C00	/* No data ordering */
+#define EXT3_MOUNT_UPDATE_JOURNAL	0x01000	/* Update the journal format */
+#define EXT3_MOUNT_NO_UID32		0x02000  /* Disable 32-bit UIDs */
+#define EXT3_MOUNT_XATTR_USER		0x04000	/* Extended user attributes */
+#define EXT3_MOUNT_POSIX_ACL		0x08000	/* POSIX Access Control Lists */
+#define EXT3_MOUNT_RESERVATION		0x10000	/* Preallocation */
+#define EXT3_MOUNT_BARRIER		0x20000 /* Use block barriers */
 
 /* Compatibility, for having both ext2_fs.h and ext3_fs.h included at once */
 #ifndef _LINUX_EXT2_FS_H
@@ -680,8 +683,7 @@
 /* balloc.c */
 extern int ext3_bg_has_super(struct super_block *sb, int group);
 extern unsigned long ext3_bg_num_gdb(struct super_block *sb, int group);
-extern int ext3_new_block (handle_t *, struct inode *, unsigned long,
-					    __u32 *, __u32 *, int *);
+extern int ext3_new_block (handle_t *, struct inode *, unsigned long, int *);
 extern void ext3_free_blocks (handle_t *, struct inode *, unsigned long,
 			      unsigned long);
 extern unsigned long ext3_count_free_blocks (struct super_block *);
@@ -689,6 +691,7 @@
 extern struct ext3_group_desc * ext3_get_group_desc(struct super_block * sb,
 						    unsigned int block_group,
 						    struct buffer_head ** bh);
+extern int ext3_should_retry_alloc(struct super_block *sb, int *retries);
 
 /* dir.c */
 extern int ext3_check_dir_entry(const char *, struct inode *,
@@ -728,6 +731,7 @@
 extern void ext3_delete_inode (struct inode *);
 extern int  ext3_sync_inode (handle_t *, struct inode *);
 extern void ext3_discard_prealloc (struct inode *);
+extern void ext3_discard_reservation (struct inode *);
 extern void ext3_dirty_inode(struct inode *);
 extern int ext3_change_inode_journal_flag(struct inode *, int);
 extern void ext3_truncate (struct inode *);
--- diff/include/linux/ext3_fs_i.h	2004-05-19 22:12:59.000000000 +0100
+++ source/include/linux/ext3_fs_i.h	2004-06-11 19:22:06.000000000 +0100
@@ -18,8 +18,16 @@
 
 #include <linux/rwsem.h>
 
+struct reserve_window {
+	struct list_head 	rsv_list;
+	__u32			rsv_start;
+	__u32			rsv_end;
+	atomic_t		rsv_goal_size;
+	__u32			rsv_alloc_hit;
+};
+
 /*
- * second extended file system inode data in memory
+ * third extended file system inode data in memory
  */
 struct ext3_inode_info {
 	__u32	i_data[15];
@@ -57,10 +65,9 @@
 	 * allocation when we detect linearly ascending requests.
 	 */
 	__u32	i_next_alloc_goal;
-#ifdef EXT3_PREALLOCATE
-	__u32	i_prealloc_block;
-	__u32	i_prealloc_count;
-#endif
+	/* block reservation window */
+	struct reserve_window i_rsv_window;
+
 	__u32	i_dir_start_lookup;
 #ifdef CONFIG_EXT3_FS_XATTR
 	/*
--- diff/include/linux/ext3_fs_sb.h	2004-05-19 22:12:59.000000000 +0100
+++ source/include/linux/ext3_fs_sb.h	2004-06-11 19:22:06.000000000 +0100
@@ -59,6 +59,10 @@
 	struct percpu_counter s_dirs_counter;
 	struct blockgroup_lock s_blockgroup_lock;
 
+	/* head of the per fs reservation window tree */
+	spinlock_t s_rsv_window_lock;
+	struct reserve_window s_rsv_window_head;
+
 	/* Journaling */
 	struct inode * s_journal_inode;
 	struct journal_s * s_journal;
--- diff/include/linux/fb.h	2004-06-11 19:17:35.000000000 +0100
+++ source/include/linux/fb.h	2004-06-11 19:22:06.000000000 +0100
@@ -125,7 +125,8 @@
 	unsigned long mmio_start;	/* Start of Memory Mapped I/O   */
 					/* (physical address) */
 	__u32 mmio_len;			/* Length of Memory Mapped I/O  */
-	__u32 accel;			/* Type of acceleration available */
+	__u32 accel;			/* Indicate to driver which	*/
+					/*  specific chip/card we have	*/
 	__u16 reserved[3];		/* Reserved for future compatibility */
 };
 
@@ -154,7 +155,7 @@
 #define FB_ACTIVATE_ALL	       64	/* change all VCs on this fb	*/
 #define FB_ACTIVATE_FORCE     128	/* force apply even when no change*/
 
-#define FB_ACCELF_TEXT		1	/* text mode acceleration */
+#define FB_ACCELF_TEXT		1	/* (OBSOLETE) see fb_info.flags and vc_mode */
 
 #define FB_SYNC_HOR_HIGH_ACT	1	/* horizontal sync high active	*/
 #define FB_SYNC_VERT_HIGH_ACT	2	/* vertical sync high active	*/
@@ -200,7 +201,7 @@
 	__u32 height;			/* height of picture in mm    */
 	__u32 width;			/* width of picture in mm     */
 
-	__u32 accel_flags;		/* acceleration flags (hints)	*/
+	__u32 accel_flags;		/* (OBSOLETE) see fb_info.flags */
 
 	/* Timing: All values in pixclocks, except pixclock (of course) */
 	__u32 pixclock;			/* pixel clock in ps (pico seconds) */
@@ -502,10 +503,37 @@
 	int (*fb_mmap)(struct fb_info *info, struct file *file, struct vm_area_struct *vma);
 };
 
+/* FBINFO_* = fb_info.flags bit flags */
+#define FBINFO_MODULE		0x0001	/* Low-level driver is a module */
+#define FBINFO_HWACCEL_DISABLED	0x0002
+	/* When FBINFO_HWACCEL_DISABLED is set:
+	 *  Hardware acceleration is turned off.  Software implementations
+	 *  of required functions (copyarea(), fillrect(), and imageblit())
+	 *  takes over; acceleration engine should be in a quiescent state */
+
+/* hints */
+#define FBINFO_PARTIAL_PAN_OK	0x0040 /* otw use pan only for double-buffering */
+#define FBINFO_READS_FAST	0x0080 /* soft-copy faster than rendering */
+
+/* hardware supported ops */
+/*  semantics: when a bit is set, it indicates that the operation is
+ *   accelerated by hardware.
+ *  required functions will still work even if the bit is not set.
+ *  optional functions may not even exist if the flag bit is not set.
+ */
+#define FBINFO_HWACCEL_NONE		0x0000
+#define FBINFO_HWACCEL_COPYAREA		0x0100 /* required */
+#define FBINFO_HWACCEL_FILLRECT		0x0200 /* required */
+#define FBINFO_HWACCEL_IMAGEBLIT	0x0400 /* required */
+#define FBINFO_HWACCEL_ROTATE		0x0800 /* optional */
+#define FBINFO_HWACCEL_XPAN		0x1000 /* optional */
+#define FBINFO_HWACCEL_YPAN		0x2000 /* optional */
+#define FBINFO_HWACCEL_YWRAP		0x4000 /* optional */
+
+
 struct fb_info {
 	int node;
 	int flags;
-#define FBINFO_FLAG_MODULE	1	/* Low-level driver is a module */
 	struct fb_var_screeninfo var;	/* Current var */
 	struct fb_fix_screeninfo fix;	/* Current fix */
 	struct fb_monspecs monspecs;	/* Current Monitor specs */
@@ -527,12 +555,24 @@
 };
 
 #ifdef MODULE
-#define FBINFO_FLAG_DEFAULT	FBINFO_FLAG_MODULE
+#define FBINFO_DEFAULT	FBINFO_MODULE
 #else
-#define FBINFO_FLAG_DEFAULT	0
+#define FBINFO_DEFAULT	0
 #endif
 
 // This will go away
+#define FBINFO_FLAG_MODULE	FBINFO_MODULE
+#define FBINFO_FLAG_DEFAULT	FBINFO_DEFAULT
+
+/* This will go away
+ * fbset currently hacks in FB_ACCELF_TEXT into var.accel_flags
+ * when it wants to turn the acceleration engine on.  This is
+ * really a separate operation, and should be modified via sysfs.
+ *  But for now, we leave it broken with the following define
+ */
+#define STUPID_ACCELF_TEXT_SHIT
+
+// This will go away
 #if defined(__sparc__)
 
 /* We map all of our framebuffers such that big-endian accesses
--- diff/include/linux/fs.h	2004-06-11 19:17:35.000000000 +0100
+++ source/include/linux/fs.h	2004-06-11 19:22:06.000000000 +0100
@@ -83,6 +83,7 @@
 #define SPECIAL 4	/* For non-blockdevice requests in request queue */
 #define READ_SYNC	(READ | (1 << BIO_RW_SYNC))
 #define WRITE_SYNC	(WRITE | (1 << BIO_RW_SYNC))
+#define WRITE_BARRIER	((1 << BIO_RW) | (1 << BIO_RW_BARRIER))
 
 #define SEL_IN		1
 #define SEL_OUT		2
@@ -326,7 +327,7 @@
 struct address_space {
 	struct inode		*host;		/* owner: inode, block_device */
 	struct radix_tree_root	page_tree;	/* radix tree of all pages */
-	spinlock_t		tree_lock;	/* and spinlock protecting it */
+	rwlock_t		tree_lock;	/* and rwlock protecting it */
 	unsigned long		nrpages;	/* number of total pages */
 	pgoff_t			writeback_index;/* writeback starts here */
 	struct address_space_operations *a_ops;	/* methods */
@@ -411,6 +412,7 @@
 struct inode {
 	struct hlist_node	i_hash;
 	struct list_head	i_list;
+	struct list_head	i_sb_list;
 	struct list_head	i_dentry;
 	unsigned long		i_ino;
 	atomic_t		i_count;
@@ -744,6 +746,7 @@
 	atomic_t		s_active;
 	void                    *s_security;
 
+	struct list_head	s_inodes;	/* all inodes */
 	struct list_head	s_dirty;	/* dirty inodes */
 	struct list_head	s_io;		/* parked for writeback */
 	struct hlist_head	s_anon;		/* anonymous dentries for (nfs) exporting */
@@ -900,6 +903,7 @@
 			struct inode *, struct dentry *);
 	int (*readlink) (struct dentry *, char __user *,int);
 	int (*follow_link) (struct dentry *, struct nameidata *);
+	void (*put_link) (struct dentry *, struct nameidata *);
 	void (*truncate) (struct inode *);
 	int (*permission) (struct inode *, int, struct nameidata *);
 	int (*setattr) (struct dentry *, struct iattr *);
@@ -1459,12 +1463,17 @@
 
 #define special_file(m) (S_ISCHR(m)||S_ISBLK(m)||S_ISFIFO(m)||S_ISSOCK(m))
 
+extern void nd_set_link(struct nameidata *, char *);
+extern char *nd_get_link(struct nameidata *);
 extern int vfs_readlink(struct dentry *, char __user *, int, const char *);
 extern int vfs_follow_link(struct nameidata *, const char *);
 extern int page_readlink(struct dentry *, char __user *, int);
 extern int page_follow_link(struct dentry *, struct nameidata *);
+extern int page_follow_link_light(struct dentry *, struct nameidata *);
+extern void page_put_link(struct dentry *, struct nameidata *);
 extern int page_symlink(struct inode *inode, const char *symname, int len);
 extern struct inode_operations page_symlink_inode_operations;
+extern int generic_readlink(struct dentry *, char __user *, int);
 extern void generic_fillattr(struct inode *, struct kstat *);
 extern int vfs_getattr(struct vfsmount *, struct dentry *, struct kstat *);
 void inode_add_bytes(struct inode *inode, loff_t bytes);
--- diff/include/linux/hiddev.h	2004-05-19 22:12:59.000000000 +0100
+++ source/include/linux/hiddev.h	2004-06-11 19:22:06.000000000 +0100
@@ -128,10 +128,11 @@
 
 /* hiddev_usage_ref_multi is used for sending multiple bytes to a control.
  * It really manifests itself as setting the value of consecutive usages */
+#define HID_MAX_MULTI_USAGES 1024
 struct hiddev_usage_ref_multi {
 	struct hiddev_usage_ref uref;
 	__u32 num_values;
-	__s32 values[HID_MAX_USAGES];
+	__s32 values[HID_MAX_MULTI_USAGES];
 };
 
 /* FIELD_INDEX_NONE is returned in read() data from the kernel when flags
@@ -212,6 +213,11 @@
  * In-kernel definitions.
  */
 
+struct hid_device;
+struct hid_usage;
+struct hid_field;
+struct hid_report;
+
 #ifdef CONFIG_USB_HIDDEV
 int hiddev_connect(struct hid_device *);
 void hiddev_disconnect(struct hid_device *);
--- diff/include/linux/i2c-id.h	2004-06-11 19:17:35.000000000 +0100
+++ source/include/linux/i2c-id.h	2004-06-11 19:22:06.000000000 +0100
@@ -101,6 +101,14 @@
 #define I2C_DRIVERID_UDA1342	53	/* UDA1342 audio codec		*/
 #define I2C_DRIVERID_ADV7170	54	/* video encoder		*/
 #define I2C_DRIVERID_RADEON	55	/* I2C bus on Radeon boards	*/
+#define I2C_DRIVERID_MAX1617	56	/* temp sensor			*/
+#define I2C_DRIVERID_SAA7191	57	/* video encoder		*/
+#define I2C_DRIVERID_INDYCAM	58	/* SGI IndyCam			*/
+#define I2C_DRIVERID_BT832	59	/* CMOS camera video processor	*/
+#define I2C_DRIVERID_TDA9887	60	/* TDA988x IF-PLL demodulator	*/
+#define I2C_DRIVERID_OVCAMCHIP	61	/* OmniVision CMOS image sens.	*/
+#define I2C_DRIVERID_TDA7313	62	/* TDA7313 audio processor	*/
+#define I2C_DRIVERID_MAX6900	63	/* MAX6900 real-time clock	*/
 
 
 #define I2C_DRIVERID_EXP0	0xF0	/* experimental use id's	*/
@@ -264,6 +272,10 @@
 #define I2C_HW_SMBUS_SCX200	0x0b
 #define I2C_HW_SMBUS_NFORCE2	0x0c
 #define I2C_HW_SMBUS_W9968CF	0x0d
+#define I2C_HW_SMBUS_OV511	0x0e	/* OV511(+) USB 1.1 webcam ICs	*/
+#define I2C_HW_SMBUS_OV518	0x0f	/* OV518(+) USB 1.1 webcam ICs	*/
+#define I2C_HW_SMBUS_OV519	0x10	/* OV519 USB 1.1 webcam IC	*/
+#define I2C_HW_SMBUS_OVFX2	0x11	/* Cypress/OmniVision FX2 webcam */
 
 /* --- ISA pseudo-adapter						*/
 #define I2C_HW_ISA 0x00
--- diff/include/linux/i2o.h	2004-06-11 19:17:35.000000000 +0100
+++ source/include/linux/i2o.h	2004-06-11 19:22:06.000000000 +0100
@@ -99,6 +99,7 @@
 	int		irq;
 	int		short_req:1;	/* Use small block sizes        */
 	int		dpt:1;		/* Don't quiesce                */
+	int		raptor:1;	/* split bar                    */
 	int		promise:1;	/* Promise controller		*/
 #ifdef CONFIG_MTRR
 	int		mtrr_reg0;
@@ -109,9 +110,9 @@
 	atomic_t users;
 	struct i2o_device *devices;		/* I2O device chain */
 	struct i2o_controller *next;		/* Controller chain */
-	unsigned long post_port;		/* Inbout port address */
-	unsigned long reply_port;		/* Outbound port address */
-	unsigned long irq_mask;			/* Interrupt register address */
+	void *post_port;			/* Inbout port address */
+	void *reply_port;			/* Outbound port address */
+	void *irq_mask;				/* Interrupt register address */
 
 	/* Dynamic LCT related data */
 	struct semaphore lct_sem;
@@ -128,8 +129,11 @@
 	dma_addr_t hrt_phys;
 	u32 hrt_len;
 
-	unsigned long mem_offset;		/* MFA offset */
-	unsigned long mem_phys;			/* MFA physical */
+	void *base_virt;			/* base virtual address */
+	unsigned long base_phys;		/* base physical address */
+
+	void *msg_virt;				/* messages virtual address */
+	unsigned long msg_phys;			/* messages physical address */
 
 	int battery:1;				/* Has a battery backup */
 	int io_alloc:1;				/* An I/O resource was allocated */
--- diff/include/linux/ide.h	2004-06-11 19:17:35.000000000 +0100
+++ source/include/linux/ide.h	2004-06-11 19:22:06.000000000 +0100
@@ -255,7 +255,7 @@
 		ide_pdc4030,	ide_rz1000,	ide_trm290,
 		ide_cmd646,	ide_cy82c693,	ide_4drives,
 		ide_pmac,	ide_etrax100,	ide_acorn,
-		ide_pc9800,	ide_forced
+		ide_forced
 } hwif_chipset_t;
 
 /*
@@ -780,6 +780,7 @@
 	u8	sect;		/* "real" sectors per track */
 	u8	bios_head;	/* BIOS/fdisk/LILO number of heads */
 	u8	bios_sect;	/* BIOS/fdisk/LILO sectors per track */
+	u8	doing_barrier;	/* state, 1=currently doing flush */
 
 	unsigned int	bios_cyl;	/* BIOS/fdisk/LILO number of cyls */
 	unsigned int	cyl;		/* "real" number of cyls */
@@ -1015,6 +1016,7 @@
 	unsigned dma;
 
 	void (*led_act)(void *data, int rw);
+	unsigned int (*max_rqsize)(ide_drive_t *);
 } ide_hwif_t;
 
 /*
@@ -1309,6 +1311,11 @@
 extern void ide_init_drive_cmd (struct request *rq);
 
 /*
+ * this function returns error location sector offset in case of a write error
+ */
+extern u64 ide_get_error_location(ide_drive_t *, char *);
+
+/*
  * "action" parameter type for ide_do_drive_cmd() below.
  */
 typedef enum {
@@ -1690,4 +1697,11 @@
 
 extern struct bus_type ide_bus_type;
 
+/* check if CACHE FLUSH (EXT) command is supported (bits defined in ATA-6) */
+#define ide_id_has_flush_cache(id)	((id)->cfs_enable_2 & 0x3000)
+
+/* some Maxtor disks have bit 13 defined incorrectly so check bit 10 too */
+#define ide_id_has_flush_cache_ext(id)	\
+	(((id)->cfs_enable_2 & 0x2400) == 0x2400)
+
 #endif /* _IDE_H */
--- diff/include/linux/idr.h	2004-06-11 19:17:35.000000000 +0100
+++ source/include/linux/idr.h	2004-06-11 19:22:06.000000000 +0100
@@ -11,14 +11,20 @@
 #include <linux/types.h>
 #include <asm/bitops.h>
 
-#define RESERVED_ID_BITS 8
-
 #if BITS_PER_LONG == 32
 # define IDR_BITS 5
 # define IDR_FULL 0xfffffffful
+/* We can only use two of the bits in the top level because there is
+   only one possible bit in the top level (5 bits * 7 levels = 35
+   bits, but you only use 31 bits in the id). */
+# define TOP_LEVEL_FULL (IDR_FULL >> 30)
 #elif BITS_PER_LONG == 64
 # define IDR_BITS 6
 # define IDR_FULL 0xfffffffffffffffful
+/* We can only use two of the bits in the top level because there is
+   only one possible bit in the top level (6 bits * 6 levels = 36
+   bits, but you only use 31 bits in the id). */
+# define TOP_LEVEL_FULL (IDR_FULL >> 62)
 #else
 # error "BITS_PER_LONG is not 32 or 64"
 #endif
@@ -26,11 +32,8 @@
 #define IDR_SIZE (1 << IDR_BITS)
 #define IDR_MASK ((1 << IDR_BITS)-1)
 
-/* Define the size of the id's */
-#define BITS_PER_INT (sizeof(int)*8)
-
-#define MAX_ID_SHIFT (BITS_PER_INT - RESERVED_ID_BITS)
-#define MAX_ID_BIT (1 << MAX_ID_SHIFT)
+#define MAX_ID_SHIFT (sizeof(int)*8 - 1)
+#define MAX_ID_BIT (1U << MAX_ID_SHIFT)
 #define MAX_ID_MASK (MAX_ID_BIT - 1)
 
 /* Leave the possibility of an incomplete final layer */
@@ -40,25 +43,23 @@
 #define IDR_FREE_MAX MAX_LEVEL + MAX_LEVEL
 
 struct idr_layer {
-	unsigned long		 bitmap;	/* A zero bit means "space here" */
+	unsigned long		 bitmap; /* A zero bit means "space here" */
 	struct idr_layer	*ary[1<<IDR_BITS];
-	int			 count;		/* When zero, we can release it */
+	int			 count;	 /* When zero, we can release it */
 };
 
 struct idr {
 	struct idr_layer *top;
 	struct idr_layer *id_free;
-	long		  count;
 	int		  layers;
 	int		  id_free_cnt;
 	spinlock_t	  lock;
 };
 
-#define IDR_INIT(name)	\
+#define IDR_INIT(name)						\
 {								\
 	.top		= NULL,					\
 	.id_free	= NULL,					\
-	.count		= 0,					\
 	.layers 	= 0,					\
 	.id_free_cnt	= 0,					\
 	.lock		= SPIN_LOCK_UNLOCKED,			\
@@ -71,9 +72,9 @@
 
 void *idr_find(struct idr *idp, int id);
 int idr_pre_get(struct idr *idp, unsigned gfp_mask);
-int idr_get_new(struct idr *idp, void *ptr);
+int idr_get_new(struct idr *idp, void *ptr, int *id);
+int idr_get_new_above(struct idr *idp, void *ptr, int starting_id, int *id);
 void idr_remove(struct idr *idp, int id);
 void idr_init(struct idr *idp);
 
 extern kmem_cache_t *idr_layer_cache;
-
--- diff/include/linux/init.h	2004-06-11 19:17:35.000000000 +0100
+++ source/include/linux/init.h	2004-06-11 19:22:06.000000000 +0100
@@ -3,6 +3,7 @@
 
 #include <linux/config.h>
 #include <linux/compiler.h>
+#include <asm/setup.h>
 
 /* These macros are used to mark some functions or 
  * initialized data (doesn't apply to uninitialized data)
@@ -66,6 +67,9 @@
 
 extern initcall_t __con_initcall_start, __con_initcall_end;
 extern initcall_t __security_initcall_start, __security_initcall_end;
+
+/* Defined in init/main.c */
+extern char saved_command_line[COMMAND_LINE_SIZE];
 #endif
   
 #ifndef MODULE
@@ -107,25 +111,33 @@
 struct obs_kernel_param {
 	const char *str;
 	int (*setup_func)(char *);
+	int early;
 };
 
-/* OBSOLETE: see moduleparam.h for the right way. */
-#define __setup_param(str, unique_id, fn)			\
+/* Only for really core code.  See moduleparam.h for the normal way. */
+#define __setup_param(str, unique_id, fn, early)			\
 	static char __setup_str_##unique_id[] __initdata = str;	\
 	static struct obs_kernel_param __setup_##unique_id	\
 		 __attribute_used__				\
 		 __attribute__((__section__(".init.setup")))	\
-		= { __setup_str_##unique_id, fn }
+		= { __setup_str_##unique_id, fn, early }
 
 #define __setup_null_param(str, unique_id)			\
-	__setup_param(str, unique_id, NULL)
+	__setup_param(str, unique_id, NULL, 0)
 
 #define __setup(str, fn)					\
-	__setup_param(str, fn, fn)
+	__setup_param(str, fn, fn, 0)
 
 #define __obsolete_setup(str)					\
 	__setup_null_param(str, __LINE__)
 
+/* NOTE: fn is as per module_param, not __setup!  Emits warning if fn
+ * returns non-zero. */
+#define early_param(str, fn)					\
+	__setup_param(str, fn, fn, 1)
+
+/* Relies on saved_command_line being set */
+void __init parse_early_param(void);
 #endif /* __ASSEMBLY__ */
 
 /**
--- diff/include/linux/input.h	2004-06-11 19:17:35.000000000 +0100
+++ source/include/linux/input.h	2004-06-11 19:22:06.000000000 +0100
@@ -527,6 +527,8 @@
 #define MSC_SERIAL		0x00
 #define MSC_PULSELED		0x01
 #define MSC_GESTURE		0x02
+#define MSC_RAW			0x03
+#define MSC_SCAN		0x04
 #define MSC_MAX			0x07
 
 /*
--- diff/include/linux/iso_fs.h	2004-05-19 22:13:00.000000000 +0100
+++ source/include/linux/iso_fs.h	2004-06-11 19:22:06.000000000 +0100
@@ -231,9 +231,75 @@
 extern struct buffer_head *isofs_bread(struct inode *, sector_t);
 extern int isofs_get_blocks(struct inode *, sector_t, struct buffer_head **, unsigned long);
 
+extern struct inode *isofs_iget(struct super_block *sb,
+                                unsigned long block,
+                                unsigned long offset);
+
+/* Because the inode number is no longer relevant to finding the
+ * underlying meta-data for an inode, we are free to choose a more
+ * convenient 32-bit number as the inode number.  Because directories
+ * and files are block aligned (except in a few very unusual cases)
+ * and because blocks are limited to 32-bits, I've chosen the starting
+ * block that holds the file or directory data as the inode number.
+ *
+ * One nice side effect of this is that you can use "ls -i" to get the
+ * inode number which will tell you exactly where you need to start a
+ * hex dump if you want to see the contents of the directory or
+ * file. */
+static inline unsigned long isofs_get_ino(struct iso_directory_record *d)
+{
+	return (unsigned long)isonum_733(d->extent)
+		+ (unsigned long)isonum_711(d->ext_attr_length);
+}
+
+/* Every directory can have many redundant directory entries scattered
+ * throughout the directory tree.  First there is the directory entry
+ * with the name of the directory stored in the parent directory.
+ * Then, there is the "." directory entry stored in the directory
+ * itself.  Finally, there are possibly many ".." directory entries
+ * stored in all the subdirectories.
+ *
+ * In order for the NFS get_parent() method to work and for the
+ * general consistency of the dcache, we need to make sure the
+ * "i_iget5_block" and "i_iget5_offset" all point to exactly one of
+ * the many redundant entries for each directory.  We normalize the
+ * block and offset by always making them point to the "."  directory.
+ *
+ * Notice that we do not use the entry for the directory with the name
+ * that is located in the parent directory.  Even though choosing this
+ * first directory is more natural, it is much easier to find the "."
+ * entry in the NFS get_parent() method because it is implicitly
+ * encoded in the "extent + ext_attr_length" fields of _all_ the
+ * redundant entries for the directory.  Thus, it can always be
+ * reached regardless of which directory entry you have in hand.
+ *
+ * This works because the "." entry is simply the first directory
+ * record when you start reading the file that holds all the directory
+ * records, and this file starts at "extent + ext_attr_length" blocks.
+ * Because the "." entry is always the first entry listed in the
+ * directories file, the normalized "offset" value is always 0.
+ *
+ * You should pass the directory entry in "de".  On return, "block"
+ * and "offset" will hold normalized values.  Only directories are
+ * affected making it safe to call even for non-directory file
+ * types. */
+static void inline
+isofs_normalize_block_and_offset(struct iso_directory_record* de,
+				 unsigned long *block,
+				 unsigned long *offset)
+{
+	/* Only directories are normalized. */
+	if (de->flags[0] & 2) {
+		*offset = 0;
+		*block = (unsigned long)isonum_733(de->extent)
+			+ (unsigned long)isonum_711(de->ext_attr_length);
+	}
+}
+
 extern struct inode_operations isofs_dir_inode_operations;
 extern struct file_operations isofs_dir_operations;
 extern struct address_space_operations isofs_symlink_aops;
+extern struct export_operations isofs_export_ops;
 
 /* The following macros are used to check for memory leaks. */
 #ifdef LEAK_CHECK
--- diff/include/linux/iso_fs_i.h	2004-05-19 22:13:00.000000000 +0100
+++ source/include/linux/iso_fs_i.h	2004-06-11 19:22:06.000000000 +0100
@@ -13,10 +13,13 @@
  * iso fs inode data in memory
  */
 struct iso_inode_info {
+	unsigned long i_iget5_block;
+	unsigned long i_iget5_offset;
 	unsigned int i_first_extent;
 	unsigned char i_file_format;
 	unsigned char i_format_parm[3];
-	unsigned long i_next_section_ino;
+	unsigned long i_next_section_block;
+	unsigned long i_next_section_offset;
 	off_t i_section_size;
 	struct inode vfs_inode;
 };
--- diff/include/linux/jbd.h	2004-05-19 22:13:00.000000000 +0100
+++ source/include/linux/jbd.h	2004-06-11 19:22:06.000000000 +0100
@@ -840,6 +840,7 @@
 #define JFS_ACK_ERR	0x004	/* The errno in the sb has been acked */
 #define JFS_FLUSHED	0x008	/* The journal superblock has been flushed */
 #define JFS_LOADED	0x010	/* The journal superblock has been loaded */
+#define JFS_BARRIER	0x020	/* Use IDE barriers */
 
 /* 
  * Function declarations for the journaling transaction and buffer
@@ -1006,6 +1007,7 @@
 int log_start_commit(journal_t *journal, tid_t tid);
 int __log_start_commit(journal_t *journal, tid_t tid);
 int journal_start_commit(journal_t *journal, tid_t *tid);
+int journal_force_commit_nested(journal_t *journal);
 int log_wait_commit(journal_t *journal, tid_t tid);
 int log_do_checkpoint(journal_t *journal);
 
--- diff/include/linux/kernel.h	2004-06-11 19:17:35.000000000 +0100
+++ source/include/linux/kernel.h	2004-06-11 19:22:06.000000000 +0100
@@ -61,7 +61,6 @@
 	ATTRIB_NORET;
 NORET_TYPE void complete_and_exit(struct completion *, long)
 	ATTRIB_NORET;
-extern int abs(int);
 extern unsigned long simple_strtoul(const char *,char **,unsigned int);
 extern long simple_strtol(const char *,char **,unsigned int);
 extern unsigned long long simple_strtoull(const char *,char **,unsigned int);
@@ -106,6 +105,13 @@
 		console_loglevel = 15;
 }
 
+static inline int abs(int x)
+{
+	if (x < 0)
+		return -x;
+	return x;
+}
+
 extern void bust_spinlocks(int yes);
 extern int oops_in_progress;		/* If set, an oops, panic(), BUG() or die() is in progress */
 extern int panic_on_oops;
--- diff/include/linux/kmalloc_sizes.h	2004-05-19 22:13:00.000000000 +0100
+++ source/include/linux/kmalloc_sizes.h	2004-06-11 19:22:06.000000000 +0100
@@ -12,6 +12,9 @@
 	CACHE(256)
 	CACHE(512)
 	CACHE(1024)
+#if (PAGE_SIZE != 4096)	/* special cache for eth skbs - 5 fit into one 8 kB page */
+	CACHE(1620)
+#endif
 	CACHE(2048)
 	CACHE(4096)
 	CACHE(8192)
--- diff/include/linux/list.h	2004-05-19 22:13:00.000000000 +0100
+++ source/include/linux/list.h	2004-06-11 19:22:06.000000000 +0100
@@ -158,8 +158,11 @@
  * Note: list_empty on entry does not return true after this, the entry is
  * in an undefined state.
  */
+#include <linux/kernel.h>	/* BUG_ON */
 static inline void list_del(struct list_head *entry)
 {
+	BUG_ON(entry->prev->next != entry);
+	BUG_ON(entry->next->prev != entry);
 	__list_del(entry->prev, entry->next);
 	entry->next = LIST_POISON1;
 	entry->prev = LIST_POISON2;
--- diff/include/linux/mca.h	2004-06-11 19:17:35.000000000 +0100
+++ source/include/linux/mca.h	2004-06-11 19:22:06.000000000 +0100
@@ -12,7 +12,9 @@
 #include <linux/device.h>
 
 /* get the platform specific defines */
+#ifdef CONFIG_MCA
 #include <asm/mca.h>
+#endif
 
 /* The detection of MCA bus is done in the real mode (using BIOS).
  * The information is exported to the protected code, where this
--- diff/include/linux/mempolicy.h	2004-06-11 19:17:35.000000000 +0100
+++ source/include/linux/mempolicy.h	2004-06-11 19:22:06.000000000 +0100
@@ -153,6 +153,9 @@
 struct mempolicy *mpol_shared_policy_lookup(struct shared_policy *sp,
 					    unsigned long idx);
 
+extern void numa_default_policy(void);
+extern void numa_policy_init(void);
+
 #else
 
 struct mempolicy {};
@@ -215,6 +218,14 @@
 #define vma_policy(vma) NULL
 #define vma_set_policy(vma, pol) do {} while(0)
 
+static inline void numa_policy_init(void)
+{
+}
+
+static inline void numa_default_policy(void)
+{
+}
+
 #endif /* CONFIG_NUMA */
 #endif /* __KERNEL__ */
 
--- diff/include/linux/miscdevice.h	2004-05-19 22:13:01.000000000 +0100
+++ source/include/linux/miscdevice.h	2004-06-11 19:22:06.000000000 +0100
@@ -33,6 +33,7 @@
 #define SGI_STREAMS_KEYBOARD 150
 /* drivers/sgi/char/usema.c */
 #define SGI_USEMACLONE	     151
+#define	HPET_MINOR	     152
 
 #define TUN_MINOR	     200
 
--- diff/include/linux/module.h	2004-06-11 19:17:35.000000000 +0100
+++ source/include/linux/module.h	2004-06-11 19:22:06.000000000 +0100
@@ -225,6 +225,22 @@
 	struct module_attribute attr[0];
 };
 
+/* Similar stuff for section attributes. */
+#define MODULE_SECT_NAME_LEN 32
+struct module_sect_attr
+{
+	struct attribute attr;
+	char name[MODULE_SECT_NAME_LEN];
+	unsigned long address;
+};
+
+struct module_sections
+{
+	struct kobject kobj;
+	struct module_sect_attr attrs[0];
+};
+
+
 struct module
 {
 	enum module_state state;
@@ -298,6 +314,9 @@
 	Elf_Sym *symtab;
 	unsigned long num_symtab;
 	char *strtab;
+
+	/* Section attributes */
+	struct module_sections *sect_attrs;
 #endif
 
 	/* Per-cpu data. */
--- diff/include/linux/mqueue.h	2004-05-19 22:13:01.000000000 +0100
+++ source/include/linux/mqueue.h	2004-06-11 19:22:06.000000000 +0100
@@ -21,6 +21,8 @@
 #include <linux/types.h>
 
 #define MQ_PRIO_MAX 	32768
+/* per-uid limit of kernel memory used by mqueue, in bytes */
+#define MQ_BYTES_MAX	819200
 
 struct mq_attr {
 	long	mq_flags;	/* message queue flags			*/
--- diff/include/linux/namei.h	2004-05-19 22:13:01.000000000 +0100
+++ source/include/linux/namei.h	2004-06-11 19:22:06.000000000 +0100
@@ -10,12 +10,15 @@
 	int	create_mode;
 };
 
+enum { MAX_NESTED_LINKS = 5 };
+
 struct nameidata {
 	struct dentry	*dentry;
 	struct vfsmount *mnt;
 	struct qstr	last;
 	unsigned int	flags;
 	int		last_type;
+	char *saved_names[MAX_NESTED_LINKS + 1];
 
 	/* Intent data */
 	union {
--- diff/include/linux/netfilter_arp.h	2004-06-11 19:17:35.000000000 +0100
+++ source/include/linux/netfilter_arp.h	2004-06-11 19:22:06.000000000 +0100
@@ -17,5 +17,4 @@
 #define NF_ARP_FORWARD	2
 #define NF_ARP_NUMHOOKS	3
 
-static DECLARE_MUTEX(arpt_mutex);
 #endif /* __LINUX_ARP_NETFILTER_H */
--- diff/include/linux/page-flags.h	2004-06-11 19:17:35.000000000 +0100
+++ source/include/linux/page-flags.h	2004-06-11 19:22:06.000000000 +0100
@@ -133,12 +133,16 @@
 	unsigned long allocstall;	/* direct reclaim calls */
 
 	unsigned long pgrotated;	/* pages rotated to tail of the LRU */
-} ____cacheline_aligned;
+};
 
 DECLARE_PER_CPU(struct page_state, page_states);
 
 extern void get_page_state(struct page_state *ret);
 extern void get_full_page_state(struct page_state *ret);
+extern unsigned long __read_page_state(unsigned offset);
+
+#define read_page_state(member) \
+	__read_page_state(offsetof(struct page_state, member))
 
 #define mod_page_state(member, delta)					\
 	do {								\
--- diff/include/linux/pci_ids.h	2004-06-11 19:17:35.000000000 +0100
+++ source/include/linux/pci_ids.h	2004-06-11 19:22:06.000000000 +0100
@@ -1770,6 +1770,8 @@
 
 #define PCI_VENDOR_ID_3WARE		0x13C1
 #define PCI_DEVICE_ID_3WARE_1000	0x1000
+#define PCI_DEVICE_ID_3WARE_7000	0x1001
+#define PCI_DEVICE_ID_3WARE_9000	0x1002
 
 #define PCI_VENDOR_ID_IOMEGA		0x13ca
 #define PCI_DEVICE_ID_IOMEGA_BUZ	0x4231
@@ -2012,6 +2014,7 @@
 #define PCI_DEVICE_ID_INTEL_82092AA_0	0x1221
 #define PCI_DEVICE_ID_INTEL_82092AA_1	0x1222
 #define PCI_DEVICE_ID_INTEL_7116	0x1223
+#define PCI_DEVICE_ID_INTEL_7501_0	0x254c
 #define PCI_DEVICE_ID_INTEL_7505_0	0x2550  
 #define PCI_DEVICE_ID_INTEL_7505_1	0x2552  
 #define PCI_DEVICE_ID_INTEL_7205_0	0x255d
--- diff/include/linux/prctl.h	2004-05-19 22:13:02.000000000 +0100
+++ source/include/linux/prctl.h	2004-06-11 19:22:06.000000000 +0100
@@ -29,6 +29,12 @@
 /* Get/set floating-point exception mode (if meaningful) */
 #define PR_GET_FPEXC	11
 #define PR_SET_FPEXC	12
+# define PR_FP_EXC_SW_ENABLE	0x80	/* Use FPEXC for FP exception enables */
+# define PR_FP_EXC_DIV		0x010000	/* floating point divide by zero */
+# define PR_FP_EXC_OVF		0x020000	/* floating point overflow */
+# define PR_FP_EXC_UND		0x040000	/* floating point underflow */
+# define PR_FP_EXC_RES		0x080000	/* floating point inexact result */
+# define PR_FP_EXC_INV		0x100000	/* floating point invalid operation */
 # define PR_FP_EXC_DISABLED	0	/* FP exceptions disabled */
 # define PR_FP_EXC_NONRECOV	1	/* async non-recoverable exc. mode */
 # define PR_FP_EXC_ASYNC	2	/* async recoverable exception mode */
--- diff/include/linux/rcupdate.h	2004-05-19 22:13:02.000000000 +0100
+++ source/include/linux/rcupdate.h	2004-06-11 19:22:06.000000000 +0100
@@ -41,6 +41,7 @@
 #include <linux/threads.h>
 #include <linux/percpu.h>
 #include <linux/cpumask.h>
+#include <linux/seqlock.h>
 
 /**
  * struct rcu_head - callback structure for use with RCU
@@ -63,14 +64,13 @@
 
 
 
-/* Control variables for rcupdate callback mechanism. */
+/* Global control variables for rcupdate callback mechanism. */
 struct rcu_ctrlblk {
-	spinlock_t	mutex;		/* Guard this struct                  */
-	long		curbatch;	/* Current batch number.	      */
-	long		maxbatch;	/* Max requested batch number.        */
-	cpumask_t	rcu_cpu_mask; 	/* CPUs that need to switch in order  */
-					/* for current batch to proceed.      */
-};
+	long	cur;		/* Current batch number.                      */
+	long	completed;	/* Number of the last completed batch         */
+	int	next_pending;	/* Is the next batch already waiting?         */
+	seqcount_t lock;	/* For atomic reads of cur and next_pending.  */
+} ____cacheline_maxaligned_in_smp;
 
 /* Is batch a before batch b ? */
 static inline int rcu_batch_before(long a, long b)
@@ -90,9 +90,14 @@
  * curlist - current batch for which quiescent cycle started if any
  */
 struct rcu_data {
+	/* 1) quiescent state handling : */
+        long		quiescbatch;     /* Batch # for grace period */
 	long		qsctr;		 /* User-mode/idle loop etc. */
         long            last_qsctr;	 /* value of qsctr at beginning */
                                          /* of rcu grace period */
+	int		qs_pending;	 /* core waits for quiesc state */
+
+	/* 2) batch handling */
         long  	       	batch;           /* Batch # for current RCU batch */
         struct list_head  nxtlist;
         struct list_head  curlist;
@@ -101,24 +106,31 @@
 DECLARE_PER_CPU(struct rcu_data, rcu_data);
 extern struct rcu_ctrlblk rcu_ctrlblk;
 
+#define RCU_quiescbatch(cpu)	(per_cpu(rcu_data, (cpu)).quiescbatch)
 #define RCU_qsctr(cpu) 		(per_cpu(rcu_data, (cpu)).qsctr)
 #define RCU_last_qsctr(cpu) 	(per_cpu(rcu_data, (cpu)).last_qsctr)
+#define RCU_qs_pending(cpu)	(per_cpu(rcu_data, (cpu)).qs_pending)
 #define RCU_batch(cpu) 		(per_cpu(rcu_data, (cpu)).batch)
 #define RCU_nxtlist(cpu) 	(per_cpu(rcu_data, (cpu)).nxtlist)
 #define RCU_curlist(cpu) 	(per_cpu(rcu_data, (cpu)).curlist)
 
-#define RCU_QSCTR_INVALID	0
-
 static inline int rcu_pending(int cpu) 
 {
-	if ((!list_empty(&RCU_curlist(cpu)) &&
-	     rcu_batch_before(RCU_batch(cpu), rcu_ctrlblk.curbatch)) ||
-	    (list_empty(&RCU_curlist(cpu)) &&
-			 !list_empty(&RCU_nxtlist(cpu))) ||
-	    cpu_isset(cpu, rcu_ctrlblk.rcu_cpu_mask))
+	/* This cpu has pending rcu entries and the grace period
+	 * for them has completed.
+	 */
+	if (!list_empty(&RCU_curlist(cpu)) &&
+		  !rcu_batch_before(rcu_ctrlblk.completed,RCU_batch(cpu)))
+		return 1;
+	/* This cpu has no pending entries, but there are new entries */
+	if (list_empty(&RCU_curlist(cpu)) &&
+			 !list_empty(&RCU_nxtlist(cpu)))
+		return 1;
+	/* The rcu core waits for a quiescent state from the cpu */
+	if (RCU_quiescbatch(cpu) != rcu_ctrlblk.cur || RCU_qs_pending(cpu))
 		return 1;
-	else
-		return 0;
+	/* nothing to do */
+	return 0;
 }
 
 #define rcu_read_lock()		preempt_disable()
@@ -126,6 +138,7 @@
 
 extern void rcu_init(void);
 extern void rcu_check_callbacks(int cpu, int user);
+extern void rcu_restart_cpu(int cpu);
 
 /* Exported interfaces */
 extern void FASTCALL(call_rcu(struct rcu_head *head, 
--- diff/include/linux/reiserfs_fs.h	2004-06-11 19:17:35.000000000 +0100
+++ source/include/linux/reiserfs_fs.h	2004-06-11 19:22:06.000000000 +0100
@@ -1238,8 +1238,12 @@
 gods only know how we are going to SMP the code that uses them.
 znodes are the way! */
 
+#define PATH_READA	0x1 /* do read ahead */
+#define PATH_READA_BACK 0x2 /* read backwards */
+
 struct  path {
   int                   path_length;                      	/* Length of the array above.   */
+  int			reada;
   struct  path_element  path_elements[EXTENDED_MAX_HEIGHT];	/* Array of the path elements.  */
   int			pos_in_item;
 };
@@ -1247,7 +1251,7 @@
 #define pos_in_item(path) ((path)->pos_in_item)
 
 #define INITIALIZE_PATH(var) \
-struct path var = {ILLEGAL_PATH_ELEMENT_OFFSET, }
+struct path var = {.path_length = ILLEGAL_PATH_ELEMENT_OFFSET, .reada = 0,}
 
 /* Get path element by path and path position. */
 #define PATH_OFFSET_PELEMENT(p_s_path,n_offset)  ((p_s_path)->path_elements +(n_offset))
@@ -1748,6 +1752,14 @@
 int reiserfs_add_ordered_list(struct inode *inode, struct buffer_head *bh);
 int journal_mark_dirty(struct reiserfs_transaction_handle *, struct super_block *, struct buffer_head *bh) ;
 
+static inline int
+reiserfs_file_data_log(struct inode *inode) {
+    if (reiserfs_data_log(inode->i_sb) ||
+       (REISERFS_I(inode)->i_flags & i_data_log))
+        return 1 ;
+    return 0 ;
+}
+
 static inline int reiserfs_transaction_running(struct super_block *s) {
     struct reiserfs_transaction_handle *th = current->journal_info ;
     if (th && th->t_super == s)
@@ -1765,7 +1777,8 @@
 int reiserfs_commit_page(struct inode *inode, struct page *page,
 		unsigned from, unsigned to);
 int reiserfs_flush_old_commits(struct super_block *);
-void reiserfs_commit_for_inode(struct inode *) ;
+int reiserfs_commit_for_inode(struct inode *) ;
+int  reiserfs_inode_needs_commit(struct inode *) ;
 void reiserfs_update_inode_transaction(struct inode *) ;
 void reiserfs_wait_on_write_block(struct super_block *s) ;
 void reiserfs_block_writes(struct reiserfs_transaction_handle *th) ;
@@ -2149,6 +2162,15 @@
 typedef struct __reiserfs_blocknr_hint reiserfs_blocknr_hint_t;
 
 int reiserfs_parse_alloc_options (struct super_block *, char *);
+void reiserfs_init_alloc_options (struct super_block *s);
+
+/*
+ * given a directory, this will tell you what packing locality
+ * to use for a new object underneat it.  The locality is returned
+ * in disk byte order (le).
+ */
+u32 reiserfs_choose_packing(struct inode *dir);
+
 int is_reusable (struct super_block * s, b_blocknr_t block, int bit_value);
 void reiserfs_free_block (struct reiserfs_transaction_handle *th, struct inode *, b_blocknr_t, int for_unformatted);
 int reiserfs_allocate_blocknrs(reiserfs_blocknr_hint_t *, b_blocknr_t * , int, int);
--- diff/include/linux/reiserfs_fs_i.h	2004-06-11 19:17:35.000000000 +0100
+++ source/include/linux/reiserfs_fs_i.h	2004-06-11 19:22:06.000000000 +0100
@@ -25,6 +25,7 @@
     i_link_saved_truncate_mask =  0x0020,
     i_priv_object              =  0x0080,
     i_has_xattr_dir            =  0x0100,
+    i_data_log	               =  0x0200,
 } reiserfs_inode_flags;
 
 
--- diff/include/linux/reiserfs_fs_sb.h	2004-06-11 19:17:35.000000000 +0100
+++ source/include/linux/reiserfs_fs_sb.h	2004-06-11 19:22:06.000000000 +0100
@@ -444,6 +444,8 @@
     REISERFS_XATTRS,
     REISERFS_XATTRS_USER,
     REISERFS_POSIXACL,
+    REISERFS_BARRIER_NONE,
+    REISERFS_BARRIER_FLUSH,
 
     REISERFS_TEST1,
     REISERFS_TEST2,
@@ -473,6 +475,8 @@
 #define reiserfs_xattrs_user(s) (REISERFS_SB(s)->s_mount_opt & (1 << REISERFS_XATTRS_USER))
 #define reiserfs_posixacl(s) (REISERFS_SB(s)->s_mount_opt & (1 << REISERFS_POSIXACL))
 #define reiserfs_xattrs_optional(s) (reiserfs_xattrs_user(s) || reiserfs_posixacl(s))
+#define reiserfs_barrier_none(s) (REISERFS_SB(s)->s_mount_opt & (1 << REISERFS_BARRIER_NONE))
+#define reiserfs_barrier_flush(s) (REISERFS_SB(s)->s_mount_opt & (1 << REISERFS_BARRIER_FLUSH))
 
 void reiserfs_file_buffer (struct buffer_head * bh, int list);
 extern struct file_system_type reiserfs_fs_type;
--- diff/include/linux/sched.h	2004-06-11 19:17:35.000000000 +0100
+++ source/include/linux/sched.h	2004-06-11 19:22:06.000000000 +0100
@@ -96,6 +96,14 @@
 extern unsigned long nr_uninterruptible(void);
 extern unsigned long nr_iowait(void);
 
+#ifdef CONFIG_SCHEDSTATS
+#define schedstat_inc(s, field)		((s)->field++)
+#define schedstat_add(s, field, amt)	((s)->field += amt)
+#else
+#define schedstat_inc(s, field)		do { } while (0)
+#define schedstat_add(d, field, amt)	do { } while (0)
+#endif
+
 #include <linux/time.h>
 #include <linux/param.h>
 #include <linux/resource.h>
@@ -314,6 +322,9 @@
 	atomic_t __count;	/* reference count */
 	atomic_t processes;	/* How many processes does this user have? */
 	atomic_t files;		/* How many open files does this user have? */
+	atomic_t sigpending;	/* How many pending signals does this user have? */
+	/* protected by mq_lock	*/
+	unsigned long mq_bytes;	/* How many bytes can be allocated to mqueue? */
 
 	/* Hash table maintenance information */
 	struct list_head uidhash_list;
@@ -347,7 +358,6 @@
 	struct sigqueue *sigq;		/* signal queue entry. */
 };
 
-
 struct io_context;			/* See blkdev.h */
 void exit_io_context(void);
 
@@ -361,6 +371,12 @@
 	gid_t *blocks[0];
 };
 
+/*
+ * get_group_info() must be called with the owning task locked (via task_lock())
+ * when task != current.  The reason being that the vast majority of callers are
+ * looking at current->group_info, which can not be changed except by the
+ * current task.  Changing current->group_info requires the task lock, too.
+ */
 #define get_group_info(group_info) do { \
 	atomic_inc(&(group_info)->usage); \
 } while (0)
@@ -592,6 +608,35 @@
 	unsigned long last_balance;	/* init to jiffies. units in jiffies */
 	unsigned int balance_interval;	/* initialise to 1. units in ms. */
 	unsigned int nr_balance_failed; /* initialise to 0 */
+
+#ifdef CONFIG_SCHEDSTATS
+	unsigned long lb_cnt[3];
+	unsigned long lb_balanced[3];
+	unsigned long lb_failed[3];
+	unsigned long lb_pulled[3];
+	unsigned long lb_hot_pulled[3];
+	unsigned long lb_imbalance[3];
+
+	/* Active load balancing */
+	unsigned long alb_cnt;
+	unsigned long alb_failed;
+	unsigned long alb_pushed;
+
+	/* Wakeups */
+	unsigned long sched_wake_remote;
+
+	/* Passive load balancing */
+	unsigned long plb_pulled;
+
+	/* Affine wakeups */
+	unsigned long afw_pulled;
+
+	/* SD_BALANCE_EXEC balances */
+	unsigned long sbe_pushed;
+
+	/* SD_BALANCE_CLONE balances */
+	unsigned long sbc_pushed;
+#endif
 };
 
 /* Common values for SMT siblings */
@@ -719,6 +764,11 @@
 
 /* per-UID process charging. */
 extern struct user_struct * alloc_uid(uid_t);
+static inline struct user_struct *get_uid(struct user_struct *u)
+{
+	atomic_inc(&u->__count);
+	return u;
+}
 extern void free_uid(struct user_struct *);
 extern void switch_uid(struct user_struct *);
 
@@ -738,7 +788,7 @@
  static inline void kick_process(struct task_struct *tsk) { }
  static inline void wake_up_forked_thread(struct task_struct * tsk)
  {
-	return wake_up_forked_process(tsk);
+	wake_up_forked_process(tsk);
  }
 #endif
 extern void FASTCALL(sched_fork(task_t * p));
@@ -922,7 +972,9 @@
 extern void unhash_process(struct task_struct *p);
 
 /*
- * Protects ->fs, ->files, ->mm, ->ptrace and synchronises with wait4().
+ * Protects ->fs, ->files, ->mm, ->ptrace, ->group_info and synchronises with
+ * wait4().
+ *
  * Nests both inside and outside of read_lock(&tasklist_lock).
  * It must not be nested with write_lock_irq(&tasklist_lock),
  * neither inside nor outside.
@@ -1008,6 +1060,7 @@
 extern void __cond_resched(void);
 static inline void cond_resched(void)
 {
+	might_sleep();
 	if (need_resched())
 		__cond_resched();
 }
--- diff/include/linux/serial_core.h	2004-06-11 19:17:35.000000000 +0100
+++ source/include/linux/serial_core.h	2004-06-11 19:22:06.000000000 +0100
@@ -59,14 +59,6 @@
 /* NEC v850.  */
 #define PORT_V850E_UART	40
 
-/* NEC PC-9800 */
-#define PORT_8251_PC98	41
-#define PORT_19K_PC98	42
-#define PORT_FIFO_PC98	43
-#define PORT_VFAST_PC98	44
-#define PORT_PC9861	45
-#define PORT_PC9801_101	46
-
 /* DZ */
 #define PORT_DZ		47
 
@@ -171,7 +163,9 @@
 	unsigned char		x_char;			/* xon/xoff char */
 	unsigned char		regshift;		/* reg offset shift */
 	unsigned char		iotype;			/* io access style */
-
+#ifdef CONFIG_KGDB
+	int			kgdb;			/* in use by kgdb */
+#endif
 #define UPIO_PORT		(0)
 #define UPIO_HUB6		(1)
 #define UPIO_MEM		(2)
--- diff/include/linux/serio.h	2004-05-19 22:13:02.000000000 +0100
+++ source/include/linux/serio.h	2004-06-11 19:22:06.000000000 +0100
@@ -17,6 +17,7 @@
 #ifdef __KERNEL__
 
 #include <linux/list.h>
+#include <linux/spinlock.h>
 
 struct serio {
 	void *private;
@@ -32,11 +33,13 @@
 	unsigned long type;
 	unsigned long event;
 
+	spinlock_t lock;
+
 	int (*write)(struct serio *, unsigned char);
 	int (*open)(struct serio *);
 	void (*close)(struct serio *);
 
-	struct serio_dev *dev;
+	struct serio_dev *dev; /* Accessed from interrupt, writes must be protected by serio_lock */
 
 	struct list_head node;
 };
@@ -105,9 +108,9 @@
 #define SERIO_8042	0x01000000UL
 #define SERIO_RS232	0x02000000UL
 #define SERIO_HIL_MLC	0x03000000UL
-#define SERIO_PC9800	0x04000000UL
 #define SERIO_PS_PSTHRU	0x05000000UL
 #define SERIO_8042_XL	0x06000000UL
+#define SERIO_8042_RAW	0x07000000UL
 
 #define SERIO_PROTO	0xFFUL
 #define SERIO_MSC	0x01
--- diff/include/linux/signal.h	2004-05-19 22:13:02.000000000 +0100
+++ source/include/linux/signal.h	2004-06-11 19:22:06.000000000 +0100
@@ -7,6 +7,9 @@
 #include <asm/siginfo.h>
 
 #ifdef __KERNEL__
+
+#define MAX_SIGPENDING	1024
+
 /*
  * Real Time signals may be queued.
  */
@@ -16,6 +19,7 @@
 	spinlock_t *lock;
 	int flags;
 	siginfo_t info;
+	struct user_struct *user;
 };
 
 /* flags values. */
--- diff/include/linux/spinlock.h	2004-06-11 19:17:35.000000000 +0100
+++ source/include/linux/spinlock.h	2004-06-11 19:22:07.000000000 +0100
@@ -15,6 +15,12 @@
 
 #include <asm/processor.h>	/* for cpu relax */
 #include <asm/system.h>
+#ifdef CONFIG_KGDB
+#include <asm/current.h>
+#define SET_WHO(x, him) (x)->who = him;
+#else
+#define SET_WHO(x, him)
+#endif
 
 /*
  * Must define these before including other files, inline functions need them
@@ -57,6 +63,9 @@
 	const char *module;
 	char *owner;
 	int oline;
+#ifdef CONFIG_KGDB
+	struct task_struct *who;
+#endif
 } spinlock_t;
 #define SPIN_LOCK_UNLOCKED (spinlock_t) { SPINLOCK_MAGIC, 0, 10, __FILE__ , NULL, 0}
 
@@ -68,6 +77,7 @@
 		(x)->module = __FILE__; \
 		(x)->owner = NULL; \
 		(x)->oline = 0; \
+                SET_WHO(x, NULL) \
 	} while (0)
 
 #define CHECK_LOCK(x) \
@@ -90,6 +100,7 @@
 		(x)->lock = 1; \
 		(x)->owner = __FILE__; \
 		(x)->oline = __LINE__; \
+                SET_WHO(x, current)       \
 	} while (0)
 
 /* without debugging, spin_is_locked on UP always says
@@ -120,6 +131,7 @@
 		(x)->lock = 1; \
 		(x)->owner = __FILE__; \
 		(x)->oline = __LINE__; \
+                SET_WHO(x, current)       \
 		1; \
 	})
 
@@ -186,6 +198,17 @@
 
 #endif /* !SMP */
 
+#ifdef CONFIG_LOCKMETER
+extern void _metered_spin_lock   (spinlock_t *lock);
+extern void _metered_spin_unlock (spinlock_t *lock);
+extern int  _metered_spin_trylock(spinlock_t *lock);
+extern void _metered_read_lock    (rwlock_t *lock);
+extern void _metered_read_unlock  (rwlock_t *lock);
+extern void _metered_write_lock   (rwlock_t *lock);
+extern void _metered_write_unlock (rwlock_t *lock);
+extern int  _metered_write_trylock(rwlock_t *lock);
+#endif
+
 /*
  * Define the various spin_lock and rw_lock methods.  Note we define these
  * regardless of whether CONFIG_SMP or CONFIG_PREEMPT are set. The various
@@ -391,6 +414,141 @@
 				_raw_spin_trylock(lock) ? 1 : \
 				({preempt_enable(); local_bh_enable(); 0;});})
 
+#ifdef CONFIG_LOCKMETER
+#undef spin_lock
+#undef spin_trylock
+#undef spin_unlock
+#undef spin_lock_irqsave
+#undef spin_lock_irq
+#undef spin_lock_bh
+#undef read_lock
+#undef read_unlock
+#undef write_lock
+#undef write_unlock
+#undef write_trylock
+#undef spin_unlock_bh
+#undef read_lock_irqsave
+#undef read_lock_irq
+#undef read_lock_bh
+#undef read_unlock_bh
+#undef write_lock_irqsave
+#undef write_lock_irq
+#undef write_lock_bh
+#undef write_unlock_bh
+
+#define spin_lock(lock) \
+do { \
+	preempt_disable(); \
+	_metered_spin_lock(lock); \
+} while(0)
+
+#define spin_trylock(lock)     ({preempt_disable(); _metered_spin_trylock(lock) ? \
+				1 : ({preempt_enable(); 0;});})
+#define spin_unlock(lock) \
+do { \
+	_metered_spin_unlock(lock); \
+	preempt_enable(); \
+} while (0)
+
+#define spin_lock_irqsave(lock, flags) \
+do { \
+	local_irq_save(flags); \
+	preempt_disable(); \
+	_metered_spin_lock(lock); \
+} while (0)
+
+#define spin_lock_irq(lock) \
+do { \
+	local_irq_disable(); \
+	preempt_disable(); \
+	_metered_spin_lock(lock); \
+} while (0)
+
+#define spin_lock_bh(lock) \
+do { \
+	local_bh_disable(); \
+	preempt_disable(); \
+	_metered_spin_lock(lock); \
+} while (0)
+
+#define spin_unlock_bh(lock) \
+do { \
+	_metered_spin_unlock(lock); \
+	preempt_enable(); \
+	local_bh_enable(); \
+} while (0)
+
+
+#define read_lock(lock)                ({preempt_disable(); _metered_read_lock(lock);})
+#define read_unlock(lock)      ({_metered_read_unlock(lock); preempt_enable();})
+#define write_lock(lock)       ({preempt_disable(); _metered_write_lock(lock);})
+#define write_unlock(lock)     ({_metered_write_unlock(lock); preempt_enable();})
+#define write_trylock(lock)    ({preempt_disable();_metered_write_trylock(lock) ? \
+				1 : ({preempt_enable(); 0;});})
+#define spin_unlock_no_resched(lock) \
+do { \
+	_metered_spin_unlock(lock); \
+	preempt_enable_no_resched(); \
+} while (0)
+
+#define read_lock_irqsave(lock, flags) \
+do { \
+	local_irq_save(flags); \
+	preempt_disable(); \
+	_metered_read_lock(lock); \
+} while (0)
+
+#define read_lock_irq(lock) \
+do { \
+	local_irq_disable(); \
+	preempt_disable(); \
+	_metered_read_lock(lock); \
+} while (0)
+
+#define read_lock_bh(lock) \
+do { \
+	local_bh_disable(); \
+	preempt_disable(); \
+	_metered_read_lock(lock); \
+} while (0)
+
+#define read_unlock_bh(lock) \
+do { \
+	_metered_read_unlock(lock); \
+	preempt_enable(); \
+	local_bh_enable(); \
+} while (0)
+
+#define write_lock_irqsave(lock, flags) \
+do { \
+	local_irq_save(flags); \
+	preempt_disable(); \
+	_metered_write_lock(lock); \
+} while (0)
+
+#define write_lock_irq(lock) \
+do { \
+	local_irq_disable(); \
+	preempt_disable(); \
+	_metered_write_lock(lock); \
+} while (0)
+
+#define write_lock_bh(lock) \
+do { \
+	local_bh_disable(); \
+	preempt_disable(); \
+	_metered_write_lock(lock); \
+} while (0)
+
+#define write_unlock_bh(lock) \
+do { \
+	_metered_write_unlock(lock); \
+	preempt_enable(); \
+	local_bh_enable(); \
+} while (0)
+
+#endif /* !CONFIG_LOCKMETER */
+
 /* "lock on reference count zero" */
 #ifndef ATOMIC_DEC_AND_LOCK
 #include <asm/atomic.h>
--- diff/include/linux/sysfs.h	2004-06-11 19:17:35.000000000 +0100
+++ source/include/linux/sysfs.h	2004-06-11 19:22:07.000000000 +0100
@@ -9,6 +9,8 @@
 #ifndef _SYSFS_H_
 #define _SYSFS_H_
 
+#include <asm/atomic.h>
+
 struct kobject;
 struct module;
 
@@ -24,6 +26,27 @@
 };
 
 
+
+/**
+ * Use these macros to make defining attributes easier. See include/linux/device.h
+ * for examples..
+ */
+
+#define __ATTR(_name,_mode,_show,_store) { \
+	.attr = {.name = __stringify(_name), .mode = _mode, .owner = THIS_MODULE },	\
+	.show	= _show,					\
+	.store	= _store,					\
+}
+
+#define __ATTR_RO(_name) { \
+	.attr	= { .name = __stringify(_name), .mode = 0444, .owner = THIS_MODULE },	\
+	.show	= _name##_show,	\
+}
+
+#define __ATTR_NULL { .attr = { .name = NULL } }
+
+#define attr_name(_attr) (_attr).attr.name
+
 struct bin_attribute {
 	struct attribute	attr;
 	size_t			size;
@@ -47,6 +70,24 @@
 extern int
 sysfs_rename_dir(struct kobject *, const char *new_name);
 
+struct sysfs_dirent {
+	atomic_t		s_count;
+	struct list_head	s_sibling;
+	struct list_head	s_children;
+	void 			* s_element;
+	int			s_type;
+	umode_t			s_mode;
+	struct dentry		* s_dentry;
+};
+
+#define SYSFS_ROOT		0x0001
+#define SYSFS_KOBJECT		0x0002
+#define SYSFS_KOBJ_ATTR 	0x0004
+#define SYSFS_KOBJ_BIN_ATTR	0x0008
+#define SYSFS_KOBJ_ATTR_GROUP	0x0010
+#define SYSFS_KOBJ_LINK 	0x0020
+#define SYSFS_NOT_PINNED	(SYSFS_KOBJ_ATTR | SYSFS_KOBJ_BIN_ATTR | SYSFS_KOBJ_LINK)
+
 extern int
 sysfs_create_file(struct kobject *, const struct attribute *);
 
--- diff/include/linux/tcp.h	2004-06-11 19:17:35.000000000 +0100
+++ source/include/linux/tcp.h	2004-06-11 19:22:07.000000000 +0100
@@ -183,6 +183,9 @@
 	__u32	tcpi_snd_cwnd;
 	__u32	tcpi_advmss;
 	__u32	tcpi_reordering;
+
+	__u32	tcpi_rcv_rtt;
+	__u32	tcpi_rcv_space;
 };
 
 #ifdef __KERNEL__
@@ -351,11 +354,11 @@
 	__u8	urg_mode;	/* In urgent mode		*/
 	__u32	snd_up;		/* Urgent pointer		*/
 
-	/* The syn_wait_lock is necessary only to avoid tcp_get_info having
+	/* The syn_wait_lock is necessary only to avoid proc interface having
 	 * to grab the main lock sock while browsing the listening hash
 	 * (otherwise it's deadlock prone).
-	 * This lock is acquired in read mode only from tcp_get_info() and
-	 * it's acquired in write mode _only_ from code that is actively
+	 * This lock is acquired in read mode only from listening_get_next()
+	 * and it's acquired in write mode _only_ from code that is actively
 	 * changing the syn_wait_queue. All readers that are holding
 	 * the master sock lock don't need to grab this lock in read mode
 	 * too as the syn_wait_queue writes are always protected from
--- diff/include/linux/udf_fs.h	2004-05-19 22:13:03.000000000 +0100
+++ source/include/linux/udf_fs.h	2004-06-11 19:22:07.000000000 +0100
@@ -40,7 +40,7 @@
 #define UDFFS_DATE			"2004/29/09"
 #define UDFFS_VERSION			"0.9.8.1"
 
-#define UDFFS_DEBUG
+#undef UDFFS_DEBUG
 
 #ifdef UDFFS_DEBUG
 #define udf_debug(f, a...) \
--- diff/include/linux/usb.h	2004-06-11 19:17:35.000000000 +0100
+++ source/include/linux/usb.h	2004-06-11 19:22:07.000000000 +0100
@@ -334,6 +334,7 @@
 
 /* mostly for devices emulating SCSI over USB */
 extern int usb_reset_device(struct usb_device *dev);
+extern int __usb_reset_device(struct usb_device *dev);
 
 extern struct usb_device *usb_find_device(u16 vendor_id, u16 product_id);
 
--- diff/include/linux/vmalloc.h	2004-05-19 22:13:03.000000000 +0100
+++ source/include/linux/vmalloc.h	2004-06-11 19:22:07.000000000 +0100
@@ -23,6 +23,7 @@
  *	Highlevel APIs for driver use
  */
 extern void *vmalloc(unsigned long size);
+extern void *vmalloc_exec(unsigned long size);
 extern void *vmalloc_32(unsigned long size);
 extern void *__vmalloc(unsigned long size, int gfp_mask, pgprot_t prot);
 extern void vfree(void *addr);
--- diff/include/scsi/scsi_driver.h	2004-05-19 22:13:07.000000000 +0100
+++ source/include/scsi/scsi_driver.h	2004-06-11 19:22:07.000000000 +0100
@@ -13,6 +13,7 @@
 
 	int (*init_command)(struct scsi_cmnd *);
 	void (*rescan)(struct device *);
+	int (*issue_flush)(struct device *, sector_t *);
 };
 #define to_scsi_driver(drv) \
 	container_of((drv), struct scsi_driver, gendrv)
--- diff/include/scsi/scsi_eh.h	2004-05-19 22:13:07.000000000 +0100
+++ source/include/scsi/scsi_eh.h	2004-06-11 19:22:07.000000000 +0100
@@ -1,6 +1,10 @@
 #ifndef _SCSI_SCSI_EH_H
 #define _SCSI_SCSI_EH_H
 
+struct scsi_cmnd;
+struct scsi_device;
+struct Scsi_Host;
+
 extern void scsi_add_timer(struct scsi_cmnd *, int,
 			   void (*)(struct scsi_cmnd *));
 extern int scsi_delete_timer(struct scsi_cmnd *);
--- diff/include/scsi/scsi_host.h	2004-05-19 22:13:07.000000000 +0100
+++ source/include/scsi/scsi_host.h	2004-06-11 19:22:07.000000000 +0100
@@ -151,7 +151,7 @@
 	 * here then you will get a call to slave_configure(), then the
 	 * device will be used for however long it is kept around, then when
 	 * the device is removed from the system (or * possibly at reboot
-	 * time), you will then get a call to slave_detach().  This is
+	 * time), you will then get a call to slave_destroy().  This is
 	 * assuming you implement slave_configure and slave_destroy.
 	 * However, if you allocate memory and hang it off the device struct,
 	 * then you must implement the slave_destroy() routine at a minimum
@@ -185,7 +185,7 @@
 	 *     specific setup basis...
 	 * 6.  Return 0 on success, non-0 on error.  The device will be marked
 	 *     as offline on error so that no access will occur.  If you return
-	 *     non-0, your slave_detach routine will never get called for this
+	 *     non-0, your slave_destroy routine will never get called for this
 	 *     device, so don't leave any loose memory hanging around, clean
 	 *     up after yourself before returning non-0
 	 *
@@ -314,6 +314,11 @@
 	unsigned emulated:1;
 
 	/*
+	 * True if the low-level driver performs its own reset-settle delays.
+	 */
+	unsigned skip_settle_delay:1;
+
+	/*
 	 * Countdown for host blocking with no commands outstanding
 	 */
 	unsigned int max_host_blocked;
--- diff/include/sound/ac97_codec.h	2004-06-11 19:17:35.000000000 +0100
+++ source/include/sound/ac97_codec.h	2004-06-11 19:22:07.000000000 +0100
@@ -441,6 +441,7 @@
 	unsigned short subsystem_vendor;
 	unsigned short subsystem_device;
 	spinlock_t reg_lock;
+	struct semaphore mutex;	/* mutex for AD18xx multi-codecs and paging (2.3) */
 	unsigned short num;	/* number of codec: 0 = primary, 1 = secondary */
 	unsigned short addr;	/* physical address of codec [0-3] */
 	unsigned int id;	/* identification of codec */
@@ -461,7 +462,6 @@
 			unsigned short id[3];		// codec IDs (lower 16-bit word)
 			unsigned short pcmreg[3];	// PCM registers
 			unsigned short codec_cfg[3];	// CODEC_CFG bits
-			struct semaphore mutex;
 		} ad18xx;
 		unsigned int dev_flags;		/* device specific */
 	} spec;
@@ -484,6 +484,10 @@
 {
 	return (ac97->ext_id & AC97_EI_AMAP) != 0;
 }
+static inline int ac97_can_spdif(ac97_t * ac97)
+{
+	return (ac97->ext_id & AC97_EI_SPDIF) != 0;
+}
 
 /* functions */
 int snd_ac97_bus(snd_card_t * card, ac97_bus_t * _bus, ac97_bus_t ** rbus); /* create new AC97 bus */
--- diff/include/sound/core.h	2004-06-11 19:17:35.000000000 +0100
+++ source/include/sound/core.h	2004-06-11 19:22:07.000000000 +0100
@@ -211,12 +211,14 @@
 				 void *private_data);
 #define snd_card_set_isa_pm_callback(card,suspend,resume,data) \
 	snd_card_set_dev_pm_callback(card, PM_ISA_DEV, suspend, resume, data)
+#ifdef CONFIG_PCI
 #ifndef SND_PCI_PM_CALLBACKS
 int snd_card_pci_suspend(struct pci_dev *dev, u32 state);
 int snd_card_pci_resume(struct pci_dev *dev);
 #define SND_PCI_PM_CALLBACKS \
 	.suspend = snd_card_pci_suspend,  .resume = snd_card_pci_resume
 #endif
+#endif
 #else
 #define snd_power_lock(card)		do { (void)(card); } while (0)
 #define snd_power_unlock(card)		do { (void)(card); } while (0)
@@ -226,8 +228,10 @@
 #define snd_card_set_pm_callback(card,suspend,resume,data) -EINVAL
 #define snd_card_set_dev_pm_callback(card,suspend,resume,data) -EINVAL
 #define snd_card_set_isa_pm_callback(card,suspend,resume,data) -EINVAL
+#ifdef CONFIG_PCI
 #define SND_PCI_PM_CALLBACKS
 #endif
+#endif
 
 /* device.c */
 
--- diff/include/sound/seq_kernel.h	2004-06-11 19:17:35.000000000 +0100
+++ source/include/sound/seq_kernel.h	2004-06-11 19:22:07.000000000 +0100
@@ -168,6 +168,9 @@
 int snd_seq_expand_var_event(const snd_seq_event_t *event, int count, char *buf, int in_kernel, int size_aligned);
 int snd_seq_dump_var_event(const snd_seq_event_t *event, snd_seq_dump_func_t func, void *private_data);
 
+/* interface for OSS emulation */
+int snd_seq_set_queue_tempo(int client, snd_seq_queue_tempo_t *tempo);
+
 /* port callback routines */
 void snd_port_init_callback(snd_seq_port_callback_t *p);
 snd_seq_port_callback_t *snd_port_alloc_callback(void);
--- diff/include/sound/version.h	2004-06-11 19:17:35.000000000 +0100
+++ source/include/sound/version.h	2004-06-11 19:22:07.000000000 +0100
@@ -1,3 +1,3 @@
 /* include/version.h.  Generated by configure.  */
-#define CONFIG_SND_VERSION "1.0.4"
-#define CONFIG_SND_DATE " (Mon May 17 14:31:44 2004 UTC)"
+#define CONFIG_SND_VERSION "1.0.5"
+#define CONFIG_SND_DATE " (Sun May 30 10:49:40 2004 UTC)"
--- diff/include/sound/vx_core.h	2004-06-11 19:17:35.000000000 +0100
+++ source/include/sound/vx_core.h	2004-06-11 19:22:07.000000000 +0100
@@ -182,6 +182,7 @@
 	/* clock and audio sources */
 	unsigned int audio_source;	/* current audio input source */
 	unsigned int audio_source_target;
+	unsigned int clock_mode;	/* clock mode (VX_CLOCK_MODE_XXX) */
 	unsigned int clock_source;	/* current clock source (INTERNAL_QUARTZ or UER_SYNC) */
 	unsigned int freq;		/* current frequency */
 	unsigned int freq_detected;	/* detected frequency from digital in */
@@ -364,6 +365,13 @@
 	UER_SYNC
 };
 
+/* clock mode */
+enum {
+	VX_CLOCK_MODE_AUTO,	/* depending on the current audio source */
+	VX_CLOCK_MODE_INTERNAL,	/* fixed to internal quartz */
+	VX_CLOCK_MODE_EXTERNAL	/* fixed to UER sync */
+};
+
 /* SPDIF/UER type */
 enum {
 	VX_UER_MODE_CONSUMER,
--- diff/include/video/sisfb.h	2004-05-19 22:13:08.000000000 +0100
+++ source/include/video/sisfb.h	2004-06-11 19:22:07.000000000 +0100
@@ -38,7 +38,8 @@
 #define TV_AVIDEO               0x00000100
 #define TV_SVIDEO               0x00000200
 #define TV_SCART                0x00000400
-#define VB_CONEXANT		0x00000800
+#define VB_CONEXANT		0x00000800	/* 661 series only */
+#define VB_TRUMPION		VB_CONEXANT	/* 300 series only */
 #define TV_PALM                 0x00001000
 #define TV_PALN                 0x00002000
 #define TV_NTSCJ		0x00001000
@@ -86,204 +87,112 @@
 #define VB_DISPMODE_DUAL	VB_DUALVIEW_MODE
 #define VB_DISPLAY_MODE       	(SINGLE_MODE | MIRROR_MODE | DUALVIEW_MODE)
 
-/* *Never* change the order of the following enum */
-typedef enum _SIS_CHIP_TYPE {
-	SIS_VGALegacy = 0,	/* chip_id in sisfb_info */
-	SIS_300,
-	SIS_630,
-	SIS_540,
-	SIS_730,
-	SIS_315H,
-	SIS_315,
-	SIS_315PRO,
-	SIS_550,
-	SIS_650,
-	SIS_740,
-	SIS_330,
-	SIS_661,
-	SIS_741,
-	SIS_660,
-	SIS_760,
-	MAX_SIS_CHIP
-} SIS_CHIP_TYPE;
-
-/* Addtional IOCTLs for communication sisfb <> X driver                */
-/* If changing this, vgatypes.h must also be changed (for X driver)    */
-
-/* ioctl for identifying and giving some info (esp. memory heap start) */
-#define SISFB_GET_INFO	  	_IOR('n',0xF8,__u32)
-/* ioctrl to get current vertical retrace status */
-#define SISFB_GET_VBRSTATUS  	_IOR('n',0xF9,__u32)
-/* ioctl to enable/disable panning auto-maximize (like nomax parameter) */
-#define SISFB_GET_AUTOMAXIMIZE 	_IOR('n',0xFA,__u32)
-#define SISFB_SET_AUTOMAXIMIZE 	_IOW('n',0xFA,__u32)
-
-/* TW: Structure argument for SISFB_GET_INFO ioctl  */
+/* Structure argument for SISFB_GET_INFO ioctl  */
 typedef struct _SISFB_INFO sisfb_info, *psisfb_info;
 
 struct _SISFB_INFO {
-	unsigned long sisfb_id;         /* for identifying sisfb */
+	__u32   sisfb_id;         	/* for identifying sisfb */
 #ifndef SISFB_ID
 #define SISFB_ID	  0x53495346    /* Identify myself with 'SISF' */
 #endif
- 	int    chip_id;			/* PCI ID of detected chip */
-	int    memory;			/* video memory in KB which sisfb manages */
-	int    heapstart;               /* heap start (= sisfb "mem" argument) in KB */
-	unsigned char fbvidmode;	/* current sisfb mode */
+ 	__u32   chip_id;		/* PCI-ID of detected chip */
+	__u32   memory;			/* video memory in KB which sisfb manages */
+	__u32   heapstart;            	/* heap start (= sisfb "mem" argument) in KB */
+	__u8    fbvidmode;		/* current sisfb mode */
 
-	unsigned char sisfb_version;
-	unsigned char sisfb_revision;
-	unsigned char sisfb_patchlevel;
+	__u8    sisfb_version;
+	__u8    sisfb_revision;
+	__u8 	sisfb_patchlevel;
 
-	unsigned char sisfb_caps;	/* Sisfb capabilities */
+	__u8 	sisfb_caps;		/* sisfb capabilities */
 
-	int    sisfb_tqlen;		/* turbo queue length (in KB) */
+	__u32	sisfb_tqlen;		/* turbo queue length (in KB) */
 
-	unsigned int sisfb_pcibus;      /* The card's PCI ID */
-	unsigned int sisfb_pcislot;
-	unsigned int sisfb_pcifunc;
+	__u32 	sisfb_pcibus;      	/* The card's PCI ID */
+	__u32 	sisfb_pcislot;
+	__u32 	sisfb_pcifunc;
 
-	unsigned char sisfb_lcdpdc;	/* PanelDelayCompensation */
+	__u8 	sisfb_lcdpdc;		/* PanelDelayCompensation */
 
-	unsigned char sisfb_lcda;	/* Detected status of LCDA for low res/text modes */
+	__u8 	sisfb_lcda;		/* Detected status of LCDA for low res/text modes */
 
-	unsigned long sisfb_vbflags;
-	unsigned long sisfb_currentvbflags;
+	__u32 	sisfb_vbflags;
+	__u32 	sisfb_currentvbflags;
 
-	int sisfb_scalelcd;
-	unsigned long sisfb_specialtiming;
+	__u32 	sisfb_scalelcd;
+	__u32 	sisfb_specialtiming;
 
-	unsigned char sisfb_haveemi;
-	unsigned char sisfb_emi30,sisfb_emi31,sisfb_emi32,sisfb_emi33;
-	unsigned char sisfb_haveemilcd;
+	__u8 	sisfb_haveemi;
+	__u8 	sisfb_emi30,sisfb_emi31,sisfb_emi32,sisfb_emi33;
+	__u8 	sisfb_haveemilcd;
 
-	char reserved[213]; 		/* for future use */
-};
+	__u8 	sisfb_lcdpdca;		/* PanelDelayCompensation for LCD-via-CRT1 */
 
-/* For fb memory manager */
-struct sis_memreq {
-	unsigned long offset;
-	unsigned long size;
-};
+	__u16	sisfb_tvxpos, sisfb_tvypos;  /* Warning: Values + 32 ! */
 
-/* More or less deprecated stuff follows: */
-typedef enum _TVTYPE {
-	TVMODE_NTSC = 0,
-	TVMODE_PAL,
-	TVMODE_HIVISION,
-	TVMODE_TOTAL
-} SIS_TV_TYPE;
-
-typedef enum _TVPLUGTYPE {
-	TVPLUG_Legacy = 0,
-	TVPLUG_COMPOSITE,
-	TVPLUG_SVIDEO,
-	TVPLUG_SCART,
-	TVPLUG_TOTAL
-} SIS_TV_PLUG;
-
-struct mode_info {
-	int    bpp;
-	int    xres;
-	int    yres;
-	int    v_xres;		/* deprecated - use var instead */
-	int    v_yres;		/* deprecated - use var instead */
-	int    org_x;		/* deprecated - use var instead */
-	int    org_y;		/* deprecated - use var instead */
-	unsigned int  vrate;
+	__u8 	reserved[208]; 		/* for future use */
 };
 
-struct ap_data {
-	struct mode_info minfo;
-	unsigned long iobase;
-	unsigned int  mem_size;
-	unsigned long disp_state;  /* deprecated */
-	SIS_CHIP_TYPE chip;
-	unsigned char hasVB;
-	SIS_TV_TYPE TV_type;	   /* deprecated */
-	SIS_TV_PLUG TV_plug;	   /* deprecated */
-	unsigned long version;
-	unsigned long vbflags;	   /* replaces deprecated entries above */
-	unsigned long currentvbflags;
-	char reserved[248];
+/* Addtional IOCTLs for communication sisfb <> X driver                */
+/* If changing this, vgatypes.h must also be changed (for X driver)    */
+
+/* ioctl for identifying and giving some info (esp. memory heap start) */
+#define SISFB_GET_INFO_SIZE  	_IOR(0xF3,0x00,__u32)
+#define SISFB_GET_INFO	  	_IOR(0xF3,0x01,struct _SISFB_INFO)
+
+/* ioctrl to get current vertical retrace status */
+#define SISFB_GET_VBRSTATUS  	_IOR(0xF3,0x02,__u32)
+
+/* ioctl to enable/disable panning auto-maximize (like nomax parameter) */
+#define SISFB_GET_AUTOMAXIMIZE 	_IOR(0xF3,0x03,__u32)
+#define SISFB_SET_AUTOMAXIMIZE 	_IOW(0xF3,0x03,__u32)
+
+/* ioctls to relocate TV output (x=D[31:16], y=D[15:0], + 32)*/
+#define SISFB_GET_TVPOSOFFSET   _IOR(0xF3,0x04,__u32)
+#define SISFB_SET_TVPOSOFFSET   _IOW(0xF3,0x04,__u32)
+
+/* ioctl for locking sisfb (no register access during lock) */
+/* As of now, only used to avoid register access during
+ * the ioctls listed above.
+ */
+#define SISFB_SET_LOCK  	_IOW(0xF3,0x06,__u32)
+
+/* more to come soon */
+
+/* ioctls 0xF3 up to 0x3F reserved for sisfb */
+
+/****************************************************************/
+/* The following are deprecated and should not be used anymore: */
+/****************************************************************/
+/* ioctl for identifying and giving some info (esp. memory heap start) */
+#define SISFB_GET_INFO_OLD  	   _IOR('n',0xF8,__u32)
+/* ioctrl to get current vertical retrace status */
+#define SISFB_GET_VBRSTATUS_OLD	   _IOR('n',0xF9,__u32)
+/* ioctl to enable/disable panning auto-maximize (like nomax parameter) */
+#define SISFB_GET_AUTOMAXIMIZE_OLD _IOR('n',0xFA,__u32)
+#define SISFB_SET_AUTOMAXIMIZE_OLD _IOW('n',0xFA,__u32)
+/****************************************************************/
+/*               End of deprecated ioctl numbers                */
+/****************************************************************/
+
+/* For fb memory manager (FBIO_ALLOC, FBIO_FREE) */
+struct sis_memreq {
+	__u32 	offset;
+	__u32 	size;
 };
 
 /**********************************************/
 /*                  PRIVATE                   */
+/*         (for IN-KERNEL usage only)         */
 /**********************************************/
 
 #ifdef __KERNEL__
-#include <linux/spinlock.h>
-
-typedef enum _VGA_ENGINE {
-	UNKNOWN_VGA = 0,
-	SIS_300_VGA,
-	SIS_315_VGA,
-} VGA_ENGINE;
-
-struct video_info {
-	int           chip_id;
-	unsigned int  video_size;
-	unsigned long video_base;
-	char  *       video_vbase;
-	unsigned long mmio_base;
-	char  *       mmio_vbase;
-	unsigned long vga_base;
-	unsigned long mtrr;
-	unsigned long heapstart;
-
-	int    video_bpp;
-	int    video_cmap_len;
-	int    video_width;
-	int    video_height;
-	int    video_vwidth;			/* DEPRECATED - use var instead */
-	int    video_vheight;			/* DEPRECATED - use var instead */
-	int    org_x;				/* DEPRECATED - use var instead */
-	int    org_y;				/* DEPRECATED - use var instead */
-	int    video_linelength;
-	unsigned int refresh_rate;
-
-	unsigned long disp_state;		/* DEPRECATED */
-	unsigned char hasVB;			/* DEPRECATED */
-	unsigned char TV_type;			/* DEPRECATED */
-	unsigned char TV_plug;			/* DEPRECATED */
-
-	SIS_CHIP_TYPE chip;
-	unsigned char revision_id;
-
-        unsigned short DstColor;		/* For 2d acceleration */
-	unsigned long  SiS310_AccelDepth;
-	unsigned long  CommandReg;
-
-	spinlock_t     lockaccel;		/* Do not use outside of kernel! */
-
-        unsigned int   pcibus;
-	unsigned int   pcislot;
-	unsigned int   pcifunc;
-
-	int 	       accel;
-
-	unsigned short subsysvendor;
-	unsigned short subsysdevice;
-
-	unsigned long  vbflags;			/* Replacing deprecated stuff from above */
-	unsigned long  currentvbflags;
-
-	int    current_bpp;
-	int    current_width;
-	int    current_height;
-	int    current_htotal;
-	int    current_vtotal;
-	__u32  current_pixclock;
-	int    current_refresh_rate;
-
-	char reserved[200];
-};
-
-extern struct video_info ivideo;
+#define	UNKNOWN_VGA  0
+#define	SIS_300_VGA  1
+#define	SIS_315_VGA  2
 
 extern void sis_malloc(struct sis_memreq *req);
-extern void sis_free(unsigned long base);
-extern void sis_dispinfo(struct ap_data *rec);
+extern void sis_free(u32 base);
 #endif
+
 #endif
--- diff/init/Kconfig	2004-06-11 19:17:35.000000000 +0100
+++ source/init/Kconfig	2004-06-11 19:22:07.000000000 +0100
@@ -50,6 +50,15 @@
 
 	  If unsure, say Y.
 
+config M68K_TOOLCHAIN
+	bool "Enable selection of firmware which requires an m68k toolchain"
+	default n
+	help
+	  Select this option if you have the as68k, ld68k and hexdump programs
+	  and wish to rebuild m68k assembly-language firmware (wanxl uses this)
+
+	  If unsure, say N.
+
 config BROKEN
 	bool
 	depends on !CLEAN_COMPILE
@@ -121,6 +130,18 @@
 	  up to the user level program to do useful things with this
 	  information.  This is generally a good idea, so say Y.
 
+config BSD_PROCESS_ACCT_V3
+	bool "BSD Process Accounting version 3 file format"
+	depends on BSD_PROCESS_ACCT
+	default n
+	help
+	  If you say Y here, the process accounting information is written
+	  in a new file format that also logs the process IDs of each
+	  process and it's parent. Note that this file format is incompatible
+	  with previous v0/v1/v2 file formats, so you will need updated tools
+	  for processing it. A preliminary version of these tools is available
+	  at <http://http://www.de.kernel.org/pub/linux/utils/>.
+
 config SYSCTL
 	bool "Sysctl support"
 	---help---
--- diff/init/main.c	2004-06-11 19:17:35.000000000 +0100
+++ source/init/main.c	2004-06-11 19:22:07.000000000 +0100
@@ -43,6 +43,7 @@
 #include <linux/efi.h>
 #include <linux/unistd.h>
 #include <linux/rmap.h>
+#include <linux/mempolicy.h>
 
 #include <asm/io.h>
 #include <asm/bugs.h>
@@ -110,6 +111,9 @@
 void (*late_time_init)(void);
 extern void softirq_init(void);
 
+/* Untouched command line (eg. for /proc) saved by arch-specific code. */
+char saved_command_line[COMMAND_LINE_SIZE];
+
 static char *execute_command;
 
 /* Setup configured maximum number of CPUs to activate */
@@ -156,8 +160,14 @@
 	do {
 		int n = strlen(p->str);
 		if (!strncmp(line, p->str, n)) {
-			if (!p->setup_func) {
-				printk(KERN_WARNING "Parameter %s is obsolete, ignored\n", p->str);
+			if (p->early) {
+				/* Already done in parse_early_param?  (Needs
+				 * exact match on param part) */
+				if (line[n] == '\0' || line[n] == '=')
+					return 1;
+			} else if (!p->setup_func) {
+				printk(KERN_WARNING "Parameter %s is obsolete,"
+				       " ignored\n", p->str);
 				return 1;
 			} else if (p->setup_func(line + n))
 				return 1;
@@ -385,10 +395,43 @@
 static void noinline rest_init(void)
 {
 	kernel_thread(init, NULL, CLONE_FS | CLONE_SIGHAND);
+	numa_default_policy();
 	unlock_kernel();
  	cpu_idle();
 } 
 
+/* Check for early params. */
+static int __init do_early_param(char *param, char *val)
+{
+	struct obs_kernel_param *p;
+	extern struct obs_kernel_param __setup_start, __setup_end;
+
+	for (p = &__setup_start; p < &__setup_end; p++) {
+		if (p->early && strcmp(param, p->str) == 0) {
+			if (p->setup_func(val) != 0)
+				printk(KERN_WARNING
+				       "Malformed early option '%s'\n", param);
+		}
+	}
+	/* We accept everything at this stage. */
+	return 0;
+}
+
+/* Arch code calls this early on, or if not, just before other parsing. */
+void __init parse_early_param(void)
+{
+	static __initdata int done = 0;
+	static __initdata char tmp_cmdline[COMMAND_LINE_SIZE];
+
+	if (done)
+		return;
+
+	/* All fall through to do_early_param. */
+	strlcpy(tmp_cmdline, saved_command_line, COMMAND_LINE_SIZE);
+	parse_args("early options", tmp_cmdline, NULL, 0, do_early_param);
+	done = 1;
+}
+
 /*
  *	Activate the first processor.
  */
@@ -396,7 +439,6 @@
 asmlinkage void __init start_kernel(void)
 {
 	char * command_line;
-	extern char saved_command_line[];
 	extern struct kernel_param __start___param[], __stop___param[];
 /*
  * Interrupts are still disabled. Do necessary setups, then
@@ -423,12 +465,13 @@
 
 	build_all_zonelists();
 	page_alloc_init();
+	trap_init();
 	printk("Kernel command line: %s\n", saved_command_line);
+	parse_early_param();
 	parse_args("Booting kernel", command_line, __start___param,
 		   __stop___param - __start___param,
 		   &unknown_bootoption);
 	sort_main_extable();
-	trap_init();
 	rcu_init();
 	init_IRQ();
 	pidhash_init();
@@ -456,6 +499,7 @@
 #endif
 	mem_init();
 	kmem_cache_init();
+	numa_policy_init();
 	if (late_time_init)
 		late_time_init();
 	calibrate_delay();
@@ -645,6 +689,7 @@
 	free_initmem();
 	unlock_kernel();
 	system_state = SYSTEM_RUNNING;
+	numa_default_policy();
 
 	if (sys_open((const char __user *) "/dev/console", O_RDWR, 0) < 0)
 		printk("Warning: unable to open an initial console.\n");
@@ -669,3 +714,16 @@
 
 	panic("No init found.  Try passing init= option to kernel.");
 }
+
+static int early_param_test(char *rest)
+{
+	printk("early_parm_test: %s\n", rest ?: "(null)");
+	return rest ? 0 : -EINVAL;
+}
+early_param("testsetup", early_param_test);
+static int early_setup_test(char *rest)
+{
+	printk("early_setup_test: %s\n", rest ?: "(null)");
+	return 0;
+}
+__setup("testsetup_long", early_setup_test);
--- diff/ipc/mqueue.c	2004-06-11 19:17:35.000000000 +0100
+++ source/ipc/mqueue.c	2004-06-11 19:22:07.000000000 +0100
@@ -43,10 +43,10 @@
 #define CTL_MSGSIZEMAX 	4
 
 /* default values */
-#define DFLT_QUEUESMAX	64	/* max number of message queues */
-#define DFLT_MSGMAX 	40	/* max number of messages in each queue */
+#define DFLT_QUEUESMAX	256	/* max number of message queues */
+#define DFLT_MSGMAX 	10	/* max number of messages in each queue */
 #define HARD_MSGMAX 	(131072/sizeof(void*))
-#define DFLT_MSGSIZEMAX 16384	/* max message size */
+#define DFLT_MSGSIZEMAX 8192	/* max message size */
 
 #define NOTIFY_COOKIE_LEN	32
 
@@ -67,6 +67,7 @@
 
 	struct sigevent notify;
 	pid_t notify_owner;
+ 	struct user_struct *user;	/* user who created, for accouting */
 	struct sock *notify_sock;
 	struct sk_buff *notify_cookie;
 
@@ -114,6 +115,9 @@
 
 		if (S_ISREG(mode)) {
 			struct mqueue_inode_info *info;
+			struct task_struct *p = current;
+			struct user_struct *u = p->user;
+			unsigned long mq_bytes, mq_msg_tblsz;
 
 			inode->i_fop = &mqueue_file_operations;
 			inode->i_size = FILENT_SIZE;
@@ -123,8 +127,10 @@
 			init_waitqueue_head(&info->wait_q);
 			INIT_LIST_HEAD(&info->e_wait_q[0].list);
 			INIT_LIST_HEAD(&info->e_wait_q[1].list);
+			info->messages = NULL;
 			info->notify_owner = 0;
 			info->qsize = 0;
+			info->user = NULL;	/* set when all is ok */
 			memset(&info->attr, 0, sizeof(info->attr));
 			info->attr.mq_maxmsg = DFLT_MSGMAX;
 			info->attr.mq_msgsize = DFLT_MSGSIZEMAX;
@@ -132,12 +138,29 @@
 				info->attr.mq_maxmsg = attr->mq_maxmsg;
 				info->attr.mq_msgsize = attr->mq_msgsize;
 			}
-			info->messages = kmalloc(info->attr.mq_maxmsg * sizeof(struct msg_msg *), GFP_KERNEL);
+			mq_msg_tblsz = info->attr.mq_maxmsg * sizeof(struct msg_msg *);
+			mq_bytes = (mq_msg_tblsz +
+				(info->attr.mq_maxmsg * info->attr.mq_msgsize));
+
+			spin_lock(&mq_lock);
+			if (u->mq_bytes + mq_bytes < u->mq_bytes ||
+		 	    u->mq_bytes + mq_bytes >
+			    p->rlim[RLIMIT_MSGQUEUE].rlim_cur) {
+				spin_unlock(&mq_lock);
+				goto out_inode;
+			}
+			u->mq_bytes += mq_bytes;
+			spin_unlock(&mq_lock);
+
+			info->messages = kmalloc(mq_msg_tblsz, GFP_KERNEL);
 			if (!info->messages) {
-				make_bad_inode(inode);
-				iput(inode);
-				inode = NULL;
+				spin_lock(&mq_lock);
+				u->mq_bytes -= mq_bytes;
+				spin_unlock(&mq_lock);
+				goto out_inode;
 			}
+			/* all is ok */
+			info->user = get_uid(u);
 		} else if (S_ISDIR(mode)) {
 			inode->i_nlink++;
 			/* Some things misbehave if size == 0 on a directory */
@@ -147,6 +170,10 @@
 		}
 	}
 	return inode;
+out_inode:
+	make_bad_inode(inode);
+	iput(inode);
+	return NULL;
 }
 
 static int mqueue_fill_super(struct super_block *sb, void *data, int silent)
@@ -205,6 +232,8 @@
 static void mqueue_delete_inode(struct inode *inode)
 {
 	struct mqueue_inode_info *info;
+	struct user_struct *user;
+	unsigned long mq_bytes;
 	int i;
 
 	if (S_ISDIR(inode->i_mode)) {
@@ -220,10 +249,15 @@
 
 	clear_inode(inode);
 
-	if (info->messages) {
+	mq_bytes = (info->attr.mq_maxmsg * sizeof(struct msg_msg *) +
+		   (info->attr.mq_maxmsg * info->attr.mq_msgsize));
+	user = info->user;
+	if (user) {
 		spin_lock(&mq_lock);
+		user->mq_bytes -= mq_bytes;
 		queues_count--;
 		spin_unlock(&mq_lock);
+		free_uid(user);
 	}
 }
 
@@ -534,6 +568,28 @@
 	info->notify_owner = 0;
 }
 
+static int mq_attr_ok(struct mq_attr *attr)
+{
+	if (attr->mq_maxmsg <= 0 || attr->mq_msgsize <= 0)
+		return 0;
+	if (capable(CAP_SYS_RESOURCE)) {
+		if (attr->mq_maxmsg > HARD_MSGMAX)
+			return 0;
+	} else {
+		if (attr->mq_maxmsg > msg_max ||
+				attr->mq_msgsize > msgsize_max)
+			return 0;
+	}
+	/* check for overflow */
+	if (attr->mq_msgsize > ULONG_MAX/attr->mq_maxmsg)
+		return 0;
+	if ((unsigned long)(attr->mq_maxmsg * attr->mq_msgsize) +
+	    (attr->mq_maxmsg * sizeof (struct msg_msg *)) <
+	    (unsigned long)(attr->mq_maxmsg * attr->mq_msgsize))
+		return 0;
+	return 1;
+}
+
 /*
  * Invoked when creating a new queue via sys_mq_open
  */
@@ -547,17 +603,8 @@
 	if (u_attr != NULL) {
 		if (copy_from_user(&attr, u_attr, sizeof(attr)))
 			return ERR_PTR(-EFAULT);
-
-		if (attr.mq_maxmsg <= 0 || attr.mq_msgsize <= 0)
+		if (!mq_attr_ok(&attr))
 			return ERR_PTR(-EINVAL);
-		if (capable(CAP_SYS_RESOURCE)) {
-			if (attr.mq_maxmsg > HARD_MSGMAX)
-				return ERR_PTR(-EINVAL);
-		} else {
-			if (attr.mq_maxmsg > msg_max ||
-					attr.mq_msgsize > msgsize_max)
-				return ERR_PTR(-EINVAL);
-		}
 		/* store for use during create */
 		dentry->d_fsdata = &attr;
 	}
--- diff/ipc/shm.c	2004-06-11 19:17:35.000000000 +0100
+++ source/ipc/shm.c	2004-06-11 19:22:07.000000000 +0100
@@ -796,10 +796,12 @@
 		 */
 		if ((vma->vm_ops == &shm_vm_ops || is_vm_hugetlb_page(vma)) &&
 			(vma->vm_start - addr)/PAGE_SIZE == vma->vm_pgoff) {
-
+			int ret;
 
 			size = vma->vm_file->f_dentry->d_inode->i_size;
-			do_munmap(mm, vma->vm_start, vma->vm_end - vma->vm_start);
+			ret = do_munmap(mm, vma->vm_start,
+					vma->vm_end - vma->vm_start);
+			WARN_ON(ret);
 			/*
 			 * We discovered the size of the shm segment, so
 			 * break out of here and fall through to the next
@@ -823,9 +825,13 @@
 
 		/* finding a matching vma now does not alter retval */
 		if ((vma->vm_ops == &shm_vm_ops || is_vm_hugetlb_page(vma)) &&
-			(vma->vm_start - addr)/PAGE_SIZE == vma->vm_pgoff)
+			(vma->vm_start - addr)/PAGE_SIZE == vma->vm_pgoff) {
+			int ret;
 
-			do_munmap(mm, vma->vm_start, vma->vm_end - vma->vm_start);
+			ret = do_munmap(mm, vma->vm_start,
+					vma->vm_end - vma->vm_start);
+			WARN_ON(ret);
+		}
 		vma = next;
 	}
 
--- diff/kernel/Makefile	2004-05-19 22:13:09.000000000 +0100
+++ source/kernel/Makefile	2004-06-11 19:22:07.000000000 +0100
@@ -12,6 +12,7 @@
 obj-$(CONFIG_FUTEX) += futex.o
 obj-$(CONFIG_GENERIC_ISA_DMA) += dma.o
 obj-$(CONFIG_SMP) += cpu.o
+obj-$(CONFIG_LOCKMETER) += lockmeter.o
 obj-$(CONFIG_UID16) += uid16.o
 obj-$(CONFIG_MODULES) += module.o
 obj-$(CONFIG_KALLSYMS) += kallsyms.o
--- diff/kernel/acct.c	2004-06-11 19:17:35.000000000 +0100
+++ source/kernel/acct.c	2004-06-11 19:22:07.000000000 +0100
@@ -302,6 +302,69 @@
 	return exp;
 }
 
+#if ACCT_VERSION==1 || ACCT_VERSION==2
+/*
+ * encode an u64 into a comp2_t (24 bits)
+ *
+ * Format: 5 bit base 2 exponent, 20 bits mantissa.
+ * The leading bit of the mantissa is not stored, but implied for
+ * non-zero exponents.
+ * Largest encodable value is 50 bits.
+ */
+
+#define MANTSIZE2       20                      /* 20 bit mantissa. */
+#define EXPSIZE2        5                       /* 5 bit base 2 exponent. */
+#define MAXFRACT2       ((1ul << MANTSIZE2) - 1) /* Maximum fractional value. */
+#define MAXEXP2         ((1 <<EXPSIZE2) - 1)    /* Maximum exponent. */
+
+static comp2_t encode_comp2_t(u64 value)
+{
+        int exp, rnd;
+
+        exp = (value > (MAXFRACT2>>1));
+        rnd = 0;
+        while (value > MAXFRACT2) {
+                rnd = value & 1;
+                value >>= 1;
+                exp++;
+        }
+
+        /*
+         * If we need to round up, do it (and handle overflow correctly).
+         */
+        if (rnd && (++value > MAXFRACT2)) {
+                value >>= 1;
+                exp++;
+        }
+
+        if (exp > MAXEXP2) {
+                /* Overflow. Return largest representable number instead. */
+                return (1ul << (MANTSIZE2+EXPSIZE2-1)) - 1;
+        } else {
+                return (value & (MAXFRACT2>>1)) | (exp << (MANTSIZE2-1));
+        }
+}
+#endif
+
+#if ACCT_VERSION==3
+/*
+ * encode an u64 into a 32 bit IEEE float
+ */
+static u32 encode_float(u64 value)
+{
+	unsigned exp = 190;
+	unsigned u;
+
+	if (value==0) return 0;
+	while ((s64)value > 0){
+		value <<= 1;
+		exp--;
+	}
+	u = (u32)(value >> 40) & 0x7fffffu;
+	return u | (exp << 23);
+}
+#endif
+
 /*
  *  Write an accounting entry for an exiting process
  *
@@ -316,7 +379,7 @@
  */
 static void do_acct_process(long exitcode, struct file *file)
 {
-	struct acct ac;
+	acct_t ac;
 	mm_segment_t fs;
 	unsigned long vsize;
 	unsigned long flim;
@@ -333,27 +396,53 @@
 	 * Fill the accounting struct with the needed info as recorded
 	 * by the different kernel functions.
 	 */
-	memset((caddr_t)&ac, 0, sizeof(struct acct));
+	memset((caddr_t)&ac, 0, sizeof(acct_t));
 
+	ac.ac_version = ACCT_VERSION;
 	strlcpy(ac.ac_comm, current->comm, sizeof(ac.ac_comm));
 
-	elapsed = jiffies_64_to_clock_t(get_jiffies_64() - current->start_time);
+	elapsed = jiffies_64_to_AHZ(get_jiffies_64() - current->start_time);
+#if ACCT_VERSION==3
+	ac.ac_etime = encode_float(elapsed);
+#else
 	ac.ac_etime = encode_comp_t(elapsed < (unsigned long) -1l ?
 	                       (unsigned long) elapsed : (unsigned long) -1l);
-	do_div(elapsed, USER_HZ);
+#endif
+#if ACCT_VERSION==1 || ACCT_VERSION==2
+	{
+		/* new enlarged etime field */
+		comp2_t etime = encode_comp2_t(elapsed);
+		ac.ac_etime_hi = etime >> 16;
+		ac.ac_etime_lo = (u16) etime;
+	}
+#endif
+	do_div(elapsed, AHZ);
 	ac.ac_btime = xtime.tv_sec - elapsed;
-	ac.ac_utime = encode_comp_t(jiffies_to_clock_t(current->utime));
-	ac.ac_stime = encode_comp_t(jiffies_to_clock_t(current->stime));
+	ac.ac_utime = encode_comp_t(jiffies_to_AHZ(current->utime));
+	ac.ac_stime = encode_comp_t(jiffies_to_AHZ(current->stime));
 	/* we really need to bite the bullet and change layout */
 	ac.ac_uid = current->uid;
 	ac.ac_gid = current->gid;
+#if ACCT_VERSION==2
+	ac.ac_ahz = AHZ;
+#endif
+#if ACCT_VERSION==1 || ACCT_VERSION==2
+	/* backward-compatible 16 bit fields */
+	ac.ac_uid16 = current->uid;
+	ac.ac_gid16 = current->gid;
+#endif
+#if ACCT_VERSION==3
+	ac.ac_pid = current->pid;
+	ac.ac_ppid = current->parent->pid;
+#endif
 
 	read_lock(&tasklist_lock);	/* pin current->signal */
 	ac.ac_tty = current->signal->tty ?
 		old_encode_dev(tty_devnum(current->signal->tty)) : 0;
 	read_unlock(&tasklist_lock);
 
-	ac.ac_flag = 0;
+	/* ABYTESEX is always set to allow byte order detection */
+	ac.ac_flag = ABYTESEX;
 	if (current->flags & PF_FORKNOEXEC)
 		ac.ac_flag |= AFORK;
 	if (current->flags & PF_SUPERPRIV)
@@ -395,7 +484,7 @@
 	flim = current->rlim[RLIMIT_FSIZE].rlim_cur;
 	current->rlim[RLIMIT_FSIZE].rlim_cur = RLIM_INFINITY;
 	file->f_op->write(file, (char *)&ac,
-			       sizeof(struct acct), &file->f_pos);
+			       sizeof(acct_t), &file->f_pos);
 	current->rlim[RLIMIT_FSIZE].rlim_cur = flim;
 	set_fs(fs);
 }
--- diff/kernel/cpu.c	2004-06-11 19:17:36.000000000 +0100
+++ source/kernel/cpu.c	2004-06-11 19:22:07.000000000 +0100
@@ -20,14 +20,6 @@
 DECLARE_MUTEX(cpucontrol);
 
 static struct notifier_block *cpu_chain;
-/*
- * Represents all cpu's present in the system
- * In systems capable of hotplug, this map could dynamically grow
- * as new cpu's are detected in the system via any platform specific
- * method, such as ACPI for e.g.
- */
-cpumask_t	cpu_present_map;
-EXPORT_SYMBOL(cpu_present_map);
 
 /* Need to know about CPUs going up/down? */
 int register_cpu_notifier(struct notifier_block *nb)
--- diff/kernel/kmod.c	2004-06-11 19:17:36.000000000 +0100
+++ source/kernel/kmod.c	2004-06-11 19:22:07.000000000 +0100
@@ -154,7 +154,6 @@
 {
 	struct subprocess_info *sub_info = data;
 	int retval;
-	cpumask_t mask = CPU_MASK_ALL;
 
 	/* Unblock all signals. */
 	flush_signals(current);
@@ -165,7 +164,7 @@
 	spin_unlock_irq(&current->sighand->siglock);
 
 	/* We can run anywhere, unlike our parent keventd(). */
-	set_cpus_allowed(current, mask);
+	set_cpus_allowed(current, CPU_MASK_ALL);
 
 	retval = -EPERM;
 	if (current->fs->root)
--- diff/kernel/kthread.c	2004-06-11 19:17:36.000000000 +0100
+++ source/kernel/kthread.c	2004-06-11 19:22:07.000000000 +0100
@@ -65,7 +65,6 @@
 	void *data;
 	sigset_t blocked;
 	int ret = -EINTR;
-	cpumask_t mask = CPU_MASK_ALL;
 
 	kthread_exit_files();
 
@@ -79,7 +78,7 @@
 	flush_signals(current);
 
 	/* By default we can run anywhere, unlike keventd. */
-	set_cpus_allowed(current, mask);
+	set_cpus_allowed(current, CPU_MASK_ALL);
 
 	/* OK, tell user we're spawned, wait for stop or wakeup */
 	__set_current_state(TASK_INTERRUPTIBLE);
--- diff/kernel/module.c	2004-06-11 19:17:36.000000000 +0100
+++ source/kernel/module.c	2004-06-11 19:22:07.000000000 +0100
@@ -36,7 +36,6 @@
 #include <linux/stop_machine.h>
 #include <asm/uaccess.h>
 #include <asm/semaphore.h>
-#include <asm/pgalloc.h>
 #include <asm/cacheflush.h>
 
 #if 0
@@ -981,6 +980,104 @@
 	return ret;
 }
 
+
+/*
+ * /sys/module/foo/sections stuff
+ * J. Corbet <corbet@lwn.net>
+ */
+#ifdef CONFIG_KALLSYMS
+static void module_sect_attrs_release(struct kobject *kobj)
+{
+	kfree(container_of(kobj, struct module_sections, kobj));
+}
+
+static ssize_t module_sect_show(struct kobject *kobj, struct attribute *attr,
+		char *buf)
+{
+	struct module_sect_attr *sattr =
+		container_of(attr, struct module_sect_attr, attr);
+	return sprintf(buf, "0x%lx\n", sattr->address);
+}
+
+static struct sysfs_ops module_sect_ops = {
+	.show = module_sect_show,
+};
+
+static struct kobj_type module_sect_ktype = {
+	.sysfs_ops = &module_sect_ops,
+	.release =   module_sect_attrs_release,
+};
+
+static void add_sect_attrs(struct module *mod, unsigned int nsect,
+		char *secstrings, Elf_Shdr *sechdrs)
+{
+	unsigned int nloaded = 0, i;
+	struct module_sect_attr *sattr;
+	
+	if (!mod->mkobj)
+		return;
+	
+	/* Count loaded sections and allocate structures */
+	for (i = 0; i < nsect; i++)
+		if (sechdrs[i].sh_flags & SHF_ALLOC)
+			nloaded++;
+	mod->sect_attrs = kmalloc(sizeof(struct module_sections) +
+			nloaded*sizeof(mod->sect_attrs->attrs[0]), GFP_KERNEL);
+	if (! mod->sect_attrs)
+		return;
+
+	/* sections entry setup */
+	memset(mod->sect_attrs, 0, sizeof(struct module_sections));
+	if (kobject_set_name(&mod->sect_attrs->kobj, "sections"))
+		goto out;
+	mod->sect_attrs->kobj.parent = &mod->mkobj->kobj;
+	mod->sect_attrs->kobj.ktype = &module_sect_ktype;
+	if (kobject_register(&mod->sect_attrs->kobj))
+		goto out;
+
+	/* And the section attributes. */
+	sattr = &mod->sect_attrs->attrs[0];
+	for (i = 0; i < nsect; i++) {
+		if (! (sechdrs[i].sh_flags & SHF_ALLOC))
+			continue;
+		sattr->address = sechdrs[i].sh_addr;
+		strlcpy(sattr->name, secstrings + sechdrs[i].sh_name,
+				MODULE_SECT_NAME_LEN);
+		sattr->attr.name = sattr->name;
+		sattr->attr.owner = mod;
+		sattr->attr.mode = S_IRUGO;
+		(void) sysfs_create_file(&mod->sect_attrs->kobj, &sattr->attr);
+		sattr++;
+	}
+	return;
+  out:
+	kfree(mod->sect_attrs);
+	mod->sect_attrs = NULL;
+}
+
+static void remove_sect_attrs(struct module *mod)
+{
+	if (mod->sect_attrs) {
+		kobject_unregister(&mod->sect_attrs->kobj);
+		mod->sect_attrs = NULL;
+	}
+}
+
+
+#else
+static inline void add_sect_attrs(struct module *mod, unsigned int nsect,
+		char *sectstrings, Elf_Shdr *sechdrs)
+{
+}
+
+static inline void remove_sect_attrs(struct module *mod)
+{
+}
+#endif /* CONFIG_KALLSYMS */
+
+
+
+
 #define to_module_attr(n) container_of(n, struct module_attribute, attr);
 
 static ssize_t module_attr_show(struct kobject *kobj,
@@ -1099,6 +1196,7 @@
 	list_del(&mod->list);
 	spin_unlock_irq(&modlist_lock);
 
+	remove_sect_attrs(mod);
 	mod_kobject_remove(mod);
 
 	/* Arch-specific cleanup. */
@@ -1712,6 +1810,7 @@
 			      / sizeof(struct kernel_param));
 	if (err < 0)
 		goto arch_cleanup;
+	add_sect_attrs(mod, hdr->e_shnum, secstrings, sechdrs);
 
 	/* Get rid of temporary copy */
 	vfree(hdr);
--- diff/kernel/pid.c	2004-05-19 22:13:09.000000000 +0100
+++ source/kernel/pid.c	2004-06-11 19:22:07.000000000 +0100
@@ -122,6 +122,8 @@
 	}
 	
 	if (!offset || !atomic_read(&map->nr_free)) {
+		if (!offset)
+			map--;
 next_map:
 		map = next_free_map(map, &max_steps);
 		if (!map)
@@ -268,6 +270,9 @@
  * machine.  From a minimum of 16 slots up to 4096 slots at one gigabyte or
  * more.
  */
+#ifdef CONFIG_KGDB
+int kgdb_pid_init_done; /* so we don't call prior to... */
+#endif
 void __init pidhash_init(void)
 {
 	int i, j, pidhash_size;
@@ -289,6 +294,9 @@
 		for (j = 0; j < pidhash_size; j++)
 			INIT_LIST_HEAD(&pid_hash[i][j]);
 	}
+#ifdef CONFIG_KGDB
+	kgdb_pid_init_done++;
+#endif
 }
 
 void __init pidmap_init(void)
--- diff/kernel/posix-timers.c	2004-05-19 22:13:09.000000000 +0100
+++ source/kernel/posix-timers.c	2004-06-11 19:22:07.000000000 +0100
@@ -397,7 +397,6 @@
 	if (!tmr)
 		return tmr;
 	memset(tmr, 0, sizeof (struct k_itimer));
-	tmr->it_id = (timer_t)-1;
 	if (unlikely(!(tmr->sigq = sigqueue_alloc()))) {
 		kmem_cache_free(posix_timers_cache, tmr);
 		tmr = 0;
@@ -405,9 +404,11 @@
 	return tmr;
 }
 
-static void release_posix_timer(struct k_itimer *tmr)
+#define IT_ID_SET	1
+#define IT_ID_NOT_SET	0
+static void release_posix_timer(struct k_itimer *tmr, int it_id_set)
 {
-	if (tmr->it_id != -1) {
+	if (it_id_set) {
 		unsigned long flags;
 		spin_lock_irqsave(&idr_lock, flags);
 		idr_remove(&posix_timers_id, tmr->it_id);
@@ -429,10 +430,11 @@
 {
 	int error = 0;
 	struct k_itimer *new_timer = NULL;
-	timer_t new_timer_id;
+	int new_timer_id;
 	struct task_struct *process = 0;
 	unsigned long flags;
 	sigevent_t event;
+	int it_id_set = IT_ID_NOT_SET;
 
 	if ((unsigned) which_clock >= MAX_CLOCKS ||
 				!posix_clocks[which_clock].res)
@@ -443,19 +445,38 @@
 		return -EAGAIN;
 
 	spin_lock_init(&new_timer->it_lock);
-	do {
-		if (unlikely(!idr_pre_get(&posix_timers_id, GFP_KERNEL))) {
-			error = -EAGAIN;
-			new_timer->it_id = (timer_t)-1;
-			goto out;
-		}
-		spin_lock_irq(&idr_lock);
-		new_timer_id = (timer_t) idr_get_new(&posix_timers_id,
-							(void *) new_timer);
-		spin_unlock_irq(&idr_lock);
-	} while (unlikely(new_timer_id == -1));
+ retry:
+	if (unlikely(!idr_pre_get(&posix_timers_id, GFP_KERNEL))) {
+		error = -EAGAIN;
+		goto out;
+	}
+	spin_lock_irq(&idr_lock);
+	error = idr_get_new(&posix_timers_id,
+			    (void *) new_timer,
+			    &new_timer_id);
+	spin_unlock_irq(&idr_lock);
+	if (error == -EAGAIN)
+		goto retry;
+	else if (error) {
+		/*
+		 * Wierd looking, but we return EAGAIN if the IDR is
+		 * full (proper POSIX return value for this)
+		 */
+		error = -EAGAIN;
+		goto out;
+	}
+
+	it_id_set = IT_ID_SET;
+	new_timer->it_id = (timer_t) new_timer_id;
+	new_timer->it_clock = which_clock;
+	new_timer->it_incr = 0;
+	new_timer->it_overrun = -1;
+	init_timer(&new_timer->it_timer);
+	new_timer->it_timer.expires = 0;
+	new_timer->it_timer.data = (unsigned long) new_timer;
+	new_timer->it_timer.function = posix_timer_fn;
+	set_timer_inactive(new_timer);
 
-	new_timer->it_id = new_timer_id;
 	/*
 	 * return the timer_id now.  The next step is hard to
 	 * back out if there is an error.
@@ -470,6 +491,10 @@
 			error = -EFAULT;
 			goto out;
 		}
+		new_timer->it_sigev_notify = event.sigev_notify;
+		new_timer->it_sigev_signo = event.sigev_signo;
+		new_timer->it_sigev_value = event.sigev_value;
+
 		read_lock(&tasklist_lock);
 		if ((process = good_sigevent(&event))) {
 			/*
@@ -489,6 +514,7 @@
 			 */
 			spin_lock_irqsave(&process->sighand->siglock, flags);
 			if (!(process->flags & PF_EXITING)) {
+				new_timer->it_process = process;
 				list_add(&new_timer->list,
 					 &process->signal->posix_timers);
 				spin_unlock_irqrestore(&process->sighand->siglock, flags);
@@ -503,35 +529,27 @@
 			error = -EINVAL;
 			goto out;
 		}
-		new_timer->it_sigev_notify = event.sigev_notify;
-		new_timer->it_sigev_signo = event.sigev_signo;
-		new_timer->it_sigev_value = event.sigev_value;
 	} else {
 		new_timer->it_sigev_notify = SIGEV_SIGNAL;
 		new_timer->it_sigev_signo = SIGALRM;
 		new_timer->it_sigev_value.sival_int = new_timer->it_id;
 		process = current->group_leader;
 		spin_lock_irqsave(&process->sighand->siglock, flags);
+		new_timer->it_process = process;
 		list_add(&new_timer->list, &process->signal->posix_timers);
 		spin_unlock_irqrestore(&process->sighand->siglock, flags);
 	}
 
-	new_timer->it_clock = which_clock;
-	new_timer->it_incr = 0;
-	new_timer->it_overrun = -1;
-	init_timer(&new_timer->it_timer);
-	new_timer->it_timer.expires = 0;
-	new_timer->it_timer.data = (unsigned long) new_timer;
-	new_timer->it_timer.function = posix_timer_fn;
-	set_timer_inactive(new_timer);
-
-	/*
-	 * Once we set the process, it can be found so do it last...
+ 	/*
+	 * In the case of the timer belonging to another task, after
+	 * the task is unlocked, the timer is owned by the other task
+	 * and may cease to exist at any time.  Don't use or modify
+	 * new_timer after the unlock call.
 	 */
-	new_timer->it_process = process;
+
 out:
 	if (error)
-		release_posix_timer(new_timer);
+		release_posix_timer(new_timer, it_id_set);
 
 	return error;
 }
@@ -952,7 +970,7 @@
 	timer->it_process = NULL;
 	}
 	unlock_timer(timer, flags);
-	release_posix_timer(timer);
+	release_posix_timer(timer, IT_ID_SET);
 	return 0;
 }
 /*
@@ -989,7 +1007,7 @@
 		timer->it_process = NULL;
 	}
 	unlock_timer(timer, flags);
-	release_posix_timer(timer);
+	release_posix_timer(timer, IT_ID_SET);
 }
 
 /*
--- diff/kernel/rcupdate.c	2004-06-11 19:17:36.000000000 +0100
+++ source/kernel/rcupdate.c	2004-06-11 19:22:07.000000000 +0100
@@ -47,8 +47,17 @@
 
 /* Definition for rcupdate control block. */
 struct rcu_ctrlblk rcu_ctrlblk = 
-	{ .mutex = SPIN_LOCK_UNLOCKED, .curbatch = 1, 
-	  .maxbatch = 1, .rcu_cpu_mask = CPU_MASK_NONE };
+	{ .cur = -300, .completed = -300 , .lock = SEQCNT_ZERO };
+
+/* Bookkeeping of the progress of the grace period */
+struct {
+	spinlock_t	mutex; /* Guard this struct and writes to rcu_ctrlblk */
+	cpumask_t	rcu_cpu_mask; /* CPUs that need to switch in order    */
+	                              /* for current batch to proceed.        */
+} rcu_state ____cacheline_maxaligned_in_smp =
+	  {.mutex = SPIN_LOCK_UNLOCKED, .rcu_cpu_mask = CPU_MASK_NONE };
+
+
 DEFINE_PER_CPU(struct rcu_data, rcu_data) = { 0L };
 
 /* Fake initialization required by compiler */
@@ -97,25 +106,58 @@
 }
 
 /*
+ * Grace period handling:
+ * The grace period handling consists out of two steps:
+ * - A new grace period is started.
+ *   This is done by rcu_start_batch. The start is not broadcasted to
+ *   all cpus, they must pick this up by comparing rcu_ctrlblk.cur with
+ *   RCU_quiescbatch(cpu). All cpus are recorded  in the
+ *   rcu_state.rcu_cpu_mask bitmap.
+ * - All cpus must go through a quiescent state.
+ *   Since the start of the grace period is not broadcasted, at least two
+ *   calls to rcu_check_quiescent_state are required:
+ *   The first call just notices that a new grace period is running. The
+ *   following calls check if there was a quiescent state since the beginning
+ *   of the grace period. If so, it updates rcu_state.rcu_cpu_mask. If
+ *   the bitmap is empty, then the grace period is completed.
+ *   rcu_check_quiescent_state calls rcu_start_batch(0) to start the next grace
+ *   period (if necessary).
+ */
+/*
  * Register a new batch of callbacks, and start it up if there is currently no
  * active batch and the batch to be registered has not already occurred.
- * Caller must hold the rcu_ctrlblk lock.
+ * Caller must hold rcu_state.mutex.
  */
-static void rcu_start_batch(long newbatch)
+static void rcu_start_batch(int next_pending)
 {
-	cpumask_t active;
+	if (next_pending)
+		rcu_ctrlblk.next_pending = 1;
 
-	if (rcu_batch_before(rcu_ctrlblk.maxbatch, newbatch)) {
-		rcu_ctrlblk.maxbatch = newbatch;
+	if (rcu_ctrlblk.next_pending &&
+			rcu_ctrlblk.completed == rcu_ctrlblk.cur) {
+		/* Can't change, since spin lock held. */
+		cpus_andnot(rcu_state.rcu_cpu_mask, cpu_online_map,
+							nohz_cpu_mask);
+		write_seqcount_begin(&rcu_ctrlblk.lock);
+		rcu_ctrlblk.next_pending = 0;
+		rcu_ctrlblk.cur++;
+		write_seqcount_end(&rcu_ctrlblk.lock);
 	}
-	if (rcu_batch_before(rcu_ctrlblk.maxbatch, rcu_ctrlblk.curbatch) ||
-	    !cpus_empty(rcu_ctrlblk.rcu_cpu_mask)) {
-		return;
+}
+
+/*
+ * cpu went through a quiescent state since the beginning of the grace period.
+ * Clear it from the cpu mask and complete the grace period if it was the last
+ * cpu. Start another grace period if someone has further entries pending
+ */
+static void cpu_quiet(int cpu)
+{
+	cpu_clear(cpu, rcu_state.rcu_cpu_mask);
+	if (cpus_empty(rcu_state.rcu_cpu_mask)) {
+		/* batch completed ! */
+		rcu_ctrlblk.completed = rcu_ctrlblk.cur;
+		rcu_start_batch(0);
 	}
-	/* Can't change, since spin lock held. */
-	active = nohz_cpu_mask;
-	cpus_complement(active);
-	cpus_and(rcu_ctrlblk.rcu_cpu_mask, cpu_online_map, active);
 }
 
 /*
@@ -127,7 +169,19 @@
 {
 	int cpu = smp_processor_id();
 
-	if (!cpu_isset(cpu, rcu_ctrlblk.rcu_cpu_mask))
+	if (RCU_quiescbatch(cpu) != rcu_ctrlblk.cur) {
+		/* new grace period: record qsctr value. */
+		RCU_qs_pending(cpu) = 1;
+		RCU_last_qsctr(cpu) = RCU_qsctr(cpu);
+		RCU_quiescbatch(cpu) = rcu_ctrlblk.cur;
+		return;
+	}
+
+	/* Grace period already completed for this cpu?
+	 * qs_pending is checked instead of the actual bitmap to avoid
+	 * cacheline trashing.
+	 */
+	if (!RCU_qs_pending(cpu))
 		return;
 
 	/* 
@@ -135,27 +189,19 @@
 	 * we may miss one quiescent state of that CPU. That is
 	 * tolerable. So no need to disable interrupts.
 	 */
-	if (RCU_last_qsctr(cpu) == RCU_QSCTR_INVALID) {
-		RCU_last_qsctr(cpu) = RCU_qsctr(cpu);
-		return;
-	}
 	if (RCU_qsctr(cpu) == RCU_last_qsctr(cpu))
 		return;
+	RCU_qs_pending(cpu) = 0;
 
-	spin_lock(&rcu_ctrlblk.mutex);
-	if (!cpu_isset(cpu, rcu_ctrlblk.rcu_cpu_mask))
-		goto out_unlock;
-
-	cpu_clear(cpu, rcu_ctrlblk.rcu_cpu_mask);
-	RCU_last_qsctr(cpu) = RCU_QSCTR_INVALID;
-	if (!cpus_empty(rcu_ctrlblk.rcu_cpu_mask))
-		goto out_unlock;
-
-	rcu_ctrlblk.curbatch++;
-	rcu_start_batch(rcu_ctrlblk.maxbatch);
+	spin_lock(&rcu_state.mutex);
+	/*
+	 * RCU_quiescbatch/batch.cur and the cpu bitmap can come out of sync
+	 * during cpu startup. Ignore the quiescent state.
+	 */
+	if (likely(RCU_quiescbatch(cpu) == rcu_ctrlblk.cur))
+		cpu_quiet(cpu);
 
-out_unlock:
-	spin_unlock(&rcu_ctrlblk.mutex);
+	spin_unlock(&rcu_state.mutex);
 }
 
 
@@ -185,25 +231,11 @@
 	 * we can block indefinitely waiting for it, so flush
 	 * it here
 	 */
-	spin_lock_irq(&rcu_ctrlblk.mutex);
-	if (cpus_empty(rcu_ctrlblk.rcu_cpu_mask))
-		goto unlock;
-
-	cpu_clear(cpu, rcu_ctrlblk.rcu_cpu_mask);
-	if (cpus_empty(rcu_ctrlblk.rcu_cpu_mask)) {
-		rcu_ctrlblk.curbatch++;
-		/* We may avoid calling start batch if
-		 * we are starting the batch only
-		 * because of the DEAD CPU (the current
-		 * CPU will start a new batch anyway for
-		 * the callbacks we will move to current CPU).
-		 * However, we will avoid this optimisation
-		 * for now.
-		 */
-		rcu_start_batch(rcu_ctrlblk.maxbatch);
-	}
+	spin_lock_bh(&rcu_state.mutex);
+	if (rcu_ctrlblk.cur != rcu_ctrlblk.completed)
+		cpu_quiet(cpu);
 unlock:
-	spin_unlock_irq(&rcu_ctrlblk.mutex);
+	spin_unlock_bh(&rcu_state.mutex);
 
 	rcu_move_batch(&RCU_curlist(cpu));
 	rcu_move_batch(&RCU_nxtlist(cpu));
@@ -213,6 +245,14 @@
 
 #endif
 
+void rcu_restart_cpu(int cpu)
+{
+	spin_lock_bh(&rcu_state.mutex);
+	RCU_quiescbatch(cpu) = rcu_ctrlblk.completed;
+	RCU_qs_pending(cpu) = 0;
+	spin_unlock_bh(&rcu_state.mutex);
+}
+
 /*
  * This does the RCU processing work from tasklet context. 
  */
@@ -222,13 +262,15 @@
 	LIST_HEAD(list);
 
 	if (!list_empty(&RCU_curlist(cpu)) &&
-	    rcu_batch_after(rcu_ctrlblk.curbatch, RCU_batch(cpu))) {
+			!rcu_batch_before(rcu_ctrlblk.completed,RCU_batch(cpu))) {
 		__list_splice(&RCU_curlist(cpu), &list);
 		INIT_LIST_HEAD(&RCU_curlist(cpu));
 	}
 
 	local_irq_disable();
 	if (!list_empty(&RCU_nxtlist(cpu)) && list_empty(&RCU_curlist(cpu))) {
+		int next_pending, seq;
+
 		__list_splice(&RCU_nxtlist(cpu), &RCU_curlist(cpu));
 		INIT_LIST_HEAD(&RCU_nxtlist(cpu));
 		local_irq_enable();
@@ -236,10 +278,19 @@
 		/*
 		 * start the next batch of callbacks
 		 */
-		spin_lock(&rcu_ctrlblk.mutex);
-		RCU_batch(cpu) = rcu_ctrlblk.curbatch + 1;
-		rcu_start_batch(RCU_batch(cpu));
-		spin_unlock(&rcu_ctrlblk.mutex);
+		do {
+			seq = read_seqcount_begin(&rcu_ctrlblk.lock);
+			/* determine batch number */
+			RCU_batch(cpu) = rcu_ctrlblk.cur + 1;
+			next_pending = rcu_ctrlblk.next_pending;
+		} while (read_seqcount_retry(&rcu_ctrlblk.lock, seq));
+
+		if (!next_pending) {
+			/* and start it/schedule start if it's a new batch */
+			spin_lock(&rcu_state.mutex);
+			rcu_start_batch(1);
+			spin_unlock(&rcu_state.mutex);
+		}
 	} else {
 		local_irq_enable();
 	}
@@ -263,6 +314,8 @@
 	tasklet_init(&RCU_tasklet(cpu), rcu_process_callbacks, 0UL);
 	INIT_LIST_HEAD(&RCU_nxtlist(cpu));
 	INIT_LIST_HEAD(&RCU_curlist(cpu));
+	RCU_quiescbatch(cpu) = rcu_ctrlblk.completed;
+	RCU_qs_pending(cpu) = 0;
 }
 
 static int __devinit rcu_cpu_notify(struct notifier_block *self, 
--- diff/kernel/sched.c	2004-06-11 19:17:36.000000000 +0100
+++ source/kernel/sched.c	2004-06-11 19:22:07.000000000 +0100
@@ -26,6 +26,7 @@
 #include <linux/highmem.h>
 #include <linux/smp_lock.h>
 #include <asm/mmu_context.h>
+#include <asm/tlb.h>
 #include <linux/interrupt.h>
 #include <linux/completion.h>
 #include <linux/kernel_stat.h>
@@ -39,7 +40,10 @@
 #include <linux/rcupdate.h>
 #include <linux/cpu.h>
 #include <linux/percpu.h>
+#include <linux/perfctr.h>
 #include <linux/kthread.h>
+#include <linux/seq_file.h>
+#include <linux/times.h>
 
 #include <asm/unistd.h>
 
@@ -217,6 +221,7 @@
 	unsigned long expired_timestamp, nr_uninterruptible;
 	unsigned long long timestamp_last_tick;
 	task_t *curr, *idle;
+
 	struct mm_struct *prev_mm;
 	prio_array_t *active, *expired, arrays[2];
 	int best_expired_prio;
@@ -232,6 +237,22 @@
 	task_t *migration_thread;
 	struct list_head migration_queue;
 #endif
+#ifdef CONFIG_SCHEDSTATS
+	/* sys_sched_yield stats */
+	unsigned long yld_exp_empty;
+	unsigned long yld_act_empty;
+	unsigned long yld_both_empty;
+	unsigned long yld_cnt;
+
+	/* schedule stats */
+	unsigned long sched_cnt;
+	unsigned long sched_switch;
+	unsigned long sched_idle;
+
+	/* wake stats */
+	unsigned long sched_wake;
+	unsigned long sched_wake_local;
+#endif
 };
 
 static DEFINE_PER_CPU(struct runqueue, runqueues);
@@ -278,6 +299,91 @@
 	spin_unlock_irqrestore(&rq->lock, *flags);
 }
 
+
+#ifdef CONFIG_SCHEDSTATS
+
+/*
+ * bump this up when changing the output format or the meaning of an existing
+ * format, so that tools can adapt (or abort)
+ */
+#define SCHEDSTAT_VERSION	7
+
+static int show_schedstat(struct seq_file *seq, void *v)
+{
+	int i;
+
+	seq_printf(seq, "version %d\n", SCHEDSTAT_VERSION);
+	seq_printf(seq, "timestamp %lu\n", jiffies);
+	for_each_cpu(i) {
+		/* Include offline CPUs */
+		runqueue_t *rq = cpu_rq(i);
+#ifdef CONFIG_SMP
+		struct sched_domain *sd;
+		int j = 0;
+#endif
+
+		seq_printf(seq,
+		    "cpu%d %lu %lu %lu %lu %lu %lu %lu %lu %lu",
+		    i,
+		    rq->yld_both_empty, rq->yld_act_empty,
+		    rq->yld_exp_empty, rq->yld_cnt,
+		    rq->sched_switch, rq->sched_cnt,
+		    rq->sched_idle, rq->sched_wake, rq->sched_wake_local);
+#ifdef CONFIG_SMP
+		for_each_domain(i, sd) {
+			char str[NR_CPUS];
+			int k;
+			cpumask_scnprintf(str, NR_CPUS, sd->span);
+			seq_printf(seq, " domain%d %s", j++, str);
+
+			for (k = 0; k < 3; k++) {
+				seq_printf(seq, " %lu %lu %lu %lu %lu %lu",
+				    sd->lb_cnt[k], sd->lb_balanced[k],
+				    sd->lb_failed[k], sd->lb_pulled[k],
+				    sd->lb_hot_pulled[k], sd->lb_imbalance[k]);
+			}
+
+			seq_printf(seq, " %lu %lu %lu %lu %lu %lu %lu %lu",
+			    sd->alb_cnt, sd->alb_failed,
+			    sd->alb_pushed, sd->sched_wake_remote,
+			    sd->plb_pulled, sd->afw_pulled,
+			    sd->sbe_pushed, sd->sbc_pushed);
+		}
+#endif
+
+		seq_printf(seq, "\n");
+	}
+
+	return 0;
+}
+
+static int schedstat_open(struct inode *inode, struct file *file)
+{
+	unsigned size = 4096 * (1 + num_online_cpus() / 32);
+	char *buf = kmalloc(size, GFP_KERNEL);
+	struct seq_file *m;
+	int res;
+
+	if (!buf)
+		return -ENOMEM;
+	res = single_open(file, show_schedstat, NULL);
+	if (!res) {
+		m = file->private_data;
+		m->buf = buf;
+		m->size = size;
+	} else
+		kfree(buf);
+	return res;
+}
+
+struct file_operations proc_schedstat_operations = {
+	.open    = schedstat_open,
+	.read    = seq_read,
+	.llseek  = seq_lseek,
+	.release = single_release,
+};
+#endif
+
 /*
  * rq_lock - lock a given runqueue and disable interrupts.
  */
@@ -696,10 +802,9 @@
 		return cpu;
 
 	cpus_and(tmp, sd->span, cpu_online_map);
-	for_each_cpu_mask(i, tmp) {
-		if (!cpu_isset(i, p->cpus_allowed))
-			continue;
+	cpus_and(tmp, tmp, p->cpus_allowed);
 
+	for_each_cpu_mask(i, tmp) {
 		if (idle_cpu(i))
 			return i;
 	}
@@ -750,7 +855,24 @@
 	cpu = task_cpu(p);
 	this_cpu = smp_processor_id();
 
+	schedstat_inc(rq, sched_wake);
+#ifndef CONFIG_SMP
+	schedstat_inc(rq, sched_wake_local);
+#endif
+
 #ifdef CONFIG_SMP
+#ifdef CONFIG_SCHEDSTATS
+	if (cpu == this_cpu)
+		schedstat_inc(rq, sched_wake_local);
+	else {
+		for_each_domain(this_cpu, sd)
+			if (cpu_isset(cpu, sd->span))
+				break;
+		if (sd)
+			schedstat_inc(sd, sched_wake_remote);
+	}
+#endif
+
 	if (unlikely(task_running(rq, p)))
 		goto out_activate;
 
@@ -792,12 +914,22 @@
 				!task_hot(p, rq->timestamp_last_tick, sd))
 			|| ((sd->flags & SD_WAKE_BALANCE) &&
 				imbalance*this_load <= 100*load) ) {
+
 			/*
 			 * Now sd has SD_WAKE_AFFINE and p is cache cold in sd
 			 * or sd has SD_WAKE_BALANCE and there is an imbalance
 			 */
-			if (cpu_isset(cpu, sd->span))
+			if (cpu_isset(cpu, sd->span)) {
+#ifdef CONFIG_SCHEDSTATS
+				if ((sd->flags & SD_WAKE_AFFINE) &&
+					!task_hot(p, rq->timestamp_last_tick, sd))
+					schedstat_inc(sd, afw_pulled);
+				else if ((sd->flags & SD_WAKE_BALANCE) &&
+					imbalance*this_load <= 100*load)
+					schedstat_inc(sd, plb_pulled);
+#endif
 				goto out_set_cpu;
+			}
 		}
 	}
 
@@ -1281,6 +1413,7 @@
 			rq->nr_running++;
 		}
 	} else {
+		schedstat_inc(sd, sbc_pushed);
 		/* Not the local CPU - must adjust timestamp */
 		p->timestamp = (p->timestamp - this_rq->timestamp_last_tick)
 					+ rq->timestamp_last_tick;
@@ -1320,6 +1453,7 @@
 		wake_up_process(mt);
 		put_task_struct(mt);
 		wait_for_completion(&req.done);
+		tlb_migrate_finish(p->mm);
 		return;
 	}
 out:
@@ -1349,6 +1483,7 @@
 	if (sd) {
 		new_cpu = find_idlest_cpu(current, this_cpu, sd);
 		if (new_cpu != this_cpu) {
+  			schedstat_inc(sd, sbe_pushed);
 			put_cpu();
 			sched_migrate_task(current, new_cpu);
 			return;
@@ -1421,6 +1556,13 @@
 			return 0;
 	}
 
+#ifdef CONFIG_SCHEDSTATS
+	if (!task_hot(p, rq->timestamp_last_tick, sd))
+		schedstat_inc(sd, lb_pulled[idle]);
+	else
+		schedstat_inc(sd, lb_hot_pulled[idle]);
+#endif
+
 	return 1;
 }
 
@@ -1680,14 +1822,20 @@
 	int nr_moved;
 
 	spin_lock(&this_rq->lock);
+	schedstat_inc(sd, lb_cnt[idle]);
 
 	group = find_busiest_group(sd, this_cpu, &imbalance, idle);
-	if (!group)
+	if (!group) {
+		schedstat_inc(sd, lb_balanced[idle]);
 		goto out_balanced;
+	}
 
 	busiest = find_busiest_queue(group);
-	if (!busiest)
+	if (!busiest) {
+		schedstat_inc(sd, lb_balanced[idle]);
 		goto out_balanced;
+	}
+
 	/*
 	 * This should be "impossible", but since load
 	 * balancing is inherently racy and statistical,
@@ -1697,6 +1845,7 @@
 		WARN_ON(1);
 		goto out_balanced;
 	}
+	schedstat_add(sd, lb_imbalance[idle], imbalance);
 
 	nr_moved = 0;
 	if (busiest->nr_running > 1) {
@@ -1714,6 +1863,7 @@
 	spin_unlock(&this_rq->lock);
 
 	if (!nr_moved) {
+		schedstat_inc(sd, lb_failed[idle]);
 		sd->nr_balance_failed++;
 
 		if (unlikely(sd->nr_balance_failed > sd->cache_nice_tries+2)) {
@@ -1768,13 +1918,20 @@
 	unsigned long imbalance;
 	int nr_moved = 0;
 
+ 	schedstat_inc(sd, lb_cnt[NEWLY_IDLE]);
 	group = find_busiest_group(sd, this_cpu, &imbalance, NEWLY_IDLE);
-	if (!group)
+	if (!group) {
+		schedstat_inc(sd, lb_balanced[NEWLY_IDLE]);
 		goto out;
+	}
 
 	busiest = find_busiest_queue(group);
-	if (!busiest || busiest == this_rq)
+	if (!busiest || busiest == this_rq) {
+		schedstat_inc(sd, lb_balanced[NEWLY_IDLE]);
 		goto out;
+	}
+
+	schedstat_add(sd, lb_imbalance[NEWLY_IDLE], imbalance);
 
 	/* Attempt to move tasks */
 	double_lock_balance(this_rq, busiest);
@@ -1819,6 +1976,7 @@
 	struct sched_domain *sd;
 	struct sched_group *group, *busy_group;
 	int i;
+	int moved = 0;
 
 	if (busiest->nr_running <= 1)
 		return;
@@ -1830,6 +1988,7 @@
 		WARN_ON(1);
 		return;
 	}
+	schedstat_inc(sd, alb_cnt);
 
  	group = sd->groups;
 	while (!cpu_isset(busiest_cpu, group->cpumask))
@@ -1866,11 +2025,16 @@
 		if (unlikely(busiest == rq))
 			goto next_group;
 		double_lock_balance(busiest, rq);
-		move_tasks(rq, push_cpu, busiest, 1, sd, IDLE);
+		moved += move_tasks(rq, push_cpu, busiest, 1, sd, IDLE);
 		spin_unlock(&rq->lock);
 next_group:
 		group = group->next;
 	} while (group != sd->groups);
+
+	if (moved)
+		schedstat_add(sd, alb_pushed, moved);
+	else
+		schedstat_inc(sd, alb_failed);
 }
 
 /*
@@ -2210,6 +2374,7 @@
 	rq = this_rq();
 
 	release_kernel_lock(prev);
+ 	schedstat_inc(rq, sched_cnt);
 	now = sched_clock();
 	if (likely(now - prev->timestamp < NS_MAX_SLEEP_AVG))
 		run_time = now - prev->timestamp;
@@ -2247,6 +2412,7 @@
 			next = rq->idle;
 			rq->expired_timestamp = 0;
 			wake_sleeping_dependent(cpu, rq);
+ 			schedstat_inc(rq, sched_idle);
 			goto switch_tasks;
 		}
 	}
@@ -2256,6 +2422,7 @@
 		/*
 		 * Switch the active and expired arrays.
 		 */
+		schedstat_inc(rq, sched_switch);
 		rq->active = rq->expired;
 		rq->expired = array;
 		array = rq->active;
@@ -2606,6 +2773,13 @@
 
 EXPORT_SYMBOL(set_user_nice);
 
+#ifdef CONFIG_KGDB
+struct task_struct *kgdb_get_idle(int this_cpu)
+{
+        return cpu_rq(this_cpu)->idle;
+}
+#endif
+
 #ifdef __ARCH_WANT_SYS_NICE
 
 /*
@@ -2941,6 +3115,21 @@
 	return retval;
 }
 
+/*
+ * Represents all cpu's present in the system
+ * In systems capable of hotplug, this map could dynamically grow
+ * as new cpu's are detected in the system via any platform specific
+ * method, such as ACPI for e.g.
+ */
+
+cpumask_t cpu_present_map;
+EXPORT_SYMBOL(cpu_present_map);
+
+#ifndef CONFIG_SMP
+cpumask_t cpu_online_map = CPU_MASK_ALL;
+cpumask_t cpu_possible_map = CPU_MASK_ALL;
+#endif
+
 /**
  * sys_sched_getaffinity - get the cpu affinity of a process
  * @pid: pid of the process
@@ -2993,6 +3182,7 @@
 	prio_array_t *array = current->array;
 	prio_array_t *target = rq->expired;
 
+	schedstat_inc(rq, yld_cnt);
 	/*
 	 * We implement yielding by moving the task into the expired
 	 * queue.
@@ -3319,8 +3509,10 @@
 	migration_req_t req;
 	runqueue_t *rq;
 
+	perfctr_set_cpus_allowed(p, new_mask);
+
 	rq = task_rq_lock(p, &flags);
-	if (any_online_cpu(new_mask) == NR_CPUS) {
+	if (!cpus_intersects(new_mask, cpu_online_map)) {
 		ret = -EINVAL;
 		goto out;
 	}
@@ -3335,6 +3527,7 @@
 		task_rq_unlock(rq, &flags);
 		wake_up_process(rq->migration_thread);
 		wait_for_completion(&req.done);
+		tlb_migrate_finish(p->mm);
 		return 0;
 	}
 out:
@@ -3495,8 +3688,7 @@
 		if (dest_cpu == NR_CPUS)
 			dest_cpu = any_online_cpu(tsk->cpus_allowed);
 		if (dest_cpu == NR_CPUS) {
-			cpus_clear(tsk->cpus_allowed);
-			cpus_complement(tsk->cpus_allowed);
+			cpus_setall(tsk->cpus_allowed);
 			dest_cpu = any_online_cpu(tsk->cpus_allowed);
 
 			/* Don't tell them about moving exiting tasks
@@ -3812,7 +4004,7 @@
 			int j;
 			char str[NR_CPUS];
 			struct sched_group *group = sd->groups;
-			cpumask_t groupmask, tmp;
+			cpumask_t groupmask;
 
 			cpumask_scnprintf(str, NR_CPUS, sd->span);
 			cpus_clear(groupmask);
@@ -3842,8 +4034,7 @@
 				if (!cpus_weight(group->cpumask))
 					printk(" ERROR empty group:");
 
-				cpus_and(tmp, groupmask, group->cpumask);
-				if (cpus_weight(tmp) > 0)
+				if (cpus_intersects(groupmask, group->cpumask))
 					printk(" ERROR repeated CPUs:");
 
 				cpus_or(groupmask, groupmask, group->cpumask);
@@ -3862,8 +4053,7 @@
 			sd = sd->parent;
 
 			if (sd) {
-				cpus_and(tmp, groupmask, sd->span);
-				if (!cpus_equal(tmp, groupmask))
+				if (!cpus_subset(groupmask, sd->span))
 					printk(KERN_DEBUG "ERROR parent span is not a superset of domain->span\n");
 			}
 
@@ -3902,16 +4092,15 @@
 	/* Set up an initial dummy domain for early boot */
 	static struct sched_domain sched_domain_init;
 	static struct sched_group sched_group_init;
-	cpumask_t cpu_mask_all = CPU_MASK_ALL;
 
 	memset(&sched_domain_init, 0, sizeof(struct sched_domain));
-	sched_domain_init.span = cpu_mask_all;
+	sched_domain_init.span = CPU_MASK_ALL;
 	sched_domain_init.groups = &sched_group_init;
 	sched_domain_init.last_balance = jiffies;
 	sched_domain_init.balance_interval = INT_MAX; /* Don't balance */
 
 	memset(&sched_group_init, 0, sizeof(struct sched_group));
-	sched_group_init.cpumask = cpu_mask_all;
+	sched_group_init.cpumask = CPU_MASK_ALL;
 	sched_group_init.next = &sched_group_init;
 	sched_group_init.cpu_power = SCHED_LOAD_SCALE;
 #endif
--- diff/kernel/signal.c	2004-06-11 19:17:36.000000000 +0100
+++ source/kernel/signal.c	2004-06-11 19:22:07.000000000 +0100
@@ -32,9 +32,6 @@
 
 static kmem_cache_t *sigqueue_cachep;
 
-atomic_t nr_queued_signals;
-int max_queued_signals = 1024;
-
 /*
  * In POSIX a signal is sent either to a specific thread (Linux task)
  * or to the process as a whole (Linux thread group).  How the signal
@@ -265,17 +262,19 @@
 	return sig;
 }
 
-struct sigqueue *__sigqueue_alloc(void)
+static struct sigqueue *__sigqueue_alloc(void)
 {
 	struct sigqueue *q = 0;
 
-	if (atomic_read(&nr_queued_signals) < max_queued_signals)
+	if (atomic_read(&current->user->sigpending) <
+			current->rlim[RLIMIT_SIGPENDING].rlim_cur)
 		q = kmem_cache_alloc(sigqueue_cachep, GFP_ATOMIC);
 	if (q) {
-		atomic_inc(&nr_queued_signals);
 		INIT_LIST_HEAD(&q->list);
 		q->flags = 0;
 		q->lock = 0;
+		q->user = get_uid(current->user);
+		atomic_inc(&q->user->sigpending);
 	}
 	return(q);
 }
@@ -284,8 +283,9 @@
 {
 	if (q->flags & SIGQUEUE_PREALLOC)
 		return;
+	atomic_dec(&q->user->sigpending);
+	free_uid(q->user);
 	kmem_cache_free(sigqueue_cachep, q);
-	atomic_dec(&nr_queued_signals);
 }
 
 static void flush_sigqueue(struct sigpending *queue)
@@ -699,7 +699,8 @@
 	}
 }
 
-static int send_signal(int sig, struct siginfo *info, struct sigpending *signals)
+static int send_signal(int sig, struct siginfo *info, struct task_struct *t,
+			struct sigpending *signals)
 {
 	struct sigqueue * q = NULL;
 	int ret = 0;
@@ -719,12 +720,14 @@
 	   make sure at least one signal gets delivered and don't
 	   pass on the info struct.  */
 
-	if (atomic_read(&nr_queued_signals) < max_queued_signals)
+	if (atomic_read(&t->user->sigpending) <
+			t->rlim[RLIMIT_SIGPENDING].rlim_cur)
 		q = kmem_cache_alloc(sigqueue_cachep, GFP_ATOMIC);
 
 	if (q) {
-		atomic_inc(&nr_queued_signals);
 		q->flags = 0;
+		q->user = get_uid(t->user);
+		atomic_inc(&q->user->sigpending);
 		list_add_tail(&q->list, &signals->list);
 		switch ((unsigned long) info) {
 		case 0:
@@ -798,7 +801,7 @@
 	if (LEGACY_QUEUE(&t->pending, sig))
 		goto out;
 
-	ret = send_signal(sig, info, &t->pending);
+	ret = send_signal(sig, info, t, &t->pending);
 	if (!ret && !sigismember(&t->blocked, sig))
 		signal_wake_up(t, sig == SIGKILL);
 out:
@@ -999,7 +1002,7 @@
 	 * We always use the shared queue for process-wide signals,
 	 * to avoid several races.
 	 */
-	ret = send_signal(sig, info, &p->signal->shared_pending);
+	ret = send_signal(sig, info, p, &p->signal->shared_pending);
 	if (unlikely(ret))
 		return ret;
 
@@ -2477,7 +2480,7 @@
 }
 #endif /* __ARCH_WANT_SYS_SIGPROCMASK */
 
-#ifndef __sparc__
+#ifdef __ARCH_WANT_SYS_RT_SIGACTION
 asmlinkage long
 sys_rt_sigaction(int sig,
 		 const struct sigaction __user *act,
@@ -2505,7 +2508,7 @@
 out:
 	return ret;
 }
-#endif /* __sparc__ */
+#endif /* __ARCH_WANT_SYS_RT_SIGACTION */
 
 #ifdef __ARCH_WANT_SYS_SGETMASK
 
--- diff/kernel/softirq.c	2004-05-19 22:13:09.000000000 +0100
+++ source/kernel/softirq.c	2004-06-11 19:22:07.000000000 +0100
@@ -132,11 +132,22 @@
 
 void local_bh_enable(void)
 {
+	if (in_irq()) {
+		printk("local_bh_enable() was called in hard irq context.   "
+			"This is probably a bug\n");
+		dump_stack();
+	}
+
 	__local_bh_enable();
-	WARN_ON(irqs_disabled());
-	if (unlikely(!in_interrupt() &&
-		     local_softirq_pending()))
+	if (unlikely(!in_interrupt() && local_softirq_pending())) {
+		if (irqs_disabled()) {
+			printk("local_bh_enable() was called with local "
+				"interrupts disabled.  This is probably a"
+				" bug\n");
+			dump_stack();
+		}
 		invoke_softirq();
+	}
 	preempt_check_resched();
 }
 EXPORT_SYMBOL(local_bh_enable);
@@ -300,8 +311,7 @@
 
 void tasklet_kill(struct tasklet_struct *t)
 {
-	if (in_interrupt())
-		printk("Attempt to kill tasklet from interrupt\n");
+	might_sleep();
 
 	while (test_and_set_bit(TASKLET_STATE_SCHED, &t->state)) {
 		do
--- diff/kernel/sys.c	2004-06-11 19:17:36.000000000 +0100
+++ source/kernel/sys.c	2004-06-11 19:22:07.000000000 +0100
@@ -280,6 +280,12 @@
 cond_syscall(sys_pciconfig_read)
 cond_syscall(sys_pciconfig_write)
 cond_syscall(sys_pciconfig_iobase)
+cond_syscall(sys_perfctr_info)
+cond_syscall(sys_vperfctr_open)
+cond_syscall(sys_vperfctr_control)
+cond_syscall(sys_vperfctr_unlink)
+cond_syscall(sys_vperfctr_iresume)
+cond_syscall(sys_vperfctr_read)
 
 static int set_one_prio(struct task_struct *p, int niceval, int error)
 {
--- diff/kernel/sysctl.c	2004-06-11 19:17:36.000000000 +0100
+++ source/kernel/sysctl.c	2004-06-11 19:22:07.000000000 +0100
@@ -53,8 +53,6 @@
 extern int sysctl_overcommit_memory;
 extern int sysctl_overcommit_ratio;
 extern int max_threads;
-extern atomic_t nr_queued_signals;
-extern int max_queued_signals;
 extern int sysrq_enabled;
 extern int core_uses_pid;
 extern char core_pattern[];
@@ -218,7 +216,7 @@
 		.ctl_name	= KERN_OSTYPE,
 		.procname	= "ostype",
 		.data		= system_utsname.sysname,
-		.maxlen		= 64,
+		.maxlen		= sizeof(system_utsname.sysname),
 		.mode		= 0444,
 		.proc_handler	= &proc_doutsstring,
 		.strategy	= &sysctl_string,
@@ -227,7 +225,7 @@
 		.ctl_name	= KERN_OSRELEASE,
 		.procname	= "osrelease",
 		.data		= system_utsname.release,
-		.maxlen		= 64,
+		.maxlen		= sizeof(system_utsname.release),
 		.mode		= 0444,
 		.proc_handler	= &proc_doutsstring,
 		.strategy	= &sysctl_string,
@@ -236,7 +234,7 @@
 		.ctl_name	= KERN_VERSION,
 		.procname	= "version",
 		.data		= system_utsname.version,
-		.maxlen		= 64,
+		.maxlen		= sizeof(system_utsname.version),
 		.mode		= 0444,
 		.proc_handler	= &proc_doutsstring,
 		.strategy	= &sysctl_string,
@@ -245,7 +243,7 @@
 		.ctl_name	= KERN_NODENAME,
 		.procname	= "hostname",
 		.data		= system_utsname.nodename,
-		.maxlen		= 64,
+		.maxlen		= sizeof(system_utsname.nodename),
 		.mode		= 0644,
 		.proc_handler	= &proc_doutsstring,
 		.strategy	= &sysctl_string,
@@ -254,7 +252,7 @@
 		.ctl_name	= KERN_DOMAINNAME,
 		.procname	= "domainname",
 		.data		= system_utsname.domainname,
-		.maxlen		= 64,
+		.maxlen		= sizeof(system_utsname.domainname),
 		.mode		= 0644,
 		.proc_handler	= &proc_doutsstring,
 		.strategy	= &sysctl_string,
@@ -429,22 +427,6 @@
 		.proc_handler	= &proc_dointvec,
 	},
 #endif
-	{
-		.ctl_name	= KERN_RTSIGNR,
-		.procname	= "rtsig-nr",
-		.data		= &nr_queued_signals,
-		.maxlen		= sizeof(int),
-		.mode		= 0444,
-		.proc_handler	= &proc_dointvec,
-	},
-	{
-		.ctl_name	= KERN_RTSIGMAX,
-		.procname	= "rtsig-max",
-		.data		= &max_queued_signals,
-		.maxlen		= sizeof(int),
-		.mode		= 0644,
-		.proc_handler	= &proc_dointvec,
-	},
 #ifdef CONFIG_SYSVIPC
 	{
 		.ctl_name	= KERN_SHMMAX,
--- diff/kernel/timer.c	2004-06-11 19:17:36.000000000 +0100
+++ source/kernel/timer.c	2004-06-11 19:22:07.000000000 +0100
@@ -31,6 +31,7 @@
 #include <linux/time.h>
 #include <linux/jiffies.h>
 #include <linux/cpu.h>
+#include <linux/perfctr.h>
 
 #include <asm/uaccess.h>
 #include <asm/unistd.h>
@@ -835,6 +836,7 @@
 	do_process_times(p, user, system);
 	do_it_virt(p, user);
 	do_it_prof(p);
+	perfctr_sample_thread(&p->thread);
 }	
 
 /*
--- diff/kernel/uid16.c	2004-05-19 22:13:09.000000000 +0100
+++ source/kernel/uid16.c	2004-06-11 19:22:07.000000000 +0100
@@ -39,7 +39,7 @@
 
 asmlinkage long sys_setgid16(old_gid_t gid)
 {
-	return sys_setgid((gid_t)gid);
+	return sys_setgid(low2highgid(gid));
 }
 
 asmlinkage long sys_setreuid16(old_uid_t ruid, old_uid_t euid)
@@ -49,7 +49,7 @@
 
 asmlinkage long sys_setuid16(old_uid_t uid)
 {
-	return sys_setuid((uid_t)uid);
+	return sys_setuid(low2highuid(uid));
 }
 
 asmlinkage long sys_setresuid16(old_uid_t ruid, old_uid_t euid, old_uid_t suid)
@@ -88,12 +88,12 @@
 
 asmlinkage long sys_setfsuid16(old_uid_t uid)
 {
-	return sys_setfsuid((uid_t)uid);
+	return sys_setfsuid(low2highuid(uid));
 }
 
 asmlinkage long sys_setfsgid16(old_gid_t gid)
 {
-	return sys_setfsgid((gid_t)gid);
+	return sys_setfsgid(low2highgid(gid));
 }
 
 static int groups16_to_user(old_gid_t __user *grouplist,
@@ -103,7 +103,7 @@
 	old_gid_t group;
 
 	for (i = 0; i < group_info->ngroups; i++) {
-		group = (old_gid_t)GROUP_AT(group_info, i);
+		group = high2lowgid(GROUP_AT(group_info, i));
 		if (put_user(group, grouplist+i))
 			return -EFAULT;
 	}
@@ -120,7 +120,7 @@
 	for (i = 0; i < group_info->ngroups; i++) {
 		if (get_user(group, grouplist+i))
 			return  -EFAULT;
-		GROUP_AT(group_info, i) = (gid_t)group;
+		GROUP_AT(group_info, i) = low2highgid(group);
 	}
 
 	return 0;
--- diff/kernel/user.c	2004-06-11 19:17:36.000000000 +0100
+++ source/kernel/user.c	2004-06-11 19:22:07.000000000 +0100
@@ -30,7 +30,9 @@
 struct user_struct root_user = {
 	.__count	= ATOMIC_INIT(1),
 	.processes	= ATOMIC_INIT(1),
-	.files		= ATOMIC_INIT(0)
+	.files		= ATOMIC_INIT(0),
+	.sigpending	= ATOMIC_INIT(0),
+	.mq_bytes	= 0
 };
 
 /*
@@ -108,6 +110,9 @@
 		atomic_set(&new->__count, 1);
 		atomic_set(&new->processes, 0);
 		atomic_set(&new->files, 0);
+		atomic_set(&new->sigpending, 0);
+
+		new->mq_bytes = 0;
 
 		/*
 		 * Before adding this, check whether we raced
--- diff/kernel/workqueue.c	2004-06-11 19:17:36.000000000 +0100
+++ source/kernel/workqueue.c	2004-06-11 19:22:07.000000000 +0100
@@ -218,6 +218,33 @@
 	return 0;
 }
 
+static void flush_cpu_workqueue(struct cpu_workqueue_struct *cwq)
+{
+	if (cwq->thread == current) {
+		/*
+		 * Probably keventd trying to flush its own queue. So simply run
+		 * it by hand rather than deadlocking.
+		 */
+		run_workqueue(cwq);
+	} else {
+		DEFINE_WAIT(wait);
+		long sequence_needed;
+
+		spin_lock_irq(&cwq->lock);
+		sequence_needed = cwq->insert_sequence;
+
+		while (sequence_needed - cwq->remove_sequence > 0) {
+			prepare_to_wait(&cwq->work_done, &wait,
+					TASK_UNINTERRUPTIBLE);
+			spin_unlock_irq(&cwq->lock);
+			schedule();
+			spin_lock_irq(&cwq->lock);
+		}
+		finish_wait(&cwq->work_done, &wait);
+		spin_unlock_irq(&cwq->lock);
+	}
+}
+
 /*
  * flush_workqueue - ensure that any scheduled work has run to completion.
  *
@@ -234,43 +261,20 @@
  */
 void fastcall flush_workqueue(struct workqueue_struct *wq)
 {
-	struct cpu_workqueue_struct *cwq;
-	int cpu;
-
 	might_sleep();
 
-	lock_cpu_hotplug();
-	for_each_online_cpu(cpu) {
-		DEFINE_WAIT(wait);
-		long sequence_needed;
-
-		if (is_single_threaded(wq))
-			cwq = wq->cpu_wq + 0; /* Always use cpu 0's area. */
-		else
-			cwq = wq->cpu_wq + cpu;
-
-		if (cwq->thread == current) {
-			/*
-			 * Probably keventd trying to flush its own queue.
-			 * So simply run it by hand rather than deadlocking.
-			 */
-			run_workqueue(cwq);
-			continue;
-		}
-		spin_lock_irq(&cwq->lock);
-		sequence_needed = cwq->insert_sequence;
+	if (is_single_threaded(wq)) {
+		/* Always use cpu 0's area. */
+		flush_cpu_workqueue(wq->cpu_wq + 0);
+	} else {
+		int cpu;
 
-		while (sequence_needed - cwq->remove_sequence > 0) {
-			prepare_to_wait(&cwq->work_done, &wait,
-					TASK_UNINTERRUPTIBLE);
-			spin_unlock_irq(&cwq->lock);
-			schedule();
-			spin_lock_irq(&cwq->lock);
-		}
-		finish_wait(&cwq->work_done, &wait);
-		spin_unlock_irq(&cwq->lock);
+		lock_cpu_hotplug();
+		for_each_online_cpu(cpu)
+			flush_cpu_workqueue(wq->cpu_wq + cpu);
+		unlock_cpu_hotplug();
 	}
-	unlock_cpu_hotplug();
+
 }
 
 static struct task_struct *create_workqueue_thread(struct workqueue_struct *wq,
--- diff/lib/bitmap.c	2004-05-19 22:13:10.000000000 +0100
+++ source/lib/bitmap.c	2004-06-11 19:22:07.000000000 +0100
@@ -12,7 +12,33 @@
 #include <asm/bitops.h>
 #include <asm/uaccess.h>
 
-int bitmap_empty(const unsigned long *bitmap, int bits)
+/*
+ * bitmaps provide an array of bits, implemented using an an
+ * array of unsigned longs.  The number of valid bits in a
+ * given bitmap does _not_ need to be an exact multiple of
+ * BITS_PER_LONG.
+ *
+ * The possible unused bits in the last, partially used word
+ * of a bitmap are 'don't care'.  The implementation makes
+ * no particular effort to keep them zero.  It ensures that
+ * their value will not affect the results of any operation.
+ * The bitmap operations that return Boolean (bitmap_empty,
+ * for example) or scalar (bitmap_weight, for example) results
+ * carefully filter out these unused bits from impacting their
+ * results.
+ *
+ * These operations actually hold to a slightly stronger rule:
+ * if you don't input any bitmaps to these ops that have some
+ * unused bits set, then they won't output any set unused bits
+ * in output bitmaps.
+ *
+ * The byte ordering of bitmaps is more natural on little
+ * endian architectures.  See the big-endian headers
+ * include/asm-ppc64/bitops.h and include/asm-s390/bitops.h
+ * for the best explanations of this ordering.
+ */
+
+int __bitmap_empty(const unsigned long *bitmap, int bits)
 {
 	int k, lim = bits/BITS_PER_LONG;
 	for (k = 0; k < lim; ++k)
@@ -20,14 +46,14 @@
 			return 0;
 
 	if (bits % BITS_PER_LONG)
-		if (bitmap[k] & ((1UL << (bits % BITS_PER_LONG)) - 1))
+		if (bitmap[k] & BITMAP_LAST_WORD_MASK(bits))
 			return 0;
 
 	return 1;
 }
-EXPORT_SYMBOL(bitmap_empty);
+EXPORT_SYMBOL(__bitmap_empty);
 
-int bitmap_full(const unsigned long *bitmap, int bits)
+int __bitmap_full(const unsigned long *bitmap, int bits)
 {
 	int k, lim = bits/BITS_PER_LONG;
 	for (k = 0; k < lim; ++k)
@@ -35,15 +61,15 @@
 			return 0;
 
 	if (bits % BITS_PER_LONG)
-		if (~bitmap[k] & ((1UL << (bits % BITS_PER_LONG)) - 1))
+		if (~bitmap[k] & BITMAP_LAST_WORD_MASK(bits))
 			return 0;
 
 	return 1;
 }
-EXPORT_SYMBOL(bitmap_full);
+EXPORT_SYMBOL(__bitmap_full);
 
-int bitmap_equal(const unsigned long *bitmap1,
-		unsigned long *bitmap2, int bits)
+int __bitmap_equal(const unsigned long *bitmap1,
+		const unsigned long *bitmap2, int bits)
 {
 	int k, lim = bits/BITS_PER_LONG;
 	for (k = 0; k < lim; ++k)
@@ -51,26 +77,26 @@
 			return 0;
 
 	if (bits % BITS_PER_LONG)
-		if ((bitmap1[k] ^ bitmap2[k]) &
-				((1UL << (bits % BITS_PER_LONG)) - 1))
+		if ((bitmap1[k] ^ bitmap2[k]) & BITMAP_LAST_WORD_MASK(bits))
 			return 0;
 
 	return 1;
 }
-EXPORT_SYMBOL(bitmap_equal);
+EXPORT_SYMBOL(__bitmap_equal);
 
-void bitmap_complement(unsigned long *bitmap, int bits)
+void __bitmap_complement(unsigned long *dst, const unsigned long *src, int bits)
 {
-	int k;
-	int nr = BITS_TO_LONGS(bits);
+	int k, lim = bits/BITS_PER_LONG;
+	for (k = 0; k < lim; ++k)
+		dst[k] = ~src[k];
 
-	for (k = 0; k < nr; ++k)
-		bitmap[k] = ~bitmap[k];
+	if (bits % BITS_PER_LONG)
+		dst[k] = ~src[k] & BITMAP_LAST_WORD_MASK(bits);
 }
-EXPORT_SYMBOL(bitmap_complement);
+EXPORT_SYMBOL(__bitmap_complement);
 
 /*
- * bitmap_shift_right - logical right shift of the bits in a bitmap
+ * __bitmap_shift_right - logical right shift of the bits in a bitmap
  *   @dst - destination bitmap
  *   @src - source bitmap
  *   @nbits - shift by this many bits
@@ -80,7 +106,7 @@
  * direction.  Zeros are fed into the vacated MS positions and the
  * LS bits shifted off the bottom are lost.
  */
-void bitmap_shift_right(unsigned long *dst,
+void __bitmap_shift_right(unsigned long *dst,
 			const unsigned long *src, int shift, int bits)
 {
 	int k, lim = BITS_TO_LONGS(bits), left = bits % BITS_PER_LONG;
@@ -110,10 +136,11 @@
 	if (off)
 		memset(&dst[lim - off], 0, off*sizeof(unsigned long));
 }
-EXPORT_SYMBOL(bitmap_shift_right);
+EXPORT_SYMBOL(__bitmap_shift_right);
+
 
 /*
- * bitmap_shift_left - logical left shift of the bits in a bitmap
+ * __bitmap_shift_left - logical left shift of the bits in a bitmap
  *   @dst - destination bitmap
  *   @src - source bitmap
  *   @nbits - shift by this many bits
@@ -123,7 +150,8 @@
  * direction.  Zeros are fed into the vacated LS bit positions
  * and those MS bits shifted off the top are lost.
  */
-void bitmap_shift_left(unsigned long *dst,
+
+void __bitmap_shift_left(unsigned long *dst,
 			const unsigned long *src, int shift, int bits)
 {
 	int k, lim = BITS_TO_LONGS(bits), left = bits % BITS_PER_LONG;
@@ -149,9 +177,9 @@
 	if (off)
 		memset(dst, 0, off*sizeof(unsigned long));
 }
-EXPORT_SYMBOL(bitmap_shift_left);
+EXPORT_SYMBOL(__bitmap_shift_left);
 
-void bitmap_and(unsigned long *dst, const unsigned long *bitmap1,
+void __bitmap_and(unsigned long *dst, const unsigned long *bitmap1,
 				const unsigned long *bitmap2, int bits)
 {
 	int k;
@@ -160,9 +188,9 @@
 	for (k = 0; k < nr; k++)
 		dst[k] = bitmap1[k] & bitmap2[k];
 }
-EXPORT_SYMBOL(bitmap_and);
+EXPORT_SYMBOL(__bitmap_and);
 
-void bitmap_or(unsigned long *dst, const unsigned long *bitmap1,
+void __bitmap_or(unsigned long *dst, const unsigned long *bitmap1,
 				const unsigned long *bitmap2, int bits)
 {
 	int k;
@@ -171,10 +199,62 @@
 	for (k = 0; k < nr; k++)
 		dst[k] = bitmap1[k] | bitmap2[k];
 }
-EXPORT_SYMBOL(bitmap_or);
+EXPORT_SYMBOL(__bitmap_or);
+
+void __bitmap_xor(unsigned long *dst, const unsigned long *bitmap1,
+				const unsigned long *bitmap2, int bits)
+{
+	int k;
+	int nr = BITS_TO_LONGS(bits);
+
+	for (k = 0; k < nr; k++)
+		dst[k] = bitmap1[k] ^ bitmap2[k];
+}
+EXPORT_SYMBOL(__bitmap_xor);
+
+void __bitmap_andnot(unsigned long *dst, const unsigned long *bitmap1,
+				const unsigned long *bitmap2, int bits)
+{
+	int k;
+	int nr = BITS_TO_LONGS(bits);
+
+	for (k = 0; k < nr; k++)
+		dst[k] = bitmap1[k] & ~bitmap2[k];
+}
+EXPORT_SYMBOL(__bitmap_andnot);
+
+int __bitmap_intersects(const unsigned long *bitmap1,
+				const unsigned long *bitmap2, int bits)
+{
+	int k, lim = bits/BITS_PER_LONG;
+	for (k = 0; k < lim; ++k)
+		if (bitmap1[k] & bitmap2[k])
+			return 1;
+
+	if (bits % BITS_PER_LONG)
+		if ((bitmap1[k] & bitmap2[k]) & BITMAP_LAST_WORD_MASK(bits))
+			return 1;
+	return 0;
+}
+EXPORT_SYMBOL(__bitmap_intersects);
+
+int __bitmap_subset(const unsigned long *bitmap1,
+				const unsigned long *bitmap2, int bits)
+{
+	int k, lim = bits/BITS_PER_LONG;
+	for (k = 0; k < lim; ++k)
+		if (bitmap1[k] & ~bitmap2[k])
+			return 0;
+
+	if (bits % BITS_PER_LONG)
+		if ((bitmap1[k] & ~bitmap2[k]) & BITMAP_LAST_WORD_MASK(bits))
+			return 0;
+	return 1;
+}
+EXPORT_SYMBOL(__bitmap_subset);
 
 #if BITS_PER_LONG == 32
-int bitmap_weight(const unsigned long *bitmap, int bits)
+int __bitmap_weight(const unsigned long *bitmap, int bits)
 {
 	int k, w = 0, lim = bits/BITS_PER_LONG;
 
@@ -182,13 +262,12 @@
 		w += hweight32(bitmap[k]);
 
 	if (bits % BITS_PER_LONG)
-		w += hweight32(bitmap[k] &
-				((1UL << (bits % BITS_PER_LONG)) - 1));
+		w += hweight32(bitmap[k] & BITMAP_LAST_WORD_MASK(bits));
 
 	return w;
 }
 #else
-int bitmap_weight(const unsigned long *bitmap, int bits)
+int __bitmap_weight(const unsigned long *bitmap, int bits)
 {
 	int k, w = 0, lim = bits/BITS_PER_LONG;
 
@@ -196,13 +275,12 @@
 		w += hweight64(bitmap[k]);
 
 	if (bits % BITS_PER_LONG)
-		w += hweight64(bitmap[k] &
-				((1UL << (bits % BITS_PER_LONG)) - 1));
+		w += hweight64(bitmap[k] & BITMAP_LAST_WORD_MASK(bits));
 
 	return w;
 }
 #endif
-EXPORT_SYMBOL(bitmap_weight);
+EXPORT_SYMBOL(__bitmap_weight);
 
 /*
  * Bitmap printing & parsing functions: first version by Bill Irwin,
@@ -319,7 +397,7 @@
 		if (nchunks == 0 && chunk == 0)
 			continue;
 
-		bitmap_shift_left(maskp, maskp, CHUNKSZ, nmaskbits);
+		__bitmap_shift_left(maskp, maskp, CHUNKSZ, nmaskbits);
 		*maskp |= chunk;
 		nchunks++;
 		nbits += (nchunks == 1) ? nbits_to_hold_value(chunk) : CHUNKSZ;
--- diff/lib/idr.c	2004-05-19 22:13:10.000000000 +0100
+++ source/lib/idr.c	2004-06-11 19:22:07.000000000 +0100
@@ -27,15 +27,6 @@
  * so you don't need to be too concerned about locking and conflicts
  * with the slab allocator.
 
- * A word on reuse.  We reuse empty id slots as soon as we can, always
- * using the lowest one available.  But we also merge a counter in the
- * high bits of the id.  The counter is RESERVED_ID_BITS (8 at this time)
- * long.  This means that if you allocate and release the same id in a 
- * loop we will reuse an id after about 256 times around the loop.  The
- * word about is used here as we will NOT return a valid id of -1 so if
- * you loop on the largest possible id (and that is 24 bits, wow!) we
- * will kick the counter to avoid -1.  (Paranoid?  You bet!)
- *
  * What you need to do is, since we don't keep the counter as part of
  * id / ptr pair, to keep a copy of it in the pointed to structure
  * (or else where) so that when you ask for a ptr you can varify that
@@ -70,14 +61,21 @@
  *   sleep, so must not be called with any spinlocks held.  If the system is
  *   REALLY out of memory this function returns 0, other wise 1.
 
- * int idr_get_new(struct idr *idp, void *ptr);
+ * int idr_get_new(struct idr *idp, void *ptr, int *id);
  
  *   This is the allocate id function.  It should be called with any
  *   required locks.  In fact, in the SMP case, you MUST lock prior to
- *   calling this function to avoid possible out of memory problems.  If
- *   memory is required, it will return a -1, in which case you should
- *   unlock and go back to the idr_pre_get() call.  ptr is the pointer
- *   you want associated with the id.  In other words:
+ *   calling this function to avoid possible out of memory problems.
+ *   If memory is required, it will return -EAGAIN, you should unlock
+ *   and go back to the idr_pre_get() call.  If the idr is full, it
+ *   will return a -ENOSPC.  ptr is the pointer you want associated
+ *   with the id.  The value is returned in the "id" field.  idr_get_new()
+ *   returns a value in the range 0 ... 0x7fffffff
+
+ * int idr_get_new_above(struct idr *idp, void *ptr, int start_id, int *id);
+
+ *   Like idr_get_new(), but the returned id is guaranteed to be at or
+ *   above start_id.
 
  * void *idr_find(struct idr *idp, int id);
  
@@ -92,6 +90,10 @@
  *   removes the given id, freeing that slot and any memory that may
  *   now be unused.  See idr_find() for locking restrictions.
 
+ * int idr_full(struct idr *idp);
+
+ *   Returns true if the idr is full and false if not.
+
  */
 
 
@@ -115,7 +117,7 @@
 
 	spin_lock(&idp->lock);
 	if (!(p = idp->id_free))
-		BUG();
+		return NULL;
 	idp->id_free = p->ary[0];
 	idp->id_free_cnt--;
 	p->ary[0] = 0;
@@ -181,8 +183,8 @@
 			sh = IDR_BITS*l;
 			id = ((id >> sh) ^ n ^ m) << sh;
 		}
-		if (id >= MAX_ID_BIT)
-			return -1;
+		if ((id >= MAX_ID_BIT) || (id < 0))
+			return -3;
 		if (l == 0)
 			break;
 		/*
@@ -220,7 +222,7 @@
 	return(id);
 }
 
-int idr_get_new_above(struct idr *idp, void *ptr, int starting_id)
+static int idr_get_new_above_int(struct idr *idp, void *ptr, int starting_id)
 {
 	struct idr_layer *p, *new;
 	int layers, v, id;
@@ -238,7 +240,7 @@
 	 * Add a new layer to the top of the tree if the requested
 	 * id is larger than the currently allocated space.
 	 */
-	while (id >= (1 << (layers*IDR_BITS))) {
+	while ((layers < MAX_LEVEL) && (id >= (1 << (layers*IDR_BITS)))) {
 		layers++;
 		if (!p->count)
 			continue;
@@ -266,23 +268,47 @@
 	v = sub_alloc(idp, ptr, &id);
 	if (v == -2)
 		goto build_up;
-	if ( likely(v >= 0 )) {
-		idp->count++;
-		v += (idp->count << MAX_ID_SHIFT);
-		if ( unlikely( v == -1 ))
-		     v += (1L << MAX_ID_SHIFT);
-	}
 	return(v);
 }
+
+int idr_get_new_above(struct idr *idp, void *ptr, int starting_id, int *id)
+{
+	int rv;
+	rv = idr_get_new_above_int(idp, ptr, starting_id);
+	/*
+	 * This is a cheap hack until the IDR code can be fixed to
+	 * return proper error values.
+	 */
+	if (rv < 0) {
+		if (rv == -1)
+			return -EAGAIN;
+		else /* Will be -3 */
+			return -ENOSPC;
+	}
+	*id = rv;
+	return 0;
+}
 EXPORT_SYMBOL(idr_get_new_above);
 
-int idr_get_new(struct idr *idp, void *ptr)
+int idr_get_new(struct idr *idp, void *ptr, int *id)
 {
-	return idr_get_new_above(idp, ptr, 0);
+	int rv;
+	rv = idr_get_new_above_int(idp, ptr, 0);
+	/*
+	 * This is a cheap hack until the IDR code can be fixed to
+	 * return proper error values.
+	 */
+	if (rv < 0) {
+		if (rv == -1)
+			return -EAGAIN;
+		else /* Will be -3 */
+			return -ENOSPC;
+	}
+	*id = rv;
+	return 0;
 }
 EXPORT_SYMBOL(idr_get_new);
 
-
 static void sub_remove(struct idr *idp, int shift, int id)
 {
 	struct idr_layer *p = idp->top;
@@ -311,10 +337,14 @@
 			idp->layers = 0;
 	}
 }
+
 void idr_remove(struct idr *idp, int id)
 {
 	struct idr_layer *p;
 
+	/* Mask off upper bits we don't use for the search. */
+	id &= MAX_ID_MASK;
+
 	sub_remove(idp, (idp->layers - 1) * IDR_BITS, id);
 	if ( idp->top && idp->top->count == 1 && 
 	     (idp->layers > 1) &&
@@ -350,6 +380,9 @@
 	if ( unlikely( (id & ~(~0 << MAX_ID_SHIFT)) >> (n + IDR_BITS)))
 	     return NULL;
 #endif
+	/* Mask off upper bits we don't use for the search. */
+	id &= MAX_ID_MASK;
+
 	while (n > 0 && p) {
 		n -= IDR_BITS;
 		p = p->ary[(id >> n) & IDR_MASK];
--- diff/lib/radix-tree.c	2004-06-11 19:17:36.000000000 +0100
+++ source/lib/radix-tree.c	2004-06-11 19:22:07.000000000 +0100
@@ -136,13 +136,12 @@
 
 static inline void tag_set(struct radix_tree_node *node, int tag, int offset)
 {
-	if (!test_bit(offset, &node->tags[tag][0]))
-		__set_bit(offset, &node->tags[tag][0]);
+	set_bit(offset, &node->tags[tag][0]);
 }
 
 static inline void tag_clear(struct radix_tree_node *node, int tag, int offset)
 {
-	__clear_bit(offset, &node->tags[tag][0]);
+	clear_bit(offset, &node->tags[tag][0]);
 }
 
 static inline int tag_get(struct radix_tree_node *node, int tag, int offset)
@@ -321,6 +320,11 @@
  *
  *	Returns the address of the tagged item.   Setting a tag on a not-present
  *	item is a bug.
+ *
+ *	radix_tree_tag_set() atomically sets the tag and does not actually
+ *	change the overall tree structure.  Consequently it is sufficient that
+ *	the caller use an rwlock in read-mode while running
+ *	radix_tree_tag_set().
  */
 void *radix_tree_tag_set(struct radix_tree_root *root,
 			unsigned long index, int tag)
@@ -362,6 +366,11 @@
  *
  *	Returns the address of the tagged item on success, else NULL.  ie:
  *	has the same return value and semantics as radix_tree_lookup().
+ *
+ *	radix_tree_tag_clear() atomically sets the tag and does not actually
+ *	change the overall tree structure.  Consequently it is sufficient that
+ *	the caller use an rwlock in read-mode while running
+ *	radix_tree_tag_clear().
  */
 void *radix_tree_tag_clear(struct radix_tree_root *root,
 			unsigned long index, int tag)
--- diff/lib/rwsem.c	2004-05-19 22:13:10.000000000 +0100
+++ source/lib/rwsem.c	2004-06-11 19:22:07.000000000 +0100
@@ -29,15 +29,15 @@
 
 /*
  * handle the lock being released whilst there are processes blocked on it that can now run
- * - if we come here, then:
- *   - the 'active part' of the count (&0x0000ffff) reached zero but has been re-incremented
+ * - if we come here from up_xxxx(), then:
+ *   - the 'active part' of the count (&0x0000ffff) had reached zero (but may have changed)
  *   - the 'waiting part' of the count (&0xffff0000) is negative (and will still be so)
  *   - there must be someone on the queue
  * - the spinlock must be held by the caller
  * - woken process blocks are discarded from the list after having task zeroed
- * - writers are only woken if wakewrite is non-zero
+ * - writers are only woken if downgrading is false
  */
-static inline struct rw_semaphore *__rwsem_do_wake(struct rw_semaphore *sem, int wakewrite)
+static inline struct rw_semaphore *__rwsem_do_wake(struct rw_semaphore *sem, int downgrading)
 {
 	struct rwsem_waiter *waiter;
 	struct task_struct *tsk;
@@ -46,10 +46,12 @@
 
 	rwsemtrace(sem,"Entering __rwsem_do_wake");
 
-	if (!wakewrite)
+	if (downgrading)
 		goto dont_wake_writers;
 
-	/* only wake someone up if we can transition the active part of the count from 0 -> 1 */
+	/* if we came through an up_xxxx() call, we only only wake someone up
+	 * if we can transition the active part of the count from 0 -> 1
+	 */
  try_again:
 	oldcount = rwsem_atomic_update(RWSEM_ACTIVE_BIAS,sem) - RWSEM_ACTIVE_BIAS;
 	if (oldcount & RWSEM_ACTIVE_MASK)
@@ -78,9 +80,10 @@
 	if (waiter->flags & RWSEM_WAITING_FOR_WRITE)
 		goto out;
 
-	/* grant an infinite number of read locks to the readers at the front of the queue
-	 * - note we increment the 'active part' of the count by the number of readers (less one
-	 *   for the activity decrement we've already done) before waking any processes up
+	/* grant an infinite number of read locks to the readers at the front
+	 * of the queue
+	 * - note we increment the 'active part' of the count by the number of
+	 *   readers before waking any processes up
 	 */
  readers_only:
 	woken = 0;
@@ -95,8 +98,10 @@
 	} while (waiter->flags & RWSEM_WAITING_FOR_READ);
 
 	loop = woken;
-	woken *= RWSEM_ACTIVE_BIAS-RWSEM_WAITING_BIAS;
-	woken -= RWSEM_ACTIVE_BIAS;
+	woken *= RWSEM_ACTIVE_BIAS - RWSEM_WAITING_BIAS;
+	if (!downgrading)
+		woken -= RWSEM_ACTIVE_BIAS; /* we'd already done one increment
+					     * earlier */
 	rwsem_atomic_add(woken,sem);
 
 	next = sem->wait_list.next;
@@ -150,7 +155,7 @@
 	 * - it might even be this process, since the waker takes a more active part
 	 */
 	if (!(count & RWSEM_ACTIVE_MASK))
-		sem = __rwsem_do_wake(sem,1);
+		sem = __rwsem_do_wake(sem, 0);
 
 	spin_unlock(&sem->wait_lock);
 
@@ -201,7 +206,7 @@
 
 /*
  * handle waking up a waiter on the semaphore
- * - up_read has decremented the active part of the count if we come here
+ * - up_read/up_write has decremented the active part of the count if we come here
  */
 struct rw_semaphore fastcall *rwsem_wake(struct rw_semaphore *sem)
 {
@@ -211,7 +216,7 @@
 
 	/* do nothing if list empty */
 	if (!list_empty(&sem->wait_list))
-		sem = __rwsem_do_wake(sem,1);
+		sem = __rwsem_do_wake(sem, 0);
 
 	spin_unlock(&sem->wait_lock);
 
@@ -233,7 +238,7 @@
 
 	/* do nothing if list empty */
 	if (!list_empty(&sem->wait_list))
-		sem = __rwsem_do_wake(sem,0);
+		sem = __rwsem_do_wake(sem, 1);
 
 	spin_unlock(&sem->wait_lock);
 
--- diff/mm/filemap.c	2004-06-11 19:17:36.000000000 +0100
+++ source/mm/filemap.c	2004-06-11 19:22:07.000000000 +0100
@@ -114,9 +114,9 @@
 	if (unlikely(!PageLocked(page)))
 		PAGE_BUG(page);
 
-	spin_lock_irq(&mapping->tree_lock);
+	write_lock_irq(&mapping->tree_lock);
 	__remove_from_page_cache(page);
-	spin_unlock_irq(&mapping->tree_lock);
+	write_unlock_irq(&mapping->tree_lock);
 }
 
 static inline int sync_page(struct page *page)
@@ -253,7 +253,7 @@
 	int error = radix_tree_preload(gfp_mask & ~__GFP_HIGHMEM);
 
 	if (error == 0) {
-		spin_lock_irq(&mapping->tree_lock);
+		write_lock_irq(&mapping->tree_lock);
 		error = radix_tree_insert(&mapping->page_tree, offset, page);
 		if (!error) {
 			page_cache_get(page);
@@ -263,7 +263,7 @@
 			mapping->nrpages++;
 			pagecache_acct(1);
 		}
-		spin_unlock_irq(&mapping->tree_lock);
+		write_unlock_irq(&mapping->tree_lock);
 		radix_tree_preload_end();
 	}
 	return error;
@@ -436,11 +436,11 @@
 	 * We scan the hash list read-only. Addition to and removal from
 	 * the hash-list needs a held write-lock.
 	 */
-	spin_lock_irq(&mapping->tree_lock);
+	read_lock_irq(&mapping->tree_lock);
 	page = radix_tree_lookup(&mapping->page_tree, offset);
 	if (page)
 		page_cache_get(page);
-	spin_unlock_irq(&mapping->tree_lock);
+	read_unlock_irq(&mapping->tree_lock);
 	return page;
 }
 
@@ -453,11 +453,11 @@
 {
 	struct page *page;
 
-	spin_lock_irq(&mapping->tree_lock);
+	read_lock_irq(&mapping->tree_lock);
 	page = radix_tree_lookup(&mapping->page_tree, offset);
 	if (page && TestSetPageLocked(page))
 		page = NULL;
-	spin_unlock_irq(&mapping->tree_lock);
+	read_unlock_irq(&mapping->tree_lock);
 	return page;
 }
 
@@ -479,15 +479,15 @@
 {
 	struct page *page;
 
-	spin_lock_irq(&mapping->tree_lock);
+	read_lock_irq(&mapping->tree_lock);
 repeat:
 	page = radix_tree_lookup(&mapping->page_tree, offset);
 	if (page) {
 		page_cache_get(page);
 		if (TestSetPageLocked(page)) {
-			spin_unlock_irq(&mapping->tree_lock);
+			read_unlock_irq(&mapping->tree_lock);
 			lock_page(page);
-			spin_lock_irq(&mapping->tree_lock);
+			read_lock_irq(&mapping->tree_lock);
 
 			/* Has the page been truncated while we slept? */
 			if (page->mapping != mapping || page->index != offset) {
@@ -497,7 +497,7 @@
 			}
 		}
 	}
-	spin_unlock_irq(&mapping->tree_lock);
+	read_unlock_irq(&mapping->tree_lock);
 	return page;
 }
 
@@ -571,12 +571,12 @@
 	unsigned int i;
 	unsigned int ret;
 
-	spin_lock_irq(&mapping->tree_lock);
+	read_lock_irq(&mapping->tree_lock);
 	ret = radix_tree_gang_lookup(&mapping->page_tree,
 				(void **)pages, start, nr_pages);
 	for (i = 0; i < ret; i++)
 		page_cache_get(pages[i]);
-	spin_unlock_irq(&mapping->tree_lock);
+	read_unlock_irq(&mapping->tree_lock);
 	return ret;
 }
 
@@ -590,14 +590,14 @@
 	unsigned int i;
 	unsigned int ret;
 
-	spin_lock_irq(&mapping->tree_lock);
+	read_lock_irq(&mapping->tree_lock);
 	ret = radix_tree_gang_lookup_tag(&mapping->page_tree,
 				(void **)pages, *index, nr_pages, tag);
 	for (i = 0; i < ret; i++)
 		page_cache_get(pages[i]);
 	if (ret)
 		*index = pages[ret - 1]->index + 1;
-	spin_unlock_irq(&mapping->tree_lock);
+	read_unlock_irq(&mapping->tree_lock);
 	return ret;
 }
 
@@ -650,7 +650,8 @@
 			     read_actor_t actor)
 {
 	struct inode *inode = mapping->host;
-	unsigned long index, offset;
+	unsigned long index, end_index, offset;
+	loff_t isize;
 	struct page *cached_page;
 	int error;
 	struct file_ra_state ra = *_ra;
@@ -659,26 +660,18 @@
 	index = *ppos >> PAGE_CACHE_SHIFT;
 	offset = *ppos & ~PAGE_CACHE_MASK;
 
+	isize = i_size_read(inode);
+	end_index = isize >> PAGE_CACHE_SHIFT;
+	if (index > end_index)
+		goto out;
+
 	for (;;) {
 		struct page *page;
-		unsigned long end_index, nr, ret;
-		loff_t isize = i_size_read(inode);
-
-		end_index = isize >> PAGE_CACHE_SHIFT;
-			
-		if (index > end_index)
-			break;
-		nr = PAGE_CACHE_SIZE;
-		if (index == end_index) {
-			nr = isize & ~PAGE_CACHE_MASK;
-			if (nr <= offset)
-				break;
-		}
+		unsigned long nr, ret;
 
 		cond_resched();
 		page_cache_readahead(mapping, &ra, filp, index);
 
-		nr = nr - offset;
 find_page:
 		page = find_get_page(mapping, index);
 		if (unlikely(page == NULL)) {
@@ -688,6 +681,17 @@
 		if (!PageUptodate(page))
 			goto page_not_up_to_date;
 page_ok:
+		/* nr is the maximum number of bytes to copy from this page */
+		nr = PAGE_CACHE_SIZE;
+		if (index == end_index) {
+			nr = isize & ~PAGE_CACHE_MASK;
+			if (nr <= offset) {
+				page_cache_release(page);
+				goto out;
+			}
+		}
+		nr = nr - offset;
+
 		/* If users can be writing to this page using arbitrary
 		 * virtual addresses, take care about potential aliasing
 		 * before reading the page on the kernel side.
@@ -719,7 +723,7 @@
 		page_cache_release(page);
 		if (ret == nr && desc->count)
 			continue;
-		break;
+		goto out;
 
 page_not_up_to_date:
 		/* Get exclusive access to the page ... */
@@ -739,22 +743,41 @@
 		}
 
 readpage:
-		/* ... and start the actual read. The read will unlock the page. */
+		/* Start the actual read. The read will unlock the page. */
 		error = mapping->a_ops->readpage(filp, page);
 
-		if (!error) {
-			if (PageUptodate(page))
-				goto page_ok;
+		if (unlikely(error))
+			goto readpage_error;
+
+		if (!PageUptodate(page)) {
 			wait_on_page_locked(page);
-			if (PageUptodate(page))
-				goto page_ok;
-			error = -EIO;
+			if (!PageUptodate(page)) {
+				error = -EIO;
+				goto readpage_error;
+			}
+		}
+
+		/*
+		 * i_size must be checked after we have done ->readpage.
+		 *
+		 * Checking i_size after the readpage allows us to calculate
+		 * the correct value for "nr", which means the zero-filled
+		 * part of the page is not copied back to userspace (unless
+		 * another truncate extends the file - this is desired though).
+		 */
+		isize = i_size_read(inode);
+		end_index = isize >> PAGE_CACHE_SHIFT;
+		if (index > end_index) {
+			page_cache_release(page);
+			goto out;
 		}
+		goto page_ok;
 
+readpage_error:
 		/* UHHUH! A synchronous read error occurred. Report it */
 		desc->error = error;
 		page_cache_release(page);
-		break;
+		goto out;
 
 no_cached_page:
 		/*
@@ -765,7 +788,7 @@
 			cached_page = page_cache_alloc_cold(mapping);
 			if (!cached_page) {
 				desc->error = -ENOMEM;
-				break;
+				goto out;
 			}
 		}
 		error = add_to_page_cache_lru(cached_page, mapping,
@@ -774,13 +797,14 @@
 			if (error == -EEXIST)
 				goto find_page;
 			desc->error = error;
-			break;
+			goto out;
 		}
 		page = cached_page;
 		cached_page = NULL;
 		goto readpage;
 	}
 
+out:
 	*_ra = ra;
 
 	*ppos = ((loff_t) index << PAGE_CACHE_SHIFT) + offset;
--- diff/mm/fremap.c	2004-06-11 19:17:36.000000000 +0100
+++ source/mm/fremap.c	2004-06-11 19:22:07.000000000 +0100
@@ -161,6 +161,7 @@
 	unsigned long end = start + size;
 	struct vm_area_struct *vma;
 	int err = -EINVAL;
+	int has_write_lock = 0;
 
 	if (__prot)
 		return err;
@@ -181,7 +182,8 @@
 #endif
 
 	/* We need down_write() to change vma->vm_flags. */
-	down_write(&mm->mmap_sem);
+	down_read(&mm->mmap_sem);
+ retry:
 	vma = find_vma(mm, start);
 
 	/*
@@ -200,6 +202,12 @@
 		/* Must set VM_NONLINEAR before any pages are populated. */
 		if (pgoff != linear_page_index(vma, start) &&
 		    !(vma->vm_flags & VM_NONLINEAR)) {
+			if (!has_write_lock) {
+				up_read(&mm->mmap_sem);
+				down_write(&mm->mmap_sem);
+				has_write_lock = 1;
+				goto retry;
+			}
 			mapping = vma->vm_file->f_mapping;
 			spin_lock(&mapping->i_mmap_lock);
 			flush_dcache_mmap_lock(mapping);
@@ -212,8 +220,6 @@
 			spin_unlock(&mapping->i_mmap_lock);
 		}
 
-		/* ->populate can take a long time, so downgrade the lock. */
-		downgrade_write(&mm->mmap_sem);
 		err = vma->vm_ops->populate(vma, start, size,
 					    vma->vm_page_prot,
 					    pgoff, flags & MAP_NONBLOCK);
@@ -223,10 +229,11 @@
 		 * it after ->populate completes, and that would prevent
 		 * downgrading the lock.  (Locks can't be upgraded).
 		 */
+	}
+	if (likely(!has_write_lock))
 		up_read(&mm->mmap_sem);
-	} else {
+	else
 		up_write(&mm->mmap_sem);
-	}
 
 	return err;
 }
--- diff/mm/highmem.c	2004-05-19 22:13:11.000000000 +0100
+++ source/mm/highmem.c	2004-06-11 19:22:07.000000000 +0100
@@ -26,7 +26,6 @@
 #include <linux/init.h>
 #include <linux/hash.h>
 #include <linux/highmem.h>
-#include <asm/pgalloc.h>
 #include <asm/tlbflush.h>
 
 static mempool_t *page_pool, *isa_page_pool;
--- diff/mm/memory.c	2004-06-11 19:17:36.000000000 +0100
+++ source/mm/memory.c	2004-06-11 19:22:07.000000000 +0100
@@ -696,6 +696,7 @@
 		struct page **pages, struct vm_area_struct **vmas)
 {
 	int i;
+	int vm_io;
 	unsigned int flags;
 
 	/* 
@@ -739,9 +740,11 @@
 			continue;
 		}
 
-		if (!vma || (pages && (vma->vm_flags & VM_IO))
-				|| !(flags & vma->vm_flags))
-			return i ? : -EFAULT;
+		if (!vma)
+			return i ? i : -EFAULT;
+		vm_io = vma->vm_flags & VM_IO;
+		if ((pages && vm_io) || !(flags & vma->vm_flags))
+			return i ? i : -EFAULT;
 
 		if (is_vm_hugetlb_page(vma)) {
 			i = follow_hugetlb_page(mm, vma, pages, vmas,
@@ -750,8 +753,15 @@
 		}
 		spin_lock(&mm->page_table_lock);
 		do {
-			struct page *map;
+			struct page *map = NULL;
 			int lookup_write = write;
+
+			/*
+			 * We don't follow pagetables for VM_IO regions - they
+			 * may have no pageframes.
+			 */
+			if (vm_io)
+				goto no_follow;
 			while (!(map = follow_page(mm, start, lookup_write))) {
 				/*
 				 * Shortcut for anonymous pages. We don't want
@@ -803,6 +813,7 @@
 				if (!PageReserved(pages[i]))
 					page_cache_get(pages[i]);
 			}
+no_follow:
 			if (vmas)
 				vmas[i] = vma;
 			i++;
@@ -1206,6 +1217,8 @@
 {
 	struct address_space *mapping = inode->i_mapping;
 	unsigned long limit;
+	loff_t i_size;
+	struct page *page;
 
 	if (inode->i_size < offset)
 		goto do_expand;
@@ -1220,8 +1233,24 @@
 		goto out_sig;
 	if (offset > inode->i_sb->s_maxbytes)
 		goto out;
-	i_size_write(inode, offset);
 
+	/*
+	 * Put a pagecache page at the current i_size and lock it while
+	 * modifying i_size to synchronise against block_write_full_page()'s
+	 * sampling of i_size.  Otherwise block_write_full_page() may decide to
+	 * memset part of this page after the application extended the file
+	 * size.
+	 */
+	i_size = inode->i_size;	/* don't need i_size_read() due to i_sem */
+	page = NULL;
+	if (i_size & (PAGE_CACHE_SIZE - 1))
+		page = grab_cache_page(inode->i_mapping,
+					i_size >> PAGE_CACHE_SHIFT);
+	i_size_write(inode, offset);
+	if (page) {
+		unlock_page(page);
+		page_cache_release(page);
+	}
 out_truncate:
 	if (inode->i_op && inode->i_op->truncate)
 		inode->i_op->truncate(inode);
--- diff/mm/mempolicy.c	2004-06-11 19:17:36.000000000 +0100
+++ source/mm/mempolicy.c	2004-06-11 19:22:07.000000000 +0100
@@ -92,14 +92,12 @@
 /* Check if all specified nodes are online */
 static int nodes_online(unsigned long *nodes)
 {
-	DECLARE_BITMAP(offline, MAX_NUMNODES);
+	DECLARE_BITMAP(online2, MAX_NUMNODES);
 
-	bitmap_copy(offline, node_online_map, MAX_NUMNODES);
-	if (bitmap_empty(offline, MAX_NUMNODES))
-		set_bit(0, offline);
-	bitmap_complement(offline, MAX_NUMNODES);
-	bitmap_and(offline, offline, nodes, MAX_NUMNODES);
-	if (!bitmap_empty(offline, MAX_NUMNODES))
+	bitmap_copy(online2, node_online_map, MAX_NUMNODES);
+	if (bitmap_empty(online2, MAX_NUMNODES))
+		set_bit(0, online2);
+	if (!bitmap_subset(nodes, online2, MAX_NUMNODES))
 		return -EINVAL;
 	return 0;
 }
@@ -1001,7 +999,8 @@
 	up(&p->sem);
 }
 
-static __init int numa_policy_init(void)
+/* assumes fs == KERNEL_DS */
+void __init numa_policy_init(void)
 {
 	policy_cache = kmem_cache_create("numa_policy",
 					 sizeof(struct mempolicy),
@@ -1010,6 +1009,17 @@
 	sn_cache = kmem_cache_create("shared_policy_node",
 				     sizeof(struct sp_node),
 				     0, SLAB_PANIC, NULL, NULL);
-	return 0;
+
+	/* Set interleaving policy for system init. This way not all
+	   the data structures allocated at system boot end up in node zero. */
+
+	if (sys_set_mempolicy(MPOL_INTERLEAVE, &node_online_map, MAX_NUMNODES) < 0)
+		printk("numa_policy_init: interleaving failed\n");
+}
+
+/* Reset policy of current process to default.
+ * Assumes fs == KERNEL_DS */
+void __init numa_default_policy(void)
+{
+	sys_set_mempolicy(MPOL_DEFAULT, NULL, 0);
 }
-module_init(numa_policy_init);
--- diff/mm/mempool.c	2004-05-19 22:13:11.000000000 +0100
+++ source/mm/mempool.c	2004-06-11 19:22:07.000000000 +0100
@@ -89,11 +89,6 @@
 }
 EXPORT_SYMBOL(mempool_create);
 
-/*
- * mempool_resize is disabled for now, because it has no callers.  Feel free
- * to turn it back on if needed.
- */
-#if 0
 /**
  * mempool_resize - resize an existing memory pool
  * @pool:       pointer to the memory pool which was allocated via
@@ -163,7 +158,6 @@
 	return 0;
 }
 EXPORT_SYMBOL(mempool_resize);
-#endif
 
 /**
  * mempool_destroy - deallocate a memory pool
--- diff/mm/mincore.c	2004-06-11 19:17:36.000000000 +0100
+++ source/mm/mincore.c	2004-06-11 19:22:07.000000000 +0100
@@ -14,7 +14,6 @@
 
 #include <asm/uaccess.h>
 #include <asm/pgtable.h>
-#include <asm/pgalloc.h>
 
 /*
  * Later we can get more picky about what "in core" means precisely.
--- diff/mm/mmap.c	2004-06-11 19:17:36.000000000 +0100
+++ source/mm/mmap.c	2004-06-11 19:22:07.000000000 +0100
@@ -25,7 +25,6 @@
 #include <linux/rmap.h>
 
 #include <asm/uaccess.h>
-#include <asm/pgalloc.h>
 #include <asm/cacheflush.h>
 #include <asm/tlb.h>
 
--- diff/mm/mprotect.c	2004-06-11 19:17:36.000000000 +0100
+++ source/mm/mprotect.c	2004-06-11 19:22:07.000000000 +0100
@@ -19,7 +19,6 @@
 #include <linux/mempolicy.h>
 
 #include <asm/uaccess.h>
-#include <asm/pgalloc.h>
 #include <asm/pgtable.h>
 #include <asm/cacheflush.h>
 #include <asm/tlbflush.h>
--- diff/mm/mremap.c	2004-06-11 19:17:36.000000000 +0100
+++ source/mm/mremap.c	2004-06-11 19:22:07.000000000 +0100
@@ -18,7 +18,6 @@
 #include <linux/security.h>
 
 #include <asm/uaccess.h>
-#include <asm/pgalloc.h>
 #include <asm/cacheflush.h>
 #include <asm/tlbflush.h>
 
--- diff/mm/msync.c	2004-06-11 19:17:36.000000000 +0100
+++ source/mm/msync.c	2004-06-11 19:22:07.000000000 +0100
@@ -14,7 +14,6 @@
 #include <linux/hugetlb.h>
 
 #include <asm/pgtable.h>
-#include <asm/pgalloc.h>
 #include <asm/tlbflush.h>
 
 /*
--- diff/mm/nommu.c	2004-06-11 19:17:36.000000000 +0100
+++ source/mm/nommu.c	2004-06-11 19:22:07.000000000 +0100
@@ -20,7 +20,6 @@
 #include <linux/blkdev.h>
 #include <linux/backing-dev.h>
 
-#include <asm/pgalloc.h>
 #include <asm/uaccess.h>
 #include <asm/tlb.h>
 #include <asm/tlbflush.h>
--- diff/mm/page-writeback.c	2004-06-11 19:17:36.000000000 +0100
+++ source/mm/page-writeback.c	2004-06-11 19:22:07.000000000 +0100
@@ -99,6 +99,22 @@
 
 static void background_writeout(unsigned long _min_pages);
 
+struct writeback_state
+{
+	unsigned long nr_dirty;
+	unsigned long nr_unstable;
+	unsigned long nr_mapped;
+	unsigned long nr_writeback;
+};
+
+static void get_writeback_state(struct writeback_state *wbs)
+{
+	wbs->nr_dirty = read_page_state(nr_dirty);
+	wbs->nr_unstable = read_page_state(nr_unstable);
+	wbs->nr_mapped = read_page_state(nr_mapped);
+	wbs->nr_writeback = read_page_state(nr_writeback);
+}
+
 /*
  * Work out the current dirty-memory clamping and background writeout
  * thresholds.
@@ -117,7 +133,7 @@
  * clamping level.
  */
 static void
-get_dirty_limits(struct page_state *ps, long *pbackground, long *pdirty)
+get_dirty_limits(struct writeback_state *wbs, long *pbackground, long *pdirty)
 {
 	int background_ratio;		/* Percentages */
 	int dirty_ratio;
@@ -126,9 +142,9 @@
 	long dirty;
 	struct task_struct *tsk;
 
-	get_page_state(ps);
+	get_writeback_state(wbs);
 
-	unmapped_ratio = 100 - (ps->nr_mapped * 100) / total_pages;
+	unmapped_ratio = 100 - (wbs->nr_mapped * 100) / total_pages;
 
 	dirty_ratio = vm_dirty_ratio;
 	if (dirty_ratio > unmapped_ratio / 2)
@@ -161,7 +177,7 @@
  */
 static void balance_dirty_pages(struct address_space *mapping)
 {
-	struct page_state ps;
+	struct writeback_state wbs;
 	long nr_reclaimable;
 	long background_thresh;
 	long dirty_thresh;
@@ -178,9 +194,9 @@
 			.nr_to_write	= write_chunk,
 		};
 
-		get_dirty_limits(&ps, &background_thresh, &dirty_thresh);
-		nr_reclaimable = ps.nr_dirty + ps.nr_unstable;
-		if (nr_reclaimable + ps.nr_writeback <= dirty_thresh)
+		get_dirty_limits(&wbs, &background_thresh, &dirty_thresh);
+		nr_reclaimable = wbs.nr_dirty + wbs.nr_unstable;
+		if (nr_reclaimable + wbs.nr_writeback <= dirty_thresh)
 			break;
 
 		dirty_exceeded = 1;
@@ -193,10 +209,10 @@
 		 */
 		if (nr_reclaimable) {
 			writeback_inodes(&wbc);
-			get_dirty_limits(&ps, &background_thresh,
+			get_dirty_limits(&wbs, &background_thresh,
 					&dirty_thresh);
-			nr_reclaimable = ps.nr_dirty + ps.nr_unstable;
-			if (nr_reclaimable + ps.nr_writeback <= dirty_thresh)
+			nr_reclaimable = wbs.nr_dirty + wbs.nr_unstable;
+			if (nr_reclaimable + wbs.nr_writeback <= dirty_thresh)
 				break;
 			pages_written += write_chunk - wbc.nr_to_write;
 			if (pages_written >= write_chunk)
@@ -205,7 +221,7 @@
 		blk_congestion_wait(WRITE, HZ/10);
 	}
 
-	if (nr_reclaimable + ps.nr_writeback <= dirty_thresh)
+	if (nr_reclaimable + wbs.nr_writeback <= dirty_thresh)
 		dirty_exceeded = 0;
 
 	if (writeback_in_progress(bdi))
@@ -232,10 +248,10 @@
  * which was newly dirtied.  The function will periodically check the system's
  * dirty state and will initiate writeback if needed.
  *
- * On really big machines, get_page_state is expensive, so try to avoid calling
- * it too often (ratelimiting).  But once we're over the dirty memory limit we
- * decrease the ratelimiting by a lot, to prevent individual processes from
- * overshooting the limit by (ratelimit_pages) each.
+ * On really big machines, get_writeback_state is expensive, so try to avoid
+ * calling it too often (ratelimiting).  But once we're over the dirty memory
+ * limit we decrease the ratelimiting by a lot, to prevent individual processes
+ * from overshooting the limit by (ratelimit_pages) each.
  */
 void balance_dirty_pages_ratelimited(struct address_space *mapping)
 {
@@ -276,12 +292,12 @@
 	};
 
 	for ( ; ; ) {
-		struct page_state ps;
+		struct writeback_state wbs;
 		long background_thresh;
 		long dirty_thresh;
 
-		get_dirty_limits(&ps, &background_thresh, &dirty_thresh);
-		if (ps.nr_dirty + ps.nr_unstable < background_thresh
+		get_dirty_limits(&wbs, &background_thresh, &dirty_thresh);
+		if (wbs.nr_dirty + wbs.nr_unstable < background_thresh
 				&& min_pages <= 0)
 			break;
 		wbc.encountered_congestion = 0;
@@ -306,10 +322,10 @@
 int wakeup_bdflush(long nr_pages)
 {
 	if (nr_pages == 0) {
-		struct page_state ps;
+		struct writeback_state wbs;
 
-		get_page_state(&ps);
-		nr_pages = ps.nr_dirty + ps.nr_unstable;
+		get_writeback_state(&wbs);
+		nr_pages = wbs.nr_dirty + wbs.nr_unstable;
 	}
 	return pdflush_operation(background_writeout, nr_pages);
 }
@@ -343,7 +359,7 @@
 	unsigned long start_jif;
 	unsigned long next_jif;
 	long nr_to_write;
-	struct page_state ps;
+	struct writeback_state wbs;
 	struct writeback_control wbc = {
 		.bdi		= NULL,
 		.sync_mode	= WB_SYNC_NONE,
@@ -355,11 +371,11 @@
 
 	sync_supers();
 
-	get_page_state(&ps);
+	get_writeback_state(&wbs);
 	oldest_jif = jiffies - (dirty_expire_centisecs * HZ) / 100;
 	start_jif = jiffies;
 	next_jif = start_jif + (dirty_writeback_centisecs * HZ) / 100;
-	nr_to_write = ps.nr_dirty + ps.nr_unstable +
+	nr_to_write = wbs.nr_dirty + wbs.nr_unstable +
 			(inodes_stat.nr_inodes - inodes_stat.nr_unused);
 	while (nr_to_write > 0) {
 		wbc.encountered_congestion = 0;
@@ -434,8 +450,8 @@
 /*
  * If ratelimit_pages is too high then we can get into dirty-data overload
  * if a large number of processes all perform writes at the same time.
- * If it is too low then SMP machines will call the (expensive) get_page_state
- * too often.
+ * If it is too low then SMP machines will call the (expensive)
+ * get_writeback_state too often.
  *
  * Here we set ratelimit_pages to a level which ensures that when all CPUs are
  * dirtying in parallel, we cannot go more than 3% (1/32) over the dirty memory
@@ -566,7 +582,7 @@
 		struct address_space *mapping = page_mapping(page);
 
 		if (mapping) {
-			spin_lock_irq(&mapping->tree_lock);
+			read_lock_irq(&mapping->tree_lock);
 			mapping = page_mapping(page);
 			if (page_mapping(page)) { /* Race with truncate? */
 				BUG_ON(page_mapping(page) != mapping);
@@ -575,7 +591,7 @@
 				radix_tree_tag_set(&mapping->page_tree,
 					page_index(page), PAGECACHE_TAG_DIRTY);
 			}
-			spin_unlock_irq(&mapping->tree_lock);
+			read_unlock_irq(&mapping->tree_lock);
 			if (mapping->host) {
 				/* !PageAnon && !swapper_space */
 				__mark_inode_dirty(mapping->host,
@@ -650,17 +666,17 @@
 	unsigned long flags;
 
 	if (mapping) {
-		spin_lock_irqsave(&mapping->tree_lock, flags);
+		read_lock_irqsave(&mapping->tree_lock, flags);
 		if (TestClearPageDirty(page)) {
 			radix_tree_tag_clear(&mapping->page_tree,
 						page_index(page),
 						PAGECACHE_TAG_DIRTY);
-			spin_unlock_irqrestore(&mapping->tree_lock, flags);
+			read_unlock_irqrestore(&mapping->tree_lock, flags);
 			if (!mapping->backing_dev_info->memory_backed)
 				dec_page_state(nr_dirty);
 			return 1;
 		}
-		spin_unlock_irqrestore(&mapping->tree_lock, flags);
+		read_unlock_irqrestore(&mapping->tree_lock, flags);
 		return 0;
 	}
 	return TestClearPageDirty(page);
@@ -707,15 +723,15 @@
 	if (mapping) {
 		unsigned long flags;
 
-		spin_lock_irqsave(&mapping->tree_lock, flags);
+		read_lock_irqsave(&mapping->tree_lock, flags);
 		if (TestClearPageDirty(page)) {
 			radix_tree_tag_clear(&mapping->page_tree,
 						page_index(page),
 						PAGECACHE_TAG_DIRTY);
-			spin_unlock_irqrestore(&mapping->tree_lock, flags);
+			read_unlock_irqrestore(&mapping->tree_lock, flags);
 			return 1;
 		}
-		spin_unlock_irqrestore(&mapping->tree_lock, flags);
+		read_unlock_irqrestore(&mapping->tree_lock, flags);
 		return 0;
 	}
 	return TestClearPageDirty(page);
@@ -729,13 +745,13 @@
 	if (mapping) {
 		unsigned long flags;
 
-		spin_lock_irqsave(&mapping->tree_lock, flags);
+		read_lock_irqsave(&mapping->tree_lock, flags);
 		ret = TestClearPageWriteback(page);
 		if (ret)
 			radix_tree_tag_clear(&mapping->page_tree,
 						page_index(page),
 						PAGECACHE_TAG_WRITEBACK);
-		spin_unlock_irqrestore(&mapping->tree_lock, flags);
+		read_unlock_irqrestore(&mapping->tree_lock, flags);
 	} else {
 		ret = TestClearPageWriteback(page);
 	}
@@ -750,7 +766,7 @@
 	if (mapping) {
 		unsigned long flags;
 
-		spin_lock_irqsave(&mapping->tree_lock, flags);
+		read_lock_irqsave(&mapping->tree_lock, flags);
 		ret = TestSetPageWriteback(page);
 		if (!ret)
 			radix_tree_tag_set(&mapping->page_tree,
@@ -760,7 +776,7 @@
 			radix_tree_tag_clear(&mapping->page_tree,
 						page_index(page),
 						PAGECACHE_TAG_DIRTY);
-		spin_unlock_irqrestore(&mapping->tree_lock, flags);
+		read_unlock_irqrestore(&mapping->tree_lock, flags);
 	} else {
 		ret = TestSetPageWriteback(page);
 	}
@@ -778,9 +794,9 @@
 	unsigned long flags;
 	int ret;
 
-	spin_lock_irqsave(&mapping->tree_lock, flags);
+	read_lock_irqsave(&mapping->tree_lock, flags);
 	ret = radix_tree_tagged(&mapping->page_tree, tag);
-	spin_unlock_irqrestore(&mapping->tree_lock, flags);
+	read_unlock_irqrestore(&mapping->tree_lock, flags);
 	return ret;
 }
 EXPORT_SYMBOL(mapping_tagged);
--- diff/mm/page_alloc.c	2004-06-11 19:17:36.000000000 +0100
+++ source/mm/page_alloc.c	2004-06-11 19:22:07.000000000 +0100
@@ -732,53 +732,12 @@
 
 EXPORT_SYMBOL(__alloc_pages);
 
-#ifdef CONFIG_NUMA
-/* Early boot: Everything is done by one cpu, but the data structures will be
- * used by all cpus - spread them on all nodes.
- */
-static __init unsigned long get_boot_pages(unsigned int gfp_mask, unsigned int order)
-{
-static int nodenr;
-	int i = nodenr;
-	struct page *page;
-
-	for (;;) {
-		if (i > nodenr + numnodes)
-			return 0;
-		if (node_present_pages(i%numnodes)) {
-			struct zone **z;
-			/* The node contains memory. Check that there is
-			 * memory in the intended zonelist.
-			 */
-			z = NODE_DATA(i%numnodes)->node_zonelists[gfp_mask & GFP_ZONEMASK].zones;
-			while (*z) {
-				if ( (*z)->free_pages > (1UL<<order))
-					goto found_node;
-				z++;
-			}
-		}
-		i++;
-	}
-found_node:
-	nodenr = i+1;
-	page = alloc_pages_node(i%numnodes, gfp_mask, order);
-	if (!page)
-		return 0;
-	return (unsigned long) page_address(page);
-}
-#endif
-
 /*
  * Common helper functions.
  */
 fastcall unsigned long __get_free_pages(unsigned int gfp_mask, unsigned int order)
 {
 	struct page * page;
-
-#ifdef CONFIG_NUMA
-	if (unlikely(system_state == SYSTEM_BOOTING))
-		return get_boot_pages(gfp_mask, order);
-#endif
 	page = alloc_pages(gfp_mask, order);
 	if (!page)
 		return 0;
@@ -988,6 +947,25 @@
 	__get_page_state(ret, sizeof(*ret) / sizeof(unsigned long));
 }
 
+unsigned long __read_page_state(unsigned offset)
+{
+	unsigned long ret = 0;
+	int cpu = 0;
+
+	offset /= sizeof(unsigned long);
+
+	for (cpu = 0; cpu < NR_CPUS; cpu++) {
+		unsigned long *in;
+
+		if (!cpu_possible(cpu))
+			continue;
+
+		in = (unsigned long *)&per_cpu(page_states, cpu);
+		ret += in[offset];
+	}
+	return ret;
+}
+
 void get_zone_counts(unsigned long *active,
 		unsigned long *inactive, unsigned long *free)
 {
--- diff/mm/pdflush.c	2004-05-19 22:13:12.000000000 +0100
+++ source/mm/pdflush.c	2004-06-11 19:22:07.000000000 +0100
@@ -88,6 +88,8 @@
 	unsigned long when_i_went_to_sleep;
 };
 
+static int wakeup_count = 100;
+
 static int __pdflush(struct pdflush_work *my_work)
 {
 	current->flags |= PF_FLUSHER;
@@ -114,7 +116,10 @@
 
 		spin_lock_irq(&pdflush_lock);
 		if (!list_empty(&my_work->list)) {
-			printk("pdflush: bogus wakeup!\n");
+			if (wakeup_count > 0) {
+				wakeup_count--;
+				printk("pdflush: bogus wakeup!\n");
+			}
 			my_work->fn = NULL;
 			continue;
 		}
@@ -190,6 +195,7 @@
 {
 	unsigned long flags;
 	int ret = 0;
+	static int poke_count = 0;
 
 	if (fn == NULL)
 		BUG();		/* Hard to diagnose if it's deferred */
@@ -198,9 +204,19 @@
 	if (list_empty(&pdflush_list)) {
 		spin_unlock_irqrestore(&pdflush_lock, flags);
 		ret = -1;
+		if (wakeup_count < 100 && poke_count < 10) {
+			printk("%s: no threads\n", __FUNCTION__);
+			dump_stack();
+			poke_count++;
+		}
 	} else {
 		struct pdflush_work *pdf;
 
+		if (wakeup_count < 100 && poke_count < 10) {
+			printk("%s: found a thread\n", __FUNCTION__);
+			dump_stack();
+			poke_count++;
+		}
 		pdf = list_entry(pdflush_list.next, struct pdflush_work, list);
 		list_del_init(&pdf->list);
 		if (list_empty(&pdflush_list))
--- diff/mm/readahead.c	2004-06-11 19:17:36.000000000 +0100
+++ source/mm/readahead.c	2004-06-11 19:22:07.000000000 +0100
@@ -234,7 +234,7 @@
 	/*
 	 * Preallocate as many pages as we will need.
 	 */
-	spin_lock_irq(&mapping->tree_lock);
+	read_lock_irq(&mapping->tree_lock);
 	for (page_idx = 0; page_idx < nr_to_read; page_idx++) {
 		unsigned long page_offset = offset + page_idx;
 		
@@ -245,16 +245,16 @@
 		if (page)
 			continue;
 
-		spin_unlock_irq(&mapping->tree_lock);
+		read_unlock_irq(&mapping->tree_lock);
 		page = page_cache_alloc_cold(mapping);
-		spin_lock_irq(&mapping->tree_lock);
+		read_lock_irq(&mapping->tree_lock);
 		if (!page)
 			break;
 		page->index = page_offset;
 		list_add(&page->lru, &page_pool);
 		ret++;
 	}
-	spin_unlock_irq(&mapping->tree_lock);
+	read_unlock_irq(&mapping->tree_lock);
 
 	/*
 	 * Now start the IO.  We ignore I/O errors - if the page is not
--- diff/mm/rmap.c	2004-06-11 19:17:36.000000000 +0100
+++ source/mm/rmap.c	2004-06-11 19:22:07.000000000 +0100
@@ -226,7 +226,7 @@
 	if (page_to_pfn(page) != pte_pfn(*pte))
 		goto out_unmap;
 
-	if (ptep_test_and_clear_young(pte))
+	if (ptep_clear_flush_young(vma, address, pte))
 		referenced++;
 
 	(*mapcount)--;
@@ -465,7 +465,24 @@
 	 * skipped over this mm) then we should reactivate it.
 	 */
 	if ((vma->vm_flags & (VM_LOCKED|VM_RESERVED)) ||
-			ptep_test_and_clear_young(pte)) {
+			ptep_clear_flush_young(vma, address, pte)) {
+		ret = SWAP_FAIL;
+		goto out_unmap;
+	}
+
+	/*
+	 * Don't pull an anonymous page out from under get_user_pages.
+	 * GUP carefully breaks COW and raises page count (while holding
+	 * page_table_lock, as we have here) to make sure that the page
+	 * cannot be freed.  If we unmap that page here, a user write
+	 * access to the virtual address will bring back the page, but
+	 * its raised count will (ironically) be taken to mean it's not
+	 * an exclusive swap page, do_wp_page will replace it by a copy
+	 * page, and the user never get to see the data GUP was holding
+	 * the original page for.
+	 */
+	if (PageSwapCache(page) &&
+	    page_count(page) != page->mapcount + 2) {
 		ret = SWAP_FAIL;
 		goto out_unmap;
 	}
@@ -592,7 +609,7 @@
 		if (PageReserved(page))
 			continue;
 
-		if (ptep_test_and_clear_young(pte))
+		if (ptep_clear_flush_young(vma, address, pte))
 			continue;
 
 		/* Nuke the page table entry. */
--- diff/mm/shmem.c	2004-06-11 19:17:36.000000000 +0100
+++ source/mm/shmem.c	2004-06-11 19:22:07.000000000 +0100
@@ -1676,51 +1676,45 @@
 	return 0;
 }
 
-static int shmem_readlink_inline(struct dentry *dentry, char __user *buffer, int buflen)
-{
-	return vfs_readlink(dentry, buffer, buflen, (const char *)SHMEM_I(dentry->d_inode));
-}
-
 static int shmem_follow_link_inline(struct dentry *dentry, struct nameidata *nd)
 {
-	return vfs_follow_link(nd, (const char *)SHMEM_I(dentry->d_inode));
+	nd_set_link(nd, (char *)SHMEM_I(dentry->d_inode));
+	return 0;
 }
 
-static int shmem_readlink(struct dentry *dentry, char __user *buffer, int buflen)
+static int shmem_follow_link(struct dentry *dentry, struct nameidata *nd)
 {
 	struct page *page = NULL;
 	int res = shmem_getpage(dentry->d_inode, 0, &page, SGP_READ, NULL);
-	if (res)
-		return res;
-	res = vfs_readlink(dentry, buffer, buflen, kmap(page));
-	kunmap(page);
-	mark_page_accessed(page);
-	page_cache_release(page);
-	return res;
+	nd_set_link(nd, res ? ERR_PTR(res) : kmap(page));
+	return 0;
 }
 
-static int shmem_follow_link(struct dentry *dentry, struct nameidata *nd)
+static void shmem_put_link(struct dentry *dentry, struct nameidata *nd)
 {
-	struct page *page = NULL;
-	int res = shmem_getpage(dentry->d_inode, 0, &page, SGP_READ, NULL);
-	if (res)
-		return res;
-	res = vfs_follow_link(nd, kmap(page));
-	kunmap(page);
-	mark_page_accessed(page);
-	page_cache_release(page);
-	return res;
+	if (!IS_ERR(nd_get_link(nd))) {
+		struct page *page;
+
+		page = find_get_page(dentry->d_inode->i_mapping, 0);
+		if (!page)
+			BUG();
+		kunmap(page);
+		mark_page_accessed(page);
+		page_cache_release(page);
+		page_cache_release(page);
+	}
 }
 
 static struct inode_operations shmem_symlink_inline_operations = {
-	.readlink	= shmem_readlink_inline,
+	.readlink	= generic_readlink,
 	.follow_link	= shmem_follow_link_inline,
 };
 
 static struct inode_operations shmem_symlink_inode_operations = {
 	.truncate	= shmem_truncate,
-	.readlink	= shmem_readlink,
+	.readlink	= generic_readlink,
 	.follow_link	= shmem_follow_link,
+	.put_link	= shmem_put_link,
 };
 
 static int shmem_parse_options(char *options, int *mode, uid_t *uid, gid_t *gid, unsigned long *blocks, unsigned long *inodes)
--- diff/mm/slab.c	2004-06-11 19:17:36.000000000 +0100
+++ source/mm/slab.c	2004-06-11 19:22:07.000000000 +0100
@@ -2030,6 +2030,15 @@
 		*dbg_redzone1(cachep, objp) = RED_ACTIVE;
 		*dbg_redzone2(cachep, objp) = RED_ACTIVE;
 	}
+	{
+		int objnr;
+		struct slab *slabp;
+
+		slabp = GET_PAGE_SLAB(virt_to_page(objp));
+
+		objnr = (objp - slabp->s_mem) / cachep->objsize;
+		slab_bufctl(slabp)[objnr] = (unsigned long)caller;
+	}
 	objp += obj_dbghead(cachep);
 	if (cachep->ctor && cachep->flags & SLAB_POISON) {
 		unsigned long	ctor_flags = SLAB_CTOR_CONSTRUCTOR;
@@ -2091,12 +2100,14 @@
 		objnr = (objp - slabp->s_mem) / cachep->objsize;
 		check_slabp(cachep, slabp);
 #if DEBUG
+#if 0
 		if (slab_bufctl(slabp)[objnr] != BUFCTL_FREE) {
 			printk(KERN_ERR "slab: double free detected in cache '%s', objp %p.\n",
 						cachep->name, objp);
 			BUG();
 		}
 #endif
+#endif
 		slab_bufctl(slabp)[objnr] = slabp->free;
 		slabp->free = objnr;
 		STATS_DEC_ACTIVE(cachep);
@@ -2946,6 +2957,29 @@
 	.show	= s_show,
 };
 
+static void do_dump_slabp(kmem_cache_t *cachep)
+{
+#if DEBUG
+	struct list_head *q;
+
+	check_irq_on();
+	spin_lock_irq(&cachep->spinlock);
+	list_for_each(q,&cachep->lists.slabs_full) {
+		struct slab *slabp;
+		int i;
+		slabp = list_entry(q, struct slab, list);
+		for (i = 0; i < cachep->num; i++) {
+			unsigned long sym = slab_bufctl(slabp)[i];
+
+			printk("obj %p/%d: %p", slabp, i, (void *)sym);
+			print_symbol(" <%s>", sym);
+			printk("\n");
+		}
+	}
+	spin_unlock_irq(&cachep->spinlock);
+#endif
+}
+
 #define MAX_SLABINFO_WRITE 128
 /**
  * slabinfo_write - Tuning for the slab allocator
@@ -2986,9 +3020,11 @@
 			    batchcount < 1 ||
 			    batchcount > limit ||
 			    shared < 0) {
-				res = -EINVAL;
+				do_dump_slabp(cachep);
+				res = 0;
 			} else {
-				res = do_tune_cpucache(cachep, limit, batchcount, shared);
+				res = do_tune_cpucache(cachep, limit,
+							batchcount, shared);
 			}
 			break;
 		}
--- diff/mm/swap_state.c	2004-06-11 19:17:36.000000000 +0100
+++ source/mm/swap_state.c	2004-06-11 19:22:07.000000000 +0100
@@ -35,7 +35,7 @@
 
 struct address_space swapper_space = {
 	.page_tree	= RADIX_TREE_INIT(GFP_ATOMIC),
-	.tree_lock	= SPIN_LOCK_UNLOCKED,
+	.tree_lock	= RW_LOCK_UNLOCKED,
 	.a_ops		= &swap_aops,
 	.i_mmap_nonlinear = LIST_HEAD_INIT(swapper_space.i_mmap_nonlinear),
 	.backing_dev_info = &swap_backing_dev_info,
@@ -74,7 +74,7 @@
 	BUG_ON(PagePrivate(page));
 	error = radix_tree_preload(gfp_mask);
 	if (!error) {
-		spin_lock_irq(&swapper_space.tree_lock);
+		write_lock_irq(&swapper_space.tree_lock);
 		error = radix_tree_insert(&swapper_space.page_tree,
 						entry.val, page);
 		if (!error) {
@@ -85,7 +85,7 @@
 			total_swapcache_pages++;
 			pagecache_acct(1);
 		}
-		spin_unlock_irq(&swapper_space.tree_lock);
+		write_unlock_irq(&swapper_space.tree_lock);
 		radix_tree_preload_end();
 	}
 	return error;
@@ -212,9 +212,9 @@
   
 	entry.val = page->private;
 
-	spin_lock_irq(&swapper_space.tree_lock);
+	write_lock_irq(&swapper_space.tree_lock);
 	__delete_from_swap_cache(page);
-	spin_unlock_irq(&swapper_space.tree_lock);
+	write_unlock_irq(&swapper_space.tree_lock);
 
 	swap_free(entry);
 	page_cache_release(page);
@@ -313,13 +313,13 @@
 {
 	struct page *page;
 
-	spin_lock_irq(&swapper_space.tree_lock);
+	read_lock_irq(&swapper_space.tree_lock);
 	page = radix_tree_lookup(&swapper_space.page_tree, entry.val);
 	if (page) {
 		page_cache_get(page);
 		INC_CACHE_INFO(find_success);
 	}
-	spin_unlock_irq(&swapper_space.tree_lock);
+	read_unlock_irq(&swapper_space.tree_lock);
 	INC_CACHE_INFO(find_total);
 	return page;
 }
@@ -342,12 +342,12 @@
 		 * called after lookup_swap_cache() failed, re-calling
 		 * that would confuse statistics.
 		 */
-		spin_lock_irq(&swapper_space.tree_lock);
+		read_lock_irq(&swapper_space.tree_lock);
 		found_page = radix_tree_lookup(&swapper_space.page_tree,
 						entry.val);
 		if (found_page)
 			page_cache_get(found_page);
-		spin_unlock_irq(&swapper_space.tree_lock);
+		read_unlock_irq(&swapper_space.tree_lock);
 		if (found_page)
 			break;
 
--- diff/mm/swapfile.c	2004-06-11 19:17:36.000000000 +0100
+++ source/mm/swapfile.c	2004-06-11 19:22:07.000000000 +0100
@@ -290,10 +290,10 @@
 		/* Is the only swap cache user the cache itself? */
 		if (p->swap_map[swp_offset(entry)] == 1) {
 			/* Recheck the page count with the swapcache lock held.. */
-			spin_lock_irq(&swapper_space.tree_lock);
+			write_lock_irq(&swapper_space.tree_lock);
 			if (page_count(page) == 2)
 				retval = 1;
-			spin_unlock_irq(&swapper_space.tree_lock);
+			write_unlock_irq(&swapper_space.tree_lock);
 		}
 		swap_info_put(p);
 	}
@@ -361,13 +361,13 @@
 	retval = 0;
 	if (p->swap_map[swp_offset(entry)] == 1) {
 		/* Recheck the page count with the swapcache lock held.. */
-		spin_lock_irq(&swapper_space.tree_lock);
+		write_lock_irq(&swapper_space.tree_lock);
 		if ((page_count(page) == 2) && !PageWriteback(page)) {
 			__delete_from_swap_cache(page);
 			SetPageDirty(page);
 			retval = 1;
 		}
-		spin_unlock_irq(&swapper_space.tree_lock);
+		write_unlock_irq(&swapper_space.tree_lock);
 	}
 	swap_info_put(p);
 
@@ -391,12 +391,12 @@
 	p = swap_info_get(entry);
 	if (p) {
 		if (swap_entry_free(p, swp_offset(entry)) == 1) {
-			spin_lock_irq(&swapper_space.tree_lock);
+			read_lock_irq(&swapper_space.tree_lock);
 			page = radix_tree_lookup(&swapper_space.page_tree,
 				entry.val);
 			if (page && TestSetPageLocked(page))
 				page = NULL;
-			spin_unlock_irq(&swapper_space.tree_lock);
+			read_unlock_irq(&swapper_space.tree_lock);
 		}
 		swap_info_put(p);
 	}
--- diff/mm/truncate.c	2004-05-19 22:13:12.000000000 +0100
+++ source/mm/truncate.c	2004-06-11 19:22:07.000000000 +0100
@@ -74,13 +74,13 @@
 	if (PagePrivate(page) && !try_to_release_page(page, 0))
 		return 0;
 
-	spin_lock_irq(&mapping->tree_lock);
+	write_lock_irq(&mapping->tree_lock);
 	if (PageDirty(page)) {
-		spin_unlock_irq(&mapping->tree_lock);
+		write_unlock_irq(&mapping->tree_lock);
 		return 0;
 	}
 	__remove_from_page_cache(page);
-	spin_unlock_irq(&mapping->tree_lock);
+	write_unlock_irq(&mapping->tree_lock);
 	ClearPageUptodate(page);
 	page_cache_release(page);	/* pagecache ref */
 	return 1;
@@ -243,6 +243,10 @@
  * where the page is seen to be mapped into process pagetables.  In that case,
  * the page is marked clean but is left attached to its address_space.
  *
+ * The page is also marked not uptodate so that a subsequent pagefault will
+ * perform I/O to bringthe page's contents back into sync with its backing
+ * store.
+ *
  * FIXME: invalidate_inode_pages2() is probably trivially livelockable.
  */
 void invalidate_inode_pages2(struct address_space *mapping)
@@ -260,10 +264,12 @@
 			if (page->mapping == mapping) {	/* truncate race? */
 				wait_on_page_writeback(page);
 				next = page->index + 1;
-				if (page_mapped(page))
+				if (page_mapped(page)) {
 					clear_page_dirty(page);
-				else
+					ClearPageUptodate(page);
+				} else {
 					invalidate_complete_page(mapping, page);
+				}
 			}
 			unlock_page(page);
 		}
--- diff/mm/vmalloc.c	2004-06-11 19:17:36.000000000 +0100
+++ source/mm/vmalloc.c	2004-06-11 19:22:07.000000000 +0100
@@ -17,7 +17,6 @@
 #include <linux/vmalloc.h>
 
 #include <asm/uaccess.h>
-#include <asm/pgalloc.h>
 #include <asm/tlbflush.h>
 
 
@@ -456,6 +455,28 @@
 EXPORT_SYMBOL(vmalloc);
 
 /**
+ *	vmalloc_exec  -  allocate virtually contiguous, executable memory
+ *
+ *	@size:		allocation size
+ *
+ *	Kernel-internal function to allocate enough pages to cover @size
+ *	the page level allocator and map them into contiguous and
+ *	executable kernel virtual space.
+ *
+ *	For tight cotrol over page level allocator and protection flags
+ *	use __vmalloc() instead.
+ */
+
+#ifndef PAGE_KERNEL_EXEC
+# define PAGE_KERNEL_EXEC PAGE_KERNEL
+#endif
+
+void *vmalloc_exec(unsigned long size)
+{
+	return __vmalloc(size, GFP_KERNEL | __GFP_HIGHMEM, PAGE_KERNEL_EXEC);
+}
+
+/**
  *	vmalloc_32  -  allocate virtually contiguous memory (32bit addressable)
  *
  *	@size:		allocation size
--- diff/mm/vmscan.c	2004-06-11 19:17:36.000000000 +0100
+++ source/mm/vmscan.c	2004-06-11 19:22:07.000000000 +0100
@@ -33,7 +33,6 @@
 #include <linux/cpu.h>
 #include <linux/notifier.h>
 
-#include <asm/pgalloc.h>
 #include <asm/tlbflush.h>
 #include <asm/div64.h>
 
@@ -240,17 +239,107 @@
 	unlock_page(page);
 }
 
+/* possible outcome of pageout() */
+typedef enum {
+	/* failed to write page out, page is locked */
+	PAGE_KEEP,
+	/* move page to the active list, page is locked */
+	PAGE_ACTIVATE,
+	/* page has been sent to the disk successfully, page is unlocked */
+	PAGE_SUCCESS,
+	/* page is clean and locked */
+	PAGE_CLEAN,
+} pageout_t;
+
 /*
- * shrink_list returns the number of reclaimed pages
+ * pageout is called by shrink_list() for each dirty page. Calls ->writepage().
  */
-static int
-shrink_list(struct list_head *page_list, unsigned int gfp_mask,
-		int *nr_scanned, int do_writepage)
+static pageout_t pageout(struct page *page, struct address_space *mapping)
+{
+	/*
+	 * If the page is dirty, only perform writeback if that write
+	 * will be non-blocking.  To prevent this allocation from being
+	 * stalled by pagecache activity.  But note that there may be
+	 * stalls if we need to run get_block().  We could test
+	 * PagePrivate for that.
+	 *
+	 * If this process is currently in generic_file_write() against
+	 * this page's queue, we can perform writeback even if that
+	 * will block.
+	 *
+	 * If the page is swapcache, write it back even if that would
+	 * block, for some throttling. This happens by accident, because
+	 * swap_backing_dev_info is bust: it doesn't reflect the
+	 * congestion state of the swapdevs.  Easy to fix, if needed.
+	 * See swapfile.c:page_queue_congested().
+	 */
+	if (!is_page_cache_freeable(page))
+		return PAGE_KEEP;
+	if (!mapping)
+		return PAGE_KEEP;
+	if (mapping->a_ops->writepage == NULL)
+		return PAGE_ACTIVATE;
+	if (!may_write_to_queue(mapping->backing_dev_info))
+		return PAGE_KEEP;
+
+	if (clear_page_dirty_for_io(page)) {
+		int res;
+		struct writeback_control wbc = {
+			.sync_mode = WB_SYNC_NONE,
+			.nr_to_write = SWAP_CLUSTER_MAX,
+			.nonblocking = 1,
+			.for_reclaim = 1,
+		};
+
+		SetPageReclaim(page);
+		res = mapping->a_ops->writepage(page, &wbc);
+		if (res < 0)
+			handle_write_error(mapping, page, res);
+		if (res == WRITEPAGE_ACTIVATE) {
+			ClearPageReclaim(page);
+			return PAGE_ACTIVATE;
+		}
+		if (!PageWriteback(page)) {
+			/* synchronous write or broken a_ops? */
+			ClearPageReclaim(page);
+		}
+
+		return PAGE_SUCCESS;
+	}
+
+	return PAGE_CLEAN;
+}
+
+struct scan_control {
+	/* Ask refill_inactive_zone, or shrink_cache to scan this many pages */
+	unsigned long nr_to_scan;
+
+	/* Incremented by the number of inactive pages that were scanned */
+	unsigned long nr_scanned;
+
+	/* Incremented by the number of pages reclaimed */
+	unsigned long nr_reclaimed;
+
+	unsigned long nr_mapped;	/* From page_state */
+
+	/* Ask shrink_caches, or shrink_zone to scan at this priority */
+	unsigned int priority;
+
+	/* This context's GFP mask */
+	unsigned int gfp_mask;
+
+	int may_writepage;
+};
+
+/*
+ * shrink_list adds the number of reclaimed pages to sc->nr_reclaimed
+ */
+static int shrink_list(struct list_head *page_list, struct scan_control *sc)
 {
 	LIST_HEAD(ret_pages);
 	struct pagevec freed_pvec;
 	int pgactivate = 0;
-	int ret = 0;
+	int reclaimed = 0;
 
 	cond_resched();
 
@@ -267,15 +356,16 @@
 		if (TestSetPageLocked(page))
 			goto keep;
 
-		/* Double the slab pressure for mapped and swapcache pages */
-		if (page_mapped(page) || PageSwapCache(page))
-			(*nr_scanned)++;
-
 		BUG_ON(PageActive(page));
 
 		if (PageWriteback(page))
 			goto keep_locked;
 
+		sc->nr_scanned++;
+		/* Double the slab pressure for mapped and swapcache pages */
+		if (page_mapped(page) || PageSwapCache(page))
+			sc->nr_scanned++;
+
 		page_map_lock(page);
 		referenced = page_referenced(page);
 		if (referenced && page_mapping_inuse(page)) {
@@ -300,8 +390,8 @@
 #endif /* CONFIG_SWAP */
 
 		mapping = page_mapping(page);
-		may_enter_fs = (gfp_mask & __GFP_FS) ||
-			(PageSwapCache(page) && (gfp_mask & __GFP_IO));
+		may_enter_fs = (sc->gfp_mask & __GFP_FS) ||
+			(PageSwapCache(page) && (sc->gfp_mask & __GFP_IO));
 
 		/*
 		 * The page is mapped into the page tables of one or more
@@ -321,60 +411,34 @@
 		}
 		page_map_unlock(page);
 
-		/*
-		 * If the page is dirty, only perform writeback if that write
-		 * will be non-blocking.  To prevent this allocation from being
-		 * stalled by pagecache activity.  But note that there may be
-		 * stalls if we need to run get_block().  We could test
-		 * PagePrivate for that.
-		 *
-		 * If this process is currently in generic_file_write() against
-		 * this page's queue, we can perform writeback even if that
-		 * will block.
-		 *
-		 * If the page is swapcache, write it back even if that would
-		 * block, for some throttling. This happens by accident, because
-		 * swap_backing_dev_info is bust: it doesn't reflect the
-		 * congestion state of the swapdevs.  Easy to fix, if needed.
-		 * See swapfile.c:page_queue_congested().
-		 */
 		if (PageDirty(page)) {
 			if (referenced)
 				goto keep_locked;
-			if (!is_page_cache_freeable(page))
-				goto keep_locked;
-			if (!mapping)
-				goto keep_locked;
-			if (mapping->a_ops->writepage == NULL)
-				goto activate_locked;
 			if (!may_enter_fs)
 				goto keep_locked;
-			if (!may_write_to_queue(mapping->backing_dev_info))
+			if (laptop_mode && !sc->may_writepage)
 				goto keep_locked;
-			if (laptop_mode && !do_writepage)
+
+			/* Page is dirty, try to write it out here */
+			switch(pageout(page, mapping)) {
+			case PAGE_KEEP:
 				goto keep_locked;
-			if (clear_page_dirty_for_io(page)) {
-				int res;
-				struct writeback_control wbc = {
-					.sync_mode = WB_SYNC_NONE,
-					.nr_to_write = SWAP_CLUSTER_MAX,
-					.nonblocking = 1,
-					.for_reclaim = 1,
-				};
-
-				SetPageReclaim(page);
-				res = mapping->a_ops->writepage(page, &wbc);
-				if (res < 0)
-					handle_write_error(mapping, page, res);
-				if (res == WRITEPAGE_ACTIVATE) {
-					ClearPageReclaim(page);
-					goto activate_locked;
-				}
-				if (!PageWriteback(page)) {
-					/* synchronous write or broken a_ops? */
-					ClearPageReclaim(page);
-				}
-				goto keep;
+			case PAGE_ACTIVATE:
+				goto activate_locked;
+			case PAGE_SUCCESS:
+				if (PageWriteback(page) || PageDirty(page))
+					goto keep;
+				/*
+				 * A synchronous write - probably a ramdisk.  Go
+				 * ahead and try to reclaim the page.
+				 */
+				if (TestSetPageLocked(page))
+					goto keep;
+				if (PageDirty(page) || PageWriteback(page))
+					goto keep_locked;
+				mapping = page_mapping(page);
+			case PAGE_CLEAN:
+				; /* try to free the page below */
 			}
 		}
 
@@ -396,11 +460,11 @@
 		 * the pages which were not successfully invalidated in
 		 * truncate_complete_page().  We try to drop those buffers here
 		 * and if that worked, and the page is no longer mapped into
-		 * process address space (page_count == 0) it can be freed.
+		 * process address space (page_count == 1) it can be freed.
 		 * Otherwise, leave the page on the LRU so it is swappable.
 		 */
 		if (PagePrivate(page)) {
-			if (!try_to_release_page(page, gfp_mask))
+			if (!try_to_release_page(page, sc->gfp_mask))
 				goto activate_locked;
 			if (!mapping && page_count(page) == 1)
 				goto free_it;
@@ -409,7 +473,7 @@
 		if (!mapping)
 			goto keep_locked;	/* truncate got there first */
 
-		spin_lock_irq(&mapping->tree_lock);
+		write_lock_irq(&mapping->tree_lock);
 
 		/*
 		 * The non-racy check for busy page.  It is critical to check
@@ -417,7 +481,7 @@
 		 * not in use by anybody. 	(pagecache + us == 2)
 		 */
 		if (page_count(page) != 2 || PageDirty(page)) {
-			spin_unlock_irq(&mapping->tree_lock);
+			write_unlock_irq(&mapping->tree_lock);
 			goto keep_locked;
 		}
 
@@ -425,7 +489,7 @@
 		if (PageSwapCache(page)) {
 			swp_entry_t swap = { .val = page->private };
 			__delete_from_swap_cache(page);
-			spin_unlock_irq(&mapping->tree_lock);
+			write_unlock_irq(&mapping->tree_lock);
 			swap_free(swap);
 			__put_page(page);	/* The pagecache ref */
 			goto free_it;
@@ -433,12 +497,12 @@
 #endif /* CONFIG_SWAP */
 
 		__remove_from_page_cache(page);
-		spin_unlock_irq(&mapping->tree_lock);
+		write_unlock_irq(&mapping->tree_lock);
 		__put_page(page);
 
 free_it:
 		unlock_page(page);
-		ret++;
+		reclaimed++;
 		if (!pagevec_add(&freed_pvec, page))
 			__pagevec_release_nonlru(&freed_pvec);
 		continue;
@@ -456,7 +520,8 @@
 	if (pagevec_count(&freed_pvec))
 		__pagevec_release_nonlru(&freed_pvec);
 	mod_page_state(pgactivate, pgactivate);
-	return ret;
+	sc->nr_reclaimed += reclaimed;
+	return reclaimed;
 }
 
 /*
@@ -464,19 +529,16 @@
  * a batch of pages and working on them outside the lock.  Any pages which were
  * not freed will be added back to the LRU.
  *
- * shrink_cache() is passed the number of pages to scan and returns the number
- * of pages which were reclaimed.
+ * shrink_cache() adds the number of pages reclaimed to sc->nr_reclaimed
  *
  * For pagecache intensive workloads, the first loop here is the hottest spot
  * in the kernel (apart from the copy_*_user functions).
  */
-static int
-shrink_cache(struct zone *zone, unsigned int gfp_mask,
-		int max_scan, int *total_scanned, int do_writepage)
+static void shrink_cache(struct zone *zone, struct scan_control *sc)
 {
 	LIST_HEAD(page_list);
 	struct pagevec pvec;
-	int ret = 0;
+	int max_scan = sc->nr_to_scan;
 
 	pagevec_init(&pvec, 1);
 
@@ -522,17 +584,11 @@
 			mod_page_state_zone(zone, pgscan_kswapd, nr_scan);
 		else
 			mod_page_state_zone(zone, pgscan_direct, nr_scan);
-		nr_freed = shrink_list(&page_list, gfp_mask,
-					total_scanned, do_writepage);
-		*total_scanned += nr_taken;
+		nr_freed = shrink_list(&page_list, sc);
 		if (current_is_kswapd())
 			mod_page_state(kswapd_steal, nr_freed);
 		mod_page_state_zone(zone, pgsteal, nr_freed);
 
-		ret += nr_freed;
-		if (nr_freed <= 0 && list_empty(&page_list))
-			goto done;
-
 		spin_lock_irq(&zone->lru_lock);
 		/*
 		 * Put back any unfreeable pages.
@@ -556,7 +612,6 @@
 	spin_unlock_irq(&zone->lru_lock);
 done:
 	pagevec_release(&pvec);
-	return ret;
 }
 
 /*
@@ -577,12 +632,12 @@
  * But we had to alter page->flags anyway.
  */
 static void
-refill_inactive_zone(struct zone *zone, const int nr_pages_in,
-			struct page_state *ps)
+refill_inactive_zone(struct zone *zone, struct scan_control *sc)
 {
 	int pgmoved;
 	int pgdeactivate = 0;
-	int nr_pages = nr_pages_in;
+	int pgscanned = 0;
+	int nr_pages = sc->nr_to_scan;
 	LIST_HEAD(l_hold);	/* The pages which were snipped off */
 	LIST_HEAD(l_inactive);	/* Pages to go onto the inactive_list */
 	LIST_HEAD(l_active);	/* Pages to go onto the active_list */
@@ -596,7 +651,7 @@
 	lru_add_drain();
 	pgmoved = 0;
 	spin_lock_irq(&zone->lru_lock);
-	while (nr_pages && !list_empty(&zone->active_list)) {
+	while (pgscanned < nr_pages && !list_empty(&zone->active_list)) {
 		page = lru_to_page(&zone->active_list);
 		prefetchw_prev_lru_page(page, &zone->active_list, flags);
 		if (!TestClearPageLRU(page))
@@ -616,7 +671,7 @@
 			list_add(&page->lru, &l_hold);
 			pgmoved++;
 		}
-		nr_pages--;
+		pgscanned++;
 	}
 	zone->nr_active -= pgmoved;
 	spin_unlock_irq(&zone->lru_lock);
@@ -632,7 +687,7 @@
 	 * mapped memory instead of just pagecache.  Work out how much memory
 	 * is mapped.
 	 */
-	mapped_ratio = (ps->nr_mapped * 100) / total_memory;
+	mapped_ratio = (sc->nr_mapped * 100) / total_memory;
 
 	/*
 	 * Now decide how much we really want to unmap some pages.  The mapped
@@ -731,7 +786,7 @@
 	spin_unlock_irq(&zone->lru_lock);
 	pagevec_release(&pvec);
 
-	mod_page_state_zone(zone, pgrefill, nr_pages_in - nr_pages);
+	mod_page_state_zone(zone, pgrefill, pgscanned);
 	mod_page_state(pgdeactivate, pgdeactivate);
 }
 
@@ -739,13 +794,14 @@
  * Scan `nr_pages' from this zone.  Returns the number of reclaimed pages.
  * This is a basic per-zone page freer.  Used by both kswapd and direct reclaim.
  */
-static int
-shrink_zone(struct zone *zone, int max_scan, unsigned int gfp_mask,
-		int *total_scanned, struct page_state *ps, int do_writepage)
+static void
+shrink_zone(struct zone *zone, struct scan_control *sc)
 {
-	unsigned long scan_active;
+	unsigned long scan_active, scan_inactive;
 	int count;
 
+	scan_inactive = (zone->nr_active + zone->nr_inactive) >> sc->priority;
+
 	/*
 	 * Try to keep the active list 2/3 of the size of the cache.  And
 	 * make sure that refill_inactive is given a decent number of pages.
@@ -758,13 +814,13 @@
 	 */
 	if (zone->nr_active >= 4*(zone->nr_inactive*2 + 1)) {
 		/* Don't scan more than 4 times the inactive list scan size */
-		scan_active = 4*max_scan;
+		scan_active = 4*scan_inactive;
 	} else {
 		unsigned long long tmp;
 
 		/* Cast to long long so the multiply doesn't overflow */
 
-		tmp = (unsigned long long)max_scan * zone->nr_active;
+		tmp = (unsigned long long)scan_inactive * zone->nr_active;
 		do_div(tmp, zone->nr_inactive*2 + 1);
 		scan_active = (unsigned long)tmp;
 	}
@@ -773,17 +829,17 @@
 	count = atomic_read(&zone->nr_scan_active);
 	if (count >= SWAP_CLUSTER_MAX) {
 		atomic_set(&zone->nr_scan_active, 0);
-		refill_inactive_zone(zone, count, ps);
+		sc->nr_to_scan = count;
+		refill_inactive_zone(zone, sc);
 	}
 
-	atomic_add(max_scan, &zone->nr_scan_inactive);
+	atomic_add(scan_inactive, &zone->nr_scan_inactive);
 	count = atomic_read(&zone->nr_scan_inactive);
 	if (count >= SWAP_CLUSTER_MAX) {
 		atomic_set(&zone->nr_scan_inactive, 0);
-		return shrink_cache(zone, gfp_mask, count,
-					total_scanned, do_writepage);
+		sc->nr_to_scan = count;
+		return shrink_cache(zone, sc);
 	}
-	return 0;
 }
 
 /*
@@ -802,29 +858,23 @@
  * If a zone is deemed to be full of pinned pages then just give it a light
  * scan then give up on it.
  */
-static int
-shrink_caches(struct zone **zones, int priority, int *total_scanned,
-		int gfp_mask, struct page_state *ps, int do_writepage)
+static void
+shrink_caches(struct zone **zones, struct scan_control *sc)
 {
-	int ret = 0;
 	int i;
 
 	for (i = 0; zones[i] != NULL; i++) {
 		struct zone *zone = zones[i];
-		int max_scan;
 
-		zone->temp_priority = priority;
-		if (zone->prev_priority > priority)
-			zone->prev_priority = priority;
+		zone->temp_priority = sc->priority;
+		if (zone->prev_priority > sc->priority)
+			zone->prev_priority = sc->priority;
 
-		if (zone->all_unreclaimable && priority != DEF_PRIORITY)
+		if (zone->all_unreclaimable && sc->priority != DEF_PRIORITY)
 			continue;	/* Let kswapd poll it */
 
-		max_scan = (zone->nr_active + zone->nr_inactive) >> priority;
-		ret += shrink_zone(zone, max_scan, gfp_mask,
-					total_scanned, ps, do_writepage);
+		shrink_zone(zone, sc);
 	}
-	return ret;
 }
  
 /*
@@ -835,25 +885,23 @@
  *
  * If the caller is !__GFP_FS then the probability of a failure is reasonably
  * high - the zone may be full of dirty or under-writeback pages, which this
- * caller can't do much about.  So for !__GFP_FS callers, we just perform a
- * small LRU walk and if that didn't work out, fail the allocation back to the
- * caller.  GFP_NOFS allocators need to know how to deal with it.  Kicking
- * bdflush, waiting and retrying will work.
- *
- * This is a fairly lame algorithm - it can result in excessive CPU burning and
- * excessive rotation of the inactive list, which is _supposed_ to be an LRU,
- * yes?
+ * caller can't do much about.  We kick pdflush and take explicit naps in the
+ * hope that some of these pages can be written.  But if the allocating task
+ * holds filesystem locks which prevent writeout this might not work, and the
+ * allocation attempt will fail.
  */
 int try_to_free_pages(struct zone **zones,
 		unsigned int gfp_mask, unsigned int order)
 {
 	int priority;
 	int ret = 0;
-	int nr_reclaimed = 0;
+	int total_scanned = 0, total_reclaimed = 0;
 	struct reclaim_state *reclaim_state = current->reclaim_state;
+	struct scan_control sc;
 	int i;
-	unsigned long total_scanned = 0;
-	int do_writepage = 0;
+
+	sc.gfp_mask = gfp_mask;
+	sc.may_writepage = 0;
 
 	inc_page_state(allocstall);
 
@@ -861,23 +909,23 @@
 		zones[i]->temp_priority = DEF_PRIORITY;
 
 	for (priority = DEF_PRIORITY; priority >= 0; priority--) {
-		int scanned = 0;
-		struct page_state ps;
-
-		get_page_state(&ps);
-		nr_reclaimed += shrink_caches(zones, priority, &scanned,
-						gfp_mask, &ps, do_writepage);
-		shrink_slab(scanned, gfp_mask);
+		sc.nr_mapped = read_page_state(nr_mapped);
+		sc.nr_scanned = 0;
+		sc.nr_reclaimed = 0;
+		sc.priority = priority;
+		shrink_caches(zones, &sc);
+		shrink_slab(sc.nr_scanned, gfp_mask);
 		if (reclaim_state) {
-			nr_reclaimed += reclaim_state->reclaimed_slab;
+			sc.nr_reclaimed += reclaim_state->reclaimed_slab;
 			reclaim_state->reclaimed_slab = 0;
 		}
-		if (nr_reclaimed >= SWAP_CLUSTER_MAX) {
+		if (sc.nr_reclaimed >= SWAP_CLUSTER_MAX) {
 			ret = 1;
 			goto out;
 		}
-		if (!(gfp_mask & __GFP_FS))
-			break;		/* Let the caller handle it */
+		total_scanned += sc.nr_scanned;
+		total_reclaimed += sc.nr_reclaimed;
+
 		/*
 		 * Try to write back as many pages as we just scanned.  This
 		 * tends to cause slow streaming writers to write data to the
@@ -885,14 +933,13 @@
 		 * that's undesirable in laptop mode, where we *want* lumpy
 		 * writeout.  So in laptop mode, write out the whole world.
 		 */
-		total_scanned += scanned;
 		if (total_scanned > SWAP_CLUSTER_MAX + SWAP_CLUSTER_MAX/2) {
 			wakeup_bdflush(laptop_mode ? 0 : total_scanned);
-			do_writepage = 1;
+			sc.may_writepage = 1;
 		}
 
 		/* Take a nap, wait for some writeback to complete */
-		if (scanned && priority < DEF_PRIORITY - 2)
+		if (sc.nr_scanned && priority < DEF_PRIORITY - 2)
 			blk_congestion_wait(WRITE, HZ/10);
 	}
 	if ((gfp_mask & __GFP_FS) && !(gfp_mask & __GFP_NORETRY))
@@ -928,15 +975,18 @@
  * the page allocator fallback scheme to ensure that aging of pages is balanced
  * across the zones.
  */
-static int balance_pgdat(pg_data_t *pgdat, int nr_pages, struct page_state *ps)
+static int balance_pgdat(pg_data_t *pgdat, int nr_pages)
 {
 	int to_free = nr_pages;
 	int priority;
 	int i;
+	int total_scanned = 0, total_reclaimed = 0;
 	struct reclaim_state *reclaim_state = current->reclaim_state;
-	unsigned long total_scanned = 0;
-	unsigned long total_reclaimed = 0;
-	int do_writepage = 0;
+	struct scan_control sc;
+
+	sc.gfp_mask = GFP_KERNEL;
+	sc.may_writepage = 0;
+	sc.nr_mapped = read_page_state(nr_mapped);
 
 	inc_page_state(pageoutrun);
 
@@ -984,9 +1034,6 @@
 		 */
 		for (i = 0; i <= end_zone; i++) {
 			struct zone *zone = pgdat->node_zones + i;
-			int max_scan;
-			int reclaimed;
-			int scanned = 0;
 
 			if (zone->all_unreclaimable && priority != DEF_PRIORITY)
 				continue;
@@ -998,16 +1045,14 @@
 			zone->temp_priority = priority;
 			if (zone->prev_priority > priority)
 				zone->prev_priority = priority;
-			max_scan = (zone->nr_active + zone->nr_inactive)
-								>> priority;
-			reclaimed = shrink_zone(zone, max_scan, GFP_KERNEL,
-					&scanned, ps, do_writepage);
-			total_scanned += scanned;
+			sc.nr_scanned = 0;
+			sc.nr_reclaimed = 0;
+			sc.priority = priority;
+			shrink_zone(zone, &sc);
 			reclaim_state->reclaimed_slab = 0;
-			shrink_slab(scanned, GFP_KERNEL);
-			reclaimed += reclaim_state->reclaimed_slab;
-			total_reclaimed += reclaimed;
-			to_free -= reclaimed;
+			shrink_slab(sc.nr_scanned, GFP_KERNEL);
+			sc.nr_reclaimed += reclaim_state->reclaimed_slab;
+			total_reclaimed += sc.nr_reclaimed;
 			if (zone->all_unreclaimable)
 				continue;
 			if (zone->pages_scanned > zone->present_pages * 2)
@@ -1019,9 +1064,9 @@
 			 */
 			if (total_scanned > SWAP_CLUSTER_MAX * 2 &&
 			    total_scanned > total_reclaimed+total_reclaimed/2)
-				do_writepage = 1;
+				sc.may_writepage = 1;
 		}
-		if (nr_pages && to_free > 0)
+		if (nr_pages && to_free > total_reclaimed)
 			continue;	/* swsusp: need to do more work */
 		if (all_zones_ok)
 			break;		/* kswapd: all done */
@@ -1085,15 +1130,13 @@
 	tsk->flags |= PF_MEMALLOC|PF_KSWAPD;
 
 	for ( ; ; ) {
-		struct page_state ps;
-
 		if (current->flags & PF_FREEZE)
 			refrigerator(PF_FREEZE);
 		prepare_to_wait(&pgdat->kswapd_wait, &wait, TASK_INTERRUPTIBLE);
 		schedule();
 		finish_wait(&pgdat->kswapd_wait, &wait);
-		get_page_state(&ps);
-		balance_pgdat(pgdat, 0, &ps);
+
+		balance_pgdat(pgdat, 0);
 	}
 }
 
@@ -1126,10 +1169,7 @@
 	current->reclaim_state = &reclaim_state;
 	for_each_pgdat(pgdat) {
 		int freed;
-		struct page_state ps;
-
-		get_page_state(&ps);
-		freed = balance_pgdat(pgdat, nr_to_free, &ps);
+		freed = balance_pgdat(pgdat, nr_to_free);
 		ret += freed;
 		nr_to_free -= freed;
 		if (nr_to_free <= 0)
--- diff/net/Kconfig	2004-05-19 22:13:12.000000000 +0100
+++ source/net/Kconfig	2004-06-11 19:22:07.000000000 +0100
@@ -650,18 +650,17 @@
 
 endmenu
 
+config KGDBOE
+	def_bool (X86 || IA64) && KGDB
+
 config NETPOLL
-	def_bool NETCONSOLE
+	def_bool NETCONSOLE || KGDBOE
 
 config NETPOLL_RX
-	bool "Netpoll support for trapping incoming packets"
-	default n
-	depends on NETPOLL
+	def_bool KGDBOE
 
 config NETPOLL_TRAP
-	bool "Netpoll traffic trapping"
-	default n
-	depends on NETPOLL
+	def_bool KGDBOE
 
 config NET_POLL_CONTROLLER
 	def_bool NETPOLL
--- diff/net/core/dev.c	2004-06-11 19:17:36.000000000 +0100
+++ source/net/core/dev.c	2004-06-11 19:22:07.000000000 +0100
@@ -1550,7 +1550,6 @@
 }
 #endif
 
-
 /**
  *	netif_rx	-	post buffer to the network code
  *	@skb: buffer to post
@@ -1870,7 +1869,6 @@
 	unsigned long start_time = jiffies;
 	int budget = netdev_max_backlog;
 
-	
 	local_irq_disable();
 
 	while (!list_empty(&queue->poll_list)) {
@@ -1896,6 +1894,10 @@
 			dev_put(dev);
 			local_irq_disable();
 		}
+
+#ifdef CONFIG_KGDBOE
+		kgdb_process_breakpoint();
+#endif
 	}
 out:
 	local_irq_enable();
--- diff/net/core/ethtool.c	2004-06-11 19:17:36.000000000 +0100
+++ source/net/core/ethtool.c	2004-06-11 19:22:07.000000000 +0100
@@ -652,6 +652,7 @@
 	struct net_device *dev = __dev_get_by_name(ifr->ifr_name);
 	void __user *useraddr = ifr->ifr_data;
 	u32 ethcmd;
+	int rc;
 
 	/*
 	 * XXX: This can be pushed down into the ethtool_* handlers that
@@ -669,70 +670,109 @@
 	if (copy_from_user(&ethcmd, useraddr, sizeof (ethcmd)))
 		return -EFAULT;
 
+	if(dev->ethtool_ops->begin)
+		if ((rc = dev->ethtool_ops->begin(dev)) < 0)
+			return rc;
+
 	switch (ethcmd) {
 	case ETHTOOL_GSET:
-		return ethtool_get_settings(dev, useraddr);
+		rc = ethtool_get_settings(dev, useraddr);
+		break;
 	case ETHTOOL_SSET:
-		return ethtool_set_settings(dev, useraddr);
+		rc = ethtool_set_settings(dev, useraddr);
+		break;
 	case ETHTOOL_GDRVINFO:
-		return ethtool_get_drvinfo(dev, useraddr);
+		rc = ethtool_get_drvinfo(dev, useraddr);
+
+		break;
 	case ETHTOOL_GREGS:
-		return ethtool_get_regs(dev, useraddr);
+		rc = ethtool_get_regs(dev, useraddr);
+		break;
 	case ETHTOOL_GWOL:
-		return ethtool_get_wol(dev, useraddr);
+		rc = ethtool_get_wol(dev, useraddr);
+		break;
 	case ETHTOOL_SWOL:
-		return ethtool_set_wol(dev, useraddr);
+		rc = ethtool_set_wol(dev, useraddr);
+		break;
 	case ETHTOOL_GMSGLVL:
-		return ethtool_get_msglevel(dev, useraddr);
+		rc = ethtool_get_msglevel(dev, useraddr);
+		break;
 	case ETHTOOL_SMSGLVL:
-		return ethtool_set_msglevel(dev, useraddr);
+		rc = ethtool_set_msglevel(dev, useraddr);
+		break;
 	case ETHTOOL_NWAY_RST:
-		return ethtool_nway_reset(dev);
+		rc = ethtool_nway_reset(dev);
+		break;
 	case ETHTOOL_GLINK:
-		return ethtool_get_link(dev, useraddr);
+		rc = ethtool_get_link(dev, useraddr);
+		break;
 	case ETHTOOL_GEEPROM:
-		return ethtool_get_eeprom(dev, useraddr);
+		rc = ethtool_get_eeprom(dev, useraddr);
+		break;
 	case ETHTOOL_SEEPROM:
-		return ethtool_set_eeprom(dev, useraddr);
+		rc = ethtool_set_eeprom(dev, useraddr);
+		break;
 	case ETHTOOL_GCOALESCE:
-		return ethtool_get_coalesce(dev, useraddr);
+		rc = ethtool_get_coalesce(dev, useraddr);
+		break;
 	case ETHTOOL_SCOALESCE:
-		return ethtool_set_coalesce(dev, useraddr);
+		rc = ethtool_set_coalesce(dev, useraddr);
+		break;
 	case ETHTOOL_GRINGPARAM:
-		return ethtool_get_ringparam(dev, useraddr);
+		rc = ethtool_get_ringparam(dev, useraddr);
+		break;
 	case ETHTOOL_SRINGPARAM:
-		return ethtool_set_ringparam(dev, useraddr);
+		rc = ethtool_set_ringparam(dev, useraddr);
+		break;
 	case ETHTOOL_GPAUSEPARAM:
-		return ethtool_get_pauseparam(dev, useraddr);
+		rc = ethtool_get_pauseparam(dev, useraddr);
+		break;
 	case ETHTOOL_SPAUSEPARAM:
-		return ethtool_set_pauseparam(dev, useraddr);
+		rc = ethtool_set_pauseparam(dev, useraddr);
+		break;
 	case ETHTOOL_GRXCSUM:
-		return ethtool_get_rx_csum(dev, useraddr);
+		rc = ethtool_get_rx_csum(dev, useraddr);
+		break;
 	case ETHTOOL_SRXCSUM:
-		return ethtool_set_rx_csum(dev, useraddr);
+		rc = ethtool_set_rx_csum(dev, useraddr);
+		break;
 	case ETHTOOL_GTXCSUM:
-		return ethtool_get_tx_csum(dev, useraddr);
+		rc = ethtool_get_tx_csum(dev, useraddr);
+		break;
 	case ETHTOOL_STXCSUM:
-		return ethtool_set_tx_csum(dev, useraddr);
+		rc = ethtool_set_tx_csum(dev, useraddr);
+		break;
 	case ETHTOOL_GSG:
-		return ethtool_get_sg(dev, useraddr);
+		rc = ethtool_get_sg(dev, useraddr);
+		break;
 	case ETHTOOL_SSG:
-		return ethtool_set_sg(dev, useraddr);
+		rc = ethtool_set_sg(dev, useraddr);
+		break;
 	case ETHTOOL_GTSO:
-		return ethtool_get_tso(dev, useraddr);
+		rc = ethtool_get_tso(dev, useraddr);
+		break;
 	case ETHTOOL_STSO:
-		return ethtool_set_tso(dev, useraddr);
+		rc = ethtool_set_tso(dev, useraddr);
+		break;
 	case ETHTOOL_TEST:
-		return ethtool_self_test(dev, useraddr);
+		rc = ethtool_self_test(dev, useraddr);
+		break;
 	case ETHTOOL_GSTRINGS:
-		return ethtool_get_strings(dev, useraddr);
+		rc = ethtool_get_strings(dev, useraddr);
+		break;
 	case ETHTOOL_PHYS_ID:
-		return ethtool_phys_id(dev, useraddr);
+		rc = ethtool_phys_id(dev, useraddr);
+		break;
 	case ETHTOOL_GSTATS:
-		return ethtool_get_stats(dev, useraddr);
+		rc = ethtool_get_stats(dev, useraddr);
+		break;
 	default:
-		return -EOPNOTSUPP;
+		rc =  -EOPNOTSUPP;
 	}
+	
+	if(dev->ethtool_ops->complete)
+		dev->ethtool_ops->complete(dev);
+	return rc;
 
  ioctl:
 	if (dev->do_ioctl)
--- diff/net/ipv4/netfilter/arp_tables.c	2004-06-11 19:17:36.000000000 +0100
+++ source/net/ipv4/netfilter/arp_tables.c	2004-06-11 19:22:07.000000000 +0100
@@ -56,6 +56,7 @@
 #endif
 #define SMP_ALIGN(x) (((x) + SMP_CACHE_BYTES-1) & ~(SMP_CACHE_BYTES-1))
 
+static DECLARE_MUTEX(arpt_mutex);
 
 #define ASSERT_READ_LOCK(x) ARP_NF_ASSERT(down_trylock(&arpt_mutex) != 0)
 #define ASSERT_WRITE_LOCK(x) ARP_NF_ASSERT(down_trylock(&arpt_mutex) != 0)
--- diff/net/ipv4/tcp_diag.c	2004-06-11 19:17:36.000000000 +0100
+++ source/net/ipv4/tcp_diag.c	2004-06-11 19:22:07.000000000 +0100
@@ -91,6 +91,9 @@
 	info->tcpi_snd_cwnd = tp->snd_cwnd;
 	info->tcpi_advmss = tp->advmss;
 	info->tcpi_reordering = tp->reordering;
+
+	info->tcpi_rcv_rtt = ((1000000*tp->rcv_rtt_est.rtt)/HZ)>>3;
+	info->tcpi_rcv_space = tp->rcvq_space.space;
 }
 
 static int tcpdiag_fill(struct sk_buff *skb, struct sock *sk,
--- diff/net/sctp/sm_make_chunk.c	2004-05-19 22:13:17.000000000 +0100
+++ source/net/sctp/sm_make_chunk.c	2004-06-11 19:22:07.000000000 +0100
@@ -1834,23 +1834,28 @@
 	/* Allocate storage for the negotiated streams if it is not a temporary 	 * association.
 	 */
 	if (!asoc->temp) {
-		sctp_assoc_t assoc_id;
+		int assoc_id;
+		int error;
 
 		asoc->ssnmap = sctp_ssnmap_new(asoc->c.sinit_max_instreams,
 					       asoc->c.sinit_num_ostreams, gfp);
 		if (!asoc->ssnmap)
 			goto clean_up;
 
-		do {
-			if (unlikely(!idr_pre_get(&sctp_assocs_id, gfp)))
-				goto clean_up;
-			spin_lock_bh(&sctp_assocs_id_lock);
-			assoc_id = (sctp_assoc_t)idr_get_new(&sctp_assocs_id,
-							     (void *)asoc);
-			spin_unlock_bh(&sctp_assocs_id_lock);
-		} while (unlikely((int)assoc_id == -1));
+	retry:
+		if (unlikely(!idr_pre_get(&sctp_assocs_id, gfp)))
+			goto clean_up;
+		spin_lock_bh(&sctp_assocs_id_lock);
+		error = idr_get_new(&sctp_assocs_id,
+				    (void *)asoc,
+				    &assoc_id);
+		spin_unlock_bh(&sctp_assocs_id_lock);
+		if (error == -EAGAIN)
+			goto retry;
+		else if (error)
+			goto clean_up;
 
-		asoc->assoc_id = assoc_id;
+		asoc->assoc_id = (sctp_assoc_t) assoc_id;
 	}
 
 	/* ADDIP Section 4.1 ASCONF Chunk Procedures
--- diff/scripts/checkstack.pl	2004-06-11 19:17:36.000000000 +0100
+++ source/scripts/checkstack.pl	2004-06-11 19:22:07.000000000 +0100
@@ -23,6 +23,7 @@
 # $1 (first bracket) matches the size of the stack growth
 #
 # use anything else and feel the pain ;)
+my (@stack, $re, $x, $xs);
 {
 	my $arch = shift;
 	if ($arch eq "") {
@@ -31,25 +32,25 @@
 
 	$x	= "[0-9a-f]";	# hex character
 	$xs	= "[0-9a-f ]";	# hex character or space
-	if ($arch =~ /^arm$/) {
+	if ($arch eq 'arm') {
 		#c0008ffc:	e24dd064	sub	sp, sp, #100	; 0x64
 		$re = qr/.*sub.*sp, sp, #(([0-9]{2}|[3-9])[0-9]{2})/o;
 	} elsif ($arch =~ /^i[3456]86$/) {
 		#c0105234:       81 ec ac 05 00 00       sub    $0x5ac,%esp
 		$re = qr/^.*[as][du][db]    \$(0x$x{1,8}),\%esp$/o;
-	} elsif ($arch =~ /^ia64$/) {
+	} elsif ($arch eq 'ia64') {
 		#e0000000044011fc:       01 0f fc 8c     adds r12=-384,r12
 		$re = qr/.*adds.*r12=-(([0-9]{2}|[3-9])[0-9]{2}),r12/o;
-	} elsif ($arch =~ /^mips64$/) {
+	} elsif ($arch eq 'mips64') {
 		#8800402c:       67bdfff0        daddiu  sp,sp,-16
 		$re = qr/.*daddiu.*sp,sp,-(([0-9]{2}|[3-9])[0-9]{2})/o;
-	} elsif ($arch =~ /^mips$/) {
+	} elsif ($arch eq 'mips') {
 		#88003254:       27bdffe0        addiu   sp,sp,-32
 		$re = qr/.*addiu.*sp,sp,-(([0-9]{2}|[3-9])[0-9]{2})/o;
-	} elsif ($arch =~ /^ppc$/) {
+	} elsif ($arch eq 'ppc') {
 		#c00029f4:       94 21 ff 30     stwu    r1,-208(r1)
 		$re = qr/.*stwu.*r1,-($x{1,8})\(r1\)/o;
-	} elsif ($arch =~ /^ppc64$/) {
+	} elsif ($arch eq 'ppc64') {
 		#XXX
 		$re = qr/.*stdu.*r1,-($x{1,8})\(r1\)/o;
 	} elsif ($arch =~ /^s390x?$/) {
@@ -62,6 +63,7 @@
 }
 
 sub bysize($) {
+	my ($asize, $bsize);
 	($asize = $a) =~ s/.*	+(.*)$/$1/;
 	($bsize = $b) =~ s/.*	+(.*)$/$1/;
 	$bsize <=> $asize
@@ -70,8 +72,9 @@
 #
 # main()
 #
-$funcre = qr/^$x* \<(.*)\>:$/;
-while ($line = <STDIN>) {
+my $funcre = qr/^$x* <(.*)>:$/;
+my $func;
+while (my $line = <STDIN>) {
 	if ($line =~ m/$funcre/) {
 		$func = $1;
 	}
@@ -85,7 +88,7 @@
 			$size += 0x80000000;
 		}
 
-		$line =~ m/^($xs*).*/;
+		next if $line !~ m/^($xs*)/;
 		my $addr = $1;
 		$addr =~ s/ /0/g;
 		$addr = "0x$addr";
@@ -97,12 +100,8 @@
 			$padlen -= 8;
 		}
 		next if ($size < 100);
-		$stack[@stack] = "$intro$size\n";
+		push @stack, "$intro$size\n";
 	}
 }
 
-@sortedstack = sort bysize @stack;
-
-foreach $i (@sortedstack) {
-	print("$i");
-}
+print sort bysize @stack;
--- diff/sound/core/memalloc.c	2004-06-11 19:17:36.000000000 +0100
+++ source/sound/core/memalloc.c	2004-06-11 19:22:07.000000000 +0100
@@ -45,10 +45,14 @@
 #ifndef SNDRV_CARDS
 #define SNDRV_CARDS	8
 #endif
+
+/* FIXME: so far only some PCI devices have the preallocation table */
+#ifdef CONFIG_PCI
 static int enable[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS-1)] = 1};
 static int boot_devs;
 module_param_array(enable, bool, boot_devs, 0444);
 MODULE_PARM_DESC(enable, "Enable cards to allocate buffers.");
+#endif
 
 /*
  */
--- diff/sound/core/pcm_native.c	2004-06-11 19:17:36.000000000 +0100
+++ source/sound/core/pcm_native.c	2004-06-11 19:22:07.000000000 +0100
@@ -3133,31 +3133,68 @@
 
 static int snd_pcm_hw_refine_old_user(snd_pcm_substream_t * substream, struct sndrv_pcm_hw_params_old __user * _oparams)
 {
-	snd_pcm_hw_params_t params;
-	struct sndrv_pcm_hw_params_old oparams;
+	snd_pcm_hw_params_t *params;
+	struct sndrv_pcm_hw_params_old *oparams = NULL;
 	int err;
-	if (copy_from_user(&oparams, _oparams, sizeof(oparams)))
-		return -EFAULT;
-	snd_pcm_hw_convert_from_old_params(&params, &oparams);
-	err = snd_pcm_hw_refine(substream, &params);
-	snd_pcm_hw_convert_to_old_params(&oparams, &params);
-	if (copy_to_user(_oparams, &oparams, sizeof(oparams)))
-		return -EFAULT;
+
+	params = kmalloc(sizeof(*params), GFP_KERNEL);
+	if (!params) {
+		err = -ENOMEM;
+		goto out;
+	}
+	oparams = kmalloc(sizeof(*oparams), GFP_KERNEL);
+	if (!oparams) {
+		err = -ENOMEM;
+		goto out;
+	}
+
+	if (copy_from_user(oparams, _oparams, sizeof(*oparams))) {
+		err = -EFAULT;
+		goto out;
+	}
+	snd_pcm_hw_convert_from_old_params(params, oparams);
+	err = snd_pcm_hw_refine(substream, params);
+	snd_pcm_hw_convert_to_old_params(oparams, params);
+	if (copy_to_user(_oparams, oparams, sizeof(*oparams))) {
+		if (!err)
+			err = -EFAULT;
+	}
+out:
+	kfree(params);
+	kfree(oparams);
 	return err;
 }
 
 static int snd_pcm_hw_params_old_user(snd_pcm_substream_t * substream, struct sndrv_pcm_hw_params_old __user * _oparams)
 {
-	snd_pcm_hw_params_t params;
-	struct sndrv_pcm_hw_params_old oparams;
+	snd_pcm_hw_params_t *params;
+	struct sndrv_pcm_hw_params_old *oparams = NULL;
 	int err;
-	if (copy_from_user(&oparams, _oparams, sizeof(oparams)))
-		return -EFAULT;
-	snd_pcm_hw_convert_from_old_params(&params, &oparams);
-	err = snd_pcm_hw_params(substream, &params);
-	snd_pcm_hw_convert_to_old_params(&oparams, &params);
-	if (copy_to_user(_oparams, &oparams, sizeof(oparams)))
-		return -EFAULT;
+
+	params = kmalloc(sizeof(*params), GFP_KERNEL);
+	if (!params) {
+		err = -ENOMEM;
+		goto out;
+	}
+	oparams = kmalloc(sizeof(*oparams), GFP_KERNEL);
+	if (!oparams) {
+		err = -ENOMEM;
+		goto out;
+	}
+	if (copy_from_user(oparams, _oparams, sizeof(*oparams))) {
+		err = -EFAULT;
+		goto out;
+	}
+	snd_pcm_hw_convert_from_old_params(params, oparams);
+	err = snd_pcm_hw_params(substream, params);
+	snd_pcm_hw_convert_to_old_params(oparams, params);
+	if (copy_to_user(_oparams, oparams, sizeof(*oparams))) {
+		if (!err)
+			err = -EFAULT;
+	}
+out:
+	kfree(params);
+	kfree(oparams);
 	return err;
 }
 
--- diff/sound/core/seq/Makefile	2004-05-19 22:13:20.000000000 +0100
+++ source/sound/core/seq/Makefile	2004-06-11 19:22:07.000000000 +0100
@@ -51,7 +51,6 @@
 obj-$(call sequencer,$(CONFIG_SND_CS4231)) += $(RAWMIDI_OBJS)
 obj-$(call sequencer,$(CONFIG_SND_CS4232)) += $(RAWMIDI_OBJS) $(OPL3_OBJS)
 obj-$(call sequencer,$(CONFIG_SND_CS4236)) += $(RAWMIDI_OBJS) $(OPL3_OBJS)
-obj-$(call sequencer,$(CONFIG_SND_PC98_CS4232)) += $(RAWMIDI_OBJS) $(OPL3_OBJS)
 obj-$(call sequencer,$(CONFIG_SND_ES1688)) += $(RAWMIDI_OBJS) $(OPL3_OBJS)
 obj-$(call sequencer,$(CONFIG_SND_GUSCLASSIC)) += $(RAWMIDI_OBJS) $(OPL3_OBJS)
 obj-$(call sequencer,$(CONFIG_SND_GUSMAX)) += $(RAWMIDI_OBJS) $(OPL3_OBJS)
--- diff/sound/core/seq/instr/Makefile	2004-05-19 22:13:20.000000000 +0100
+++ source/sound/core/seq/instr/Makefile	2004-06-11 19:22:07.000000000 +0100
@@ -26,7 +26,6 @@
 obj-$(call sequencer,$(CONFIG_SND_AD1816A)) += snd-ainstr-fm.o
 obj-$(call sequencer,$(CONFIG_SND_CS4232)) += snd-ainstr-fm.o
 obj-$(call sequencer,$(CONFIG_SND_CS4236)) += snd-ainstr-fm.o
-obj-$(call sequencer,$(CONFIG_SND_PC98_CS4232)) += snd-ainstr-fm.o
 obj-$(call sequencer,$(CONFIG_SND_ES1688)) += snd-ainstr-fm.o
 obj-$(call sequencer,$(CONFIG_SND_GUSCLASSIC)) += snd-ainstr-iw.o snd-ainstr-gf1.o snd-ainstr-simple.o
 obj-$(call sequencer,$(CONFIG_SND_GUSMAX)) += snd-ainstr-iw.o snd-ainstr-gf1.o snd-ainstr-simple.o
--- diff/sound/core/seq/oss/seq_oss_timer.c	2004-05-19 22:13:20.000000000 +0100
+++ source/sound/core/seq/oss/seq_oss_timer.c	2004-06-11 19:22:07.000000000 +0100
@@ -168,7 +168,7 @@
 	tmprec.queue = dp->queue;
 	tmprec.ppq = timer->ppq;
 	tmprec.tempo = timer->tempo;
-	snd_seq_kernel_client_ctl(dp->cseq, SNDRV_SEQ_IOCTL_SET_QUEUE_TEMPO, &tmprec);
+	snd_seq_set_queue_tempo(dp->cseq, &tmprec);
 
 	send_timer_event(dp, SNDRV_SEQ_EVENT_START, 0);
 	timer->running = 1;
--- diff/sound/core/seq/seq.c	2004-06-11 19:17:36.000000000 +0100
+++ source/sound/core/seq/seq.c	2004-06-11 19:22:07.000000000 +0100
@@ -133,6 +133,7 @@
 EXPORT_SYMBOL(snd_seq_kernel_client_dispatch);
 EXPORT_SYMBOL(snd_seq_kernel_client_ctl);
 EXPORT_SYMBOL(snd_seq_kernel_client_write_poll);
+EXPORT_SYMBOL(snd_seq_set_queue_tempo);
   /* seq_memory.c */
 EXPORT_SYMBOL(snd_seq_expand_var_event);
 EXPORT_SYMBOL(snd_seq_dump_var_event);
--- diff/sound/core/seq/seq_clientmgr.c	2004-06-11 19:17:36.000000000 +0100
+++ source/sound/core/seq/seq_clientmgr.c	2004-06-11 19:22:07.000000000 +0100
@@ -1694,6 +1694,13 @@
 
 
 /* SET_QUEUE_TEMPO ioctl() */
+int snd_seq_set_queue_tempo(int client, snd_seq_queue_tempo_t *tempo)
+{
+	if (!snd_seq_queue_check_access(tempo->queue, client))
+		return -EPERM;
+	return snd_seq_queue_timer_set_tempo(tempo->queue, client, tempo);
+}
+
 static int snd_seq_ioctl_set_queue_tempo(client_t * client, void __user *arg)
 {
 	int result;
@@ -1702,15 +1709,8 @@
 	if (copy_from_user(&tempo, arg, sizeof(tempo)))
 		return -EFAULT;
 
-	if (snd_seq_queue_check_access(tempo.queue, client->number)) {
-		result = snd_seq_queue_timer_set_tempo(tempo.queue, client->number, &tempo);
-		if (result < 0)
-			return result;
-	} else {
-		return -EPERM;
-	}	
-
-	return 0;
+	result = snd_seq_set_queue_tempo(client->number, &tempo);
+	return result < 0 ? result : 0;
 }
 
 
--- diff/sound/drivers/mpu401/mpu401.c	2004-06-11 19:17:36.000000000 +0100
+++ source/sound/drivers/mpu401/mpu401.c	2004-06-11 19:22:07.000000000 +0100
@@ -52,9 +52,6 @@
 #endif
 static long port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT;	/* MPU-401 port number */
 static int irq[SNDRV_CARDS] = SNDRV_DEFAULT_IRQ;	/* MPU-401 IRQ */
-#ifdef CONFIG_X86_PC9800
-static int pc98ii[SNDRV_CARDS];				/* PC98-II dauther board */
-#endif
 static int boot_devs;
 
 module_param_array(index, int, boot_devs, 0444);
@@ -77,11 +74,6 @@
 module_param_array(irq, int, boot_devs, 0444);
 MODULE_PARM_DESC(irq, "IRQ # for MPU-401 device.");
 MODULE_PARM_SYNTAX(irq, SNDRV_IRQ_DESC);
-#ifdef CONFIG_X86_PC9800
-module_param_array(pc98ii, bool, boot_devs, 0444);
-MODULE_PARM_DESC(pc98ii, "Roland MPU-PC98II support.");
-MODULE_PARM_SYNTAX(pc98ii, SNDRV_BOOLEAN_FALSE_DESC);
-#endif
 
 #ifndef CONFIG_ACPI_BUS
 struct acpi_device;
@@ -188,9 +180,6 @@
 	}
 #endif
 	if (snd_mpu401_uart_new(card, 0,
-#ifdef CONFIG_X86_PC9800
-				pc98ii[dev] ? MPU401_HW_PC98II :
-#endif
 				MPU401_HW_MPU401,
 				port[dev], 0,
 				irq[dev], irq[dev] >= 0 ? SA_INTERRUPT : 0, NULL) < 0) {
--- diff/sound/drivers/opl3/opl3_lib.c	2004-05-19 22:13:20.000000000 +0100
+++ source/sound/drivers/opl3/opl3_lib.c	2004-06-11 19:22:07.000000000 +0100
@@ -416,26 +416,6 @@
 	case OPL3_HW_OPL3_FM801:
 		opl3->command = &snd_opl3_command;
 		break;
-	case OPL3_HW_OPL3_PC98:
-		opl3->command = &snd_opl3_command;
-
-		/* Initialize? */
-		opl3->command(opl3, OPL3_RIGHT | 0x05, 0x05);
-		opl3->command(opl3, OPL3_RIGHT | 0x08, 0x04);
-		opl3->command(opl3, OPL3_RIGHT | 0x08, 0x00);
-		opl3->command(opl3, OPL3_LEFT | 0xf7, 0x00);
-		opl3->command(opl3, OPL3_LEFT | 0x04, 0x60);
-		opl3->command(opl3, OPL3_LEFT | 0x04, 0x80);
-		inb(opl3->l_port);
-		
-		opl3->command(opl3, OPL3_LEFT | 0x02, 0xff);
-		opl3->command(opl3, OPL3_LEFT | 0x04, 0x21);
-		inb(opl3->l_port);
-		
-		opl3->command(opl3, OPL3_LEFT | 0x04, 0x60);
-		opl3->command(opl3, OPL3_LEFT | 0x04, 0x80);
-
-		break;
 	case OPL3_HW_OPL3_CS4281:
 		opl3->command = &snd_opl3_cs4281_command;
 		break;
--- diff/sound/drivers/vx/vx_core.c	2004-05-19 22:13:20.000000000 +0100
+++ source/sound/drivers/vx/vx_core.c	2004-06-11 19:22:07.000000000 +0100
@@ -572,6 +572,7 @@
 	if (cold_reset) {
 		chip->audio_source_target = chip->audio_source;
 		chip->clock_source = INTERNAL_QUARTZ;
+		chip->clock_mode = VX_CLOCK_MODE_AUTO;
 		chip->freq = 48000;
 		chip->uer_detected = VX_UER_MODE_NOT_PRESENT;
 		chip->uer_bits = SNDRV_PCM_DEFAULT_CON_SPDIF;
@@ -606,6 +607,7 @@
 	vx_core_t *chip = snd_magic_cast(vx_core_t, entry->private_data, return);
 	static char *audio_src_vxp[] = { "Line", "Mic", "Digital" };
 	static char *audio_src_vx2[] = { "Analog", "Analog", "Digital" };
+	static char *clock_mode[] = { "Auto", "Internal", "External" };
 	static char *clock_src[] = { "Internal", "External" };
 	static char *uer_type[] = { "Consumer", "Professional", "Not Present" };
 	
@@ -629,6 +631,7 @@
 	snd_iprintf(buffer, "Input Source: %s\n", vx_is_pcmcia(chip) ?
 		    audio_src_vxp[chip->audio_source] :
 		    audio_src_vx2[chip->audio_source]);
+	snd_iprintf(buffer, "Clock Mode: %s\n", clock_mode[chip->clock_mode]);
 	snd_iprintf(buffer, "Clock Source: %s\n", clock_src[chip->clock_source]);
 	snd_iprintf(buffer, "Frequency: %d\n", chip->freq);
 	snd_iprintf(buffer, "Detected Frequency: %d\n", chip->freq_detected);
--- diff/sound/drivers/vx/vx_mixer.c	2004-05-19 22:13:20.000000000 +0100
+++ source/sound/drivers/vx/vx_mixer.c	2004-06-11 19:22:07.000000000 +0100
@@ -524,6 +524,54 @@
 };
 
 /*
+ * clock mode selection
+ */
+static int vx_clock_mode_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo)
+{
+	static char *texts[3] = {
+		"Auto", "Internal", "External"
+	};
+
+	uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
+	uinfo->count = 1;
+	uinfo->value.enumerated.items = 3;
+	if (uinfo->value.enumerated.item > 2)
+		uinfo->value.enumerated.item = 2;
+	strcpy(uinfo->value.enumerated.name,
+	       texts[uinfo->value.enumerated.item]);
+	return 0;
+}
+
+static int vx_clock_mode_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
+{
+	vx_core_t *chip = snd_kcontrol_chip(kcontrol);
+	ucontrol->value.enumerated.item[0] = chip->clock_mode;
+	return 0;
+}
+
+static int vx_clock_mode_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
+{
+	vx_core_t *chip = snd_kcontrol_chip(kcontrol);
+	down(&chip->mixer_mutex);
+	if (chip->clock_mode != ucontrol->value.enumerated.item[0]) {
+		chip->clock_mode = ucontrol->value.enumerated.item[0];
+		vx_set_clock(chip, chip->freq);
+		up(&chip->mixer_mutex);
+		return 1;
+	}
+	up(&chip->mixer_mutex);
+	return 0;
+}
+
+static snd_kcontrol_new_t vx_control_clock_mode = {
+	.iface =	SNDRV_CTL_ELEM_IFACE_MIXER,
+	.name =		"Clock Mode",
+	.info =		vx_clock_mode_info,
+	.get =		vx_clock_mode_get,
+	.put =		vx_clock_mode_put,
+};
+
+/*
  * Audio Gain
  */
 static int vx_audio_gain_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo)
@@ -913,6 +961,9 @@
 	/* Audio source */
 	if ((err = snd_ctl_add(card, snd_ctl_new1(&vx_control_audio_src, chip))) < 0)
 		return err;
+	/* clock mode */
+	if ((err = snd_ctl_add(card, snd_ctl_new1(&vx_control_clock_mode, chip))) < 0)
+		return err;
 	/* IEC958 controls */
 	if ((err = snd_ctl_add(card, snd_ctl_new1(&vx_control_iec958_mask, chip))) < 0)
 		return err;
--- diff/sound/drivers/vx/vx_pcm.c	2004-05-19 22:13:20.000000000 +0100
+++ source/sound/drivers/vx/vx_pcm.c	2004-06-11 19:22:07.000000000 +0100
@@ -48,6 +48,7 @@
 #include <sound/driver.h>
 #include <linux/slab.h>
 #include <linux/vmalloc.h>
+#include <linux/delay.h>
 #include <sound/core.h>
 #include <sound/asoundef.h>
 #include <sound/pcm.h>
@@ -381,7 +382,7 @@
  */
 static int vx_toggle_pipe(vx_core_t *chip, vx_pipe_t *pipe, int state)
 {
-	int err, i, cur_state, delay;
+	int err, i, cur_state;
 
 	/* Check the pipe is not already in the requested state */
 	if (vx_get_pipe_state(chip, pipe, &cur_state) < 0)
@@ -394,17 +395,14 @@
 	 * enough sound buffer for this pipe)
 	 */
 	if (state) {
-		int delay = CAN_START_DELAY;
 		for (i = 0 ; i < MAX_WAIT_FOR_DSP; i++) {
-			snd_vx_delay(chip, delay);
 			err = vx_pipe_can_start(chip, pipe);
 			if (err > 0)
 				break;
 			/* Wait for a few, before asking again
 			 * to avoid flooding the DSP with our requests
 			 */
-			if ((i % 4 ) == 0)
-				delay <<= 1;
+			mdelay(1);
 		}
 	}
     
@@ -418,15 +416,12 @@
 	 * reaching the expected state before returning
 	 * Check one pipe only (since they are synchronous)
 	 */
-	delay = WAIT_STATE_DELAY;
 	for (i = 0; i < MAX_WAIT_FOR_DSP; i++) {
-		snd_vx_delay(chip, delay);
 		err = vx_get_pipe_state(chip, pipe, &cur_state);
 		if (err < 0 || cur_state == state)
 			break;
 		err = -EIO;
-		if ((i % 4 ) == 0)
-			delay <<= 1;
+		mdelay(1);
 	}
 	return err < 0 ? -EIO : 0;
 }
--- diff/sound/drivers/vx/vx_uer.c	2004-05-19 22:13:20.000000000 +0100
+++ source/sound/drivers/vx/vx_uer.c	2004-06-11 19:22:07.000000000 +0100
@@ -263,17 +263,17 @@
 	/* change the audio source if possible */
 	vx_sync_audio_source(chip);
 
-	switch (chip->audio_source) {
-	case VX_AUDIO_SRC_DIGITAL:
+	if (chip->clock_mode == VX_CLOCK_MODE_EXTERNAL ||
+	    (chip->clock_mode == VX_CLOCK_MODE_AUTO &&
+	     chip->audio_source == VX_AUDIO_SRC_DIGITAL)) {
 		if (chip->clock_source != UER_SYNC) {
 			vx_change_clock_source(chip, UER_SYNC);
 			mdelay(6);
 			src_changed = 1;
 		}
-		if (chip->freq == freq)
-			return 0;
-		break;
-	default:
+	} else if (chip->clock_mode == VX_CLOCK_MODE_INTERNAL ||
+		   (chip->clock_mode == VX_CLOCK_MODE_AUTO &&
+		    chip->audio_source != VX_AUDIO_SRC_DIGITAL)) {
 		if (chip->clock_source != INTERNAL_QUARTZ) {
 			vx_change_clock_source(chip, INTERNAL_QUARTZ);
 			src_changed = 1;
@@ -283,8 +283,9 @@
 		vx_set_internal_clock(chip, freq);
 		if (src_changed)
 			vx_modify_board_inputs(chip);
-		break;
 	}
+	if (chip->freq == freq)
+		return 0;
 	chip->freq = freq;
 	vx_modify_board_clock(chip, 1);
 	return 0;
--- diff/sound/isa/Kconfig	2004-05-19 22:13:20.000000000 +0100
+++ source/sound/isa/Kconfig	2004-06-11 19:22:07.000000000 +0100
@@ -51,16 +51,6 @@
 	  Say 'Y' or 'M' to include support for CS4235,CS4236,CS4237B,CS4238B,CS4239
 	  chips from Cirrus Logic - Crystal Semiconductors.
 
-config SND_PC98_CS4232
-	tristate "NEC PC9800 CS4232 driver"
-	depends on SND && X86_PC9800
-	select SND_OPL3_LIB
-	select SND_MPU401_UART
-	select SND_PCM
-	help
-	  Say 'Y' or 'M' to include support for NEC PC-9801/PC-9821 on-board
-	  soundchip based on CS4232.
-
 config SND_ES968
 	tristate "Generic ESS ES968 driver"
 	depends on SND && ISAPNP
--- diff/sound/isa/cs423x/Makefile	2004-05-19 22:13:20.000000000 +0100
+++ source/sound/isa/cs423x/Makefile	2004-06-11 19:22:07.000000000 +0100
@@ -8,7 +8,6 @@
 snd-cs4231-objs := cs4231.o
 snd-cs4232-objs := cs4232.o
 snd-cs4236-objs := cs4236.o
-snd-pc98-cs4232-objs := pc98.o
 
 # Toplevel Module Dependency
 obj-$(CONFIG_SND_AZT2320) += snd-cs4231-lib.o
@@ -22,6 +21,5 @@
 obj-$(CONFIG_SND_OPTI92X_CS4231) += snd-cs4231-lib.o
 obj-$(CONFIG_SND_WAVEFRONT) += snd-cs4231-lib.o
 obj-$(CONFIG_SND_SSCAPE) += snd-cs4231-lib.o
-obj-$(CONFIG_SND_PC98_CS4232) += snd-pc98-cs4232.o snd-cs4231-lib.o
 
 obj-m := $(sort $(obj-m))
--- diff/sound/isa/wavefront/wavefront_synth.c	2004-06-11 19:17:36.000000000 +0100
+++ source/sound/isa/wavefront/wavefront_synth.c	2004-06-11 19:22:07.000000000 +0100
@@ -1961,6 +1961,12 @@
 			break;
 		}
 
+		if (section_length < 0 || section_length > WF_SECTION_MAX) {
+			snd_printk ("invalid firmware section length %d\n",
+				    section_length);
+			goto failure;
+		}
+
 		if (sys_read (fd, section, section_length) != section_length) {
 			snd_printk ("firmware section "
 				"read error.\n");
--- diff/sound/oss/dmasound/dmasound_atari.c	2004-05-19 22:13:24.000000000 +0100
+++ source/sound/oss/dmasound/dmasound_atari.c	2004-06-11 19:22:07.000000000 +0100
@@ -22,7 +22,6 @@
 #include <linux/spinlock.h>
 #include <linux/interrupt.h>
 
-#include <asm/pgalloc.h>
 #include <asm/uaccess.h>
 #include <asm/atariints.h>
 #include <asm/atari_stram.h>
--- diff/sound/parisc/harmony.c	2004-06-11 19:17:36.000000000 +0100
+++ source/sound/parisc/harmony.c	2004-06-11 19:22:07.000000000 +0100
@@ -556,7 +556,7 @@
 	harmony->sample_rate = snd_card_harmony_rate_bits(runtime->rate);
 
 	/* data format */
-	harmony->data_format = snd_harmony_set_data_format(haromny, runtime->format);
+	harmony->data_format = snd_harmony_set_data_format(harmony, runtime->format);
 
 	/* number of channels */
 	if (runtime->channels == 2)
@@ -587,7 +587,7 @@
 	harmony->sample_rate = snd_card_harmony_rate_bits(runtime->rate);
 	
 	/* data format */
-	harmony->data_format = snd_harmony_set_data_format(haromny, runtime->format);
+	harmony->data_format = snd_harmony_set_data_format(harmony, runtime->format);
 	
 	/* number of channels */
 	if (runtime->channels == 1)
@@ -751,6 +751,8 @@
 	int err;
 	
 	err = snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(hw_params));
+	if (err > 0 && substream->dma_device.type == SNDRV_DMA_TYPE_CONTINUOUS)
+		substream->runtime->dma_addr = __pa(substream->runtime->dma_area);
 	DPRINTK(KERN_INFO PFX "HW Params returned %d, dma_addr %lx\n", err,
 			(unsigned long)substream->runtime->dma_addr);
 	return err;
@@ -784,7 +786,7 @@
 	.pointer =		snd_card_harmony_capture_pointer,
 };
 
-static int snd_card_harmony_pcm_init(snd_card_harmony_t *harmony, int device)
+static int snd_card_harmony_pcm_init(snd_card_harmony_t *harmony)
 {
 	snd_pcm_t *pcm;
 	int err;
@@ -797,7 +799,7 @@
 	
 	snd_harmony_disable_interrupts(harmony);
 	
-   	if ((err = snd_pcm_new(harmony->card, "Harmony", device, 1, 1, &pcm)) < 0)
+   	if ((err = snd_pcm_new(harmony->card, "Harmony", 0, 1, 1, &pcm)) < 0)
 		return err;
 	
 	snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_card_harmony_playback_ops);
@@ -813,26 +815,46 @@
 	harmony->dma_dev.dev = &harmony->pa_dev->dev;
 	err = snd_dma_alloc_pages(&harmony->dma_dev, HARMONY_BUF_SIZE*GRAVEYARD_BUFS,
 				  &harmony->graveyard_dma);
-	if (err < 0)
+	if (err == -ENOMEM) {
+		/* use continuous buffers */
+		harmony->dma_dev.type = SNDRV_DMA_TYPE_CONTINUOUS;
+		harmony->dma_dev.dev = snd_dma_continuous_data(GFP_KERNEL);
+		err = snd_dma_alloc_pages(&harmony->dma_dev, HARMONY_BUF_SIZE*GRAVEYARD_BUFS,
+					  &harmony->graveyard_dma);
+	}
+	if (err < 0) {
+		printk(KERN_ERR PFX "can't allocate graveyard buffer\n");
 		return err;
+	}
 	harmony->graveyard_count = 0;
 	
 	/* initialize silence buffers */
 	err = snd_dma_alloc_pages(&harmony->dma_dev, HARMONY_BUF_SIZE*SILENCE_BUFS,
 				  &harmony->silence_dma);
-	if (err < 0)
+	if (err < 0) {
+		printk(KERN_ERR PFX "can't allocate silence buffer\n");
 		return err;
+	}
 	harmony->silence_count = 0;
 
+	if (harmony->dma_dev.type == SNDRV_DMA_TYPE_CONTINUOUS) {
+		harmony->graveyard_dma.addr = __pa(harmony->graveyard_dma.area);
+		harmony->silence_dma.addr = __pa(harmony->silence_dma.area);
+	}
+
 	harmony->ply_stopped = harmony->cap_stopped = 1;
 	
 	harmony->playback_substream = NULL;
 	harmony->capture_substream = NULL;
 	harmony->graveyard_count = 0;
-	
-	snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV,
-					      &harmony->pa_dev->dev,
-					      MAX_BUFFER_SIZE, MAX_BUFFER_SIZE);
+
+	err = snd_pcm_lib_preallocate_pages_for_all(pcm, harmony->dma_dev.type,
+						    harmony->dma_dev.dev,
+						    MAX_BUFFER_SIZE, MAX_BUFFER_SIZE);
+	if (err < 0) {
+		printk(KERN_ERR PFX "buffer allocation error %d\n", err);
+		// return err;
+	}
 
 	return 0;
 }
@@ -1037,7 +1059,7 @@
 		snd_card_free(card);
 		return err;
 	}
-	if ((err = snd_card_harmony_pcm_init(chip, dev)) < 0) {
+	if ((err = snd_card_harmony_pcm_init(chip)) < 0) {
 		printk(KERN_ERR PFX "PCM Init failed\n");
 		snd_card_free(card);
 		return err;
--- diff/sound/pci/ac97/ac97_codec.c	2004-06-11 19:17:36.000000000 +0100
+++ source/sound/pci/ac97/ac97_codec.c	2004-06-11 19:22:07.000000000 +0100
@@ -108,12 +108,13 @@
 { 0x41445375, 0xffffffff, "AD1985",		patch_ad1985,	NULL },
 { 0x414c4300, 0xffffff00, "ALC100/100P", 	NULL,		NULL },
 { 0x414c4710, 0xfffffff0, "ALC200/200P",	NULL,		NULL },
+{ 0x414c4721, 0xffffffff, "ALC650D",		NULL,	NULL }, /* already patched */
+{ 0x414c4722, 0xffffffff, "ALC650E",		NULL,	NULL }, /* already patched */
+{ 0x414c4723, 0xffffffff, "ALC650F",		NULL,	NULL }, /* already patched */
 { 0x414c4720, 0xfffffff0, "ALC650",		patch_alc650,	NULL },
-{ 0x414c4721, 0xfffffff0, "ALC650D",		patch_alc650,	NULL },
-{ 0x414c4722, 0xfffffff0, "ALC650E",		patch_alc650,	NULL },
-{ 0x414c4723, 0xfffffff0, "ALC650F",		patch_alc650,	NULL },
 { 0x414c4760, 0xfffffff0, "ALC655",		patch_alc655,	NULL },
 { 0x414c4780, 0xfffffff0, "ALC658",		patch_alc655,	NULL },
+{ 0x414c4790, 0xfffffff0, "ALC850",		patch_alc850,	NULL },
 { 0x414c4730, 0xffffffff, "ALC101",		NULL,		NULL },
 { 0x414c4740, 0xfffffff0, "ALC202",		NULL,		NULL },
 { 0x414c4750, 0xfffffff0, "ALC250",		NULL,		NULL },
@@ -274,7 +275,7 @@
 {
 	if (!snd_ac97_valid_reg(ac97, reg))
 		return;
-	if ((ac97->id & 0xffffff00) == 0x414c4300) {
+	if ((ac97->id & 0xffffff00) == AC97_ID_ALC100) {
 		/* Fix H/W bug of ALC100/100P */
 		if (reg == AC97_MASTER || reg == AC97_HEADPHONE)
 			ac97->bus->write(ac97, AC97_RESET, 0);	/* reset audio codec */
@@ -398,7 +399,7 @@
 	int change;
 	unsigned short old, new, cfg;
 
-	down(&ac97->spec.ad18xx.mutex);
+	down(&ac97->mutex);
 	spin_lock(&ac97->reg_lock);
 	old = ac97->spec.ad18xx.pcmreg[codec];
 	new = (old & ~mask) | value;
@@ -418,7 +419,7 @@
 				 cfg | 0x7000);
 	} else
 		spin_unlock(&ac97->reg_lock);
-	up(&ac97->spec.ad18xx.mutex);
+	up(&ac97->mutex);
 	return change;
 }
 
@@ -545,7 +546,7 @@
 	int reg = kcontrol->private_value & 0xff;
 	int shift = (kcontrol->private_value >> 8) & 0xff;
 	int mask = (kcontrol->private_value >> 16) & 0xff;
-	int invert = (kcontrol->private_value >> 24) & 0xff;
+	int invert = (kcontrol->private_value >> 24) & 0x01;
 	
 	ucontrol->value.integer.value[0] = (snd_ac97_read_cache(ac97, reg) >> shift) & mask;
 	if (invert)
@@ -559,7 +560,7 @@
 	int reg = kcontrol->private_value & 0xff;
 	int shift = (kcontrol->private_value >> 8) & 0xff;
 	int mask = (kcontrol->private_value >> 16) & 0xff;
-	int invert = (kcontrol->private_value >> 24) & 0xff;
+	int invert = (kcontrol->private_value >> 24) & 0x01;
 	unsigned short val;
 	
 	val = (ucontrol->value.integer.value[0] & mask);
@@ -625,6 +626,40 @@
 				    (val1 << shift_left) | (val2 << shift_right));
 }
 
+int snd_ac97_getput_page(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol,
+			 int (*func)(snd_kcontrol_t *, snd_ctl_elem_value_t *))
+{
+	ac97_t *ac97 = snd_kcontrol_chip(kcontrol);
+	int reg = kcontrol->private_value & 0xff;
+	int err;
+
+	if ((ac97->ext_id & AC97_EI_REV_MASK) >= AC97_EI_REV_23 &&
+	    (reg >= 0x60 && reg < 0x70)) {
+		unsigned short page_save;
+		unsigned short page = (kcontrol->private_value >> 25) & 0x0f;
+		down(&ac97->mutex); /* lock paging */
+		page_save = snd_ac97_read(ac97, AC97_INT_PAGING) & AC97_PAGE_MASK;
+		snd_ac97_update_bits(ac97, AC97_INT_PAGING, AC97_PAGE_MASK, page);
+		err = func(kcontrol, ucontrol);
+		snd_ac97_update_bits(ac97, AC97_INT_PAGING, AC97_PAGE_MASK, page_save);
+		up(&ac97->mutex); /* unlock paging */
+	} else
+		err = func(kcontrol, ucontrol);
+	return err;
+}
+
+/* for rev2.3 paging */
+int snd_ac97_page_get_single(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
+{
+	return snd_ac97_getput_page(kcontrol, ucontrol, snd_ac97_get_single);
+}
+
+/* for rev2.3 paging */
+int snd_ac97_page_put_single(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
+{
+	return snd_ac97_getput_page(kcontrol, ucontrol, snd_ac97_put_single);
+}
+
 static const snd_kcontrol_new_t snd_ac97_controls_master_mono[2] = {
 AC97_SINGLE("Master Mono Playback Switch", AC97_MASTER_MONO, 15, 1, 1),
 AC97_SINGLE("Master Mono Playback Volume", AC97_MASTER_MONO, 0, 31, 1)
@@ -1120,6 +1155,7 @@
 	snd_ac97_write_cache(ac97, reg, 0x8000);
 }
 
+/* check the volume resolution of center/lfe */
 static void snd_ac97_change_volume_params2(ac97_t * ac97, int reg, int shift, unsigned char *max)
 {
 	unsigned short val, val1;
@@ -1135,6 +1171,7 @@
 	snd_ac97_write_cache(ac97, reg, 0x8080);
 }
 
+/* check whether the volume resolution is 4 or 5 bits */
 static void snd_ac97_change_volume_params3(ac97_t * ac97, int reg, unsigned char *max)
 {
 	unsigned short val, val1;
@@ -1150,6 +1187,18 @@
 	snd_ac97_write_cache(ac97, reg, 0x8000);
 }
 
+/* check whether the volume is mono or stereo */
+static int snd_ac97_is_stereo_vol(ac97_t *ac97, int reg)
+{
+	unsigned short val, val1, val2;
+	val = snd_ac97_read(ac97, reg);
+	val1 = val | 0x8000 | (0x01 << 8);
+	snd_ac97_write(ac97, reg, val1);
+	val2 = snd_ac97_read(ac97, reg);
+	snd_ac97_write(ac97, reg, val); /* restore */
+	return val1 == val2;
+}
+
 static inline int printable(unsigned int x)
 {
 	x &= 0xff;
@@ -1239,6 +1288,8 @@
 }
 
 
+static unsigned int snd_ac97_determine_spdif_rates(ac97_t *ac97);
+
 static int snd_ac97_mixer_build(ac97_t * ac97)
 {
 	snd_card_t *card = ac97->bus->card;
@@ -1293,11 +1344,8 @@
 	}
 
 	/* build headphone controls */
-	if (snd_ac97_try_volume_mix(ac97, AC97_HEADPHONE) || ac97->id == AC97_ID_STAC9708) {
-		const char *name = ac97->id == AC97_ID_STAC9708 ? 
-			"Sigmatel Surround Playback" :
-			"Headphone Playback";
-		if ((err = snd_ac97_cmix_new(card, name, AC97_HEADPHONE, 1, ac97)) < 0)
+	if (snd_ac97_try_volume_mix(ac97, AC97_HEADPHONE)) {
+		if ((err = snd_ac97_cmix_new(card, "Headphone Playback", AC97_HEADPHONE, 1, ac97)) < 0)
 			return err;
 	}
 	
@@ -1332,7 +1380,8 @@
 		for (idx = 0; idx < 2; idx++)
 			if ((err = snd_ctl_add(card, snd_ac97_cnew(&snd_ac97_controls_pc_beep[idx], ac97))) < 0)
 				return err;
-		snd_ac97_write_cache(ac97, AC97_PC_BEEP, 0x801e);
+		snd_ac97_write_cache(ac97, AC97_PC_BEEP,
+				     snd_ac97_read(ac97, AC97_PC_BEEP) | 0x801e);
 	}
 	
 	/* build Phone controls */
@@ -1349,15 +1398,26 @@
 	
 	/* build MIC controls */
 	snd_ac97_change_volume_params3(ac97, AC97_MIC, &max);
-	for (idx = 0; idx < 3; idx++) {
-		if ((err = snd_ctl_add(card, kctl = snd_ac97_cnew(&snd_ac97_controls_mic[idx], ac97))) < 0)
+	if (snd_ac97_is_stereo_vol(ac97, AC97_MIC)) {
+		/* build stereo mic */
+		if ((err = snd_ac97_cmute_new(card, "Mic Playback Switch", AC97_MIC, ac97)) < 0)
 			return err;
-		if (idx == 1) {		// volume
-			kctl->private_value &= ~(0xff << 16);
-			kctl->private_value |= (int)max << 16;
+		if ((err = snd_ac97_cvol_new(card, "Mic Playback Volume", AC97_MIC, max, ac97)) < 0)
+			return err;
+		if ((err = snd_ctl_add(card, snd_ac97_cnew(&snd_ac97_controls_mic[2], ac97))) < 0)
+			return err;
+	} else {
+		/* build mono mic */
+		for (idx = 0; idx < 3; idx++) {
+			if ((err = snd_ctl_add(card, kctl = snd_ac97_cnew(&snd_ac97_controls_mic[idx], ac97))) < 0)
+				return err;
+			if (idx == 1) {		// volume
+				kctl->private_value &= ~(0xff << 16);
+				kctl->private_value |= (int)max << 16;
+			}
 		}
+		snd_ac97_write_cache(ac97, AC97_MIC, 0x8000 | max);
 	}
-	snd_ac97_write_cache(ac97, AC97_MIC, 0x8000 | max);
 
 	/* build Line controls */
 	if ((err = snd_ac97_cmix_new(card, "Line Playback", AC97_LINE, 0, ac97)) < 0)
@@ -1410,9 +1470,7 @@
 		if ((err = snd_ac97_cmute_new(card, "PCM Playback Switch", AC97_PCM, ac97)) < 0)
 			return err;
 		/* FIXME: C-Media chips have no PCM volume!! */
-		if (/*ac97->id == 0x434d4941 ||*/
-		    ac97->id == 0x434d4942 ||
-		    ac97->id == 0x434d4961)
+		if (ac97->id == AC97_ID_CM9739)
 			snd_ac97_write_cache(ac97, AC97_PCM, 0x9f1f);
 		else {
 			if ((err = snd_ac97_cvol_new(card, "PCM Playback Volume", AC97_PCM, 31, ac97)) < 0)
@@ -1520,6 +1578,7 @@
 			/* set default PCM S/PDIF params */
 			/* consumer,PCM audio,no copyright,no preemphasis,PCM coder,original,48000Hz */
 			snd_ac97_write_cache(ac97, AC97_SPDIF, 0x2a20);
+			ac97->rates[AC97_RATES_SPDIF] = snd_ac97_determine_spdif_rates(ac97);
 		}
 		ac97->spdif_status = SNDRV_PCM_DEFAULT_CON_SPDIF;
 	}
@@ -1675,7 +1734,7 @@
 		if (snd_ac97_read(ac97, AC97_REC_GAIN) == 0x8a05)
 			return 0;
 		set_current_state(TASK_UNINTERRUPTIBLE);
-		schedule_timeout(HZ/100);
+		schedule_timeout(1);
 	} while (time_after_eq(end_time, jiffies));
 	return -ENODEV;
 }
@@ -1774,6 +1833,7 @@
 	ac97->bus = bus;
 	bus->codec[ac97->num] = ac97;
 	spin_lock_init(&ac97->reg_lock);
+	init_MUTEX(&ac97->mutex);
 
 	if (ac97->pci) {
 		pci_read_config_word(ac97->pci, PCI_SUBSYSTEM_VENDOR_ID, &ac97->subsystem_vendor);
@@ -1789,8 +1849,14 @@
 		bus->wait(ac97);
 	else {
 		udelay(50);
-		if (ac97_reset_wait(ac97, HZ/2, 0) < 0 &&
-		    ac97_reset_wait(ac97, HZ/2, 1) < 0) {
+		if (ac97->scaps & AC97_SCAP_SKIP_AUDIO)
+			err = ac97_reset_wait(ac97, HZ/2, 1);
+		else {
+			err = ac97_reset_wait(ac97, HZ/2, 0);
+			if (err < 0)
+				err = ac97_reset_wait(ac97, 0, 1);
+		}
+		if (err < 0) {
 			snd_printk(KERN_WARNING "AC'97 %d does not respond - RESET\n", ac97->num);
 			/* proceed anyway - it's often non-critical */
 		}
@@ -1803,20 +1869,6 @@
 		snd_ac97_free(ac97);
 		return -EIO;
 	}
-	/* AC97 audio codec chip revision detection. */
-	/* Currently only Realtek ALC650 detection implemented. */
-	switch(ac97->id & 0xfffffff0) {
-	case 0x414c4720:        /* ALC650 */
-		reg = snd_ac97_read(ac97, AC97_ALC650_REVISION);
-		if (((reg & 0x3f) >= 0) && ((reg & 0x3f) < 3))
-			ac97->id = 0x414c4720;          /* Old version */
-		else if (((reg & 0x3f) >= 3) && ((reg & 0x3f) < 0x10))
-			ac97->id = 0x414c4721;          /* D version */
-		else if ((reg&0x30) == 0x10)
-			ac97->id = 0x414c4722;          /* E version */
-		else if ((reg&0x30) == 0x20)
-			ac97->id = 0x414c4723;          /* F version */
-        }
 	
 	/* test for AC'97 */
 	if (!(ac97->scaps & AC97_SCAP_SKIP_AUDIO) && !(ac97->scaps & AC97_SCAP_AUDIO)) {
@@ -1865,9 +1917,9 @@
 			if ((snd_ac97_read(ac97, AC97_POWERDOWN) & 0x0f) == 0x0f)
 				goto __ready_ok;
 			set_current_state(TASK_UNINTERRUPTIBLE);
-			schedule_timeout(HZ/10);
+			schedule_timeout(1);
 		} while (time_after_eq(end_time, jiffies));
-		snd_printk(KERN_ERR "AC'97 %d analog subsections not ready\n", ac97->num);
+		snd_printk(KERN_WARNING "AC'97 %d analog subsections not ready\n", ac97->num);
 	}
 
 	/* FIXME: add powerdown control */
@@ -1898,9 +1950,9 @@
 			if ((snd_ac97_read(ac97, AC97_EXTENDED_MSTATUS) & tmp) == tmp)
 				goto __ready_ok;
 			set_current_state(TASK_UNINTERRUPTIBLE);
-			schedule_timeout(HZ/10);
+			schedule_timeout(1);
 		} while (time_after_eq(end_time, jiffies));
-		snd_printk(KERN_ERR "MC'97 %d converters and GPIO not ready (0x%x)\n", ac97->num, snd_ac97_read(ac97, AC97_EXTENDED_MSTATUS));
+		snd_printk(KERN_WARNING "MC'97 %d converters and GPIO not ready (0x%x)\n", ac97->num, snd_ac97_read(ac97, AC97_EXTENDED_MSTATUS));
 	}
 	
       __ready_ok:
@@ -1919,12 +1971,7 @@
 	}
 	if (ac97->ext_id & AC97_EI_SPDIF) {
 		/* codec specific code (patch) should override these values */
-		if (ac97->flags & AC97_CS_SPDIF)
-			ac97->rates[AC97_RATES_SPDIF] = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_44100;
-		else if (ac97->id == AC97_ID_CM9739)
-			ac97->rates[AC97_RATES_SPDIF] = SNDRV_PCM_RATE_48000;
-		else
-			ac97->rates[AC97_RATES_SPDIF] = snd_ac97_determine_spdif_rates(ac97);
+		ac97->rates[AC97_RATES_SPDIF] = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_32000;
 	}
 	if (ac97->ext_id & AC97_EI_VRM) {	/* MIC VRA support */
 		snd_ac97_determine_rates(ac97, AC97_PCM_MIC_ADC_RATE, 0, &ac97->rates[AC97_RATES_MIC_ADC]);
@@ -1942,8 +1989,8 @@
 	/* additional initializations */
 	if (bus->init)
 		bus->init(ac97);
-	snd_ac97_get_name(ac97, ac97->id, name, 0);
-	snd_ac97_get_name(NULL, ac97->id, name, 0);  // ac97->id might be changed in the special setup code
+	snd_ac97_get_name(ac97, ac97->id, name, !ac97_is_audio(ac97));
+	snd_ac97_get_name(NULL, ac97->id, name, !ac97_is_audio(ac97));  // ac97->id might be changed in the special setup code
 	if (ac97_is_audio(ac97)) {
 		if (card->mixername[0] == '\0') {
 			strcpy(card->mixername, name);
@@ -2066,18 +2113,28 @@
 	snd_ac97_write(ac97, AC97_GENERAL_PURPOSE, 0);
 
 	snd_ac97_write(ac97, AC97_POWERDOWN, ac97->regs[AC97_POWERDOWN]);
-	ac97->bus->write(ac97, AC97_MASTER, 0x8101);
-	for (i = 0; i < 10; i++) {
-		if (snd_ac97_read(ac97, AC97_MASTER) == 0x8101)
-			break;
-		set_current_state(TASK_UNINTERRUPTIBLE);
-		schedule_timeout(1);
-	}
-	/* FIXME: extra delay */
-	ac97->bus->write(ac97, AC97_MASTER, 0x8000);
-	if (snd_ac97_read(ac97, AC97_MASTER) != 0x8000) {
-		set_current_state(TASK_UNINTERRUPTIBLE);
-		schedule_timeout(HZ/4);
+	if (ac97_is_audio(ac97)) {
+		ac97->bus->write(ac97, AC97_MASTER, 0x8101);
+		for (i = HZ/10; i >= 0; i--) {
+			if (snd_ac97_read(ac97, AC97_MASTER) == 0x8101)
+				break;
+			set_current_state(TASK_UNINTERRUPTIBLE);
+			schedule_timeout(1);
+		}
+		/* FIXME: extra delay */
+		ac97->bus->write(ac97, AC97_MASTER, 0x8000);
+		if (snd_ac97_read(ac97, AC97_MASTER) != 0x8000) {
+			set_current_state(TASK_UNINTERRUPTIBLE);
+			schedule_timeout(HZ/4);
+		}
+	} else {
+		for (i = HZ/10; i >= 0; i--) {
+			unsigned short val = snd_ac97_read(ac97, AC97_EXTENDED_MID);
+			if (val != 0xffff && (val & 1) != 0)
+				break;
+			set_current_state(TASK_UNINTERRUPTIBLE);
+			schedule_timeout(1);
+		}
 	}
 __reset_ready:
 
@@ -2151,42 +2208,57 @@
 
 /*
  */
-int snd_ac97_remove_ctl(ac97_t *ac97, const char *name)
+static void set_ctl_name(char *dst, const char *src, const char *suffix)
+{
+	if (suffix)
+		sprintf(dst, "%s %s", src, suffix);
+	else
+		strcpy(dst, src);
+}	
+
+int snd_ac97_remove_ctl(ac97_t *ac97, const char *name, const char *suffix)
 {
 	snd_ctl_elem_id_t id;
 	memset(&id, 0, sizeof(id));
-	strcpy(id.name, name);
+	set_ctl_name(id.name, name, suffix);
 	id.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
 	return snd_ctl_remove_id(ac97->bus->card, &id);
 }
 
-static snd_kcontrol_t *ctl_find(ac97_t *ac97, const char *name)
+static snd_kcontrol_t *ctl_find(ac97_t *ac97, const char *name, const char *suffix)
 {
 	snd_ctl_elem_id_t sid;
 	memset(&sid, 0, sizeof(sid));
-	strcpy(sid.name, name);
+	set_ctl_name(sid.name, name, suffix);
 	sid.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
 	return snd_ctl_find_id(ac97->bus->card, &sid);
 }
 
-int snd_ac97_rename_ctl(ac97_t *ac97, const char *src, const char *dst)
+int snd_ac97_rename_ctl(ac97_t *ac97, const char *src, const char *dst, const char *suffix)
 {
-	snd_kcontrol_t *kctl = ctl_find(ac97, src);
+	snd_kcontrol_t *kctl = ctl_find(ac97, src, suffix);
 	if (kctl) {
-		strcpy(kctl->id.name, dst);
+		set_ctl_name(kctl->id.name, dst, suffix);
 		return 0;
 	}
 	return -ENOENT;
 }
 
-int snd_ac97_swap_ctl(ac97_t *ac97, const char *s1, const char *s2)
+/* rename both Volume and Switch controls - don't check the return value */
+void snd_ac97_rename_vol_ctl(ac97_t *ac97, const char *src, const char *dst)
+{
+	snd_ac97_rename_ctl(ac97, src, dst, "Switch");
+	snd_ac97_rename_ctl(ac97, src, dst, "Volume");
+}
+
+int snd_ac97_swap_ctl(ac97_t *ac97, const char *s1, const char *s2, const char *suffix)
 {
 	snd_kcontrol_t *kctl1, *kctl2;
-	kctl1 = ctl_find(ac97, s1);
-	kctl2 = ctl_find(ac97, s2);
+	kctl1 = ctl_find(ac97, s1, suffix);
+	kctl2 = ctl_find(ac97, s2, suffix);
 	if (kctl1 && kctl2) {
-		strcpy(kctl1->id.name, s2);
-		strcpy(kctl2->id.name, s1);
+		set_ctl_name(kctl1->id.name, s2, suffix);
+		set_ctl_name(kctl2->id.name, s1, suffix);
 		return 0;
 	}
 	return -ENOENT;
@@ -2194,26 +2266,22 @@
 
 static int swap_headphone(ac97_t *ac97, int remove_master)
 {
-	/* FIXME: error checks.. */
 	if (remove_master) {
-		if (ctl_find(ac97, "Headphone Playback Switch") == NULL)
+		if (ctl_find(ac97, "Headphone Playback Switch", NULL) == NULL)
 			return 0;
-		snd_ac97_remove_ctl(ac97, "Master Playback Switch");
-		snd_ac97_remove_ctl(ac97, "Master Playback Volume");
-	} else {
-		snd_ac97_rename_ctl(ac97, "Master Playback Switch", "Line-Out Playback Switch");
-		snd_ac97_rename_ctl(ac97, "Master Playback Volume", "Line-Out Playback Volume");
-	}
-	snd_ac97_rename_ctl(ac97, "Headphone Playback Switch", "Master Playback Switch");
-	snd_ac97_rename_ctl(ac97, "Headphone Playback Volume", "Master Playback Volume");
+		snd_ac97_remove_ctl(ac97, "Master Playback", "Switch");
+		snd_ac97_remove_ctl(ac97, "Master Playback", "Volume");
+	} else
+		snd_ac97_rename_vol_ctl(ac97, "Master Playback", "Line-Out Playback");
+	snd_ac97_rename_vol_ctl(ac97, "Headphone Playback", "Master Playback");
 	return 0;
 }
 
 static int swap_surround(ac97_t *ac97)
 {
 	/* FIXME: error checks.. */
-	snd_ac97_swap_ctl(ac97, "Master Playback Switch", "Surround Playback Switch");
-	snd_ac97_swap_ctl(ac97, "Master Playback Volume", "Surround Playback Volume");
+	snd_ac97_swap_ctl(ac97, "Master Playback", "Surround Playback", "Switch");
+	snd_ac97_swap_ctl(ac97, "Master Playback", "Surround Playback", "Volume");
 	return 0;
 }
 
--- diff/sound/pci/ac97/ac97_id.h	2004-05-19 22:13:24.000000000 +0100
+++ source/sound/pci/ac97/ac97_id.h	2004-06-11 19:22:07.000000000 +0100
@@ -45,7 +45,14 @@
 #define AC97_ID_CS4201		0x43525948
 #define AC97_ID_CS4205		0x43525958
 #define AC97_ID_CS_MASK		0xfffffff8	/* bit 0-2: rev */
+#define AC97_ID_ALC100		0x414c4300
 #define AC97_ID_ALC650		0x414c4720
+#define AC97_ID_ALC650D		0x414c4721
+#define AC97_ID_ALC650E		0x414c4722
+#define AC97_ID_ALC650F		0x414c4723
+#define AC97_ID_ALC655		0x414c4760
+#define AC97_ID_ALC658		0x414c4780
+#define AC97_ID_ALC850		0x414c4790
 #define AC97_ID_YMF753		0x594d4803
 #define AC97_ID_VT1616		0x49434551
 #define AC97_ID_CM9738		0x434d4941
--- diff/sound/pci/ac97/ac97_local.h	2004-06-11 19:17:36.000000000 +0100
+++ source/sound/pci/ac97/ac97_local.h	2004-06-11 19:22:07.000000000 +0100
@@ -23,10 +23,15 @@
  */
 
 #define AC97_SINGLE_VALUE(reg,shift,mask,invert) ((reg) | ((shift) << 8) | ((mask) << 16) | ((invert) << 24))
+#define AC97_PAGE_SINGLE_VALUE(reg,shift,mask,invert,page) ((reg) | ((shift) << 8) | ((mask) << 16) | ((invert) << 24) | ((page) << 25))
 #define AC97_SINGLE(xname, reg, shift, mask, invert) \
 { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .info = snd_ac97_info_single, \
   .get = snd_ac97_get_single, .put = snd_ac97_put_single, \
   .private_value =  AC97_SINGLE_VALUE(reg, shift, mask, invert) }
+#define AC97_PAGE_SINGLE(xname, reg, shift, mask, invert, page)		\
+{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .info = snd_ac97_info_single, \
+  .get = snd_ac97_page_get_single, .put = snd_ac97_page_put_single, \
+  .private_value =  AC97_PAGE_SINGLE_VALUE(reg, shift, mask, invert, page) }
 
 /* ac97_codec.c */
 extern const char *snd_ac97_stereo_enhancements[];
@@ -37,10 +42,13 @@
 int snd_ac97_info_single(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo);
 int snd_ac97_get_single(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol);
 int snd_ac97_put_single(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol);
+int snd_ac97_page_get_single(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol);
+int snd_ac97_page_put_single(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol);
 int snd_ac97_try_bit(ac97_t * ac97, int reg, int bit);
-int snd_ac97_remove_ctl(ac97_t *ac97, const char *name);
-int snd_ac97_rename_ctl(ac97_t *ac97, const char *src, const char *dst);
-int snd_ac97_swap_ctl(ac97_t *ac97, const char *s1, const char *s2);
+int snd_ac97_remove_ctl(ac97_t *ac97, const char *name, const char *suffix);
+int snd_ac97_rename_ctl(ac97_t *ac97, const char *src, const char *dst, const char *suffix);
+int snd_ac97_swap_ctl(ac97_t *ac97, const char *s1, const char *s2, const char *suffix);
+void snd_ac97_rename_vol_ctl(ac97_t *ac97, const char *src, const char *dst);
 
 /* ac97_proc.c */
 void snd_ac97_bus_proc_init(ac97_bus_t * ac97);
--- diff/sound/pci/ac97/ac97_patch.c	2004-06-11 19:17:36.000000000 +0100
+++ source/sound/pci/ac97/ac97_patch.c	2004-06-11 19:22:07.000000000 +0100
@@ -51,6 +51,21 @@
 	return 0;
 }
 
+/* set to the page, update bits and restore the page */
+static int ac97_update_bits_page(ac97_t *ac97, unsigned short reg, unsigned short mask, unsigned short value, unsigned short page)
+{
+	unsigned short page_save;
+	int ret;
+
+	down(&ac97->mutex);
+	page_save = snd_ac97_read(ac97, AC97_INT_PAGING) & AC97_PAGE_MASK;
+	snd_ac97_update_bits(ac97, AC97_INT_PAGING, AC97_PAGE_MASK, page);
+	ret = snd_ac97_update_bits(ac97, reg, mask, value);
+	snd_ac97_update_bits(ac97, AC97_INT_PAGING, AC97_PAGE_MASK, page_save);
+	up(&ac97->mutex); /* unlock paging */
+	return ret;
+}
+
 /* The following snd_ac97_ymf753_... items added by David Shust (dshust@shustring.com) */
 
 /* It is possible to indicate to the Yamaha YMF753 the type of speakers being used. */
@@ -204,7 +219,7 @@
 	if ((err = snd_ctl_add(ac97->bus->card, kctl = snd_ac97_cnew(&snd_ac97_controls_3d[0], ac97))) < 0)
 		return err;
 	strcpy(kctl->id.name, "3D Control - Wide");
-	kctl->private_value = AC97_3D_CONTROL | (9 << 8) | (7 << 16);
+	kctl->private_value = AC97_SINGLE_VALUE(AC97_3D_CONTROL, 9, 7, 0);
 	snd_ac97_write_cache(ac97, AC97_3D_CONTROL, 0x0000);
 	if ((err = snd_ctl_add(ac97->bus->card, snd_ac97_cnew(&snd_ac97_ymf753_controls_speaker, ac97))) < 0)
 		return err;
@@ -315,7 +330,7 @@
 	if ((err = snd_ctl_add(ac97->bus->card, kctl = snd_ac97_cnew(&snd_ac97_controls_3d[0], ac97))) < 0)
 		return err;
 	strcpy(kctl->id.name, "3D Control Sigmatel - Depth");
-	kctl->private_value = AC97_3D_CONTROL | (3 << 16);
+	kctl->private_value = AC97_SINGLE_VALUE(AC97_3D_CONTROL, 2, 3, 0);
 	snd_ac97_write_cache(ac97, AC97_3D_CONTROL, 0x0000);
 	return 0;
 }
@@ -328,11 +343,11 @@
 	if ((err = snd_ctl_add(ac97->bus->card, kctl = snd_ac97_cnew(&snd_ac97_controls_3d[0], ac97))) < 0)
 		return err;
 	strcpy(kctl->id.name, "3D Control Sigmatel - Depth");
-	kctl->private_value = AC97_3D_CONTROL | (3 << 16);
+	kctl->private_value = AC97_SINGLE_VALUE(AC97_3D_CONTROL, 0, 3, 0);
 	if ((err = snd_ctl_add(ac97->bus->card, kctl = snd_ac97_cnew(&snd_ac97_controls_3d[0], ac97))) < 0)
 		return err;
 	strcpy(kctl->id.name, "3D Control Sigmatel - Rear Depth");
-	kctl->private_value = AC97_3D_CONTROL | (2 << 8) | (3 << 16);
+	kctl->private_value = AC97_SINGLE_VALUE(AC97_3D_CONTROL, 2, 3, 0);
 	snd_ac97_write_cache(ac97, AC97_3D_CONTROL, 0x0000);
 	return 0;
 }
@@ -373,17 +388,23 @@
 	.build_specific	= patch_sigmatel_stac97xx_specific
 };
 
-static struct snd_ac97_build_ops patch_sigmatel_stac9708_ops = {
-	.build_3d	= patch_sigmatel_stac9708_3d,
-	.build_specific	= patch_sigmatel_stac97xx_specific
-};
-
 int patch_sigmatel_stac9700(ac97_t * ac97)
 {
 	ac97->build_ops = &patch_sigmatel_stac9700_ops;
 	return 0;
 }
 
+static int patch_sigmatel_stac9708_specific(ac97_t *ac97)
+{
+	snd_ac97_rename_vol_ctl(ac97, "Headphone Playback", "Sigmatel Surround Playback");
+	return patch_sigmatel_stac97xx_specific(ac97);
+}
+
+static struct snd_ac97_build_ops patch_sigmatel_stac9708_ops = {
+	.build_3d	= patch_sigmatel_stac9708_3d,
+	.build_specific	= patch_sigmatel_stac9708_specific
+};
+
 int patch_sigmatel_stac9708(ac97_t * ac97)
 {
 	unsigned int codec72, codec6c;
@@ -467,11 +488,11 @@
 	int shift = kcontrol->private_value;
 	unsigned short val;
 
-	val = ac97->regs[AC97_SIGMATEL_OUTSEL];
-	if (!((val >> shift) & 4))
+	val = ac97->regs[AC97_SIGMATEL_OUTSEL] >> shift;
+	if (!(val & 4))
 		ucontrol->value.enumerated.item[0] = 0;
 	else
-		ucontrol->value.enumerated.item[0] = 1 + ((val >> shift) & 3);
+		ucontrol->value.enumerated.item[0] = 1 + (val & 3);
 	return 0;
 }
 
@@ -480,6 +501,7 @@
 	ac97_t *ac97 = snd_kcontrol_chip(kcontrol);
 	int shift = kcontrol->private_value;
 	unsigned short val;
+	int ret;
 
 	if (ucontrol->value.enumerated.item[0] > 4)
 		return -EINVAL;
@@ -487,8 +509,10 @@
 		val = 0;
 	else
 		val = 4 | (ucontrol->value.enumerated.item[0] - 1);
-	return snd_ac97_update_bits(ac97, AC97_SIGMATEL_OUTSEL,
-				    7 << shift, val << shift);
+	ret = snd_ac97_update_bits(ac97, AC97_SIGMATEL_OUTSEL,
+				   7 << shift, val << shift);
+	up(&ac97->mutex);
+	return ret;
 }
 
 static int snd_ac97_stac9758_input_jack_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo)
@@ -521,8 +545,8 @@
 	ac97_t *ac97 = snd_kcontrol_chip(kcontrol);
 	int shift = kcontrol->private_value;
 
-	return snd_ac97_update_bits(ac97, AC97_SIGMATEL_INSEL, 7 << shift,
-				    ucontrol->value.enumerated.item[0] << shift);
+	return ac97_update_bits_page(ac97, AC97_SIGMATEL_INSEL, 7 << shift,
+				     ucontrol->value.enumerated.item[0] << shift, 0);
 }
 
 static int snd_ac97_stac9758_phonesel_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo)
@@ -550,8 +574,8 @@
 {
 	ac97_t *ac97 = snd_kcontrol_chip(kcontrol);
 
-	return snd_ac97_update_bits(ac97, AC97_SIGMATEL_IOMISC, 3,
-				    ucontrol->value.enumerated.item[0]);
+	return ac97_update_bits_page(ac97, AC97_SIGMATEL_IOMISC, 3,
+				     ucontrol->value.enumerated.item[0], 0);
 }
 
 #define STAC9758_OUTPUT_JACK(xname, shift) \
@@ -596,6 +620,14 @@
 				   ARRAY_SIZE(snd_ac97_sigmatel_stac9758_controls));
 	if (err < 0)
 		return err;
+	/* DAC-A direct */
+	snd_ac97_rename_vol_ctl(ac97, "Headphone Playback", "Front Playback");
+	/* DAC-A to Mix = PCM */
+	/* DAC-B direct = Surround */
+	/* DAC-B to Mix */
+	snd_ac97_rename_vol_ctl(ac97, "Video Playback", "Surround Mix Playback");
+	/* DAC-C direct = Center/LFE */
+
 	return 0;
 }
 
@@ -613,16 +645,16 @@
 		AC97_SIGMATEL_VARIOUS
 	};
 	static unsigned short def_regs[4] = {
-		/* OUTSEL */ 0xd794,
+		/* OUTSEL */ 0xd794, /* CL:CL, SR:SR, LO:MX, LI:DS, MI:DS */
 		/* IOMISC */ 0x2001,
-		/* INSEL */ 0x0201,
+		/* INSEL */ 0x0201, /* LI:LI, MI:M1 */
 		/* VARIOUS */ 0x0040
 	};
 	static unsigned short m675_regs[4] = {
-		/* OUTSEL */ 0x9040,
-		/* IOMISC */ 0x2102,
-		/* INSEL */ 0x0203,
-		/* VARIOUS */ 0x0041
+		/* OUTSEL */ 0xfc70, /* CL:MX, SR:MX, LO:DS, LI:MX, MI:DS */
+		/* IOMISC */ 0x2102, /* HP amp on */
+		/* INSEL */ 0x0203, /* LI:LI, MI:FR */
+		/* VARIOUS */ 0x0041 /* stereo mic */
 	};
 	unsigned short *pregs = def_regs;
 	int i;
@@ -635,6 +667,8 @@
 
 	// patch for SigmaTel
 	ac97->build_ops = &patch_sigmatel_stac9758_ops;
+	/* FIXME: assume only page 0 for writing cache */
+	snd_ac97_update_bits(ac97, AC97_INT_PAGING, AC97_PAGE_MASK, AC97_PAGE_VENDOR);
 	for (i = 0; i < 4; i++)
 		snd_ac97_write_cache(ac97, regs[i], pregs[i]);
 
@@ -654,8 +688,10 @@
 {
 	int err;
 
+	/* con mask, pro mask, default */
 	if ((err = patch_build_controls(ac97, &snd_ac97_controls_spdif[0], 3)) < 0)
 		return err;
+	/* switch, spsa */
 	if ((err = patch_build_controls(ac97, &snd_ac97_cirrus_controls_spdif[0], 1)) < 0)
 		return err;
 	switch (ac97->id & AC97_ID_CS_MASK) {
@@ -714,8 +750,10 @@
 {
 	int err;
 
+	/* con mask, pro mask, default */
 	if ((err = patch_build_controls(ac97, &snd_ac97_controls_spdif[0], 3)) < 0)
 		return err;
+	/* switch */
 	if ((err = patch_build_controls(ac97, &snd_ac97_conexant_controls_spdif[0], 1)) < 0)
 		return err;
 	/* set default PCM S/PDIF params */
@@ -734,6 +772,7 @@
 	ac97->build_ops = &patch_conexant_ops;
 	ac97->flags |= AC97_CX_SPDIF;
         ac97->ext_id |= AC97_EI_SPDIF;	/* force the detection of spdif */
+	ac97->rates[AC97_RATES_SPDIF] = SNDRV_PCM_RATE_48000; /* 48k only */
 	return 0;
 }
 
@@ -821,8 +860,6 @@
 	unsigned short val;
 	int idx, num;
 
-	init_MUTEX(&ac97->spec.ad18xx.mutex);
-
 	val = snd_ac97_read(ac97, AC97_AD_SERIAL_CFG);
 	snd_ac97_write_cache(ac97, AC97_AD_SERIAL_CFG, val);
 	codecs[0] = patch_ad1881_unchained(ac97, 0, (1<<12));
@@ -1114,10 +1151,8 @@
 static int patch_ad1888_specific(ac97_t *ac97)
 {
 	/* rename 0x04 as "Master" and 0x02 as "Master Surround" */
-	snd_ac97_rename_ctl(ac97, "Master Playback Switch", "Master Surround Playback Switch");
-	snd_ac97_rename_ctl(ac97, "Master Playback Volume", "Master Surround Playback Volume");
-	snd_ac97_rename_ctl(ac97, "Headphone Playback Switch", "Master Playback Switch");
-	snd_ac97_rename_ctl(ac97, "Headphone Playback Volume", "Master Playback Volume");
+	snd_ac97_rename_vol_ctl(ac97, "Master Playback", "Master Surround Playback");
+	snd_ac97_rename_vol_ctl(ac97, "Headphone Playback", "Master Playback");
 	return patch_build_controls(ac97, snd_ac97_ad1888_controls, ARRAY_SIZE(snd_ac97_ad1888_controls));
 }
 
@@ -1213,7 +1248,7 @@
 }
 
 /*
- * realtek ALC65x codecs
+ * realtek ALC65x/850 codecs
  */
 static int snd_ac97_alc650_mic_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t * ucontrol)
 {
@@ -1303,6 +1338,17 @@
 
 	ac97->build_ops = &patch_alc650_ops;
 
+	/* determine the revision */
+	val = snd_ac97_read(ac97, AC97_ALC650_REVISION) & 0x3f;
+	if (val < 3)
+		ac97->id = 0x414c4720;          /* Old version */
+	else if (val < 0x10)
+		ac97->id = 0x414c4721;          /* D version */
+	else if (val < 0x20)
+		ac97->id = 0x414c4722;          /* E version */
+	else if (val < 0x30)
+		ac97->id = 0x414c4723;          /* F version */
+
 	/* revision E or F */
 	/* FIXME: what about revision D ? */
 	ac97->spec.dev_flags = (ac97->id == 0x414c4722 ||
@@ -1351,20 +1397,19 @@
 static int snd_ac97_alc655_mic_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t * ucontrol)
 {
         ac97_t *ac97 = snd_kcontrol_chip(kcontrol);
-        int change;
 
 	/* misc control; vrefout disable */
 	snd_ac97_update_bits(ac97, AC97_ALC650_CLOCK, 1 << 12,
 			     ucontrol->value.integer.value[0] ? (1 << 12) : 0);
-	change = snd_ac97_update_bits(ac97, AC97_ALC650_MULTICH, 1 << 10,
-				      ucontrol->value.integer.value[0] ? (1 << 10) : 0);
-	return change;
+	return ac97_update_bits_page(ac97, AC97_ALC650_MULTICH, 1 << 10,
+				     ucontrol->value.integer.value[0] ? (1 << 10) : 0,
+				     0);
 }
 
 
 static const snd_kcontrol_new_t snd_ac97_controls_alc655[] = {
-	AC97_SINGLE("Duplicate Front", AC97_ALC650_MULTICH, 0, 1, 0),
-	AC97_SINGLE("Line-In As Surround", AC97_ALC650_MULTICH, 9, 1, 0),
+	AC97_PAGE_SINGLE("Duplicate Front", AC97_ALC650_MULTICH, 0, 1, 0, 0),
+	AC97_PAGE_SINGLE("Line-In As Surround", AC97_ALC650_MULTICH, 9, 1, 0, 0),
 	{
 		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
 		.name = "Mic As Center/LFE",
@@ -1391,7 +1436,6 @@
 	       texts_658[uinfo->value.enumerated.item] :
 	       texts_655[uinfo->value.enumerated.item]);
 	return 0;
-
 }
 
 static int alc655_iec958_route_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
@@ -1410,13 +1454,15 @@
 static int alc655_iec958_route_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
 {
 	ac97_t *ac97 = snd_kcontrol_chip(kcontrol);
-	return snd_ac97_update_bits(ac97, AC97_ALC650_MULTICH, 3 << 12,
-				    (unsigned short)ucontrol->value.enumerated.item[0]);
+
+	return ac97_update_bits_page(ac97, AC97_ALC650_MULTICH, 3 << 12,
+				     (unsigned short)ucontrol->value.enumerated.item[0],
+				     0);
 }
 
 static const snd_kcontrol_new_t snd_ac97_spdif_controls_alc655[] = {
-        AC97_SINGLE("IEC958 Capture Switch", AC97_ALC650_MULTICH, 11, 1, 0),
-        AC97_SINGLE("IEC958 Input Monitor", AC97_ALC650_MULTICH, 14, 1, 0),
+        AC97_PAGE_SINGLE("IEC958 Capture Switch", AC97_ALC650_MULTICH, 11, 1, 0, 0),
+        AC97_PAGE_SINGLE("IEC958 Input Monitor", AC97_ALC650_MULTICH, 14, 1, 0, 0),
 	{
 		.iface  = SNDRV_CTL_ELEM_IFACE_MIXER,
 		.name   = "IEC958 Playback Route",
@@ -1451,6 +1497,9 @@
 
 	ac97->build_ops = &patch_alc655_ops;
 
+	/* assume only page 0 for writing cache */
+	snd_ac97_update_bits(ac97, AC97_INT_PAGING, AC97_PAGE_MASK, AC97_PAGE_VENDOR);
+
 	/* adjust default values */
 	val = snd_ac97_read(ac97, 0x7a); /* misc control */
 	val |= (1 << 1); /* spdif input pin */
@@ -1469,6 +1518,120 @@
 	return 0;
 }
 
+
+#define AC97_ALC850_JACK_SELECT	0x76
+#define AC97_ALC850_MISC1	0x7a
+
+static int ac97_alc850_surround_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t * ucontrol)
+{
+        ac97_t *ac97 = snd_kcontrol_chip(kcontrol);
+        ucontrol->value.integer.value[0] = ((ac97->regs[AC97_ALC850_JACK_SELECT] >> 12) & 7) == 2;
+        return 0;
+}
+
+static int ac97_alc850_surround_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t * ucontrol)
+{
+        ac97_t *ac97 = snd_kcontrol_chip(kcontrol);
+
+	/* SURR 1kOhm (bit4), Amp (bit5) */
+	snd_ac97_update_bits(ac97, AC97_ALC850_MISC1, (1<<4)|(1<<5),
+			     ucontrol->value.integer.value[0] ? (1<<5) : (1<<4));
+	/* LINE-IN = 0, SURROUND = 2 */
+	return snd_ac97_update_bits(ac97, AC97_ALC850_JACK_SELECT, 7 << 12,
+				    ucontrol->value.integer.value[0] ? (2<<12) : (0<<12));
+}
+
+static int ac97_alc850_mic_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t * ucontrol)
+{
+        ac97_t *ac97 = snd_kcontrol_chip(kcontrol);
+        ucontrol->value.integer.value[0] = ((ac97->regs[AC97_ALC850_JACK_SELECT] >> 4) & 7) == 2;
+        return 0;
+}
+
+static int ac97_alc850_mic_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t * ucontrol)
+{
+        ac97_t *ac97 = snd_kcontrol_chip(kcontrol);
+
+	/* Vref disable (bit12), 1kOhm (bit13) */
+	snd_ac97_update_bits(ac97, AC97_ALC850_MISC1, (1<<12)|(1<<13),
+			     ucontrol->value.integer.value[0] ? (1<<12) : (1<<13));
+	/* MIC-IN = 1, CENTER-LFE = 2 */
+	return snd_ac97_update_bits(ac97, AC97_ALC850_JACK_SELECT, 7 << 4,
+				    ucontrol->value.integer.value[0] ? (2<<4) : (1<<4));
+}
+
+static const snd_kcontrol_new_t snd_ac97_controls_alc850[] = {
+	AC97_PAGE_SINGLE("Duplicate Front", AC97_ALC650_MULTICH, 0, 1, 0, 0),
+	{
+		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+		.name = "Line-In As Surround",
+		.info = snd_ac97_info_single,
+		.get = ac97_alc850_surround_get,
+		.put = ac97_alc850_surround_put,
+		.private_value = AC97_SINGLE_VALUE(0, 0, 1, 0) /* only mask needed */
+	},
+	{
+		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+		.name = "Mic As Center/LFE",
+		.info = snd_ac97_info_single,
+		.get = ac97_alc850_mic_get,
+		.put = ac97_alc850_mic_put,
+		.private_value = AC97_SINGLE_VALUE(0, 0, 1, 0) /* only mask needed */
+	},
+
+};
+
+static int patch_alc850_specific(ac97_t *ac97)
+{
+	int err;
+
+	if ((err = patch_build_controls(ac97, snd_ac97_controls_alc850, ARRAY_SIZE(snd_ac97_controls_alc850))) < 0)
+		return err;
+	if (ac97->ext_id & AC97_EI_SPDIF) {
+		if ((err = patch_build_controls(ac97, snd_ac97_spdif_controls_alc655, ARRAY_SIZE(snd_ac97_spdif_controls_alc655))) < 0)
+			return err;
+	}
+	return 0;
+}
+
+static struct snd_ac97_build_ops patch_alc850_ops = {
+	.build_specific	= patch_alc850_specific
+};
+
+int patch_alc850(ac97_t *ac97)
+{
+	ac97->build_ops = &patch_alc850_ops;
+
+	ac97->spec.dev_flags = 0; /* for IEC958 playback route - ALC655 compatible */
+
+	/* assume only page 0 for writing cache */
+	snd_ac97_update_bits(ac97, AC97_INT_PAGING, AC97_PAGE_MASK, AC97_PAGE_VENDOR);
+
+	/* adjust default values */
+	/* set default: spdif-in enabled,
+	   spdif-in monitor off, spdif-in PCM off
+	   center on mic off, surround on line-in off
+	   duplicate front off
+	*/
+	snd_ac97_write_cache(ac97, AC97_ALC650_MULTICH, 1<<15);
+	/* SURR_OUT: on, Surr 1kOhm: on, Surr Amp: off, Front 1kOhm: off
+	 * Front Amp: on, Vref: enable, Center 1kOhm: on, Mix: on
+	 */
+	snd_ac97_write_cache(ac97, 0x7a, (1<<1)|(1<<4)|(0<<5)|(1<<6)|
+			     (1<<7)|(0<<12)|(1<<13)|(0<<14));
+	/* detection UIO2,3: all path floating, UIO3: MIC, Vref2: disable,
+	 * UIO1: FRONT, Vref3: disable, UIO3: LINE, Front-Mic: mute
+	 */
+	snd_ac97_write_cache(ac97, 0x76, (0<<0)|(0<<2)|(1<<4)|(1<<7)|(2<<8)|
+			     (1<<11)|(0<<12)|(1<<15));
+
+	/* full DAC volume */
+	snd_ac97_write_cache(ac97, AC97_ALC650_SURR_DAC_VOL, 0x0808);
+	snd_ac97_write_cache(ac97, AC97_ALC650_LFE_DAC_VOL, 0x0808);
+	return 0;
+}
+
+
 /*
  * C-Media CM97xx codecs
  */
@@ -1599,8 +1762,10 @@
 		/* enable spdif in */
 		snd_ac97_write_cache(ac97, AC97_CM9739_SPDIF_CTRL,
 				     snd_ac97_read(ac97, AC97_CM9739_SPDIF_CTRL) | 0x01);
+		ac97->rates[AC97_RATES_SPDIF] = SNDRV_PCM_RATE_48000; /* 48k only */
 	} else {
 		ac97->ext_id &= ~AC97_EI_SPDIF; /* disable extended-id */
+		ac97->rates[AC97_RATES_SPDIF] = 0;
 	}
 
 	/* set-up multi channel */
--- diff/sound/pci/ac97/ac97_patch.h	2004-05-19 22:13:24.000000000 +0100
+++ source/sound/pci/ac97/ac97_patch.h	2004-06-11 19:22:07.000000000 +0100
@@ -49,6 +49,7 @@
 int patch_ad1985(ac97_t * ac97);
 int patch_alc650(ac97_t * ac97);
 int patch_alc655(ac97_t * ac97);
+int patch_alc850(ac97_t * ac97);
 int patch_cm9738(ac97_t * ac97);
 int patch_cm9739(ac97_t * ac97);
 int patch_vt1616(ac97_t * ac97);
--- diff/sound/pci/ac97/ac97_proc.c	2004-06-11 19:17:36.000000000 +0100
+++ source/sound/pci/ac97/ac97_proc.c	2004-06-11 19:22:07.000000000 +0100
@@ -292,9 +292,9 @@
 {
 	ac97_t *ac97 = snd_magic_cast(ac97_t, entry->private_data, return);
 	
+	down(&ac97->mutex);
 	if ((ac97->id & 0xffffff40) == AC97_ID_AD1881) {	// Analog Devices AD1881/85/86
 		int idx;
-		down(&ac97->spec.ad18xx.mutex);
 		for (idx = 0; idx < 3; idx++)
 			if (ac97->spec.ad18xx.id[idx]) {
 				/* select single codec */
@@ -305,7 +305,6 @@
 			}
 		/* select all codecs */
 		snd_ac97_update_bits(ac97, AC97_AD_SERIAL_CFG, 0x7000, 0x7000);
-		up(&ac97->spec.ad18xx.mutex);
 		
 		snd_iprintf(buffer, "\nAD18XX configuration\n");
 		snd_iprintf(buffer, "Unchained        : 0x%04x,0x%04x,0x%04x\n",
@@ -319,6 +318,7 @@
 	} else {
 		snd_ac97_proc_read_main(ac97, buffer, 0);
 	}
+	up(&ac97->mutex);
 }
 
 #ifdef CONFIG_SND_DEBUG
@@ -328,6 +328,7 @@
 	ac97_t *ac97 = snd_magic_cast(ac97_t, entry->private_data, return);
 	char line[64];
 	unsigned int reg, val;
+	down(&ac97->mutex);
 	while (!snd_info_get_line(buffer, line, sizeof(line))) {
 		if (sscanf(line, "%x %x", &reg, &val) != 2)
 			continue;
@@ -335,6 +336,7 @@
 		if (reg < 0x80 && (reg & 1) == 0 && val <= 0xffff)
 			snd_ac97_write_cache(ac97, reg, val);
 	}
+	up(&ac97->mutex);
 }
 #endif
 
@@ -353,10 +355,10 @@
 {
 	ac97_t *ac97 = snd_magic_cast(ac97_t, entry->private_data, return);
 
+	down(&ac97->mutex);
 	if ((ac97->id & 0xffffff40) == AC97_ID_AD1881) {	// Analog Devices AD1881/85/86
 
 		int idx;
-		down(&ac97->spec.ad18xx.mutex);
 		for (idx = 0; idx < 3; idx++)
 			if (ac97->spec.ad18xx.id[idx]) {
 				/* select single codec */
@@ -366,10 +368,10 @@
 			}
 		/* select all codecs */
 		snd_ac97_update_bits(ac97, AC97_AD_SERIAL_CFG, 0x7000, 0x7000);
-		up(&ac97->spec.ad18xx.mutex);
 	} else {
 		snd_ac97_proc_regs_read_main(ac97, buffer, 0);
 	}	
+	up(&ac97->mutex);
 }
 
 void snd_ac97_proc_init(ac97_t * ac97)
--- diff/sound/pci/atiixp.c	2004-06-11 19:17:36.000000000 +0100
+++ source/sound/pci/atiixp.c	2004-06-11 19:22:07.000000000 +0100
@@ -1,5 +1,5 @@
 /*
- *   ALSA driver for ATI IXP 150/200/250 AC97 controllers
+ *   ALSA driver for ATI IXP 150/200/250/300 AC97 controllers
  *
  *	Copyright (c) 2004 Takashi Iwai <tiwai@suse.de>
  *
@@ -1387,17 +1387,9 @@
 		ac97.num = i;
 		ac97.scaps = AC97_SCAP_SKIP_MODEM;
 		if ((err = snd_ac97_mixer(pbus, &ac97, &chip->ac97[i])) < 0) {
-			if (chip->codec_not_ready_bits)
-				/* codec(s) was detected but not available.
-				 * return the error
-				 */
-				return err;
-			else {
-				/* codec(s) was NOT detected, so just ignore here */
-				chip->ac97[i] = NULL; /* to be sure */
-				snd_printd("atiixp: codec %d not found\n", i);
-				continue;
-			}
+			chip->ac97[i] = NULL; /* to be sure */
+			snd_printdd("atiixp: codec %d not available for audio\n", i);
+			continue;
 		}
 		codec_count++;
 	}
--- diff/sound/pci/cs46xx/dsp_spos_scb_lib.c	2004-05-19 22:13:24.000000000 +0100
+++ source/sound/pci/cs46xx/dsp_spos_scb_lib.c	2004-06-11 19:22:07.000000000 +0100
@@ -246,6 +246,12 @@
 		if ((entry = snd_info_create_card_entry(ins->snd_card, scb->scb_name, 
 							ins->proc_dsp_dir)) != NULL) {
 			scb_info = kmalloc(sizeof(proc_scb_info_t), GFP_KERNEL);
+			if (!scb_info) {
+				snd_info_free_entry(entry);
+				entry = NULL;
+				goto out;
+			}
+
 			scb_info->chip = chip;
 			scb_info->scb_desc = scb;
       
@@ -262,7 +268,7 @@
 				entry = NULL;
 			}
 		}
-
+out:
 		scb->proc_info = entry;
 	}
 }
--- diff/sound/pci/ice1712/Makefile	2004-06-11 19:17:37.000000000 +0100
+++ source/sound/pci/ice1712/Makefile	2004-06-11 19:22:07.000000000 +0100
@@ -5,7 +5,7 @@
 
 snd-ice17xx-ak4xxx-objs := ak4xxx.o
 snd-ice1712-objs := ice1712.o delta.o hoontech.o ews.o
-snd-ice1724-objs := ice1724.o amp.o revo.o aureon.o
+snd-ice1724-objs := ice1724.o amp.o revo.o aureon.o vt1720_mobo.o
 
 # Toplevel Module Dependency
 obj-$(CONFIG_SND_ICE1712) += snd-ice1712.o snd-ice17xx-ak4xxx.o
--- diff/sound/pci/ice1712/ice1724.c	2004-06-11 19:17:37.000000000 +0100
+++ source/sound/pci/ice1712/ice1724.c	2004-06-11 19:22:07.000000000 +0100
@@ -44,6 +44,7 @@
 #include "amp.h"
 #include "revo.h"
 #include "aureon.h"
+#include "vt1720_mobo.h"
 
 
 MODULE_AUTHOR("Jaroslav Kysela <perex@suse.cz>");
@@ -54,6 +55,7 @@
 	       REVO_DEVICE_DESC
 	       AMP_AUDIO2000_DEVICE_DESC
 	       AUREON_DEVICE_DESC
+	       VT1720_MOBO_DEVICE_DESC
 		"{VIA,VT1720},"
 		"{VIA,VT1724},"
 		"{ICEnsemble,Generic ICE1724},"
@@ -419,7 +421,7 @@
 	ice->cur_rate = rate;
 
 	/* check MT02 */
-	if (ice->eeprom.data[ICE_EEP2_ACLINK] & 0x80) {
+	if (ice->eeprom.data[ICE_EEP2_ACLINK] & VT1724_CFG_PRO_I2S) {
 		val = old = inb(ICEMT1724(ice, I2S_FORMAT));
 		if (rate > 96000)
 			val |= VT1724_MT_I2S_MCLK_128X; /* 128x MCLK */
@@ -446,15 +448,6 @@
 		if (ice->akm[i].ops.set_rate_val)
 			ice->akm[i].ops.set_rate_val(&ice->akm[i], rate);
 	}
-
-	/* set up AC97 registers if needed */
-	if (! (ice->eeprom.data[ICE_EEP2_ACLINK] & 0x80) && ice->ac97) {
-		snd_ac97_set_rate(ice->ac97, AC97_PCM_FRONT_DAC_RATE, rate);
-		snd_ac97_set_rate(ice->ac97, AC97_PCM_SURR_DAC_RATE, rate);
-		snd_ac97_set_rate(ice->ac97, AC97_PCM_LFE_DAC_RATE, rate);
-		snd_ac97_set_rate(ice->ac97, AC97_SPDIF, rate);
-		snd_ac97_set_rate(ice->ac97, AC97_PCM_LR_ADC_RATE, rate);
-	}
 }
 
 static int snd_vt1724_pcm_hw_params(snd_pcm_substream_t * substream,
@@ -698,7 +691,7 @@
 static int set_rate_constraints(ice1712_t *ice, snd_pcm_substream_t *substream)
 {
 	snd_pcm_runtime_t *runtime = substream->runtime;
-	if (ice->eeprom.data[ICE_EEP2_ACLINK] & 0x80) {
+	if (ice->eeprom.data[ICE_EEP2_ACLINK] & VT1724_CFG_PRO_I2S) {
 		/* I2S */
 		if (ice->eeprom.data[ICE_EEP2_I2S] & 0x08)
 			return snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, &hw_constraints_rates_192);
@@ -714,15 +707,9 @@
 			ratec = AC97_RATES_FRONT_DAC;
 		else
 			ratec = AC97_RATES_ADC;
-		runtime->hw.rates = ice->ac97->rates[ratec];
 		runtime->hw.rate_max = 48000;
-		if (runtime->hw.rates == SNDRV_PCM_RATE_48000) {
-			runtime->hw.rate_min = 48000;
-			return 0;
-		} else {
-			runtime->hw.rates = SNDRV_PCM_RATE_KNOT | SNDRV_PCM_RATE_8000_48000;
-			return snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, &hw_constraints_rates_48);
-		}
+		runtime->hw.rates = SNDRV_PCM_RATE_KNOT | SNDRV_PCM_RATE_8000_48000;
+		return snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, &hw_constraints_rates_48);
 	}
 	return 0;
 }
@@ -1815,6 +1802,7 @@
 	snd_vt1724_revo_cards,
 	snd_vt1724_amp_cards, 
 	snd_vt1724_aureon_cards,
+	snd_vt1720_mobo_cards,
 	0,
 };
 
@@ -1930,9 +1918,6 @@
 
 	outb(0, ICEREG1724(ice, POWERDOWN));
 
-	/* read back to check the availability of SPDIF out */
-	ice->eeprom.data[ICE_EEP2_SPDIF] = inb(ICEREG1724(ice, SPDIF_CFG));
-
 	return 0;
 }
 
--- diff/sound/pci/via82xx.c	2004-06-11 19:17:37.000000000 +0100
+++ source/sound/pci/via82xx.c	2004-06-11 19:22:08.000000000 +0100
@@ -1060,19 +1060,6 @@
 	int err;
 	unsigned long flags;
 	struct via_rate_lock *ratep;
-	struct ratetbl {
-		int rate;
-		unsigned int bit;
-	} ratebits[] = {
-		{8000, SNDRV_PCM_RATE_8000},
-		{11025, SNDRV_PCM_RATE_11025},
-		{16000, SNDRV_PCM_RATE_16000},
-		{22050, SNDRV_PCM_RATE_22050},
-		{32000, SNDRV_PCM_RATE_32000},
-		{44100, SNDRV_PCM_RATE_44100},
-		{48000, SNDRV_PCM_RATE_48000},
-	};
-	int i;
 
 	runtime->hw = snd_via82xx_hw;
 	
@@ -1080,10 +1067,10 @@
 	ratep = &chip->rates[viadev->direction];
 	spin_lock_irqsave(&ratep->lock, flags);
 	ratep->used++;
-	if (chip->spdif_on) {
-		runtime->hw.rates = SNDRV_PCM_RATE_32000|SNDRV_PCM_RATE_44100|SNDRV_PCM_RATE_48000;
-		runtime->hw.rate_min = 32000;
-		runtime->hw.rate_max = 48000;
+	if (chip->spdif_on && viadev->reg_offset == 0x30) {
+		/* DXS#3 and spdif is on */
+		runtime->hw.rates = chip->ac97->rates[AC97_RATES_SPDIF];
+		snd_pcm_limit_hw_rates(runtime);
 	} else if (chip->dxs_fixed && viadev->reg_offset < 0x40) {
 		/* fixed DXS playback rate */
 		runtime->hw.rates = SNDRV_PCM_RATE_48000;
@@ -1091,27 +1078,10 @@
 	} else if (! ratep->rate) {
 		int idx = viadev->direction ? AC97_RATES_ADC : AC97_RATES_FRONT_DAC;
 		runtime->hw.rates = chip->ac97->rates[idx];
-		for (i = 0; i < (int)ARRAY_SIZE(ratebits); i++) {
-			if (runtime->hw.rates & ratebits[i].bit) {
-				runtime->hw.rate_min = ratebits[i].rate;
-				break;
-			}
-		}
-		for (i = ARRAY_SIZE(ratebits) - 1; i >= 0; i--) {
-			if (runtime->hw.rates & ratebits[i].bit) {
-				runtime->hw.rate_max = ratebits[i].rate;
-				break;
-			}
-		}
+		snd_pcm_limit_hw_rates(runtime);
 	} else {
 		/* a fixed rate */
 		runtime->hw.rates = SNDRV_PCM_RATE_KNOT;
-		for (i = 0; i < (int)ARRAY_SIZE(ratebits); i++) {
-			if (ratep->rate == ratebits[i].rate) {
-				runtime->hw.rates = ratebits[i].bit;
-				break;
-			}
-		}
 		runtime->hw.rate_max = runtime->hw.rate_min = ratep->rate;
 	}
 	spin_unlock_irqrestore(&ratep->lock, flags);
@@ -1363,6 +1333,10 @@
 							 snd_dma_pci_data(chip->pci), 64*1024, 128*1024)) < 0)
 		return err;
 
+	/* SPDIF supported? */
+	if (! ac97_can_spdif(chip->ac97))
+		return 0;
+
 	/* PCM #1:  DXS3 playback (for spdif) */
 	err = snd_pcm_new(chip->card, chip->card->shortname, 1, 1, 0, &pcm);
 	if (err < 0)
@@ -1660,9 +1634,11 @@
 		if (err < 0)
 			return err;
 	}
-	err = snd_ctl_add(chip->card, snd_ctl_new1(&snd_via8233_dxs3_spdif_control, chip));
-	if (err < 0)
-		return err;
+	if (ac97_can_spdif(chip->ac97)) {
+		err = snd_ctl_add(chip->card, snd_ctl_new1(&snd_via8233_dxs3_spdif_control, chip));
+		if (err < 0)
+			return err;
+	}
 	if (chip->chip_type != TYPE_VIA8233A) {
 		err = snd_ctl_add(chip->card, snd_ctl_new1(&snd_via8233_dxs_volume_control, chip));
 		if (err < 0)
@@ -1672,6 +1648,7 @@
 	/* select spdif data slot 10/11 */
 	pci_read_config_byte(chip->pci, VIA8233_SPDIF_CTRL, &val);
 	val = (val & ~VIA8233_SPDIF_SLOT_MASK) | VIA8233_SPDIF_SLOT_1011;
+	val &= ~VIA8233_SPDIF_DX3; /* SPDIF off as default */
 	pci_write_config_byte(chip->pci, VIA8233_SPDIF_CTRL, val);
 
 	return 0;
@@ -2114,6 +2091,7 @@
 		{ .vendor = 0x1043, .device = 0x8095, .action = VIA_DXS_NO_VRA }, /* ASUS A7V8X (FIXME: possibly VIA_DXS_ENABLE?)*/
 		{ .vendor = 0x1043, .device = 0x80a1, .action = VIA_DXS_NO_VRA }, /* ASUS A7V8-X */
 		{ .vendor = 0x1043, .device = 0x80b0, .action = VIA_DXS_NO_VRA }, /* ASUS A7V600 & K8V*/ 
+		{ .vendor = 0x1071, .device = 0x8375, .action = VIA_DXS_NO_VRA }, /* Vobis/Yakumo/Mitac notebook */
 		{ .vendor = 0x10cf, .device = 0x118e, .action = VIA_DXS_ENABLE }, /* FSC laptop */
 		{ .vendor = 0x1106, .device = 0x4161, .action = VIA_DXS_NO_VRA }, /* ASRock K7VT2 */
 		{ .vendor = 0x1106, .device = 0xaa01, .action = VIA_DXS_NO_VRA }, /* EPIA MII */
--- diff/Documentation/fb/sisfb.txt	1970-01-01 01:00:00.000000000 +0100
+++ source/Documentation/fb/sisfb.txt	2004-06-11 19:22:00.000000000 +0100
@@ -0,0 +1,158 @@
+
+What is sisfb?
+==============
+
+sisfb is a framebuffer device driver for SiS (Silicon Integrated Systems)
+graphics chips. Supported are:
+
+- SiS 300 series: SiS 300/305, 540, 630(S), 730(S)
+- SiS 315 series: SiS 315/H/PRO, 55x, (M)65x, 740, (M)661(F/M)X, (M)741(GX)
+- SiS 330 series: SiS 330 ("Xabre"), (M)760
+
+
+Why do I need a framebuffer driver?
+===================================
+
+sisfb is eg. useful if you want a high-resolution text console. Besides that,
+sisfb is required to run DirectFB (which comes with an additional, dedicated
+driver for the 315 series).
+
+On the 300 series, sisfb on kernels older than 2.6.3 furthermore plays an
+important role in connection with DRM/DRI: Sisfb manages the memory heap
+used by DRM/DRI for 3D texture and other data. This memory management is
+required for using DRI/DRM.
+
+Kernels >= around 2.6.3 do not need sisfb any longer for DRI/DRM memory
+management. The SiS DRM driver has been updated and features a memory manager
+of its own (which will be used if sisfb is not compiled). So unless you want
+a graphical console, you don't need sisfb on kernels >=2.6.3.
+
+Sidenote: Since this seems to be a commonly made mistake: sisfb and vesafb
+cannot be active at the same time! Do only select one of them in your kernel
+configuration.
+
+
+How are parameters passed to sisfb?
+===================================
+
+Well, it depends: If compiled statically into the kernel, use lilo's append
+statement to add the parameters to the kernel command line. Please see lilo's
+(or GRUB's) documentation for more information. If sisfb is a kernel module,
+parameters are given with the modprobe (or insmod) command.
+
+Example for sisfb as part of the static kernel: Add the following line to your
+lilo.conf:
+
+     append="video=sisfb:mode:1024x768x16,mem:12288,rate:75"
+
+Example for sisfb as a module: Start sisfb by typing
+
+     modprobe sisfb mode=1024x768x16 rate=75 mem=12288
+
+A common mistake is that folks use a wrong parameter format when using the
+driver compiled into the kernel. Please note: If compiled into the kernel,
+the parameter format is video=sisfb:mode:none or video=sisfb:mode:1024x768x16
+(or whatever mode you want to use, alternatively using any other format
+described above or the vesa keyword instead of mode). If compiled as a module,
+the parameter format reads mode=none or mode=1024x768x16 (or whatever mode you
+want to use). Using a "=" for a ":" (and vice versa) is a huge difference!
+Additionally: If you give more than one argument to the in-kernel sisfb, the
+arguments are separated with ",". For example:
+
+   video=sisfb:mode:1024x768x16,rate:75,mem:12288
+
+
+How do I use it?
+================
+
+Preface statement: This file only covers very little of the driver's
+capabilities and features. Please refer to the author's and maintainer's
+website at http://www.winischhofer.net/linuxsisvga.shtml for more
+information. Additionally, "modinfo sisfb" gives an overview over all
+supported options including some explanation.
+
+The desired display mode can be specified using the keyword "mode" with
+a parameter in one of the follwing formats:
+  - XxYxDepth or
+  - XxY-Depth or
+  - XxY-Depth@Rate or
+  - XxY
+  - or simply use the VESA mode number in hexadecimal or decimal.
+
+For example: 1024x768x16, 1024x768-16@75, 1280x1024-16. If no depth is
+specified, it defaults to 8. If no rate is given, it defaults to 60Hz. Depth 32
+means 24bit color depth (but 32 bit framebuffer depth, which is not relevant
+to the user).
+
+Additionally, sisfb understands the keyword "vesa" followed by a VESA mode
+number in decimal or hexadecimal. For example: vesa=791 or vesa=0x117. Please
+use either "mode" or "vesa" but not both.
+
+Linux 2.4 only: If no mode is given, sisfb defaults to "no mode" (mode=none) if
+compiled as a module; if sisfb is statically compiled into the kernel, it
+defaults to 800x600x8 unless CRT2 type is LCD, in which case the LCD's native
+resolution is used. If you want to switch to a different mode, use the fbset
+shell command.
+
+Linux 2.6 only: If no mode is given, sisfb defaults to 800x600x8 unless CRT2
+type is LCD, in which case it defaults to the LCD's native resolution. If
+you want to switch to another mode, use the stty shell command.
+
+You should compile in both vgacon (to boot if you remove you SiS card from
+your system) and sisfb (for graphics mode). Under Linux 2.6, also "Framebuffer
+console support" (fbcon) is needed for a graphical console.
+
+You should *not* compile-in vesafb. And please do not use the "vga=" keyword
+in lilo's or grub's configuration file; mode selection is done using the
+"mode" or "vesa" keywords as a parameter. See above and below.
+
+
+X11
+===
+
+If using XFree86 or X.org, it is recommended that you don't use the "fbdev"
+driver but the dedicated "sis" X driver. The "sis" X driver and sisfb are
+developed by the same person (Thomas Winischhofer) and cooperate well with
+each other.
+
+
+SVGALib
+=======
+
+SVGALib, if directly accessing the hardware, never restores the screen
+correctly, especially on laptops or if the output devices are LCD or TV.
+Therefore, use the chipset "FBDEV" in SVGALib configuration. This will make
+SVGALib use the framebuffer device for mode switches and restoration.
+
+
+Configuration
+=============
+
+(Some) accepted options:
+
+off      - Disable sisfb. This option is only understood if sisfb is
+           in-kernel, not a module.
+mem:X    - size of memory for the console, rest will be used for DRI/DRM. X
+           is in kilobytes. On 300 series, the default is 4096, 8192 or
+	   16384 (each in kilobyte) depending on how much video ram the card
+           has. On 315/330 series, the default is the maximum available ram
+	   (since DRI/DRM is not supported for these chipsets).
+noaccel  - do not use 2D acceleration engine. (Default: use acceleration)
+noypan   - disable y-panning and scroll by redrawing the entire screen.
+           This is much slower than y-panning. (Default: use y-panning)
+vesa:X   - selects startup videomode. X is number from 0 to 0x1FF and
+           represents the VESA mode number (can be given in decimal or
+	   hexadecimal form, the latter prefixed with "0x").
+mode:X   - selects startup videomode. Please see above for the format of
+           "X".
+
+Boolean options such as "noaccel" or "noypan" are to be given without a
+parameter if sisfb is in-kernel (for example "video=sisfb:noypan). If
+sisfb is a module, these are to be set to 1 (for example "modprobe sisfb
+noypan=1").
+
+--
+Thomas Winischhofer <thomas@winischhofer.net>
+May 27, 2004
+
+
--- diff/Documentation/hpet.txt	1970-01-01 01:00:00.000000000 +0100
+++ source/Documentation/hpet.txt	2004-06-11 19:22:00.000000000 +0100
@@ -0,0 +1,298 @@
+		High Precision Event Timer Driver for Linux
+
+The High Precision Event Timer (HPET) hardware is the future replacement for the 8254 and Real
+Time Clock (RTC) periodic timer functionality.  Each HPET can have up two 32 timers.  It is possible
+to configure the first two timers as legacy replacements for 8254 and RTC periodic.  A specification
+done by INTEL and Microsoft can be found at http://www.intel.com/labs/platcomp/hpet/hpetspec.htm.
+
+The driver supports detection of HPET driver allocation and initialization of the HPET before the
+driver module_init routine is called.  This enables platform code which uses timer 0 or 1 as the
+main timer to intercept HPET initialization.  An example of this initialization can be found in
+arch/i386/kernel/time_hpet.c.
+
+The driver provides two APIs which are very similar to the API found in the rtc.c driver.
+There is a user space API and a kernel space API.  An example user space program is provided
+below.
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <string.h>
+#include <memory.h>
+#include <malloc.h>
+#include <time.h>
+#include <ctype.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <signal.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <sys/time.h>
+#include <linux/hpet.h>
+
+
+extern void hpet_open_close(int, const char **);
+extern void hpet_info(int, const char **);
+extern void hpet_poll(int, const char **);
+extern void hpet_fasync(int, const char **);
+extern void hpet_read(int, const char **);
+
+#include <sys/poll.h>
+#include <sys/ioctl.h>
+#include <signal.h>
+
+struct hpet_command {
+	char		*command;
+	void		(*func)(int argc, const char ** argv);
+} hpet_command[] = {
+	{
+		"open-close",
+		hpet_open_close
+	},
+	{
+		"info",
+		hpet_info
+	},
+	{
+		"poll",
+		hpet_poll
+	},
+	{
+		"fasync",
+		hpet_fasync
+	},
+};
+
+int
+main(int argc, const char ** argv)
+{
+	int	i;
+
+	argc--;
+	argv++;
+
+	if (!argc) {
+		fprintf(stderr, "-hpet: requires command\n");
+		return -1;
+	}
+
+
+	for (i = 0; i < (sizeof (hpet_command) / sizeof (hpet_command[0])); i++)
+		if (!strcmp(argv[0], hpet_command[i].command)) {
+			argc--;
+			argv++;
+			fprintf(stderr, "-hpet: executing %s\n",
+				hpet_command[i].command);
+			hpet_command[i].func(argc, argv);
+			return 0;
+		}
+
+	fprintf(stderr, "do_hpet: command %s not implemented\n", argv[0]);
+
+	return -1;
+}
+
+void
+hpet_open_close(int argc, const char **argv)
+{
+	int	fd;
+
+	if (argc != 1) {
+		fprintf(stderr, "hpet_open_close: device-name\n");
+		return;
+	}
+
+	fd = open(argv[0], O_RDWR);
+	if (fd < 0)
+		fprintf(stderr, "hpet_open_close: open failed\n");
+	else
+		close(fd);
+
+	return;
+}
+
+void
+hpet_info(int argc, const char **argv)
+{
+}
+
+void
+hpet_poll(int argc, const char **argv)
+{
+	unsigned long		freq;
+	int			iterations, i, fd;
+	struct pollfd		pfd;
+	struct hpet_info	info;
+	struct timeval		stv, etv;
+	struct timezone		tz;
+	long			usec;
+
+	if (argc != 3) {
+		fprintf(stderr, "hpet_poll: device-name freq iterations\n");
+		return;
+	}
+
+	freq = atoi(argv[1]);
+	iterations = atoi(argv[2]);
+
+	fd = open(argv[0], O_RDWR);
+
+	if (fd < 0) {
+		fprintf(stderr, "hpet_poll: open of %s failed\n", argv[0]);
+		return;
+	}
+
+	if (ioctl(fd, HPET_IRQFREQ, freq) < 0) {
+		fprintf(stderr, "hpet_poll: HPET_IRQFREQ failed\n");
+		goto out;
+	}
+
+	if (ioctl(fd, HPET_INFO, &info) < 0) {
+		fprintf(stderr, "hpet_poll: failed to get info\n");
+		goto out;
+	}
+
+	fprintf(stderr, "hpet_poll: info.hi_flags 0x%lx\n", info.hi_flags);
+
+	if (info.hi_flags && (ioctl(fd, HPET_EPI, 0) < 0)) {
+		fprintf(stderr, "hpet_poll: HPET_EPI failed\n");
+		goto out;
+	}
+
+	if (ioctl(fd, HPET_IE_ON, 0) < 0) {
+		fprintf(stderr, "hpet_poll, HPET_IE_ON failed\n");
+		goto out;
+	}
+
+	pfd.fd = fd;
+	pfd.events = POLLIN;
+
+	for (i = 0; i < iterations; i++) {
+		pfd.revents = 0;
+		gettimeofday(&stv, &tz);
+		if (poll(&pfd, 1, -1) < 0)
+			fprintf(stderr, "hpet_poll: poll failed\n");
+		else {
+			long 	data;
+
+			gettimeofday(&etv, &tz);
+			usec = stv.tv_sec * 1000000 + stv.tv_usec;
+			usec = (etv.tv_sec * 1000000 + etv.tv_usec) - usec;
+
+			fprintf(stderr,
+				"hpet_poll: expired time = 0x%lx\n", usec);
+
+			fprintf(stderr, "hpet_poll: revents = 0x%x\n",
+				pfd.revents);
+
+			if (read(fd, &data, sizeof(data)) != sizeof(data)) {
+				fprintf(stderr, "hpet_poll: read failed\n");
+			}
+			else
+				fprintf(stderr, "hpet_poll: data 0x%lx\n",
+					data);
+		}
+	}
+
+out:
+	close(fd);
+	return;
+}
+
+static int hpet_sigio_count;
+
+static void
+hpet_sigio(int val)
+{
+	fprintf(stderr, "hpet_sigio: called\n");
+	hpet_sigio_count++;
+}
+
+void
+hpet_fasync(int argc, const char **argv)
+{
+	unsigned long		freq;
+	int			iterations, i, fd, value;
+	sig_t			oldsig;
+	struct hpet_info	info;
+
+	hpet_sigio_count = 0;
+	fd = -1;
+
+	if ((oldsig = signal(SIGIO, hpet_sigio)) == SIG_ERR) {
+		fprintf(stderr, "hpet_fasync: failed to set signal handler\n");
+		return;
+	}
+
+	if (argc != 3) {
+		fprintf(stderr, "hpet_fasync: device-name freq iterations\n");
+		goto out;
+	}
+
+	fd = open(argv[0], O_RDWR);
+
+	if (fd < 0) {
+		fprintf(stderr, "hpet_fasync: failed to open %s\n", argv[0]);
+		return;
+	}
+
+
+	if ((fcntl(fd, F_SETOWN, getpid()) == 1) ||
+		((value = fcntl(fd, F_GETFL)) == 1) ||
+		(fcntl(fd, F_SETFL, value | O_ASYNC) == 1)) {
+		fprintf(stderr, "hpet_fasync: fcntl failed\n");
+		goto out;
+	}
+
+	freq = atoi(argv[1]);
+	iterations = atoi(argv[2]);
+
+	if (ioctl(fd, HPET_IRQFREQ, freq) < 0) {
+		fprintf(stderr, "hpet_fasync: HPET_IRQFREQ failed\n");
+		goto out;
+	}
+
+	if (ioctl(fd, HPET_INFO, &info) < 0) {
+		fprintf(stderr, "hpet_fasync: failed to get info\n");
+		goto out;
+	}
+
+	fprintf(stderr, "hpet_fasync: info.hi_flags 0x%lx\n", info.hi_flags);
+
+	if (info.hi_flags && (ioctl(fd, HPET_EPI, 0) < 0)) {
+		fprintf(stderr, "hpet_fasync: HPET_EPI failed\n");
+		goto out;
+	}
+
+	if (ioctl(fd, HPET_IE_ON, 0) < 0) {
+		fprintf(stderr, "hpet_fasync, HPET_IE_ON failed\n");
+		goto out;
+	}
+
+	for (i = 0; i < iterations; i++) {
+		(void) pause();
+		fprintf(stderr, "hpet_fasync: count = %d\n", hpet_sigio_count);
+	}
+
+out:
+	signal(SIGIO, oldsig);
+
+	if (fd >= 0)
+		close(fd);
+
+	return;
+}
+
+The kernel API has three interfaces exported from the driver:
+
+	hpet_register(struct hpet_task *tp, int periodic)
+	hpet_unregister(struct hpet_task *tp)
+	hpet_control(struct hpet_task *tp, unsigned int cmd, unsigned long arg)
+
+The kernel module using this interface fills in the ht_func and ht_data members of the
+hpet_task structure before calling hpet_register.  hpet_control simply vectors to the hpet_ioctl
+routine and has the same commands and respective arguments as the user API.  hpet_unregister
+is used to terminate usage of the HPET timer reserved by hpet_register.
+
+
--- diff/Documentation/i386/kgdb/andthen	1970-01-01 01:00:00.000000000 +0100
+++ source/Documentation/i386/kgdb/andthen	2004-06-11 19:22:01.000000000 +0100
@@ -0,0 +1,100 @@
+
+define	set_andthen
+	set var $thp=0
+	set var $thp=(struct kgdb_and_then_struct *)&kgdb_data[0]
+	set var $at_size = (sizeof kgdb_data)/(sizeof *$thp)
+	set var $at_oc=kgdb_and_then_count
+	set var $at_cc=$at_oc
+end
+
+define andthen_next
+	set var $at_cc=$arg0
+end
+
+define andthen
+	andthen_set_edge
+	if ($at_cc >= $at_oc)
+		printf "Outside window.  Window size is %d\n",($at_oc-$at_low)
+	else
+		printf "%d: ",$at_cc
+		output *($thp+($at_cc++ % $at_size ))
+		printf "\n"
+	end
+end
+define andthen_set_edge
+	set var $at_oc=kgdb_and_then_count
+	set var $at_low = $at_oc - $at_size
+	if ($at_low < 0 )
+		set var $at_low = 0
+	end
+	if (( $at_cc > $at_oc) || ($at_cc < $at_low))
+		printf "Count outside of window, setting count to "
+		if ($at_cc >= $at_oc)
+			set var $at_cc = $at_oc
+		else
+			set var $at_cc = $at_low
+		end
+		printf "%d\n",$at_cc
+	end
+end
+
+define beforethat
+	andthen_set_edge
+	if ($at_cc <= $at_low)
+		printf "Outside window.  Window size is %d\n",($at_oc-$at_low)
+	else
+		printf "%d: ",$at_cc-1
+		output *($thp+(--$at_cc % $at_size ))
+		printf "\n"
+	end
+end
+
+document andthen_next
+	andthen_next <count>
+	.	sets the number of the event to display next. If this event
+	.	is not in the event pool, either andthen or beforethat will
+	.	correct it to the nearest event pool edge.  The event pool
+	.	ends at the last event recorded and begins <number of events>
+	.	prior to that.  If beforethat is used next, it will display
+	.	event <count> -1.
+.
+	andthen commands are: set_andthen, andthen_next, andthen and beforethat
+end
+
+
+document andthen
+	andthen
+.	displays the next event in the list.  <set_andthen> sets up to display
+.	the oldest saved event first.
+.	<count> (optional) count of the event to display.
+.	note the number of events saved is specified at configure time.
+.	if events are saved between calls to andthen the index will change
+.	but the displayed event will be the next one (unless the event buffer
+.	is overrun).
+.
+.	andthen commands are: set_andthen, andthen_next, andthen and beforethat
+end
+
+document set_andthen
+	set_andthen
+.	sets up to use the <andthen> and <beforethat> commands.
+.		if you have defined your own struct, use the above and
+.		then enter the following:
+.		p $thp=(struct kgdb_and_then_structX *)&kgdb_data[0]
+.		where <kgdb_and_then_structX> is the name of your structure.
+.
+.	andthen commands are: set_andthen, andthen_next, andthen and beforethat
+end
+
+document beforethat
+	beforethat
+.	displays the next prior event in the list. <set_andthen> sets up to
+.	display the last occuring event first.
+.
+.	note the number of events saved is specified at configure time.
+.	if events are saved between calls to beforethat the index will change
+.	but the displayed event will be the next one (unless the event buffer
+.	is overrun).
+.
+.	andthen commands are: set_andthen, andthen_next, andthen and beforethat
+end
--- diff/Documentation/i386/kgdb/debug-nmi.txt	1970-01-01 01:00:00.000000000 +0100
+++ source/Documentation/i386/kgdb/debug-nmi.txt	2004-06-11 19:22:01.000000000 +0100
@@ -0,0 +1,37 @@
+Subject: Debugging with NMI
+Date: Mon, 12 Jul 1999 11:28:31 -0500
+From: David Grothe <dave@gcom.com>
+Organization: Gcom, Inc
+To: David Grothe <dave@gcom.com>
+
+Kernel hackers:
+
+Maybe this is old hat, but it is new to me --
+
+On an ISA bus machine, if you short out the A1 and B1 pins of an ISA
+slot you will generate an NMI to the CPU.  This interrupts even a
+machine that is hung in a loop with interrupts disabled.  Used in
+conjunction with kgdb <
+ftp://ftp.gcom.com/pub/linux/src/kgdb-2.3.35/kgdb-2.3.35.tgz > you can
+gain debugger control of a machine that is hung in the kernel!  Even
+without kgdb the kernel will print a stack trace so you can find out
+where it was hung.
+
+The A1/B1 pins are directly opposite one another and the farthest pins
+towards the bracket end of the ISA bus socket.  You can stick a paper
+clip or multi-meter probe between them to short them out.
+
+I had a spare ISA bus to PC104 bus adapter around.  The PC104 end of the
+board consists of two rows of wire wrap pins.  So I wired a push button
+between the A1/B1 pins and now have an ISA board that I can stick into
+any ISA bus slot for debugger entry.
+
+Microsoft has a circuit diagram of a PCI card at
+http://www.microsoft.com/hwdev/DEBUGGING/DMPSW.HTM.  If you want to
+build one you will have to mail them and ask for the PAL equations.
+Nobody makes one comercially.
+
+[THIS TIP COMES WITH NO WARRANTY WHATSOEVER.  It works for me, but if
+your machine catches fire, it is your problem, not mine.]
+
+-- Dave (the kgdb guy)
--- diff/Documentation/i386/kgdb/gdb-globals.txt	1970-01-01 01:00:00.000000000 +0100
+++ source/Documentation/i386/kgdb/gdb-globals.txt	2004-06-11 19:22:01.000000000 +0100
@@ -0,0 +1,71 @@
+Sender: akale@veritas.com
+Date: Fri, 23 Jun 2000 19:26:35 +0530
+From: "Amit S. Kale" <akale@veritas.com>
+Organization: Veritas Software (India)
+To: Dave Grothe <dave@gcom.com>, linux-kernel@vger.rutgers.edu
+CC: David Milburn <dmilburn@wirespeed.com>,
+        "Edouard G. Parmelan" <Edouard.Parmelan@quadratec.fr>,
+        ezannoni@cygnus.com, Keith Owens <kaos@ocs.com.au>
+Subject: Re: Module debugging using kgdb
+
+Dave Grothe wrote:
+>
+> Amit:
+>
+> There is a 2.4.0 version of kgdb on our ftp site:
+> ftp://ftp.gcom.com/pub/linux/src/kgdb.  I mirrored your version of gdb
+> and loadmodule.sh there.
+>
+> Have a look at the README file and see if I go it right.  If not, send
+> me some corrections and I will update it.
+>
+> Does your version of gdb solve the global variable problem?
+
+Yes.
+Thanks to Elena Zanoni, gdb (developement version) can now calculate
+correctly addresses  of dynamically loaded object files. I have not been
+following gdb developement for sometime and am not sure when symbol
+address calculation fix is going to appear in a gdb stable version.
+
+Elena, any idea when the fix will make it to a prebuilt gdb from a
+redhat release?
+
+For the time being I have built a gdb developement version. It can be
+used for module debugging with loadmodule.sh script.
+
+The problem with calculating of module addresses with previous versions
+of gdb was as follows:
+gdb did not use base address of a section while calculating address of
+a symbol in the section in an object file loaded via 'add-symbol-file'.
+It used address of .text segment instead. Due to this addresses of
+symbols in .data, .bss etc. (e.g. global variables) were calculated incorrectly.
+
+Above mentioned fix allow gdb to use base address of a segment while
+calculating address of a symbol in it. It adds a parameter '-s' to
+'add-symbol-file' command for specifying base address of a segment.
+
+loadmodule.sh script works as follows.
+
+1. Copy a module file to target machine.
+2. Load the module on the target machine using insmod with -m parameter.
+insmod produces a module load map which contains base addresses of all
+sections in the module and addresses of symbols in the module file.
+3. Find all sections and their base addresses in the module from
+the module map.
+4. Generate a script that loads the module file. The script uses
+'add-symbol-file' and specifies address of text segment followed by
+addresses of all segments in the module.
+
+Here is an example gdb script produced by loadmodule.sh script.
+
+add-symbol-file foo 0xd082c060 -s .text.lock 0xd08cbfb5
+-s .fixup 0xd08cfbdf -s .rodata 0xd08cfde0 -s __ex_table 0xd08e3b38
+-s .data 0xd08e3d00 -s .bss 0xd08ec8c0 -s __ksymtab 0xd08ee838
+
+With this command gdb can calculate addresses of symbols in ANY segment
+in a module file.
+
+Regards.
+--
+Amit Kale
+Veritas Software ( http://www.veritas.com )
--- diff/Documentation/i386/kgdb/gdbinit	1970-01-01 01:00:00.000000000 +0100
+++ source/Documentation/i386/kgdb/gdbinit	2004-06-11 19:22:01.000000000 +0100
@@ -0,0 +1,14 @@
+shell echo -e "\003" >/dev/ttyS0
+set remotebaud 38400
+target remote /dev/ttyS0
+define si
+stepi
+printf "EAX=%08x EBX=%08x ECX=%08x EDX=%08x\n", $eax, $ebx, $ecx, $edx
+printf "ESI=%08x EDI=%08x EBP=%08x ESP=%08x\n", $esi, $edi, $ebp, $esp
+x/i $eip
+end
+define ni
+nexti
+printf "EAX=%08x EBX=%08x ECX=%08x EDX=%08x\n", $eax, $ebx, $ecx, $edx
+printf "ESI=%08x EDI=%08x EBP=%08x ESP=%08x\n", $esi, $edi, $ebp, $esp
+x/i $eip
--- diff/Documentation/i386/kgdb/gdbinit-modules	1970-01-01 01:00:00.000000000 +0100
+++ source/Documentation/i386/kgdb/gdbinit-modules	2004-06-11 19:22:01.000000000 +0100
@@ -0,0 +1,146 @@
+#
+# Usefull GDB user-command to debug Linux Kernel Modules with gdbstub.
+#
+# This don't work for Linux-2.0 or older.
+#
+# Author Edouard G. Parmelan <Edouard.Parmelan@quadratec.fr>
+#
+#
+# Fri Apr 30 20:33:29 CEST 1999
+#   First public release.
+#
+#   Major cleanup after experiment Linux-2.0 kernel without success.
+#   Symbols of a module are not in the correct order, I can't explain
+#   why :(
+#
+# Fri Mar 19 15:41:40 CET 1999
+#   Initial version.
+#
+# Thu Jan  6 16:29:03 CST 2000
+#   A little fixing by Dave Grothe <dave@gcom.com>
+#
+# Mon Jun 19 09:33:13 CDT 2000
+#   Alignment changes from Edouard Parmelan
+#
+# The basic idea is to find where insmod load the module and inform
+# GDB to load the symbol table of the module with the GDB command
+# ``add-symbol-file <object> <address>''.
+#
+# The Linux kernel holds the list of all loaded modules in module_list,
+# this list end with &kernel_module (exactly with module->next == NULL,
+# but the last module is not a real module).
+#
+# Insmod allocates the struct module before the object file.  Since
+# Linux-2.1, this structure contain his size.  The real address of
+# the object file is then (char*)module + module->size_of_struct.
+#
+# You can use three user functions ``mod-list'', ``mod-print-symbols''
+# and ``add-module-symbols''.
+#
+# mod-list list all loaded modules with the format:
+#    <module-address> <module-name>
+#
+# As soon as you have found the address of your module, you can
+# print its exported symbols (mod-print-symbols) or inform GDB to add
+# symbols from your module file (mod-add-symbols).
+#
+# The argument that you give to mod-print-symbols or mod-add-symbols
+# is the <module-address> from the mod-list command.
+#
+# When using the mod-add-symbols command you must also give the full
+# pathname of the modules object code file.
+#
+# The command mod-add-lis is an example of how to make this easier.
+# You can edit this macro to contain the path name of your own
+# favorite module and then use it as a shorthand to load it.  You
+# still need the module-address, however.
+#
+# The internal function ``mod-validate'' set the GDB variable $mod
+# as a ``struct module*'' if the kernel known the module otherwise
+# $mod is set to NULL.  This ensure to not add symbols for a wrong
+# address.
+#
+# Have a nice hacking day !
+#
+#
+define mod-list
+    set $mod = (struct module*)module_list
+    # the last module is the kernel, ignore it
+    while $mod != &kernel_module
+    	printf "%p\t%s\n", (long)$mod, ($mod)->name
+	set $mod = $mod->next
+    end
+end
+document mod-list
+List all modules in the form: <module-address> <module-name>
+Use the <module-address> as the argument for the other
+mod-commands: mod-print-symbols, mod-add-symbols.
+end
+
+define mod-validate
+    set $mod = (struct module*)module_list
+    while ($mod != $arg0) && ($mod != &kernel_module)
+    	set $mod = $mod->next
+    end
+    if $mod == &kernel_module
+	set $mod = 0
+    	printf "%p is not a module\n", $arg0
+    end
+end
+document mod-validate
+mod-validate <module-address>
+Internal user-command used to validate the module parameter.
+If <module> is a real loaded module, set $mod to it otherwise set $mod to 0.
+end
+
+
+define mod-print-symbols
+    mod-validate $arg0
+    if $mod != 0
+	set $i = 0
+	while $i < $mod->nsyms
+	    set $sym = $mod->syms[$i]
+	    printf "%p\t%s\n", $sym->value, $sym->name
+	    set $i = $i + 1
+	end
+    end
+end
+document mod-print-symbols
+mod-print-symbols <module-address>
+Print all exported symbols of the module.  see mod-list
+end
+
+
+define mod-add-symbols-align
+    mod-validate $arg0
+    if $mod != 0
+	set $mod_base = ($mod->size_of_struct + (long)$mod)
+	if ($arg2 != 0) && (($mod_base & ($arg2 - 1)) != 0)
+	    set $mod_base = ($mod_base | ($arg2 - 1)) + 1
+	end
+	add-symbol-file $arg1 $mod_base
+    end
+end
+document mod-add-symbols-align
+mod-add-symbols-align <module-address> <object file path name> <align>
+Load the symbols table of the module from the object file where
+first section aligment is <align>.
+To retreive alignment, use `objdump -h <object file path name>'.
+end
+
+define mod-add-symbols
+    mod-add-symbols-align $arg0 $arg1 sizeof(long)
+end
+document mod-add-symbols
+mod-add-symbols <module-address> <object file path name>
+Load the symbols table of the module from the object file.
+Default alignment is 4.  See mod-add-symbols-align.
+end
+
+define mod-add-lis
+    mod-add-symbols-align $arg0 /usr/src/LiS/streams.o 16
+end
+document mod-add-lis
+mod-add-lis <module-address>
+Does mod-add-symbols <module-address> /usr/src/LiS/streams.o
+end
--- diff/Documentation/i386/kgdb/gdbinit.hw	1970-01-01 01:00:00.000000000 +0100
+++ source/Documentation/i386/kgdb/gdbinit.hw	2004-06-11 19:22:01.000000000 +0100
@@ -0,0 +1,117 @@
+
+#Using ia-32 hardware breakpoints.
+#
+#4 hardware breakpoints are available in ia-32 processors. These breakpoints
+#do not need code modification. They are set using debug registers.
+#
+#Each hardware breakpoint can be of one of the
+#three types: execution, write, access.
+#1. An Execution breakpoint is triggered when code at the breakpoint address is
+#executed.
+#2. A write breakpoint ( aka watchpoints ) is triggered when memory location
+#at the breakpoint address is written.
+#3. An access breakpoint is triggered when memory location at the breakpoint
+#address is either read or written.
+#
+#As hardware breakpoints are available in limited number, use software
+#breakpoints ( br command in gdb ) instead of execution hardware breakpoints.
+#
+#Length of an access or a write breakpoint defines length of the datatype to
+#be watched. Length is 1 for char, 2 short , 3 int.
+#
+#For placing execution, write and access breakpoints, use commands
+#hwebrk, hwwbrk, hwabrk
+#To remove a breakpoint use hwrmbrk command.
+#
+#These commands take following types of arguments. For arguments associated
+#with each command, use help command.
+#1. breakpointno: 0 to 3
+#2. length: 1 to 3
+#3. address: Memory location in hex ( without 0x ) e.g c015e9bc
+#
+#Use the command exinfo to find which hardware breakpoint occured.
+
+#hwebrk breakpointno address
+define hwebrk
+	maintenance packet Y$arg0,0,0,$arg1
+end
+document hwebrk
+	hwebrk <breakpointno> <address>
+	Places a hardware execution breakpoint
+	<breakpointno> = 0 - 3
+	<address> = Hex digits without leading "0x".
+end
+
+#hwwbrk breakpointno length address
+define hwwbrk
+	maintenance packet Y$arg0,1,$arg1,$arg2
+end
+document hwwbrk
+	hwwbrk <breakpointno> <length> <address>
+	Places a hardware write breakpoint
+	<breakpointno> = 0 - 3
+	<length> = 1 (1 byte), 2 (2 byte), 3 (4 byte)
+	<address> = Hex digits without leading "0x".
+end
+
+#hwabrk breakpointno length address
+define hwabrk
+	maintenance packet Y$arg0,1,$arg1,$arg2
+end
+document hwabrk
+	hwabrk <breakpointno> <length> <address>
+	Places a hardware access breakpoint
+	<breakpointno> = 0 - 3
+	<length> = 1 (1 byte), 2 (2 byte), 3 (4 byte)
+	<address> = Hex digits without leading "0x".
+end
+
+#hwrmbrk breakpointno
+define hwrmbrk
+	maintenance packet y$arg0
+end
+document hwrmbrk
+	hwrmbrk <breakpointno>
+	<breakpointno> = 0 - 3
+	Removes a hardware breakpoint
+end
+
+define reboot
+        maintenance packet r
+end
+#exinfo
+define exinfo
+	maintenance packet qE
+end
+document exinfo
+	exinfo
+	Gives information about a breakpoint.
+end
+define get_th
+	p $th=(struct thread_info *)((int)$esp & ~8191)
+end
+document get_th
+	get_tu
+	Gets and prints the current thread_info pointer, Defines th to be it.
+end
+define get_cu
+	p $cu=((struct thread_info *)((int)$esp & ~8191))->task
+end
+document get_cu
+	get_cu
+	Gets and print the "current" value.  Defines $cu to be it.
+end
+define int_off
+	set var $flags=$eflags
+	set $eflags=$eflags&~0x200
+	end
+define int_on
+	set var $eflags|=$flags&0x200
+	end
+document int_off
+	saves the current interrupt state and clears the processor interrupt
+	flag.  Use int_on to restore the saved flag.
+end
+document int_on
+	Restores the interrupt flag saved by int_off.
+end
--- diff/Documentation/i386/kgdb/kgdb.txt	1970-01-01 01:00:00.000000000 +0100
+++ source/Documentation/i386/kgdb/kgdb.txt	2004-06-11 19:22:01.000000000 +0100
@@ -0,0 +1,775 @@
+Last edit: <20030806.1637.12>
+This file has information specific to the i386 kgdb option.  Other
+platforms with the kgdb option may behave in a similar fashion.
+
+New features:
+============
+20030806.1557.37
+This version was made against the 2.6.0-test2 kernel. We have made the
+following changes:
+
+- The getthread() code in the stub calls find_task_by_pid().  It fails
+  if we are early in the bring up such that the pid arrays have yet to
+  be allocated.  We have added a line to kernel/pid.c to make
+  "kgdb_pid_init_done" true once the arrays are allocated.  This way the
+  getthread() code knows not to call.  This is only used by the thread
+  debugging stuff and threads will not yet exist at this point in the
+  boot.
+
+- For some reason, gdb was not asking for a new thread list when the
+  "info thread" command was given.  We changed to the newer version of
+  the thread info command and gdb now seems to ask when needed.  Result,
+  we now get all threads in the thread list.
+
+- We now respond to the ThreadExtraInfo request from gdb with the thread
+  name from task_struct .comm.  This then appears in the thread list.
+  Thoughts on additional options for this are welcome.  Things such as
+  "has BKL" and "Preempted" come to mind.  I think we could have a flag
+  word that could enable different bits of info here.
+
+- We now honor, sort of, the C and S commands.  These are continue and
+  single set after delivering a signal.  We ignore the signal and do the
+  requested action.  This only happens when we told gdb that a signal
+  was the reason for entry, which is only done on memory faults.  The
+  result is that you can now continue into the Oops.
+
+- We changed the -g to -gdwarf-2.  This seems to be the same as -ggdb,
+  but it is more exact on what language to use.
+
+- We added two dwarf2 include files and a bit of code at the end of
+  entry.S.  This does not yet work, so it is disabled.  Still we want to
+  keep track of the code and "maybe" someone out there can fix it.
+
+- Randy Dunlap sent some fix ups for this file which are now merged.
+
+- Hugh Dickins sent a fix to a bit of code in traps.c that prevents a
+  compiler warning if CONFIG_KGDB is off (now who would do that :).
+
+- Andrew Morton sent a fix for the serial driver which is now merged.
+
+- Andrew also sent a change to the stub around the cpu managment code
+  which is also merged.
+
+- Andrew also sent a patch to make "f" as well as "g" work as SysRq
+  commands to enter kgdb, merged.
+
+- If CONFIG_KGDB and CONFIG_DEBUG_SPINLOCKS are both set we added a
+  "who" field to the spinlock data struct.  This is filled with
+  "current" when ever the spinlock suceeds.  Useful if you want to know
+  who has the lock.
+
+_ And last, but not least, we fixed the "get_cu" macro to properly get
+  the current value of "current".
+
+New features:
+============
+20030505.1827.27
+We are starting to align with the sourceforge version, at least in
+commands.  To this end, the boot command string to start kgdb at
+boot time has been changed from "kgdb" to "gdb".
+
+Andrew Morton sent a couple of patches which are now included as follows:
+1.) We now return a flag to the interrupt handler.
+2.) We no longer use smp_num_cpus (a conflict with the lock meter).
+3.) And from William Lee Irwin III <wli@holomorphy.com> code to make
+    sure high-mem is set up before we attempt to register our interrupt
+    handler.
+We now include asm/kgdb.h from config.h so you will most likely never
+have to include it.  It also 'NULLS' the kgdb macros you might have in
+your code when CONFIG_KGDB is not defined.  This allows you to just
+turn off CONFIG_KGDB to turn off all the kgdb_ts() calls and such.
+This include is conditioned on the machine being an x86 so as to not
+mess with other archs.
+
+20020801.1129.03
+This is currently the version for the 2.4.18 (and beyond?) kernel.
+
+We have several new "features" beginning with this version:
+
+1.) Kgdb now syncs the "other" CPUs with a cross-CPU NMI.  No more
+    waiting and it will pull that guy out of an IRQ off spin lock :)
+
+2.) We doctored up the code that tells where a task is waiting and
+    included it so that the "info thread" command will show a bit more
+    than "schedule()".  Try it...
+
+3.) Added the ability to call a function from gdb.  All the standard gdb
+    issues apply, i.e. if you hit a breakpoint in the function, you are
+    not allowed to call another (gdb limitation, not kgdb).  To help
+    this capability we added a memory allocation function.  Gdb does not
+    return this memory (it is used for strings that you pass to that function
+    you are calling from gdb) so we fixed up a way to allow you to
+    manually return the memory (see below).
+
+4.) Kgdb time stamps (kgdb_ts()) are enhanced to expand what was the
+    interrupt flag to now also include the preemption count and the
+    "in_interrupt" info.  The flag is now called "with_pif" to indicate
+    the order, preempt_count, in_interrupt, flag.  The preempt_count is
+    shifted left by 4 bits so you can read the count in hex by dropping
+    the low order digit.  In_interrupt is in bit 1, and the flag is in
+    bit 0.
+
+5.) The command: "p kgdb_info" is now expanded and prints something
+    like:
+(gdb) p kgdb_info
+$2 = {used_malloc = 0, called_from = 0xc0107506, entry_tsc = 67468627259,
+  errcode = 0, vector = 3, print_debug_info = 0, hold_on_sstep = 1,
+  cpus_waiting = {{task = 0xc027a000, pid = 32768, hold = 0,
+      regs = 0xc027bf84}, {task = 0x0, pid = 0, hold = 0, regs = 0x0}}}
+
+    Things to note here: a.) used_malloc is the amount of memory that
+    has been malloc'ed to do calls from gdb.  You can reclaim this
+    memory like this: "p kgdb_info.used_malloc=0" Cool, huh?  b.)
+    cpus_waiting is now "sized" by the number of CPUs you enter at
+    configure time in the kgdb configure section.  This is NOT used
+    anywhere else in the system, but it is "nice" here.  c.)  The task's
+    "pid" is now in the structure.  This is the pid you will need to use
+    to decode to the thread id to get gdb to look at that thread.
+    Remember that the "info thread" command prints a list of threads
+    wherein it numbers each thread with its reference number followed
+    by the thread's pid.  Note that the per-CPU idle threads actually
+    have pids of 0 (yes, there is more than one pid 0 in an SMP system).
+    To avoid confusion, kgdb numbers these threads with numbers beyond
+    the MAX_PID.  That is why you see 32768 and above.
+
+6.) A subtle change, we now provide the complete register set for tasks
+    that are active on the other CPUs.  This allows better trace back on
+    those tasks.
+
+    And, let's mention what we could not fix.  Back-trace from all but the
+    thread that we trapped will, most likely, have a bogus entry in it.
+    The problem is that gdb does not recognize the entry code for
+    functions that use "current" near (at all?) the entry.  The compiler
+    is putting the "current" decode as the first two instructions of the
+    function where gdb expects to find %ebp changing code.  Back trace
+    also has trouble with interrupt frames.  I am talking with Daniel
+    Jacobowitz about some way to fix this, but don't hold your breath.
+
+20011220.0050.35
+Major enhancement with this version is the ability to hold one or more
+CPUs in an SMP system while allowing the others to continue.  Also, by
+default only the current CPU is enabled on single-step commands (please
+note that gdb issues single-step commands at times other than when you
+use the si command).
+
+Another change is to collect some useful information in
+a global structure called "kgdb_info".  You should be able to just:
+
+p kgdb_info
+
+although I have seen cases where the first time this is done gdb just
+prints the first member but prints the whole structure if you then enter
+CR (carriage return or enter).  This also works:
+
+p *&kgdb_info
+
+Here is a sample:
+(gdb) p kgdb_info
+$4 = {called_from = 0xc010732c, entry_tsc = 32804123790856, errcode = 0,
+  vector = 3, print_debug_info = 0}
+
+"Called_from" is the return address from the current entry into kgdb.
+Sometimes it is useful to know why you are in kgdb, for example, was
+it an NMI or a real breakpoint?  The simple way to interrogate this
+return address is:
+
+l *0xc010732c
+
+which will print the surrounding few lines of source code.
+
+"Entry_tsc" is the CPU TSC on entry to kgdb (useful to compare to the
+kgdb_ts entries).
+
+"errcode" and "vector" are other entry parameters which may be helpful on
+some traps.
+
+"print_debug_info" is the internal debugging kgdb print enable flag.  Yes,
+you can modify it.
+
+In SMP systems kgdb_info also includes the "cpus_waiting" structure and
+"hold_on_step":
+
+(gdb) p kgdb_info
+$7 = {called_from = 0xc0112739, entry_tsc = 1034936624074, errcode = 0,
+  vector = 2, print_debug_info = 0, hold_on_sstep = 1, cpus_waiting = {{
+      task = 0x0, hold = 0, regs = 0x0}, {task = 0xc71b8000, hold = 0,
+      regs = 0xc71b9f70}, {task = 0x0, hold = 0, regs = 0x0}, {task = 0x0,
+      hold = 0, regs = 0x0}, {task = 0x0, hold = 0, regs = 0x0}, {task = 0x0,
+      hold = 0, regs = 0x0}, {task = 0x0, hold = 0, regs = 0x0}, {task = 0x0,
+      hold = 0, regs = 0x0}}}
+
+"Cpus_waiting" has an entry for each CPU other than the current one that
+has been stopped.  Each entry contains the task_struct address for that
+CPU, the address of the regs for that task and a hold flag.  All these
+have the proper typing so that, for example:
+
+p *kgdb_info.cpus_waiting[1].regs
+
+will print the registers for CPU 1.
+
+"Hold_on_sstep" is a new feature with this version and comes up set or
+true.  What this means is that whenever kgdb is asked to single-step all
+other CPUs are held (i.e. not allowed to execute).  The flag applies to
+all but the current CPU and, again, can be changed:
+
+p kgdb_info.hold_on_sstep=0
+
+restores the old behavior of letting all CPUs run during single-stepping.
+
+Likewise, each CPU has a "hold" flag, which if set, locks that CPU out
+of execution.  Note that this has some risk in cases where the CPUs need
+to communicate with each other.  If kgdb finds no CPU available on exit,
+it will push a message thru gdb and stay in kgdb.  Note that it is legal
+to hold the current CPU as long as at least one CPU can execute.
+
+20010621.1117.09
+This version implements an event queue.  Events are signaled by calling
+a function in the kgdb stub and may be examined from gdb.  See EVENTS
+below for details.  This version also tightens up the interrupt and SMP
+handling to not allow interrupts on the way to kgdb from a breakpoint
+trap.  It is fine to allow these interrupts for user code, but not
+system debugging.
+
+Version
+=======
+
+This version of the kgdb package was developed and tested on
+kernel version 2.4.16.  It will not install on any earlier kernels.
+It is possible that it will continue to work on later versions
+of 2.4 and then versions of 2.5 (I hope).
+
+
+Debugging Setup
+===============
+
+Designate one machine as the "development" machine.  This is the
+machine on which you run your compiles and which has your source
+code for the kernel.  Designate a second machine as the "target"
+machine.  This is the machine that will run your experimental
+kernel.
+
+The two machines will be connected together via a serial line out
+one or the other of the COM ports of the PC.  You will need the
+appropriate modem eliminator (null modem) cable(s) for this.
+
+Decide on which tty port you want the machines to communicate, then
+connect them up back-to-back using the null modem cable.  COM1 is
+/dev/ttyS0 and COM2 is /dev/ttyS1. You should test this connection
+with the two machines prior to trying to debug a kernel.  Once you
+have it working, on the TARGET machine, enter:
+
+setserial /dev/ttyS0 (or what ever tty you are using)
+
+and record the port address and the IRQ number.
+
+On the DEVELOPMENT machine you need to apply the patch for the kgdb
+hooks.  You have probably already done that if you are reading this
+file.
+
+On your DEVELOPMENT machine, go to your kernel source directory and do
+"make Xconfig" where X is one of "x", "menu", or "".  If you are
+configuring in the standard serial driver, it must not be a module.
+Either yes or no is ok, but making the serial driver a module means it
+will initialize after kgdb has set up the UART interrupt code and may
+cause a failure of the control-C option discussed below.  The configure
+question for the serial driver is under the "Character devices" heading
+and is:
+
+"Standard/generic (8250/16550 and compatible UARTs) serial support"
+
+Go down to the kernel debugging menu item and open it up.  Enable the
+kernel kgdb stub code by selecting that item.  You can also choose to
+turn on the "-ggdb -O1" compile options.  The -ggdb causes the compiler
+to put more debug info (like local symbols) in the object file.  On the
+i386 -g and -ggdb are the same so this option just reduces to "O1".  The
+-O1 reduces the optimization level.  This may be helpful in some cases,
+be aware, however, that this may also mask the problem you are looking
+for.
+
+The baud rate.  Default is 115200.  What ever you choose be sure that
+the host machine is set to the same speed.  I recommend the default.
+
+The port.  This is the I/O address of the serial UART that you should
+have gotten using setserial as described above.  The standard COM1 port
+(3f8) using IRQ 4 is default.  COM2 is 2f8 which by convention uses IRQ
+3.
+
+The port IRQ (see above).
+
+Stack overflow test.  This option makes a minor change in the trap,
+system call and interrupt code to detect stack overflow and transfer
+control to kgdb if it happens.  (Some platforms have this in the
+baseline code, but the i386 does not.)
+
+You can also configure the system to recognize the boot option
+"console=kgdb" which if given will cause all console output during
+booting to be put thru gdb as well as other consoles.  This option
+requires that gdb and kgdb be connected prior to sending console output
+so, if they are not, a breakpoint is executed to force the connection.
+This will happen before any kernel output (it is going thru gdb, right),
+and will stall the boot until the connection is made.
+
+You can also configure in a patch to SysRq to enable the kGdb SysRq.
+This request generates a breakpoint.  Since the serial port IRQ line is
+set up after any serial drivers, it is possible that this command will
+work when the control-C will not.
+
+Save and exit the Xconfig program.  Then do "make clean" , "make dep"
+and "make bzImage" (or whatever target you want to make).  This gets the
+kernel compiled with the "-g" option set -- necessary for debugging.
+
+You have just built the kernel on your DEVELOPMENT machine that you
+intend to run on your TARGET machine.
+
+To install this new kernel, use the following installation procedure.
+Remember, you are on the DEVELOPMENT machine patching the kernel source
+for the kernel that you intend to run on the TARGET machine.
+
+Copy this kernel to your target machine using your usual procedures.  I
+usually arrange to copy development:
+/usr/src/linux/arch/i386/boot/bzImage to /vmlinuz on the TARGET machine
+via a LAN based NFS access.  That is, I run the cp command on the target
+and copy from the development machine via the LAN.  Run Lilo (see "man
+lilo" for details on how to set this up) on the new kernel on the target
+machine so that it will boot!  Then boot the kernel on the target
+machine.
+
+On the DEVELOPMENT machine, create a file called .gdbinit in the
+directory /usr/src/linux.  An example .gdbinit file looks like this:
+
+shell echo -e "\003" >/dev/ttyS0
+set remotebaud 38400 (or what ever speed you have chosen)
+target remote /dev/ttyS0
+
+
+Change the "echo" and "target" definition so that it specifies the tty
+port that you intend to use.  Change the "remotebaud" definition to
+match the data rate that you are going to use for the com line.
+
+You are now ready to try it out.
+
+Boot your target machine with "kgdb" in the boot command i.e. something
+like:
+
+lilo> test kgdb
+
+or if you also want console output thru gdb:
+
+lilo> test kgdb console=kgdb
+
+You should see the lilo message saying it has loaded the kernel and then
+all output stops.  The kgdb stub is trying to connect with gdb.  Start
+gdb something like this:
+
+
+On your DEVELOPMENT machine, cd /usr/src/linux and enter "gdb vmlinux".
+When gdb gets the symbols loaded it will read your .gdbinit file and, if
+everything is working correctly, you should see gdb print out a few
+lines indicating that a breakpoint has been taken.  It will actually
+show a line of code in the target kernel inside the kgdb activation
+code.
+
+The gdb interaction should look something like this:
+
+    linux-dev:/usr/src/linux# gdb vmlinux
+    GDB is free software and you are welcome to distribute copies of it
+     under certain conditions; type "show copying" to see the conditions.
+    There is absolutely no warranty for GDB; type "show warranty" for details.
+    GDB 4.15.1 (i486-slackware-linux),
+    Copyright 1995 Free Software Foundation, Inc...
+    breakpoint () at i386-stub.c:750
+    750     }
+    (gdb)
+
+You can now use whatever gdb commands you like to set breakpoints.
+Enter "continue" to start your target machine executing again.  At this
+point the target system will run at full speed until it encounters
+your breakpoint or gets a segment violation in the kernel, or whatever.
+
+If you have the kgdb console enabled when you continue, gdb will print
+out all the console messages.
+
+The above example caused a breakpoint relatively early in the boot
+process.  For the i386 kgdb it is possible to code a break instruction
+as the first C-language point in init/main.c, i.e. as the first instruction
+in start_kernel().  This could be done as follows:
+
+#include <asm/kgdb.h>
+	 breakpoint();
+
+This breakpoint() is really a function that sets up the breakpoint and
+single-step hardware trap cells and then executes a breakpoint.  Any
+early hard coded breakpoint will need to use this function.  Once the
+trap cells are set up they need not be set again, but doing it again
+does not hurt anything, so you don't need to be concerned about which
+breakpoint is hit first.  Once the trap cells are set up (and the kernel
+sets them up in due course even if breakpoint() is never called) the
+macro:
+
+BREAKPOINT;
+
+will generate an inline breakpoint.  This may be more useful as it stops
+the processor at the instruction instead of in a function a step removed
+from the location of interest.  In either case <asm/kgdb.h> must be
+included to define both breakpoint() and BREAKPOINT.
+
+Triggering kgdbstub at other times
+==================================
+
+Often you don't need to enter the debugger until much later in the boot
+or even after the machine has been running for some time.  Once the
+kernel is booted and interrupts are on, you can force the system to
+enter the debugger by sending a control-C to the debug port. This is
+what the first line of the recommended .gdbinit file does.  This allows
+you to start gdb any time after the system is up as well as when the
+system is already at a breakpoint.  (In the case where the system is
+already at a breakpoint the control-C is not needed, however, it will
+be ignored by the target so no harm is done.  Also note the the echo
+command assumes that the port speed is already set.  This will be true
+once gdb has connected, but it is best to set the port speed before you
+run gdb.)
+
+Another simple way to do this is to put the following file in you ~/bin
+directory:
+
+#!/bin/bash
+echo  -e "\003"  > /dev/ttyS0
+
+Here, the ttyS0 should be replaced with what ever port you are using.
+The "\003" is control-C.  Once you are connected with gdb, you can enter
+control-C at the command prompt.
+
+An alternative way to get control to the debugger is to enable the kGdb
+SysRq command.  Then you would enter Alt-SysRq-g (all three keys at the
+same time, but push them down in the order given).  To refresh your
+memory of the available SysRq commands try Alt-SysRq-=.  Actually any
+undefined command could replace the "=", but I like to KNOW that what I
+am pushing will never be defined.
+
+Debugging hints
+===============
+
+You can break into the target machine at any time from the development
+machine by typing ^C (see above paragraph).  If the target machine has
+interrupts enabled this will stop it in the kernel and enter the
+debugger.
+
+There is unfortunately no way of breaking into the kernel if it is
+in a loop with interrupts disabled, so if this happens to you then
+you need to place exploratory breakpoints or printk's into the kernel
+to find out where it is looping.  The exploratory breakpoints can be
+entered either thru gdb or hard coded into the source.  This is very
+handy if you do something like:
+
+if (<it hurts>) BREAKPOINT;
+
+
+There is a copy of an e-mail in the Documentation/i386/kgdb/ directory
+(debug-nmi.txt) which describes how to create an NMI on an ISA bus
+machine using a paper clip.  I have a sophisticated version of this made
+by wiring a push button switch into a PC104/ISA bus adapter card.  The
+adapter card nicely furnishes wire wrap pins for all the ISA bus
+signals.
+
+When you are done debugging the kernel on the target machine it is a
+good idea to leave it in a running state.  This makes reboots faster,
+bypassing the fsck.  So do a gdb "continue" as the last gdb command if
+this is possible.  To terminate gdb itself on the development machine
+and leave the target machine running, first clear all breakpoints and
+continue, then type ^Z to suspend gdb and then kill it with "kill %1" or
+something similar.
+
+If gdbstub Does Not Work
+========================
+
+If it doesn't work, you will have to troubleshoot it.  Do the easy
+things first like double checking your cabling and data rates.  You
+might try some non-kernel based programs to see if the back-to-back
+connection works properly.  Just something simple like cat /etc/hosts
+>/dev/ttyS0 on one machine and cat /dev/ttyS0 on the other will tell you
+if you can send data from one machine to the other.  Make sure it works
+in both directions.  There is no point in tearing out your hair in the
+kernel if the line doesn't work.
+
+All of the real action takes place in the file
+/usr/src/linux/arch/i386/kernel/kgdb_stub.c.  That is the code on the target
+machine that interacts with gdb on the development machine.  In gdb you can
+turn on a debug switch with the following command:
+
+	set remotedebug
+
+This will print out the protocol messages that gdb is exchanging with
+the target machine.
+
+Another place to look is /usr/src/arch/i386/lib/kgdb_serial.c. This is
+the code that talks to the serial port on the target side.  There might
+be a problem there.  In particular there is a section of this code that
+tests the UART which will tell you what UART you have if you define
+"PRNT" (just remove "_off" from the #define PRNT_off).  To view this
+report you will need to boot the system without any beakpoints.  This
+allows the kernel to run to the point where it calls kgdb to set up
+interrupts.  At this time kgdb will test the UART and print out the type
+it finds.  (You need to wait so that the printks are actually being
+printed.  Early in the boot they are cached, waiting for the console to
+be enabled.  Also, if kgdb is entered thru a breakpoint it is possible
+to cause a dead lock by calling printk when the console is locked.  The
+stub thus avoids doing printks from breakpoints, especially in the
+serial code.)  At this time, if the UART fails to do the expected thing,
+kgdb will print out (using printk) information on what failed.  (These
+messages will be buried in all the other boot up messages.  Look for
+lines that start with "gdb_hook_interrupt:".  You may want to use dmesg
+once the system is up to view the log.  If this fails or if you still
+don't connect, review your answers for the port address.  Use:
+
+setserial /dev/ttyS0
+
+to get the current port and IRQ information.  This command will also
+tell you what the system found for the UART type. The stub recognizes
+the following UART types:
+
+16450, 16550, and 16550A
+
+If you are really desperate you can use printk debugging in the
+kgdbstub code in the target kernel until you get it working.  In particular,
+there is a global variable in /usr/src/linux/arch/i386/kernel/kgdb_stub.c
+named "remote_debug".  Compile your kernel with this set to 1, rather
+than 0 and the debug stub will print out lots of stuff as it does
+what it does.  Likewise there are debug printks in the kgdb_serial.c
+code that can be turned on with simple changes in the macro defines.
+
+
+Debugging Loadable Modules
+==========================
+
+This technique comes courtesy of Edouard Parmelan
+<Edouard.Parmelan@quadratec.fr>
+
+When you run gdb, enter the command
+
+source gdbinit-modules
+
+This will read in a file of gdb macros that was installed in your
+kernel source directory when kgdb was installed.  This file implements
+the following commands:
+
+mod-list
+    Lists the loaded modules in the form <module-address> <module-name>
+
+mod-print-symbols <module-address>
+    Prints all the symbols in the indicated module.
+
+mod-add-symbols <module-address> <object-file-path-name>
+    Loads the symbols from the object file and associates them
+    with the indicated module.
+
+After you have loaded the module that you want to debug, use the command
+mod-list to find the <module-address> of your module.  Then use that
+address in the mod-add-symbols command to load your module's symbols.
+From that point onward you can debug your module as if it were a part
+of the kernel.
+
+The file gdbinit-modules also contains a command named mod-add-lis as
+an example of how to construct a command of your own to load your
+favorite module.  The idea is to "can" the pathname of the module
+in the command so you don't have to type so much.
+
+Threads
+=======
+
+Each process in a target machine is seen as a gdb thread. gdb thread
+related commands (info threads, thread n) can be used.
+
+ia-32 hardware breakpoints
+==========================
+
+kgdb stub contains support for hardware breakpoints using debugging features
+of ia-32(x86) processors. These breakpoints do not need code modification.
+They use debugging registers. 4 hardware breakpoints are available in ia-32
+processors.
+
+Each hardware breakpoint can be of one of the following three types.
+
+1. Execution breakpoint - An Execution breakpoint is triggered when code
+	at the breakpoint address is executed.
+
+	As limited number of hardware breakpoints are available, it is
+	advisable to use software breakpoints ( break command ) instead
+	of execution hardware breakpoints, unless modification of code
+	is to be avoided.
+
+2. Write breakpoint - A write breakpoint is triggered when memory
+	location at the breakpoint address is written.
+
+	A write or can be placed for data of variable length. Length of
+	a write breakpoint indicates length of the datatype to be
+	watched. Length is 1 for 1 byte data , 2 for 2 byte data, 3 for
+	4 byte data.
+
+3. Access breakpoint - An access breakpoint is triggered when memory
+	location at the breakpoint address is either read or written.
+
+	Access breakpoints also have lengths similar to write breakpoints.
+
+IO breakpoints in ia-32 are not supported.
+
+Since gdb stub at present does not use the protocol used by gdb for hardware
+breakpoints, hardware breakpoints are accessed through gdb macros. gdb macros
+for hardware breakpoints are described below.
+
+hwebrk	- Places an execution breakpoint
+	hwebrk breakpointno address
+hwwbrk	- Places a write breakpoint
+	hwwbrk breakpointno length address
+hwabrk	- Places an access breakpoint
+	hwabrk breakpointno length address
+hwrmbrk	- Removes a breakpoint
+	hwrmbrk breakpointno
+exinfo	- Tells whether a software or hardware breakpoint has occurred.
+	Prints number of the hardware breakpoint if a hardware breakpoint has
+	occurred.
+
+Arguments required by these commands are as follows
+breakpointno	- 0 to 3
+length		- 1 to 3
+address		- Memory location in hex digits ( without 0x ) e.g c015e9bc
+
+SMP support
+==========
+
+When a breakpoint occurs or user issues a break ( Ctrl + C ) to gdb
+client, all the processors are forced to enter the debugger. Current
+thread corresponds to the thread running on the processor where
+breakpoint occurred.  Threads running on other processor(s) appear
+similar to other non-running threads in the 'info threads' output.
+Within the kgdb stub there is a structure "waiting_cpus" in which kgdb
+records the values of "current" and "regs" for each CPU other than the
+one that hit the breakpoint.  "current" is a pointer to the task
+structure for the task that CPU is running, while "regs" points to the
+saved registers for the task.  This structure can be examined with the
+gdb "p" command.
+
+ia-32 hardware debugging registers on all processors are set to same
+values.  Hence any hardware breakpoints may occur on any processor.
+
+gdb troubleshooting
+===================
+
+1. gdb hangs
+Kill it. restart gdb. Connect to target machine.
+
+2. gdb cannot connect to target machine (after killing a gdb and
+restarting another) If the target machine was not inside debugger when
+you killed gdb, gdb cannot connect because the target machine won't
+respond.  In this case echo "Ctrl+C"(ASCII 3) to the serial line.
+e.g. echo -e "\003" > /dev/ttyS1
+This forces that target machine into the debugger, after which you
+can connect.
+
+3. gdb cannot connect even after echoing Ctrl+C into serial line
+Try changing serial line settings min to 1 and time to 0
+e.g. stty min 1 time 0 < /dev/ttyS1
+Try echoing again
+
+Check serial line speed and set it to correct value if required
+e.g. stty ispeed 115200 ospeed 115200 < /dev/ttyS1
+
+EVENTS
+======
+
+Ever want to know the order of things happening?  Which CPU did what and
+when?  How did the spinlock get the way it is?  Then events are for
+you.  Events are defined by calls to an event collection interface and
+saved for later examination.  In this case, kgdb events are saved by a
+very fast bit of code in kgdb which is fully SMP and interrupt protected
+and they are examined by using gdb to display them.  Kgdb keeps only
+the last N events, where N must be a power of two and is defined at
+configure time.
+
+
+Events are signaled to kgdb by calling:
+
+kgdb_ts(data0,data1)
+
+For each call kgdb records each call in an array along with other info.
+Here is the array definition:
+
+struct kgdb_and_then_struct {
+#ifdef CONFIG_SMP
+	int	on_cpu;
+#endif
+	long long at_time;
+	int  	from_ln;
+	char	* in_src;
+	void	*from;
+        int     with_if;
+	int	data0;
+	int	data1;
+};
+
+For SMP machines the CPU is recorded, for all machines the TSC is
+recorded (gets a time stamp) as well as the line number and source file
+the call was made from.  The address of the (from), the "if" (interrupt
+flag) and the two data items are also recorded.  The macro kgdb_ts casts
+the types to int, so you can put any 32-bit values here.  There is a
+configure option to select the number of events you want to keep.  A
+nice number might be 128, but you can keep up to 1024 if you want.  The
+number must be a power of two.  An "andthen" macro library is provided
+for gdb to help you look at these events.  It is also possible to define
+a different structure for the event storage and cast the data to this
+structure.  For example the following structure is defined in kgdb:
+
+struct kgdb_and_then_struct2 {
+#ifdef CONFIG_SMP
+	int	on_cpu;
+#endif
+	long long at_time;
+	int  	from_ln;
+	char	* in_src;
+	void	*from;
+        int     with_if;
+	struct task_struct *t1;
+	struct task_struct *t2;
+};
+
+If you use this for display, the data elements will be displayed as
+pointers to task_struct entries.  You may want to define your own
+structure to use in casting.  You should only change the last two items
+and you must keep the structure size the same.  Kgdb will handle these
+as 32-bit ints, but within that constraint you can define a structure to
+cast to any 32-bit quantity.  This need only be available to gdb and is
+only used for casting in the display code.
+
+Final Items
+===========
+
+I picked up this code from Amit S. Kale and enhanced it.
+
+If you make some really cool modification to this stuff, or if you
+fix a bug, please let me know.
+
+George Anzinger
+<george@mvista.com>
+
+Amit S. Kale
+<akale@veritas.com>
+
+(First kgdb by David Grothe <dave@gcom.com>)
+
+(modified by Tigran Aivazian <tigran@sco.com>)
+    Putting gdbstub into the kernel config menu.
+
+(modified by Scott Foehner <sfoehner@engr.sgi.com>)
+    Hooks for entering gdbstub at boot time.
+
+(modified by Amit S. Kale <akale@veritas.com>)
+    Threads, ia-32 hw debugging, mp support, console support,
+    nmi watchdog handling.
+
+(modified by George Anzinger <george@mvista.com>)
+    Extended threads to include the idle threads.
+    Enhancements to allow breakpoint() at first C code.
+    Use of module_init() and __setup() to automate the configure.
+    Enhanced the cpu "collection" code to work in early bring-up.
+    Added ability to call functions from gdb
+    Print info thread stuff without going back to schedule()
+    Now collect the "other" cpus with an IPI/ NMI.
--- diff/Documentation/i386/kgdb/kgdbeth.txt	1970-01-01 01:00:00.000000000 +0100
+++ source/Documentation/i386/kgdb/kgdbeth.txt	2004-06-11 19:22:01.000000000 +0100
@@ -0,0 +1,92 @@
+KGDB over ethernet
+==================
+
+Authors
+-------
+
+Robert Walsh <rjwalsh@durables.org>  (2.6 port)
+wangdi <wangdi@clusterfs.com>        (2.6 port)
+Matt Mackall <mpm@selenic.com>       (netpoll api)
+San Mehat                            (original 2.4 code)
+
+
+Introduction
+------------
+
+KGDB supports debugging over ethernet (kgdboe) via polling of a given
+network interface. Most cards should be supported automatically.
+Debugging facilities are available as soon as the network driver and
+kgdboe have initialized. Unfortunately, this is too late in the boot
+process for debugging some issues, but works quite well for many
+others. This should not interfere with normal network usage and
+doesn't require a dedicated NIC.
+
+Terminology
+-----------
+
+This document uses the following terms:
+
+  TARGET: the machine being debugged.
+  HOST:   the machine running gdb.
+
+
+Usage
+-----
+
+You need to use the following command-line option on the TARGET kernel:
+
+  kgdboe=[tgt-port]@<tgt-ip>/[dev],[host-port]@<host-ip>/[host-macaddr]
+
+    where
+        tgt-port      source for UDP packets (defaults to 6443)
+        tgt-ip        source IP to use (interface address)
+        dev           network interface (eth0)
+        host-port     HOST UDP port (6442) (not really used)
+        host-ip       IP address for HOST machine
+        host-macaddr  ethernet MAC address for HOST (ff:ff:ff:ff:ff:ff)
+
+  examples:
+
+    kgdboe=7000@192.168.0.1/eth1,7001@192.168.0.2/00:05:3C:04:47:5D
+        this machine is 192.168.0.1 on eth1
+        remote machine is 192.168.0.2 with MAC address 00:05:3C:04:47:5D
+        listen for gdb packets on port 7000
+        send unsolicited gdb packets to port 7001
+
+    kgdboe=@192.168.0.1/,@192.168.0.2/
+        this machine is 192.168.0.1 on default interface eth0
+        remote machine is 192.168.0.2, use default broadcast MAC address
+        listen for gdb packets on default port 6443
+        send unsolicited gdb packets to port 6442
+
+Only packets originating from the configured HOST IP address will be
+accepted by the debugger.
+
+On the HOST side, run gdb as normal and use a remote UDP host as the
+target:
+
+   % gdb ./vmlinux
+   GNU gdb Red Hat Linux (5.3post-0.20021129.18rh)
+   Copyright 2003 Free Software Foundation, Inc.
+   GDB is free software, covered by the GNU General Public License, and you are
+   welcome to change it and/or distribute copies of it under certain conditions.
+   Type "show copying" to see the conditions.
+   There is absolutely no warranty for GDB.  Type "show warranty" for details.
+   This GDB was configured as "i386-redhat-linux-gnu"...
+   (gdb) target remote udp:HOSTNAME:6443
+
+You can now continue as if you were debugging over a serial line.
+
+Limitations
+-----------
+
+The current release of this code is exclusive of using kgdb on a
+serial interface, so you must boot without the kgdboe option to use
+serial debugging. Trying to debug the network driver while using it
+will prove interesting.
+
+Bug reports
+-----------
+
+Send bug reports to Robert Walsh <rjwalsh@durables.org> and Matt
+Mackall <mpm@selenic.com>.
--- diff/Documentation/i386/kgdb/loadmodule.sh	1970-01-01 01:00:00.000000000 +0100
+++ source/Documentation/i386/kgdb/loadmodule.sh	2004-06-11 19:22:01.000000000 +0100
@@ -0,0 +1,78 @@
+#/bin/sh
+# This script loads a module on a target machine and generates a gdb script.
+# source generated gdb script to load the module file at appropriate addresses
+# in gdb.
+#
+# Usage:
+# Loading the module on target machine and generating gdb script)
+#	[foo]$ loadmodule.sh <modulename>
+#
+# Loading the module file into gdb
+#	(gdb) source <gdbscriptpath>
+#
+# Modify following variables according to your setup.
+#	TESTMACHINE - Name of the target machine
+#	GDBSCRIPTS - The directory where a gdb script will be generated
+#
+# Author: Amit S. Kale (akale@veritas.com).
+#
+# If you run into problems, please check files pointed to by following
+# variables.
+#	ERRFILE - /tmp/<modulename>.errs contains stderr output of insmod
+#	MAPFILE - /tmp/<modulename>.map contains stdout output of insmod
+#	GDBSCRIPT - $GDBSCRIPTS/load<modulename> gdb script.
+
+TESTMACHINE=foo
+GDBSCRIPTS=/home/bar
+
+if [ $# -lt 1 ] ; then {
+	echo Usage: $0 modulefile
+	exit
+} ; fi
+
+MODULEFILE=$1
+MODULEFILEBASENAME=`basename $1`
+
+if [ $MODULEFILE = $MODULEFILEBASENAME ] ; then {
+	MODULEFILE=`pwd`/$MODULEFILE
+} fi
+
+ERRFILE=/tmp/$MODULEFILEBASENAME.errs
+MAPFILE=/tmp/$MODULEFILEBASENAME.map
+GDBSCRIPT=$GDBSCRIPTS/load$MODULEFILEBASENAME
+
+function findaddr() {
+	local ADDR=0x$(echo "$SEGMENTS" | \
+		grep "$1" | sed 's/^[^ ]*[ ]*[^ ]*[ ]*//' | \
+		sed 's/[ ]*[^ ]*$//')
+	echo $ADDR
+}
+
+function checkerrs() {
+	if [ "`cat $ERRFILE`" != "" ] ; then {
+		cat $ERRFILE
+		exit
+	} fi
+}
+
+#load the module
+echo Copying $MODULEFILE to $TESTMACHINE
+rcp $MODULEFILE root@${TESTMACHINE}:
+
+echo Loading module $MODULEFILE
+rsh -l root $TESTMACHINE  /sbin/insmod -m ./`basename $MODULEFILE` \
+	> $MAPFILE 2> $ERRFILE
+checkerrs
+
+SEGMENTS=`head -n 11 $MAPFILE | tail -n 10`
+TEXTADDR=$(findaddr "\\.text[^.]")
+LOADSTRING="add-symbol-file $MODULEFILE $TEXTADDR"
+SEGADDRS=`echo "$SEGMENTS" | awk '//{
+	if ($1 != ".text" && $1 != ".this" &&
+	    $1 != ".kstrtab" && $1 != ".kmodtab") {
+		print " -s " $1 " 0x" $3 " "
+	}
+}'`
+LOADSTRING="$LOADSTRING $SEGADDRS"
+echo Generating script $GDBSCRIPT
+echo $LOADSTRING > $GDBSCRIPT
--- diff/Documentation/ia64/kgdb.txt	1970-01-01 01:00:00.000000000 +0100
+++ source/Documentation/ia64/kgdb.txt	2004-06-11 19:22:01.000000000 +0100
@@ -0,0 +1,9 @@
+IA64 kgdb requires a patch to gdb/remote.c. The proposed patch will eventually be in gdb but
+until then, within gdb do "show remote" and look for "Support for remote protocol `p' (fetch-register) packet is auto-detected, currently unknown."  Should this line not appear, then you must
+obtain the patch, apply it and build gdb.
+
+CONFIG_KGDB_EARLY enables one with serial kgdb support to debug the kernel starting at the
+end of the routine setup_arch.  A boot option of "kgdb=1" will result in a kernel breakpoint
+and requires gdb to continue from the breakpoint.
+
+For further information consult the i386 kgdb documentation.
--- diff/Documentation/must-fix.txt	1970-01-01 01:00:00.000000000 +0100
+++ source/Documentation/must-fix.txt	2004-06-11 19:22:01.000000000 +0100
@@ -0,0 +1,249 @@
+
+Must-fix bugs
+=============
+
+drivers/char/
+~~~~~~~~~~~~~
+
+o TTY locking is broken.
+
+  o see FIXME in do_tty_hangup().  This causes ppp BUGs in local_bh_enable()
+
+  o Other problems: aviro, dipankar, Alan have details.
+
+  o somebody will have to document the tty driver and ldisc API
+
+drivers/tty
+~~~~~~~~~~~
+
+o viro: tty_driver refcounting, tty/misc/upper levels of sound still not
+  completely fixed.
+
+drivers/block/
+~~~~~~~~~~~~~~
+
+o loop.c: Concurrent write access on block devices might cause a deadlock
+  of the complete system. See:
+  http://marc.theaimsgroup.com/?l=linux-kernel&m=106275365925769&w==
+  http://bugzilla.kernel.org/show_bug.cgi?id=1198
+  Thread of possible fix:
+  http://www.kerneli.org/pipermail/cryptoapi-devel/2003-October/000676.html
+
+  (Fruhwirth Clemens)
+
+o ideraid hasn't been ported to 2.5 at all yet.
+
+  We need to understand whether the proposed BIO split code will suffice
+  for this.
+
+drivers/input/
+~~~~~~~~~~~~~~
+
+o rmk: unconverted keyboard/mouse drivers (there's a deadline of 2.6.0
+  currently on these remaining in my/Linus' tree.)
+
+o viro: large absence of locking.
+
+o viro: parport is nearly as bad as that and there the code is more hairy.
+  IMO parport is more of "figure out what API changes are needed for its
+  users, get them done ASAP, then fix generic layer at leisure"
+
+
+drivers/misc/
+~~~~~~~~~~~~~
+
+o rmk: UCB1[23]00 drivers, currently sitting in drivers/misc in the ARM
+  tree.  (touchscreen, audio, gpio, type device.)
+
+  These need to be moved out of drivers/misc/ and into real places
+
+o viro: actually, misc.c has a good chance to die.  With cdev-cidr that's
+  trivial.
+
+drivers/net/
+~~~~~~~~~~~~
+
+drivers/net/irda/
+~~~~~~~~~~~~~~~~~
+
+  (Jean Tourrilhes)
+
+o irport need to be converted to sir-kthread
+
+o dongle drivers need to be converted to sir-dev (in progress)
+
+o new drivers (irtty-sir/smsc-ircc2/donauboe) need more testing (in progress)
+
+
+drivers/pci/
+~~~~~~~~~~~~
+
+o alan: Some cardbus crashes the system
+
+  (bugzilla, please?)
+
+drivers/pcmcia/
+~~~~~~~~~~~~~~~
+
+o alan: This is a locking disaster.
+
+  (rmk, brodo: in progress)
+
+drivers/pld/
+~~~~~~~~~~~~
+
+o rmk: EPXA (ARM platform) PLD hotswap drivers (drivers/pld)
+
+  (rmk: will work out what to do here.  maybe drivers/arm/)
+
+drivers/video/
+~~~~~~~~~~~~~~
+
+o Lots of drivers don't compile, others do but don't work.
+
+drivers/scsi/
+~~~~~~~~~~~~~
+
+o Convert am53c974, dpt_i2o, initio and pci2220i to DMA-mapping
+
+o Make inia100, cpqfc, pci2000 and dc390t compile
+
+o Convert
+
+   wd33c99 based: a2091 a3000 gpv11 mvme174 sgiwd93
+
+   53c7xx based: amiga7xxx bvme6000 mvme16x initio am53c974 pci2000
+   pci2220i dc390t
+
+  To new error handling
+
+  It also might be possible to shift the 53c7xx based drivers over to
+  53c700 which does the new EH stuff, but I don't have the hardware to check
+  such a shift.
+
+  For the non-compiling stuff, I've probably missed a few that just aren't
+  compilable on my platforms, so any updates would be welcome.  Also, are
+  some of our non-compiling or unconverted drivers obsolete?
+
+fs/
+~~~
+
+o viro: fs/char_dev.c needs removal of aeb stuff and merge of cdev-cidr.
+  In progress.
+
+o viro: there is some generic stuff for namei/namespace/super, but that's a
+  slow-merge and can go in 2.6 just fine
+
+
+kernel/sched.c
+~~~~~~~~~~~~~~
+
+o Starvation, general interactivity need close monitoring.
+
+
+kernel/
+~~~~~~~
+
+o Alan: 32bit uid support is *still* broken for process accounting.
+
+  Create a 32bit uid, turn accounting on.  Shock horror it doesn't work
+  because the field is 16bit.  We need an acct structure flag day for 2.6
+  IMHO
+
+  (alan has patch)
+
+o viro: core sysctl code is racy.  And its interaction wiuth sysfs
+
+
+lib/kobject.c
+~~~~~~~~~~~~~
+
+o kobject refcounting (comments from Al Viro):
+
+  _anything_ can grab a temporary reference to kobject.  IOW, if kobject is
+  embedded into something that could be freed - it _MUST_ have a destructor
+  and that destructor _MUST_ be the destructor for containing object.
+
+  Any violation of the above (and we already have a bunch of those) is a
+  user-triggerable memory corruption.
+
+  We can tolerate it for a while in 2.5 (e.g.  during work on susbsystem we
+  can decide to switch to that way of handling objects and have subsystem
+  vulnerable for a while), but all such windows must be closed before 2.6
+  and during 2.6 we can't open them at all.
+
+o All block drivers which control multiple gendisks with a single
+  request_queue are broken, due to one-to-one assumptions in the request
+  queue sysfs hookup.
+
+mm/
+~~~
+
+o GFP_DMA32 (or something like that).  Lots of ideas.  jejb, zaitcev,
+  willy, arjan, wli.
+
+  Specifically, 64-bit systems need to be able to enforce 32-bit addressing
+  limits for device metadata like network cards' ring buffers and SCSI
+  command descriptors.
+
+o access_process_vm() doesn't flush right.  We probably need new flushing
+  primitives to do this (davem?)
+
+
+modules
+~~~~~~~
+
+  (Rusty)
+
+net/
+~~~~
+
+  (davem)
+
+o UDP apps can in theory deadlock, because the ip_append_data path can end
+  up sleeping while the socket lock is held.
+
+  It is OK to sleep with the socket held held, normally.  But in this case
+  the sleep happens while waiting for socket memory/space to become
+  available, if another context needs to take the socket lock to free up the
+  space we could hang.
+
+  I sent a rough patch on how to fix this to Alexey, and he is analyzing
+  the situation.  I expect a final fix from him next week or so.
+
+o Semantics for IPSEC during operations such as TCP connect suck currently.
+
+  When we first try to connect to a destination, we may need to ask the
+  IPSEC key management daemon to resolve the IPSEC routes for us.  For the
+  purposes of what the kernel needs to do, you can think of it like ARP.  We
+  can't send the packet out properly until we resolve the path.
+
+  What happens now for IPSEC is basically this:
+
+  O_NONBLOCK: returns -EAGAIN over and over until route is resolved
+
+  !O_NONBLOCK: Sleeps until route is resolved
+
+  These semantics are total crap.  The solution, which Alexey is working
+  on, is to allow incomplete routes to exist.  These "incomplete" routes
+  merely put the packet onto a "resolution queue", and once the key manager
+  does it's thing we finish the output of the packet.  This is precisely how
+  ARP works.
+
+  I don't know when Alexey will be done with this.
+
+net/*/netfilter/
+~~~~~~~~~~~~~~~~
+
+  (Rusty)
+
+sound/
+~~~~~~
+
+global
+~~~~~~
+
+o A couple of hundred real looking bugzilla bugs
+
+o viro: cdev rework. Mostly done.
+
--- diff/Documentation/should-fix.txt	1970-01-01 01:00:00.000000000 +0100
+++ source/Documentation/should-fix.txt	2004-06-11 19:22:01.000000000 +0100
@@ -0,0 +1,422 @@
+Not-ready features and speedups
+===============================
+
+Legend:
+
+PRI1:	We're totally lame if this doesn't get in
+PRI2:	Would be nice
+PRI3:	Not very important
+
+drivers/block/
+~~~~~~~~~~~~~~
+
+drivers/char/rtc/
+~~~~~~~~~~~~~~~~~
+
+o rmk, trini: add support for alarms to the existing generic rtc driver.
+
+  PRI2
+
+console drivers
+~~~~~~~~~~~~~~~
+  (Pavel Machek <pavel@ucw.cz>)
+
+o There are few must-fix bugs in cursor handling.
+
+o Play with gpm selection for a while and your cursor gets corrupted with
+  random dots. Ouch.
+
+device mapper
+~~~~~~~~~~~~~
+
+o ioctl interface cleanup patch is ready (redo the structure layouts)
+
+  PRI1
+
+o A port of the 2.4 snapshot and mirror targets is in progress
+
+  PRI1
+
+o the fs interface to dm needs to be redone.  gregkh was going to work on
+  this.  viro is interested in seeing work thus-far.
+
+  PRI2
+
+drivers/net/wireless/
+~~~~~~~~~~~~~~~~~~~~~
+
+  (Jean Tourrilhes <jt@bougret.hpl.hp.com>)
+
+o get HostAP driver in the kernel.  No consolidation of the 802.11
+  management across driver can happen until this one is in (which is probably
+  2.7.X material).  I think Jouni is mostly ready but didn't find time for
+  it.
+
+  PRI2
+
+o get more wireless drivers into the kernel.  The most "integrable" drivers
+  at this point seem the NWN driver, Pavel's Spectrum driver.
+
+  PRI1
+
+drivers/usb/gadget/
+~~~~~~~~~~~~~~~~~~~
+
+o rmk: SA11xx USB client/gadget code (David B has been doing some work on
+  this, and keeps trying to prod me, but unfortunately I haven't had the time
+  to look at his work, sorry David.)
+
+  PRI3
+
+fs/
+~~~
+
+o ext3 and ext2 block allocators have serious failure modes - interleaved
+  allocations. (Reservation patch in -mm).
+
+  PRI3
+
+o Integrate Chris Mason's 2.4 reiserfs ordered data and data journaling
+  patches.  They make reiserfs a lot safer.
+
+  Ordered: PRI2
+  data journalled: PRI3
+
+o viro: convert more filesystems to use lib/parser.c for options.
+
+  PRI2
+
+o aio: fs IO isn't async at present.  suparna has restart patches, they're
+  in -mm.  Need to get Ben to review/comment.
+
+  PRI1.
+
+o drepper: various filesystems use ->pid wrongly
+
+  PRI1
+
+kernel/
+~~~~~~~
+
+o rusty: Zippel's Reference count simplification.  Tricky code, but cuts
+  about 120 lines from module.c.  Patch exists, needs stressing.
+
+  PRI3
+
+o rusty: Fix module-failed-init races by starting module "disabled".  Patch
+  exists, requires some subsystems (ie.  add_partition) to explicitly say
+  "make module live now".  Without patch we are no worse off than 2.4 etc.
+
+  PRI1
+
+o kexec.  Seems to work, was in -mm.
+
+  PRI3
+
+o rmk: lib/inflate.c must not use static variables (causes these to be
+  referenced via GOTOFF relocations in PIC decompressor.  We have a PIC
+  decompressor to avoid having to hard code a per platform zImage link
+  address into the makefiles.)
+
+  PRI2
+
+
+mm/
+~~~
+
+
+net/
+~~~~
+
+  (davem)
+
+o Real serious use of IPSEC is hampered by lack of MPLS support.  MPLS is a
+  switching technology that works by switching based upon fixed length labels
+  prepended to packets.  Many people use this and IPSEC to implement VPNs
+  over public networks, it is also used for things like traffic engineering.
+
+  A good reference site is:
+
+	http://www.mplsrc.com/
+
+  Anyways, an existing (crappy) implementation exists.  I've almost
+  completed a rewrite, I should have something in the tree next week.
+
+  PRI1
+
+o Sometimes we generate IP fragments when it truly isn't necessary.
+
+  The way IP fragmentation is specified, each fragment must be modulo 8
+  bytes in length.  So suppose the device has an MTU that is not 0 modulo 8,
+  ethernet even classifies in this way.  1500 == (8 * 187) + 4
+
+  Our IP fragmenting engine can fragment on packets that are sized within
+  the last modulo 8 bytes of the MTU.  This happens in obscure cases, but it
+  does happen.
+
+  I've proposed a fix to Alexey, whereby very late in the output path we
+  check the packet, if we fragmented but the data length would fit into the
+  MTU we unfragment the packet.
+
+  This is low priority, because technically it creates suboptimal behavior
+  rather than mis-operation.
+
+  PRI1
+
+net/*/netfilter/
+~~~~~~~~~~~~~~~~
+
+o Lots of misc. cleanups, which are happening slowly.
+
+  PRI2
+
+power management
+~~~~~~~~~~~~~~~~
+
+o Pat and Pavel disagree over swsusp. Need to sort that out.
+
+  PRI2
+
+o Frame buffer, AGP, DRI restore.
+
+  PRI2
+
+o XFree86 hooks
+
+  PRI2
+
+o IDE suspend/resume without races (Ben is looking at this a little)
+
+  PRI2
+
+o Pat: There are already CPU device structures; MTRRs should be a
+  dynamically registered interface of CPUs, which implies there needs
+  to be some other glue to know that there are MTRRs that need to be
+  saved/restored.
+
+  PRI1
+
+global
+~~~~~~
+
+o viro: 64-bit dev_t (not a mustfix for 2.6.0). 32-bit dev_t is done, 64-bit
+  means extra work on nfsd/raid/etc.
+
+o We need a kernel side API for reporting error events to userspace (could
+  be async to 2.6 itself)
+
+  (Prototype core based on netlink exists)
+
+  PRI2
+
+o Kai: Introduce a sane, easy and standard way to build external modules
+  - make clean and make modules_install are both broken
+
+  PRI2
+
+drivers
+~~~~~~~
+
+o Alan: Cardbus/PCMCIA requires all Russell's stuff is merged to do
+  multiheader right and so on
+
+  PRI1
+
+drivers/acpi/
+~~~~~~~~~~~~~
+
+o alan: VIA APIC stuff is one bit of this, there are also some other
+  reports that were caused by ACPI not setting level v edge trigger some
+  times
+
+  PRI1
+
+o mochel: it seems the acpi irq routing code could use a serious rewrite.
+
+  grover: The problem is the ACPI irq routing code is trying to piggyback
+  on the existing MPS-specific data structures, and it's generally a hack.
+  So yes mochel is right, but it is also purging MPS-ities from common code
+  as well.  I've done some preliminary work in this area and it doesn't seem
+  to break anything (yet) but a rewrite in this area imho should not be
+  rushed out the door.  And, I think the above bugs can be fixed w/o the
+  rewrite.
+
+  PRI2
+
+o mochel: ACPI suspend doesn't work.  Important, not cricital.  Pat is
+  working it.
+
+  PRI2
+
+drivers/block/
+~~~~~~~~~~~~~~
+
+
+drivers/char/
+~~~~~~~~~~~~~
+
+
+drivers/ide/
+~~~~~~~~~~~~
+
+  (Alan)
+
+o IDE races, PIO problems, simplex, hotplug, taskfile.
+
+  PRI2
+
+
+drivers/isdn/
+~~~~~~~~~~~~~
+
+  (Kai, rmk)
+
+o locking fixes, cleanups, adaption to recent APIs etc
+
+  PRI2
+
+o fixup tty-based ISDN drivers which provide TIOCM* ioctls (see my recent
+  3-set patch for serial stuff)
+
+  Alternatively, we could re-introduce the fallback to driver ioctl parsing
+  for these if not enough drivers get updated.
+
+  PRI3
+
+drivers/net/
+~~~~~~~~~~~~
+
+o davej: Either Wireless network drivers or PCMCIA broke somewhen.  A
+  configuration that worked fine under 2.4 doesn't receive any packets.  Need
+  to look into this more to make sure I don't have any misconfiguration that
+  just 'happened to work' under 2.4
+
+  PRI1
+
+drivers/scsi/
+~~~~~~~~~~~~~
+
+o jejb: qlogic -
+
+  o Merge the feral driver.  It covers all qlogic chips: 1020 all the way
+    up to 23xxx. http://linux-scsi.bkbits.net/scsi-isp-2.5
+
+  o qla2xxx: only for FC chips.  Has significant build issues.  hch
+    promises to send me a "must fix" list for this.
+    http://linux-scsi.bkbits.net/scsi-qla2xxx-2.5
+
+  PRI2
+
+o hch, Mike Anderson, Badari Pulavarty: scsi locking issues
+
+  o there are lots of members of struct Scsi_Host/scsi_device/scsi_cmnd
+    with very unclear locking, many of them probably want to become
+    atomic_t's or bitmaps (for the 1bit bitfields).
+
+  o there's lots of volatile abuse in the scsi code that needs to be
+    thought about.
+
+  o there's some global variables incremented without any locks
+
+  PRI2
+
+sound/
+~~~~~~
+
+  (rmk)
+
+o ALSA-fication of drivers, forward port 2.4 bugfixes
+  (Killing off OSS is 2.7 material)
+
+PRI2
+
+arch/i386/
+~~~~~~~~~~
+
+o davej: PAT support (for mtrr exhaustion w/ AGP)
+
+  PRI2
+
+o ECC driver questions are not yet sorted (DaveJ is working on this) (Dan
+  Hollis)
+
+  alan: ECC - I have some test bits from Dan's stuff - they need no kernel
+  core changes for most platforms.  That means we can treat it as a random
+  driver merge.
+
+  PRI3
+
+
+arch/x86_64/
+~~~~~~~~~~~~
+
+  (Andi)
+
+o need to coredump 64bit vsyscall code with dwarf2
+
+  PRI2
+
+o move 64bit signal trampolines into vsyscall code and add dwarf2 for it.
+  (in progress)
+
+  PRI1
+
+o describe kernel assembly with dwarf2 annotations for kgdb
+
+  PRI3
+
+arch/alpha/
+~~~~~~~~~~~
+
+o rth: Ptrace writes are broken.  This means we can't (reliably) set
+  breakpoints or modify variables from gdb.
+
+  PRI1
+
+arch/arm/
+~~~~~~~~~
+
+o rmk: missing raw keyboard translation tables for all ARM machines.
+  Haven't even looked into this at all.  This could be messy since there
+  isn't an ARM architecture standard.  I'm presently hoping that it won't be
+  an issue.  If it does, I guess we'll see drivers/char/keyboard.c explode.
+
+  PRI2
+
+arch/others/
+~~~~~~~~~~~~
+
+o SH needs resyncing, as do some other ports. SH64 needs merging.
+  No impact on mainstream platforms hopefully.
+
+  PRI2
+
+arch/s390/
+~~~~~~~~~
+
+
+drivers/s390/
+~~~~~~~~~~~~~
+
+o The 3270 console driver needs to be replaced with a working one
+  (prototype is there, needs to be finished).
+
+  PRI2
+
+o Minor interface changes are pending in cio/ when the z990 machines are
+  out.
+
+  PRI2
+
+o a block device driver for ramdisks shared among virtual machines
+
+  PRI3
+
+o driver for crypto hardware
+
+  PRI3
+
+o 'claw' network device driver
+
+  PRI3
+
--- diff/arch/i386/kernel/kgdb_stub.c	1970-01-01 01:00:00.000000000 +0100
+++ source/arch/i386/kernel/kgdb_stub.c	2004-06-11 19:21:57.000000000 +0100
@@ -0,0 +1,2454 @@
+/*
+ *
+ * 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, 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.
+ *
+ */
+
+/*
+ * Copyright (c) 2000 VERITAS Software Corporation.
+ *
+ */
+/****************************************************************************
+ *  Header: remcom.c,v 1.34 91/03/09 12:29:49 glenne Exp $
+ *
+ *  Module name: remcom.c $
+ *  Revision: 1.34 $
+ *  Date: 91/03/09 12:29:49 $
+ *  Contributor:     Lake Stevens Instrument Division$
+ *
+ *  Description:     low level support for gdb debugger. $
+ *
+ *  Considerations:  only works on target hardware $
+ *
+ *  Written by:	     Glenn Engel $
+ *  Updated by:	     David Grothe <dave@gcom.com>
+ *  Updated by:	     Robert Walsh <rjwalsh@durables.org>
+ *  Updated by:	     wangdi <wangdi@clusterfs.com>
+ *  ModuleState:     Experimental $
+ *
+ *  NOTES:	     See Below $
+ *
+ *  Modified for 386 by Jim Kingdon, Cygnus Support.
+ *  Compatibility with 2.1.xx kernel by David Grothe <dave@gcom.com>
+ *
+ *  Changes to allow auto initilization.  All that is needed is that it
+ *  be linked with the kernel and a break point (int 3) be executed.
+ *  The header file <asm/kgdb.h> defines BREAKPOINT to allow one to do
+ *  this. It should also be possible, once the interrupt system is up, to
+ *  call putDebugChar("+").  Once this is done, the remote debugger should
+ *  get our attention by sending a ^C in a packet. George Anzinger
+ *  <george@mvista.com>
+ *  Integrated into 2.2.5 kernel by Tigran Aivazian <tigran@sco.com>
+ *  Added thread support, support for multiple processors,
+ *	support for ia-32(x86) hardware debugging.
+ *	Amit S. Kale ( akale@veritas.com )
+ *
+ *  Modified to support debugging over ethernet by Robert Walsh
+ *  <rjwalsh@durables.org> and wangdi <wangdi@clusterfs.com>, based on
+ *  code by San Mehat.
+ *
+ *
+ *  To enable debugger support, two things need to happen.  One, a
+ *  call to set_debug_traps() is necessary in order to allow any breakpoints
+ *  or error conditions to be properly intercepted and reported to gdb.
+ *  Two, a breakpoint needs to be generated to begin communication.  This
+ *  is most easily accomplished by a call to breakpoint().  Breakpoint()
+ *  simulates a breakpoint by executing an int 3.
+ *
+ *************
+ *
+ *    The following gdb commands are supported:
+ *
+ * command	    function				   Return value
+ *
+ *    g		    return the value of the CPU registers  hex data or ENN
+ *    G		    set the value of the CPU registers	   OK or ENN
+ *
+ *    mAA..AA,LLLL  Read LLLL bytes at address AA..AA	   hex data or ENN
+ *    MAA..AA,LLLL: Write LLLL bytes at address AA.AA	   OK or ENN
+ *
+ *    c		    Resume at current address		   SNN	 ( signal NN)
+ *    cAA..AA	    Continue at address AA..AA		   SNN
+ *
+ *    s		    Step one instruction		   SNN
+ *    sAA..AA	    Step one instruction from AA..AA	   SNN
+ *
+ *    k		    kill
+ *
+ *    ?		    What was the last sigval ?		   SNN	 (signal NN)
+ *
+ * All commands and responses are sent with a packet which includes a
+ * checksum.  A packet consists of
+ *
+ * $<packet info>#<checksum>.
+ *
+ * where
+ * <packet info> :: <characters representing the command or response>
+ * <checksum>	 :: < two hex digits computed as modulo 256 sum of <packetinfo>>
+ *
+ * When a packet is received, it is first acknowledged with either '+' or '-'.
+ * '+' indicates a successful transfer.	 '-' indicates a failed transfer.
+ *
+ * Example:
+ *
+ * Host:		  Reply:
+ * $m0,10#2a		   +$00010203040506070809101112131415#42
+ *
+ ****************************************************************************/
+#define KGDB_VERSION "<20030915.1651.33>"
+#include <linux/config.h>
+#include <linux/types.h>
+#include <asm/string.h>		/* for strcpy */
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <asm/vm86.h>
+#include <asm/system.h>
+#include <asm/ptrace.h>		/* for linux pt_regs struct */
+#include <asm/kgdb_local.h>
+#include <linux/list.h>
+#include <asm/atomic.h>
+#include <asm/processor.h>
+#include <linux/irq.h>
+#include <asm/desc.h>
+#include <linux/inet.h>
+#include <linux/netpoll.h>
+
+/************************************************************************
+ *
+ * external low-level support routines
+ */
+typedef void (*Function) (void);	/* pointer to a function */
+
+/* Thread reference */
+typedef unsigned char threadref[8];
+
+extern int tty_putDebugChar(int);     /* write a single character      */
+extern int tty_getDebugChar(void);    /* read and return a single char */
+extern void tty_flushDebugChar(void); /* flush pending characters      */
+extern int eth_putDebugChar(int);     /* write a single character      */
+extern int eth_getDebugChar(void);    /* read and return a single char */
+extern void eth_flushDebugChar(void); /* flush pending characters      */
+
+/************************************************************************/
+/* BUFMAX defines the maximum number of characters in inbound/outbound buffers*/
+/* at least NUMREGBYTES*2 are needed for register packets */
+/* Longer buffer is needed to list all threads */
+#define BUFMAX 400
+
+char *kgdb_version = KGDB_VERSION;
+
+/*  debug >  0 prints ill-formed commands in valid packets & checksum errors */
+int debug_regs = 0;		/* set to non-zero to print registers */
+
+/* filled in by an external module */
+char *gdb_module_offsets;
+
+static const char hexchars[] = "0123456789abcdef";
+
+/* Number of bytes of registers.  */
+#define NUMREGBYTES 64
+/*
+ * Note that this register image is in a different order than
+ * the register image that Linux produces at interrupt time.
+ *
+ * Linux's register image is defined by struct pt_regs in ptrace.h.
+ * Just why GDB uses a different order is a historical mystery.
+ */
+enum regnames { _EAX,		/* 0 */
+	_ECX,			/* 1 */
+	_EDX,			/* 2 */
+	_EBX,			/* 3 */
+	_ESP,			/* 4 */
+	_EBP,			/* 5 */
+	_ESI,			/* 6 */
+	_EDI,			/* 7 */
+	_PC /* 8 also known as eip */ ,
+	_PS /* 9 also known as eflags */ ,
+	_CS,			/* 10 */
+	_SS,			/* 11 */
+	_DS,			/* 12 */
+	_ES,			/* 13 */
+	_FS,			/* 14 */
+	_GS			/* 15 */
+};
+
+/***************************  ASSEMBLY CODE MACROS *************************/
+/*
+ * Put the error code here just in case the user cares.
+ * Likewise, the vector number here (since GDB only gets the signal
+ * number through the usual means, and that's not very specific).
+ * The called_from is the return address so he can tell how we entered kgdb.
+ * This will allow him to seperate out the various possible entries.
+ */
+#define REMOTE_DEBUG 0		/* set != to turn on printing (also available in info) */
+
+#define PID_MAX PID_MAX_DEFAULT
+
+#ifdef CONFIG_SMP
+void smp_send_nmi_allbutself(void);
+#define IF_SMP(x) x
+#undef MAX_NO_CPUS
+#ifndef CONFIG_NO_KGDB_CPUS
+#define CONFIG_NO_KGDB_CPUS 2
+#endif
+#if CONFIG_NO_KGDB_CPUS > NR_CPUS
+#define MAX_NO_CPUS NR_CPUS
+#else
+#define MAX_NO_CPUS CONFIG_NO_KGDB_CPUS
+#endif
+#define hold_init hold_on_sstep: 1,
+#define MAX_CPU_MASK (unsigned long)((1LL << MAX_NO_CPUS) - 1LL)
+#define NUM_CPUS num_online_cpus()
+#else
+#define IF_SMP(x)
+#define hold_init
+#undef MAX_NO_CPUS
+#define MAX_NO_CPUS 1
+#define NUM_CPUS 1
+#endif
+#define NOCPU (struct task_struct *)0xbad1fbad
+/* *INDENT-OFF*	 */
+struct kgdb_info {
+	int used_malloc;
+	void *called_from;
+	long long entry_tsc;
+	int errcode;
+	int vector;
+	int print_debug_info;
+#ifdef CONFIG_SMP
+	int hold_on_sstep;
+	struct {
+		volatile struct task_struct *task;
+		int pid;
+		int hold;
+		struct pt_regs *regs;
+	} cpus_waiting[MAX_NO_CPUS];
+#endif
+} kgdb_info = {hold_init print_debug_info:REMOTE_DEBUG, vector:-1};
+
+/* *INDENT-ON*	*/
+
+#define used_m kgdb_info.used_malloc
+/*
+ * This is little area we set aside to contain the stack we
+ * need to build to allow gdb to call functions.  We use one
+ * per cpu to avoid locking issues.  We will do all this work
+ * with interrupts off so that should take care of the protection
+ * issues.
+ */
+#define LOOKASIDE_SIZE 200	/* should be more than enough */
+#define MALLOC_MAX   200	/* Max malloc size */
+struct {
+	unsigned int esp;
+	int array[LOOKASIDE_SIZE];
+} fn_call_lookaside[MAX_NO_CPUS];
+
+static int trap_cpu;
+static unsigned int OLD_esp;
+
+#define END_OF_LOOKASIDE  &fn_call_lookaside[trap_cpu].array[LOOKASIDE_SIZE]
+#define IF_BIT 0x200
+#define TF_BIT 0x100
+
+#define MALLOC_ROUND 8-1
+
+static char malloc_array[MALLOC_MAX];
+IF_SMP(static void to_gdb(const char *mess));
+void *
+malloc(int size)
+{
+
+	if (size <= (MALLOC_MAX - used_m)) {
+		int old_used = used_m;
+		used_m += ((size + MALLOC_ROUND) & (~MALLOC_ROUND));
+		return &malloc_array[old_used];
+	} else {
+		return NULL;
+	}
+}
+
+/*
+ * I/O dispatch functions...
+ * Based upon kgdboe, either call the ethernet
+ * handler or the serial one..
+ */
+void
+putDebugChar(int c)
+{
+	if (!kgdboe) {
+		tty_putDebugChar(c);
+	} else {
+		eth_putDebugChar(c);
+	}
+}
+
+int
+getDebugChar(void)
+{
+	if (!kgdboe) {
+		return tty_getDebugChar();
+	} else {
+		return eth_getDebugChar();
+	}
+}
+
+void
+flushDebugChar(void)
+{
+	if (!kgdboe) {
+		tty_flushDebugChar();
+	} else {
+		eth_flushDebugChar();
+	}
+}
+
+/*
+ * Gdb calls functions by pushing agruments, including a return address
+ * on the stack and the adjusting EIP to point to the function.	 The
+ * whole assumption in GDB is that we are on a different stack than the
+ * one the "user" i.e. code that hit the break point, is on.  This, of
+ * course is not true in the kernel.  Thus various dodges are needed to
+ * do the call without directly messing with EIP (which we can not change
+ * as it is just a location and not a register.	 To adjust it would then
+ * require that we move every thing below EIP up or down as needed.  This
+ * will not work as we may well have stack relative pointer on the stack
+ * (such as the pointer to regs, for example).
+
+ * So here is what we do:
+ * We detect gdb attempting to store into the stack area and instead, store
+ * into the fn_call_lookaside.array at the same relative location as if it
+ * were the area ESP pointed at.  We also trap ESP modifications
+ * and uses these to adjust fn_call_lookaside.esp.  On entry
+ * fn_call_lookaside.esp will be set to point at the last entry in
+ * fn_call_lookaside.array.  This allows us to check if it has changed, and
+ * if so, on exit, we add the registers we will use to do the move and a
+ * trap/ interrupt return exit sequence.  We then adjust the eflags in the
+ * regs array (remember we now have a copy in the fn_call_lookaside.array) to
+ * kill the interrupt bit, AND we change EIP to point at our set up stub.
+ * As part of the register set up we preset the registers to point at the
+ * begining and end of the fn_call_lookaside.array, so all the stub needs to
+ * do is move words from the array to the stack until ESP= the desired value
+ * then do the rti.  This will then transfer to the desired function with
+ * all the correct registers.  Nifty huh?
+ */
+extern asmlinkage void fn_call_stub(void);
+extern asmlinkage void fn_rtn_stub(void);
+/*					   *INDENT-OFF*	 */
+__asm__("fn_rtn_stub:\n\t"
+	"movl %eax,%esp\n\t"
+	"fn_call_stub:\n\t"
+	"1:\n\t"
+	"addl $-4,%ebx\n\t"
+	"movl (%ebx), %eax\n\t"
+	"pushl %eax\n\t"
+	"cmpl %esp,%ecx\n\t"
+	"jne  1b\n\t"
+	"popl %eax\n\t"
+	"popl %ebx\n\t"
+	"popl %ecx\n\t"
+	"iret \n\t");
+/*					     *INDENT-ON*  */
+#define gdb_i386vector	kgdb_info.vector
+#define gdb_i386errcode kgdb_info.errcode
+#define waiting_cpus	kgdb_info.cpus_waiting
+#define remote_debug	kgdb_info.print_debug_info
+#define hold_cpu(cpu)	kgdb_info.cpus_waiting[cpu].hold
+/* gdb locks */
+
+#ifdef CONFIG_SMP
+static int in_kgdb_called;
+static spinlock_t waitlocks[MAX_NO_CPUS] =
+    {[0 ... MAX_NO_CPUS - 1] = SPIN_LOCK_UNLOCKED };
+/*
+ * The following array has the thread pointer of each of the "other"
+ * cpus.  We make it global so it can be seen by gdb.
+ */
+volatile int in_kgdb_entry_log[MAX_NO_CPUS];
+volatile struct pt_regs *in_kgdb_here_log[MAX_NO_CPUS];
+/*
+static spinlock_t continuelocks[MAX_NO_CPUS];
+*/
+spinlock_t kgdb_spinlock = SPIN_LOCK_UNLOCKED;
+/* waiters on our spinlock plus us */
+static atomic_t spinlock_waiters = ATOMIC_INIT(1);
+static int spinlock_count = 0;
+static int spinlock_cpu = 0;
+/*
+ * Note we use nested spin locks to account for the case where a break
+ * point is encountered when calling a function by user direction from
+ * kgdb. Also there is the memory exception recursion to account for.
+ * Well, yes, but this lets other cpus thru too.  Lets add a
+ * cpu id to the lock.
+ */
+#define KGDB_SPIN_LOCK(x) if( spinlock_count == 0 || \
+			      spinlock_cpu != smp_processor_id()){\
+				      atomic_inc(&spinlock_waiters); \
+				      while (! spin_trylock(x)) {\
+					    in_kgdb(&regs);\
+				      }\
+				      atomic_dec(&spinlock_waiters); \
+				      spinlock_count = 1; \
+				      spinlock_cpu = smp_processor_id(); \
+			  }else{  \
+				      spinlock_count++; \
+			  }
+#define KGDB_SPIN_UNLOCK(x) if( --spinlock_count == 0) spin_unlock(x)
+#else
+unsigned kgdb_spinlock = 0;
+#define KGDB_SPIN_LOCK(x) --*x
+#define KGDB_SPIN_UNLOCK(x) ++*x
+#endif
+
+int
+hex(char ch)
+{
+	if ((ch >= 'a') && (ch <= 'f'))
+		return (ch - 'a' + 10);
+	if ((ch >= '0') && (ch <= '9'))
+		return (ch - '0');
+	if ((ch >= 'A') && (ch <= 'F'))
+		return (ch - 'A' + 10);
+	return (-1);
+}
+
+/* scan for the sequence $<data>#<checksum>	*/
+void
+getpacket(char *buffer)
+{
+	unsigned char checksum;
+	unsigned char xmitcsum;
+	int i;
+	int count;
+	char ch;
+
+	do {
+		/* wait around for the start character, ignore all other characters */
+		while ((ch = (getDebugChar() & 0x7f)) != '$') ;
+		checksum = 0;
+		xmitcsum = -1;
+
+		count = 0;
+
+		/* now, read until a # or end of buffer is found */
+		while (count < BUFMAX) {
+			ch = getDebugChar() & 0x7f;
+			if (ch == '#')
+				break;
+			checksum = checksum + ch;
+			buffer[count] = ch;
+			count = count + 1;
+		}
+		buffer[count] = 0;
+
+		if (ch == '#') {
+			xmitcsum = hex(getDebugChar() & 0x7f) << 4;
+			xmitcsum += hex(getDebugChar() & 0x7f);
+			if ((remote_debug) && (checksum != xmitcsum)) {
+				printk
+				    ("bad checksum.	My count = 0x%x, sent=0x%x. buf=%s\n",
+				     checksum, xmitcsum, buffer);
+			}
+
+			if (checksum != xmitcsum)
+				putDebugChar('-');	/* failed checksum */
+			else {
+				putDebugChar('+');	/* successful transfer */
+				/* if a sequence char is present, reply the sequence ID */
+				if (buffer[2] == ':') {
+					putDebugChar(buffer[0]);
+					putDebugChar(buffer[1]);
+					/* remove sequence chars from buffer */
+					count = strlen(buffer);
+					for (i = 3; i <= count; i++)
+						buffer[i - 3] = buffer[i];
+				}
+			}
+		}
+	} while (checksum != xmitcsum);
+
+	if (remote_debug)
+		printk("R:%s\n", buffer);
+	flushDebugChar();
+}
+
+/* send the packet in buffer.  */
+
+void
+putpacket(char *buffer)
+{
+	unsigned char checksum;
+	int count;
+	char ch;
+
+	/*  $<packet info>#<checksum>. */
+
+	if (!kgdboe) {
+		do {
+			if (remote_debug)
+				printk("T:%s\n", buffer);
+			putDebugChar('$');
+			checksum = 0;
+			count = 0;
+
+			while ((ch = buffer[count])) {
+				putDebugChar(ch);
+				checksum += ch;
+				count += 1;
+			}
+
+			putDebugChar('#');
+			putDebugChar(hexchars[checksum >> 4]);
+			putDebugChar(hexchars[checksum % 16]);
+			flushDebugChar();
+
+		} while ((getDebugChar() & 0x7f) != '+');
+	} else {
+		/*
+		 * For udp, we can not transfer too much bytes once.
+		 * We only transfer MAX_SEND_COUNT size bytes each time
+		 */
+
+#define MAX_SEND_COUNT 30
+
+		int send_count = 0, i = 0;
+		char send_buf[MAX_SEND_COUNT];
+
+		do {
+			if (remote_debug)
+				printk("T:%s\n", buffer);
+			putDebugChar('$');
+			checksum = 0;
+			count = 0;
+			send_count = 0;
+			while ((ch = buffer[count])) {
+				if (send_count >= MAX_SEND_COUNT) {
+					for(i = 0; i < MAX_SEND_COUNT; i++) {
+						putDebugChar(send_buf[i]);
+					}
+					flushDebugChar();
+					send_count = 0;
+				} else {
+					send_buf[send_count] = ch;
+					checksum += ch;
+					count ++;
+					send_count++;
+				}
+			}
+			for(i = 0; i < send_count; i++)
+				putDebugChar(send_buf[i]);
+			putDebugChar('#');
+			putDebugChar(hexchars[checksum >> 4]);
+			putDebugChar(hexchars[checksum % 16]);
+			flushDebugChar();
+		} while ((getDebugChar() & 0x7f) != '+');
+	}
+}
+
+static char remcomInBuffer[BUFMAX];
+static char remcomOutBuffer[BUFMAX];
+static short error;
+
+void
+debug_error(char *format, char *parm)
+{
+	if (remote_debug)
+		printk(format, parm);
+}
+
+static void
+print_regs(struct pt_regs *regs)
+{
+	printk("EAX=%08lx ", regs->eax);
+	printk("EBX=%08lx ", regs->ebx);
+	printk("ECX=%08lx ", regs->ecx);
+	printk("EDX=%08lx ", regs->edx);
+	printk("\n");
+	printk("ESI=%08lx ", regs->esi);
+	printk("EDI=%08lx ", regs->edi);
+	printk("EBP=%08lx ", regs->ebp);
+	printk("ESP=%08lx ", (long) &regs->esp);
+	printk("\n");
+	printk(" DS=%08x ", regs->xds);
+	printk(" ES=%08x ", regs->xes);
+	printk(" SS=%08x ", __KERNEL_DS);
+	printk(" FL=%08lx ", regs->eflags);
+	printk("\n");
+	printk(" CS=%08x ", regs->xcs);
+	printk(" IP=%08lx ", regs->eip);
+#if 0
+	printk(" FS=%08x ", regs->fs);
+	printk(" GS=%08x ", regs->gs);
+#endif
+	printk("\n");
+
+}				/* print_regs */
+
+#define NEW_esp fn_call_lookaside[trap_cpu].esp
+
+static void
+regs_to_gdb_regs(int *gdb_regs, struct pt_regs *regs)
+{
+	gdb_regs[_EAX] = regs->eax;
+	gdb_regs[_EBX] = regs->ebx;
+	gdb_regs[_ECX] = regs->ecx;
+	gdb_regs[_EDX] = regs->edx;
+	gdb_regs[_ESI] = regs->esi;
+	gdb_regs[_EDI] = regs->edi;
+	gdb_regs[_EBP] = regs->ebp;
+	gdb_regs[_DS] = regs->xds;
+	gdb_regs[_ES] = regs->xes;
+	gdb_regs[_PS] = regs->eflags;
+	gdb_regs[_CS] = regs->xcs;
+	gdb_regs[_PC] = regs->eip;
+	/* Note, as we are a debugging the kernel, we will always
+	 * trap in kernel code, this means no priviledge change,
+	 * and so the pt_regs structure is not completely valid.  In a non
+	 * privilege change trap, only EFLAGS, CS and EIP are put on the stack,
+	 * SS and ESP are not stacked, this means that the last 2 elements of
+	 * pt_regs is not valid (they would normally refer to the user stack)
+	 * also, using regs+1 is no good because you end up will a value that is
+	 * 2 longs (8) too high.  This used to cause stepping over functions
+	 * to fail, so my fix is to use the address of regs->esp, which
+	 * should point at the end of the stack frame.	Note I have ignored
+	 * completely exceptions that cause an error code to be stacked, such
+	 * as double fault.  Stuart Hughes, Zentropix.
+	 * original code: gdb_regs[_ESP] =  (int) (regs + 1) ;
+
+	 * this is now done on entry and moved to OLD_esp (as well as NEW_esp).
+	 */
+	gdb_regs[_ESP] = NEW_esp;
+	gdb_regs[_SS] = __KERNEL_DS;
+	gdb_regs[_FS] = 0xFFFF;
+	gdb_regs[_GS] = 0xFFFF;
+}				/* regs_to_gdb_regs */
+
+static void
+gdb_regs_to_regs(int *gdb_regs, struct pt_regs *regs)
+{
+	regs->eax = gdb_regs[_EAX];
+	regs->ebx = gdb_regs[_EBX];
+	regs->ecx = gdb_regs[_ECX];
+	regs->edx = gdb_regs[_EDX];
+	regs->esi = gdb_regs[_ESI];
+	regs->edi = gdb_regs[_EDI];
+	regs->ebp = gdb_regs[_EBP];
+	regs->xds = gdb_regs[_DS];
+	regs->xes = gdb_regs[_ES];
+	regs->eflags = gdb_regs[_PS];
+	regs->xcs = gdb_regs[_CS];
+	regs->eip = gdb_regs[_PC];
+	NEW_esp = gdb_regs[_ESP];	/* keep the value */
+#if 0				/* can't change these */
+	regs->esp = gdb_regs[_ESP];
+	regs->xss = gdb_regs[_SS];
+	regs->fs = gdb_regs[_FS];
+	regs->gs = gdb_regs[_GS];
+#endif
+
+}				/* gdb_regs_to_regs */
+
+int thread_list = 0;
+
+void
+get_gdb_regs(struct task_struct *p, struct pt_regs *regs, int *gdb_regs)
+{
+	unsigned long stack_page;
+	int count = 0;
+	IF_SMP(int i);
+	if (!p || p == current) {
+		regs_to_gdb_regs(gdb_regs, regs);
+		return;
+	}
+#ifdef CONFIG_SMP
+	for (i = 0; i < MAX_NO_CPUS; i++) {
+		if (p == kgdb_info.cpus_waiting[i].task) {
+			regs_to_gdb_regs(gdb_regs,
+					 kgdb_info.cpus_waiting[i].regs);
+			gdb_regs[_ESP] =
+			    (int) &kgdb_info.cpus_waiting[i].regs->esp;
+
+			return;
+		}
+	}
+#endif
+	memset(gdb_regs, 0, NUMREGBYTES);
+	gdb_regs[_ESP] = p->thread.esp;
+	gdb_regs[_PC] = p->thread.eip;
+	gdb_regs[_EBP] = *(int *) gdb_regs[_ESP];
+	gdb_regs[_EDI] = *(int *) (gdb_regs[_ESP] + 4);
+	gdb_regs[_ESI] = *(int *) (gdb_regs[_ESP] + 8);
+
+/*
+ * This code is to give a more informative notion of where a process
+ * is waiting.	It is used only when the user asks for a thread info
+ * list.  If he then switches to the thread, s/he will find the task
+ * is in schedule, but a back trace should show the same info we come
+ * up with.  This code was shamelessly purloined from process.c.  It was
+ * then enhanced to provide more registers than simply the program
+ * counter.
+ */
+
+	if (!thread_list) {
+		return;
+	}
+
+	if (p->state == TASK_RUNNING)
+		return;
+	stack_page = (unsigned long) p->thread_info;
+	if (gdb_regs[_ESP] < stack_page || gdb_regs[_ESP] >
+	    THREAD_SIZE - sizeof(long) + stack_page)
+		return;
+	/* include/asm-i386/system.h:switch_to() pushes ebp last. */
+	do {
+		if (gdb_regs[_EBP] < stack_page ||
+		    gdb_regs[_EBP] > THREAD_SIZE - 2*sizeof(long) + stack_page)
+			return;
+		gdb_regs[_PC] = *(unsigned long *) (gdb_regs[_EBP] + 4);
+		gdb_regs[_ESP] = gdb_regs[_EBP] + 8;
+		gdb_regs[_EBP] = *(unsigned long *) gdb_regs[_EBP];
+		if (!in_sched_functions(gdb_regs[_PC]))
+			return;
+	} while (count++ < 16);
+	return;
+}
+
+/* Indicate to caller of mem2hex or hex2mem that there has been an
+   error.  */
+static volatile int mem_err = 0;
+static volatile int mem_err_expected = 0;
+static volatile int mem_err_cnt = 0;
+static int garbage_loc = -1;
+
+int
+get_char(char *addr)
+{
+	return *addr;
+}
+
+void
+set_char(char *addr, int val, int may_fault)
+{
+	/*
+	 * This code traps references to the area mapped to the kernel
+	 * stack as given by the regs and, instead, stores to the
+	 * fn_call_lookaside[cpu].array
+	 */
+	if (may_fault &&
+	    (unsigned int) addr < OLD_esp &&
+	    ((unsigned int) addr > (OLD_esp - (unsigned int) LOOKASIDE_SIZE))) {
+		addr = (char *) END_OF_LOOKASIDE - ((char *) OLD_esp - addr);
+	}
+	*addr = val;
+}
+
+/* convert the memory pointed to by mem into hex, placing result in buf */
+/* return a pointer to the last char put in buf (null) */
+/* If MAY_FAULT is non-zero, then we should set mem_err in response to
+   a fault; if zero treat a fault like any other fault in the stub.  */
+char *
+mem2hex(char *mem, char *buf, int count, int may_fault)
+{
+	int i;
+	unsigned char ch;
+
+	if (may_fault) {
+		mem_err_expected = 1;
+		mem_err = 0;
+	}
+	for (i = 0; i < count; i++) {
+		/* printk("%lx = ", mem) ; */
+
+		ch = get_char(mem++);
+
+		/* printk("%02x\n", ch & 0xFF) ; */
+		if (may_fault && mem_err) {
+			if (remote_debug)
+				printk("Mem fault fetching from addr %lx\n",
+				       (long) (mem - 1));
+			*buf = 0;	/* truncate buffer */
+			return (buf);
+		}
+		*buf++ = hexchars[ch >> 4];
+		*buf++ = hexchars[ch % 16];
+	}
+	*buf = 0;
+	if (may_fault)
+		mem_err_expected = 0;
+	return (buf);
+}
+
+/* convert the hex array pointed to by buf into binary to be placed in mem */
+/* return a pointer to the character AFTER the last byte written */
+/* NOTE: We use the may fault flag to also indicate if the write is to
+ * the registers (0) or "other" memory (!=0)
+ */
+char *
+hex2mem(char *buf, char *mem, int count, int may_fault)
+{
+	int i;
+	unsigned char ch;
+
+	if (may_fault) {
+		mem_err_expected = 1;
+		mem_err = 0;
+	}
+	for (i = 0; i < count; i++) {
+		ch = hex(*buf++) << 4;
+		ch = ch + hex(*buf++);
+		set_char(mem++, ch, may_fault);
+
+		if (may_fault && mem_err) {
+			if (remote_debug)
+				printk("Mem fault storing to addr %lx\n",
+				       (long) (mem - 1));
+			return (mem);
+		}
+	}
+	if (may_fault)
+		mem_err_expected = 0;
+	return (mem);
+}
+
+/**********************************************/
+/* WHILE WE FIND NICE HEX CHARS, BUILD AN INT */
+/* RETURN NUMBER OF CHARS PROCESSED	      */
+/**********************************************/
+int
+hexToInt(char **ptr, int *intValue)
+{
+	int numChars = 0;
+	int hexValue;
+
+	*intValue = 0;
+
+	while (**ptr) {
+		hexValue = hex(**ptr);
+		if (hexValue >= 0) {
+			*intValue = (*intValue << 4) | hexValue;
+			numChars++;
+		} else
+			break;
+
+		(*ptr)++;
+	}
+
+	return (numChars);
+}
+
+#define stubhex(h) hex(h)
+#ifdef old_thread_list
+
+static int
+stub_unpack_int(char *buff, int fieldlength)
+{
+	int nibble;
+	int retval = 0;
+
+	while (fieldlength) {
+		nibble = stubhex(*buff++);
+		retval |= nibble;
+		fieldlength--;
+		if (fieldlength)
+			retval = retval << 4;
+	}
+	return retval;
+}
+#endif
+static char *
+pack_hex_byte(char *pkt, int byte)
+{
+	*pkt++ = hexchars[(byte >> 4) & 0xf];
+	*pkt++ = hexchars[(byte & 0xf)];
+	return pkt;
+}
+
+#define BUF_THREAD_ID_SIZE 16
+
+static char *
+pack_threadid(char *pkt, threadref * id)
+{
+	char *limit;
+	unsigned char *altid;
+
+	altid = (unsigned char *) id;
+	limit = pkt + BUF_THREAD_ID_SIZE;
+	while (pkt < limit)
+		pkt = pack_hex_byte(pkt, *altid++);
+	return pkt;
+}
+
+#ifdef old_thread_list
+static char *
+unpack_byte(char *buf, int *value)
+{
+	*value = stub_unpack_int(buf, 2);
+	return buf + 2;
+}
+
+static char *
+unpack_threadid(char *inbuf, threadref * id)
+{
+	char *altref;
+	char *limit = inbuf + BUF_THREAD_ID_SIZE;
+	int x, y;
+
+	altref = (char *) id;
+
+	while (inbuf < limit) {
+		x = stubhex(*inbuf++);
+		y = stubhex(*inbuf++);
+		*altref++ = (x << 4) | y;
+	}
+	return inbuf;
+}
+#endif
+void
+int_to_threadref(threadref * id, int value)
+{
+	unsigned char *scan;
+
+	scan = (unsigned char *) id;
+	{
+		int i = 4;
+		while (i--)
+			*scan++ = 0;
+	}
+	*scan++ = (value >> 24) & 0xff;
+	*scan++ = (value >> 16) & 0xff;
+	*scan++ = (value >> 8) & 0xff;
+	*scan++ = (value & 0xff);
+}
+int
+int_to_hex_v(unsigned char * id, int value)
+{
+	unsigned char *start = id;
+	int shift;
+	int ch;
+
+	for (shift = 28; shift >= 0; shift -= 4) {
+		if ((ch = (value >> shift) & 0xf) || (id != start)) {
+			*id = hexchars[ch];
+			id++;
+		}
+	}
+	if (id == start)
+		*id++ = '0';
+	return id - start;
+}
+#ifdef old_thread_list
+
+static int
+threadref_to_int(threadref * ref)
+{
+	int i, value = 0;
+	unsigned char *scan;
+
+	scan = (char *) ref;
+	scan += 4;
+	i = 4;
+	while (i-- > 0)
+		value = (value << 8) | ((*scan++) & 0xff);
+	return value;
+}
+#endif
+static int
+cmp_str(char *s1, char *s2, int count)
+{
+	while (count--) {
+		if (*s1++ != *s2++)
+			return 0;
+	}
+	return 1;
+}
+
+#if 1				/* this is a hold over from 2.4 where O(1) was "sometimes" */
+extern struct task_struct *kgdb_get_idle(int cpu);
+#define idle_task(cpu) kgdb_get_idle(cpu)
+#else
+#define idle_task(cpu) init_tasks[cpu]
+#endif
+
+extern int kgdb_pid_init_done;
+
+struct task_struct *
+getthread(int pid)
+{
+	struct task_struct *thread;
+	if (pid >= PID_MAX && pid <= (PID_MAX + MAX_NO_CPUS)) {
+
+		return idle_task(pid - PID_MAX);
+	} else {
+		/*
+		 * find_task_by_pid is relatively safe all the time
+		 * Other pid functions require lock downs which imply
+		 * that we may be interrupting them (as we get here
+		 * in the middle of most any lock down).
+		 * Still we don't want to call until the table exists!
+		 */
+		if (kgdb_pid_init_done){
+			thread = find_task_by_pid(pid);
+			if (thread) {
+				return thread;
+			}
+		}
+	}
+	return NULL;
+}
+/* *INDENT-OFF*	 */
+struct hw_breakpoint {
+	unsigned enabled;
+	unsigned type;
+	unsigned len;
+	unsigned addr;
+} breakinfo[4] = { {enabled:0},
+		   {enabled:0},
+		   {enabled:0},
+		   {enabled:0}};
+/* *INDENT-ON*	*/
+unsigned hw_breakpoint_status;
+void
+correct_hw_break(void)
+{
+	int breakno;
+	int correctit;
+	int breakbit;
+	unsigned dr7;
+
+	asm volatile ("movl %%db7, %0\n":"=r" (dr7)
+		      :);
+	/* *INDENT-OFF*	 */
+	do {
+		unsigned addr0, addr1, addr2, addr3;
+		asm volatile ("movl %%db0, %0\n"
+			      "movl %%db1, %1\n"
+			      "movl %%db2, %2\n"
+			      "movl %%db3, %3\n"
+			      :"=r" (addr0), "=r"(addr1),
+			      "=r"(addr2), "=r"(addr3)
+			      :);
+	} while (0);
+	/* *INDENT-ON*	*/
+	correctit = 0;
+	for (breakno = 0; breakno < 3; breakno++) {
+		breakbit = 2 << (breakno << 1);
+		if (!(dr7 & breakbit) && breakinfo[breakno].enabled) {
+			correctit = 1;
+			dr7 |= breakbit;
+			dr7 &= ~(0xf0000 << (breakno << 2));
+			dr7 |= (((breakinfo[breakno].len << 2) |
+				 breakinfo[breakno].type) << 16) <<
+			    (breakno << 2);
+			switch (breakno) {
+			case 0:
+				asm volatile ("movl %0, %%dr0\n"::"r"
+					      (breakinfo[breakno].addr));
+				break;
+
+			case 1:
+				asm volatile ("movl %0, %%dr1\n"::"r"
+					      (breakinfo[breakno].addr));
+				break;
+
+			case 2:
+				asm volatile ("movl %0, %%dr2\n"::"r"
+					      (breakinfo[breakno].addr));
+				break;
+
+			case 3:
+				asm volatile ("movl %0, %%dr3\n"::"r"
+					      (breakinfo[breakno].addr));
+				break;
+			}
+		} else if ((dr7 & breakbit) && !breakinfo[breakno].enabled) {
+			correctit = 1;
+			dr7 &= ~breakbit;
+			dr7 &= ~(0xf0000 << (breakno << 2));
+		}
+	}
+	if (correctit) {
+		asm volatile ("movl %0, %%db7\n"::"r" (dr7));
+	}
+}
+
+int
+remove_hw_break(unsigned breakno)
+{
+	if (!breakinfo[breakno].enabled) {
+		return -1;
+	}
+	breakinfo[breakno].enabled = 0;
+	return 0;
+}
+
+int
+set_hw_break(unsigned breakno, unsigned type, unsigned len, unsigned addr)
+{
+	if (breakinfo[breakno].enabled) {
+		return -1;
+	}
+	breakinfo[breakno].enabled = 1;
+	breakinfo[breakno].type = type;
+	breakinfo[breakno].len = len;
+	breakinfo[breakno].addr = addr;
+	return 0;
+}
+
+#ifdef CONFIG_SMP
+static int in_kgdb_console = 0;
+
+int
+in_kgdb(struct pt_regs *regs)
+{
+	unsigned flags;
+	int cpu = smp_processor_id();
+	in_kgdb_called = 1;
+	if (!spin_is_locked(&kgdb_spinlock)) {
+		if (in_kgdb_here_log[cpu] ||	/* we are holding this cpu */
+		    in_kgdb_console) {	/* or we are doing slow i/o */
+			return 1;
+		}
+		return 0;
+	}
+
+	/* As I see it the only reason not to let all cpus spin on
+	 * the same spin_lock is to allow selected ones to proceed.
+	 * This would be a good thing, so we leave it this way.
+	 * Maybe someday....  Done !
+
+	 * in_kgdb() is called from an NMI so we don't pretend
+	 * to have any resources, like printk() for example.
+	 */
+
+	kgdb_local_irq_save(flags);	/* only local here, to avoid hanging */
+	/*
+	 * log arival of this cpu
+	 * The NMI keeps on ticking.  Protect against recurring more
+	 * than once, and ignor the cpu that has the kgdb lock
+	 */
+	in_kgdb_entry_log[cpu]++;
+	in_kgdb_here_log[cpu] = regs;
+	if (cpu == spinlock_cpu || waiting_cpus[cpu].task)
+		goto exit_in_kgdb;
+
+	/*
+	 * For protection of the initilization of the spin locks by kgdb
+	 * it locks the kgdb spinlock before it gets the wait locks set
+	 * up.	We wait here for the wait lock to be taken.  If the
+	 * kgdb lock goes away first??	Well, it could be a slow exit
+	 * sequence where the wait lock is removed prior to the kgdb lock
+	 * so if kgdb gets unlocked, we just exit.
+	 */
+
+	while (spin_is_locked(&kgdb_spinlock) &&
+	       !spin_is_locked(waitlocks + cpu)) ;
+	if (!spin_is_locked(&kgdb_spinlock))
+		goto exit_in_kgdb;
+
+	waiting_cpus[cpu].task = current;
+	waiting_cpus[cpu].pid = (current->pid) ? : (PID_MAX + cpu);
+	waiting_cpus[cpu].regs = regs;
+
+	spin_unlock_wait(waitlocks + cpu);
+
+	/*
+	 * log departure of this cpu
+	 */
+	waiting_cpus[cpu].task = 0;
+	waiting_cpus[cpu].pid = 0;
+	waiting_cpus[cpu].regs = 0;
+	correct_hw_break();
+      exit_in_kgdb:
+	in_kgdb_here_log[cpu] = 0;
+	kgdb_local_irq_restore(flags);
+	return 1;
+	/*
+	   spin_unlock(continuelocks + smp_processor_id());
+	 */
+}
+
+void
+smp__in_kgdb(struct pt_regs regs)
+{
+	ack_APIC_irq();
+	in_kgdb(&regs);
+}
+#else
+int
+in_kgdb(struct pt_regs *regs)
+{
+	return (kgdb_spinlock);
+}
+#endif
+
+void
+printexceptioninfo(int exceptionNo, int errorcode, char *buffer)
+{
+	unsigned dr6;
+	int i;
+	switch (exceptionNo) {
+	case 1:		/* debug exception */
+		break;
+	case 3:		/* breakpoint */
+		sprintf(buffer, "Software breakpoint");
+		return;
+	default:
+		sprintf(buffer, "Details not available");
+		return;
+	}
+	asm volatile ("movl %%db6, %0\n":"=r" (dr6)
+		      :);
+	if (dr6 & 0x4000) {
+		sprintf(buffer, "Single step");
+		return;
+	}
+	for (i = 0; i < 4; ++i) {
+		if (dr6 & (1 << i)) {
+			sprintf(buffer, "Hardware breakpoint %d", i);
+			return;
+		}
+	}
+	sprintf(buffer, "Unknown trap");
+	return;
+}
+
+/*
+ * This function does all command procesing for interfacing to gdb.
+ *
+ * NOTE:  The INT nn instruction leaves the state of the interrupt
+ *	  enable flag UNCHANGED.  That means that when this routine
+ *	  is entered via a breakpoint (INT 3) instruction from code
+ *	  that has interrupts enabled, then interrupts will STILL BE
+ *	  enabled when this routine is entered.	 The first thing that
+ *	  we do here is disable interrupts so as to prevent recursive
+ *	  entries and bothersome serial interrupts while we are
+ *	  trying to run the serial port in polled mode.
+ *
+ * For kernel version 2.1.xx the kgdb_cli() actually gets a spin lock so
+ * it is always necessary to do a restore_flags before returning
+ * so as to let go of that lock.
+ */
+int
+kgdb_handle_exception(int exceptionVector,
+		      int signo, int err_code, struct pt_regs *linux_regs)
+{
+	struct task_struct *usethread = NULL;
+	struct task_struct *thread_list_start = 0, *thread = NULL;
+	int addr, length;
+	int breakno, breaktype;
+	char *ptr;
+	int newPC;
+	threadref thref;
+	int threadid;
+	int thread_min = PID_MAX + MAX_NO_CPUS;
+#ifdef old_thread_list
+	int maxthreads;
+#endif
+	int nothreads;
+	unsigned long flags;
+	int gdb_regs[NUMREGBYTES / 4];
+	int dr6;
+	IF_SMP(int entry_state = 0);	/* 0, ok, 1, no nmi, 2 sync failed */
+#define NO_NMI 1
+#define NO_SYNC 2
+#define	regs	(*linux_regs)
+#define NUMREGS NUMREGBYTES/4
+	/*
+	 * If the entry is not from the kernel then return to the Linux
+	 * trap handler and let it process the interrupt normally.
+	 */
+	if ((linux_regs->eflags & VM_MASK) || (3 & linux_regs->xcs)) {
+		printk("ignoring non-kernel exception\n");
+		print_regs(&regs);
+		return (0);
+	}
+	/*
+	 * If we're using eth mode, set the 'mode' in the netdevice.
+	 */
+
+	if (kgdboe)
+		netpoll_set_trap(1);
+
+	kgdb_local_irq_save(flags);
+
+	/* Get kgdb spinlock */
+
+	KGDB_SPIN_LOCK(&kgdb_spinlock);
+	rdtscll(kgdb_info.entry_tsc);
+	/*
+	 * We depend on this spinlock and the NMI watch dog to control the
+	 * other cpus.	They will arrive at "in_kgdb()" as a result of the
+	 * NMI and will wait there for the following spin locks to be
+	 * released.
+	 */
+#ifdef CONFIG_SMP
+
+#if 0
+	if (cpu_callout_map & ~MAX_CPU_MASK) {
+		printk("kgdb : too many cpus, possibly not mapped"
+		       " in contiguous space, change MAX_NO_CPUS"
+		       " in kgdb_stub and make new kernel.\n"
+		       " cpu_callout_map is %lx\n", cpu_callout_map);
+		goto exit_just_unlock;
+	}
+#endif
+	if (spinlock_count == 1) {
+		int time = 0, end_time, dum = 0;
+		int i;
+		int cpu_logged_in[MAX_NO_CPUS] = {[0 ... MAX_NO_CPUS - 1] = (0)
+		};
+		if (remote_debug) {
+			printk("kgdb : cpu %d entry, syncing others\n",
+			       smp_processor_id());
+		}
+		for (i = 0; i < MAX_NO_CPUS; i++) {
+			/*
+			 * Use trylock as we may already hold the lock if
+			 * we are holding the cpu.  Net result is all
+			 * locked.
+			 */
+			spin_trylock(&waitlocks[i]);
+		}
+		for (i = 0; i < MAX_NO_CPUS; i++)
+			cpu_logged_in[i] = 0;
+		/*
+		 * Wait for their arrival.  We know the watch dog is active if
+		 * in_kgdb() has ever been called, as it is always called on a
+		 * watchdog tick.
+		 */
+		rdtsc(dum, time);
+		end_time = time + 2;	/* Note: we use the High order bits! */
+		i = 1;
+		if (num_online_cpus() > 1) {
+			int me_in_kgdb = in_kgdb_entry_log[smp_processor_id()];
+			smp_send_nmi_allbutself();
+
+			while (i < num_online_cpus() && time != end_time) {
+				int j;
+				for (j = 0; j < MAX_NO_CPUS; j++) {
+					if (waiting_cpus[j].task &&
+					    waiting_cpus[j].task != NOCPU &&
+					    !cpu_logged_in[j]) {
+						i++;
+						cpu_logged_in[j] = 1;
+						if (remote_debug) {
+							printk
+							    ("kgdb : cpu %d arrived at kgdb\n",
+							     j);
+						}
+						break;
+					} else if (!waiting_cpus[j].task &&
+						   !cpu_online(j)) {
+						waiting_cpus[j].task = NOCPU;
+						cpu_logged_in[j] = 1;
+						waiting_cpus[j].hold = 1;
+						break;
+					}
+					if (!waiting_cpus[j].task &&
+					    in_kgdb_here_log[j]) {
+
+						int wait = 100000;
+						while (wait--) ;
+						if (!waiting_cpus[j].task &&
+						    in_kgdb_here_log[j]) {
+							printk
+							    ("kgdb : cpu %d stall"
+							     " in in_kgdb\n",
+							     j);
+							i++;
+							cpu_logged_in[j] = 1;
+							waiting_cpus[j].task =
+							    (struct task_struct
+							     *) 1;
+						}
+					}
+				}
+
+				if (in_kgdb_entry_log[smp_processor_id()] >
+				    (me_in_kgdb + 10)) {
+					break;
+				}
+
+				rdtsc(dum, time);
+			}
+			if (i < num_online_cpus()) {
+				printk
+				    ("kgdb : time out, proceeding without sync\n");
+#if 0
+				printk("kgdb : Waiting_cpus: 0 = %d, 1 = %d\n",
+				       waiting_cpus[0].task != 0,
+				       waiting_cpus[1].task != 0);
+				printk("kgdb : Cpu_logged in: 0 = %d, 1 = %d\n",
+				       cpu_logged_in[0], cpu_logged_in[1]);
+				printk
+				    ("kgdb : in_kgdb_here_log in: 0 = %d, 1 = %d\n",
+				     in_kgdb_here_log[0] != 0,
+				     in_kgdb_here_log[1] != 0);
+#endif
+				entry_state = NO_SYNC;
+			} else {
+#if 0
+				int ent =
+				    in_kgdb_entry_log[smp_processor_id()] -
+				    me_in_kgdb;
+				printk("kgdb : sync after %d entries\n", ent);
+#endif
+			}
+		} else {
+			if (remote_debug) {
+				printk
+				    ("kgdb : %d cpus, but watchdog not active\n"
+				     "proceeding without locking down other cpus\n",
+				     num_online_cpus());
+				entry_state = NO_NMI;
+			}
+		}
+	}
+#endif
+
+	if (remote_debug) {
+		unsigned long *lp = (unsigned long *) &linux_regs;
+
+		printk("handle_exception(exceptionVector=%d, "
+		       "signo=%d, err_code=%d, linux_regs=%p)\n",
+		       exceptionVector, signo, err_code, linux_regs);
+		if (debug_regs) {
+			print_regs(&regs);
+			printk("Stk: %8lx %8lx %8lx %8lx"
+			       "  %8lx %8lx %8lx %8lx\n",
+			       lp[0], lp[1], lp[2], lp[3],
+			       lp[4], lp[5], lp[6], lp[7]);
+			printk("     %8lx %8lx %8lx %8lx"
+			       "  %8lx %8lx %8lx %8lx\n",
+			       lp[8], lp[9], lp[10], lp[11],
+			       lp[12], lp[13], lp[14], lp[15]);
+			printk("     %8lx %8lx %8lx %8lx  "
+			       "%8lx %8lx %8lx %8lx\n",
+			       lp[16], lp[17], lp[18], lp[19],
+			       lp[20], lp[21], lp[22], lp[23]);
+			printk("     %8lx %8lx %8lx %8lx  "
+			       "%8lx %8lx %8lx %8lx\n",
+			       lp[24], lp[25], lp[26], lp[27],
+			       lp[28], lp[29], lp[30], lp[31]);
+		}
+	}
+
+	/* Disable hardware debugging while we are in kgdb */
+	/* Get the debug register status register */
+/*				       *INDENT-OFF*  */
+      __asm__("movl %0,%%db7"
+	      :	/* no output */
+	      :"r"(0));
+
+	asm volatile ("movl %%db6, %0\n"
+		      :"=r" (hw_breakpoint_status)
+		      :);
+
+/*				       *INDENT-ON*  */
+	switch (exceptionVector) {
+	case 0:		/* divide error */
+	case 1:		/* debug exception */
+	case 2:		/* NMI */
+	case 3:		/* breakpoint */
+	case 4:		/* overflow */
+	case 5:		/* bounds check */
+	case 6:		/* invalid opcode */
+	case 7:		/* device not available */
+	case 8:		/* double fault (errcode) */
+	case 10:		/* invalid TSS (errcode) */
+	case 12:		/* stack fault (errcode) */
+	case 16:		/* floating point error */
+	case 17:		/* alignment check (errcode) */
+	default:		/* any undocumented */
+		break;
+	case 11:		/* segment not present (errcode) */
+	case 13:		/* general protection (errcode) */
+	case 14:		/* page fault (special errcode) */
+	case 19:		/* cache flush denied */
+		if (mem_err_expected) {
+			/*
+			 * This fault occured because of the
+			 * get_char or set_char routines.  These
+			 * two routines use either eax of edx to
+			 * indirectly reference the location in
+			 * memory that they are working with.
+			 * For a page fault, when we return the
+			 * instruction will be retried, so we
+			 * have to make sure that these
+			 * registers point to valid memory.
+			 */
+			mem_err = 1;	/* set mem error flag */
+			mem_err_expected = 0;
+			mem_err_cnt++;	/* helps in debugging */
+			/* make valid address */
+			regs.eax = (long) &garbage_loc;
+			/* make valid address */
+			regs.edx = (long) &garbage_loc;
+			if (remote_debug)
+				printk("Return after memory error: "
+				       "mem_err_cnt=%d\n", mem_err_cnt);
+			if (debug_regs)
+				print_regs(&regs);
+			goto exit_kgdb;
+		}
+		break;
+	}
+	if (remote_debug)
+		printk("kgdb : entered kgdb on cpu %d\n", smp_processor_id());
+
+	gdb_i386vector = exceptionVector;
+	gdb_i386errcode = err_code;
+	kgdb_info.called_from = __builtin_return_address(0);
+#ifdef CONFIG_SMP
+	/*
+	 * OK, we can now communicate, lets tell gdb about the sync.
+	 * but only if we had a problem.
+	 */
+	switch (entry_state) {
+	case NO_NMI:
+		to_gdb("NMI not active, other cpus not stopped\n");
+		break;
+	case NO_SYNC:
+		to_gdb("Some cpus not stopped, see 'kgdb_info' for details\n");
+	default:;
+	}
+
+#endif
+/*
+ * Set up the gdb function call area.
+ */
+	trap_cpu = smp_processor_id();
+	OLD_esp = NEW_esp = (int) (&linux_regs->esp);
+
+      IF_SMP(once_again:)
+	    /* reply to host that an exception has occurred */
+	    remcomOutBuffer[0] = 'S';
+	remcomOutBuffer[1] = hexchars[signo >> 4];
+	remcomOutBuffer[2] = hexchars[signo % 16];
+	remcomOutBuffer[3] = 0;
+
+	putpacket(remcomOutBuffer);
+
+	while (1 == 1) {
+		error = 0;
+		remcomOutBuffer[0] = 0;
+		getpacket(remcomInBuffer);
+		switch (remcomInBuffer[0]) {
+		case '?':
+			remcomOutBuffer[0] = 'S';
+			remcomOutBuffer[1] = hexchars[signo >> 4];
+			remcomOutBuffer[2] = hexchars[signo % 16];
+			remcomOutBuffer[3] = 0;
+			break;
+		case 'd':
+			remote_debug = !(remote_debug);	/* toggle debug flag */
+			printk("Remote debug %s\n",
+			       remote_debug ? "on" : "off");
+			break;
+		case 'g':	/* return the value of the CPU registers */
+			get_gdb_regs(usethread, &regs, gdb_regs);
+			mem2hex((char *) gdb_regs,
+				remcomOutBuffer, NUMREGBYTES, 0);
+			break;
+		case 'G':	/* set the value of the CPU registers - return OK */
+			hex2mem(&remcomInBuffer[1],
+				(char *) gdb_regs, NUMREGBYTES, 0);
+			if (!usethread || usethread == current) {
+				gdb_regs_to_regs(gdb_regs, &regs);
+				strcpy(remcomOutBuffer, "OK");
+			} else {
+				strcpy(remcomOutBuffer, "E00");
+			}
+			break;
+
+		case 'P':{	/* set the value of a single CPU register -
+				   return OK */
+				/*
+				 * For some reason, gdb wants to talk about psudo
+				 * registers (greater than 15).	 These may have
+				 * meaning for ptrace, but for us it is safe to
+				 * ignor them.	We do this by dumping them into
+				 * _GS which we also ignor, but do have memory for.
+				 */
+				int regno;
+
+				ptr = &remcomInBuffer[1];
+				regs_to_gdb_regs(gdb_regs, &regs);
+				if ((!usethread || usethread == current) &&
+				    hexToInt(&ptr, &regno) &&
+				    *ptr++ == '=' && (regno >= 0)) {
+					regno =
+					    (regno >= NUMREGS ? _GS : regno);
+					hex2mem(ptr, (char *) &gdb_regs[regno],
+						4, 0);
+					gdb_regs_to_regs(gdb_regs, &regs);
+					strcpy(remcomOutBuffer, "OK");
+					break;
+				}
+				strcpy(remcomOutBuffer, "E01");
+				break;
+			}
+
+			/* mAA..AA,LLLL	 Read LLLL bytes at address AA..AA */
+		case 'm':
+			/* TRY TO READ %x,%x.  IF SUCCEED, SET PTR = 0 */
+			ptr = &remcomInBuffer[1];
+			if (hexToInt(&ptr, &addr) &&
+			    (*(ptr++) == ',') && (hexToInt(&ptr, &length))) {
+				ptr = 0;
+				/*
+				 * hex doubles the byte count
+				 */
+				if (length > (BUFMAX / 2))
+					length = BUFMAX / 2;
+				mem2hex((char *) addr,
+					remcomOutBuffer, length, 1);
+				if (mem_err) {
+					strcpy(remcomOutBuffer, "E03");
+					debug_error("memory fault\n", NULL);
+				}
+			}
+
+			if (ptr) {
+				strcpy(remcomOutBuffer, "E01");
+				debug_error
+				    ("malformed read memory command: %s\n",
+				     remcomInBuffer);
+			}
+			break;
+
+			/* MAA..AA,LLLL:
+			   Write LLLL bytes at address AA.AA return OK */
+		case 'M':
+			/* TRY TO READ '%x,%x:'.  IF SUCCEED, SET PTR = 0 */
+			ptr = &remcomInBuffer[1];
+			if (hexToInt(&ptr, &addr) &&
+			    (*(ptr++) == ',') &&
+			    (hexToInt(&ptr, &length)) && (*(ptr++) == ':')) {
+				hex2mem(ptr, (char *) addr, length, 1);
+
+				if (mem_err) {
+					strcpy(remcomOutBuffer, "E03");
+					debug_error("memory fault\n", NULL);
+				} else {
+					strcpy(remcomOutBuffer, "OK");
+				}
+
+				ptr = 0;
+			}
+			if (ptr) {
+				strcpy(remcomOutBuffer, "E02");
+				debug_error
+				    ("malformed write memory command: %s\n",
+				     remcomInBuffer);
+			}
+			break;
+		case 'S':
+			remcomInBuffer[0] = 's';
+		case 'C':
+			/* Csig;AA..AA where ;AA..AA is optional
+			 * continue with signal
+			 * Since signals are meaning less to us, delete that
+			 * part and then fall into the 'c' code.
+			 */
+			ptr = &remcomInBuffer[1];
+			length = 2;
+			while (*ptr && *ptr != ';') {
+				length++;
+				ptr++;
+			}
+			if (*ptr) {
+				do {
+					ptr++;
+					*(ptr - length++) = *ptr;
+				} while (*ptr);
+			} else {
+				remcomInBuffer[1] = 0;
+			}
+
+			/* cAA..AA  Continue at address AA..AA(optional) */
+			/* sAA..AA  Step one instruction from AA..AA(optional) */
+			/* D	    detach, reply OK and then continue */
+		case 'c':
+		case 's':
+		case 'D':
+
+			/* try to read optional parameter,
+			   pc unchanged if no parm */
+			ptr = &remcomInBuffer[1];
+			if (hexToInt(&ptr, &addr)) {
+				if (remote_debug)
+					printk("Changing EIP to 0x%x\n", addr);
+
+				regs.eip = addr;
+			}
+
+			newPC = regs.eip;
+
+			/* clear the trace bit */
+			regs.eflags &= 0xfffffeff;
+
+			/* set the trace bit if we're stepping */
+			if (remcomInBuffer[0] == 's')
+				regs.eflags |= 0x100;
+
+			/* detach is a friendly version of continue. Note that
+			   debugging is still enabled (e.g hit control C)
+			 */
+			if (remcomInBuffer[0] == 'D') {
+				strcpy(remcomOutBuffer, "OK");
+				putpacket(remcomOutBuffer);
+			}
+
+			if (remote_debug) {
+				printk("Resuming execution\n");
+				print_regs(&regs);
+			}
+			asm volatile ("movl %%db6, %0\n":"=r" (dr6)
+				      :);
+			if (!(dr6 & 0x4000)) {
+				for (breakno = 0; breakno < 4; ++breakno) {
+					if (dr6 & (1 << breakno) &&
+					    (breakinfo[breakno].type == 0)) {
+						/* Set restore flag */
+						regs.eflags |= 0x10000;
+						break;
+					}
+				}
+			}
+
+			if (kgdboe)
+				netpoll_set_trap(0);
+
+			correct_hw_break();
+			asm volatile ("movl %0, %%db6\n"::"r" (0));
+			goto exit_kgdb;
+
+			/* kill the program */
+		case 'k':	/* do nothing */
+			break;
+
+			/* query */
+		case 'q':
+			nothreads = 0;
+			switch (remcomInBuffer[1]) {
+			case 'f':
+				threadid = 1;
+				thread_list = 2;
+				thread_list_start = (usethread ? : current);
+			case 's':
+				if (!cmp_str(&remcomInBuffer[2],
+					     "ThreadInfo", 10))
+					break;
+
+				remcomOutBuffer[nothreads++] = 'm';
+				for (; threadid < PID_MAX + MAX_NO_CPUS;
+				     threadid++) {
+					thread = getthread(threadid);
+					if (thread) {
+						nothreads += int_to_hex_v(
+							&remcomOutBuffer[
+								nothreads],
+							threadid);
+						if (thread_min > threadid)
+							thread_min = threadid;
+						remcomOutBuffer[
+							nothreads] = ',';
+						nothreads++;
+						if (nothreads > BUFMAX - 10)
+							break;
+					}
+				}
+				if (remcomOutBuffer[nothreads - 1] == 'm') {
+					remcomOutBuffer[nothreads - 1] = 'l';
+				} else {
+					nothreads--;
+				}
+				remcomOutBuffer[nothreads] = 0;
+				break;
+
+#ifdef old_thread_list /* Old thread info request */
+			case 'L':
+				/* List threads */
+				thread_list = 2;
+				thread_list_start = (usethread ? : current);
+				unpack_byte(remcomInBuffer + 3, &maxthreads);
+				unpack_threadid(remcomInBuffer + 5, &thref);
+				do {
+					int buf_thread_limit =
+					    (BUFMAX - 22) / BUF_THREAD_ID_SIZE;
+					if (maxthreads > buf_thread_limit) {
+						maxthreads = buf_thread_limit;
+					}
+				} while (0);
+				remcomOutBuffer[0] = 'q';
+				remcomOutBuffer[1] = 'M';
+				remcomOutBuffer[4] = '0';
+				pack_threadid(remcomOutBuffer + 5, &thref);
+
+				threadid = threadref_to_int(&thref);
+				for (nothreads = 0;
+				     nothreads < maxthreads &&
+				     threadid < PID_MAX + MAX_NO_CPUS;
+				     threadid++) {
+					thread = getthread(threadid);
+					if (thread) {
+						int_to_threadref(&thref,
+								 threadid);
+						pack_threadid(remcomOutBuffer +
+							      21 +
+							      nothreads * 16,
+							      &thref);
+						nothreads++;
+						if (thread_min > threadid)
+							thread_min = threadid;
+					}
+				}
+
+				if (threadid == PID_MAX + MAX_NO_CPUS) {
+					remcomOutBuffer[4] = '1';
+				}
+				pack_hex_byte(remcomOutBuffer + 2, nothreads);
+				remcomOutBuffer[21 + nothreads * 16] = '\0';
+				break;
+#endif
+			case 'C':
+				/* Current thread id */
+				remcomOutBuffer[0] = 'Q';
+				remcomOutBuffer[1] = 'C';
+				threadid = current->pid;
+				if (!threadid) {
+					/*
+					 * idle thread
+					 */
+					for (threadid = PID_MAX;
+					     threadid < PID_MAX + MAX_NO_CPUS;
+					     threadid++) {
+						if (current ==
+						    idle_task(threadid -
+							      PID_MAX))
+							break;
+					}
+				}
+				int_to_threadref(&thref, threadid);
+				pack_threadid(remcomOutBuffer + 2, &thref);
+				remcomOutBuffer[18] = '\0';
+				break;
+
+			case 'E':
+				/* Print exception info */
+				printexceptioninfo(exceptionVector,
+						   err_code, remcomOutBuffer);
+				break;
+			case 'T':{
+				char * nptr;
+				/* Thread extra info */
+				if (!cmp_str(&remcomInBuffer[2],
+					    "hreadExtraInfo,", 15)) {
+					break;
+				}
+				ptr = &remcomInBuffer[17];
+				hexToInt(&ptr, &threadid);
+				thread = getthread(threadid);
+				nptr = &thread->comm[0];
+				length = 0;
+				ptr = &remcomOutBuffer[0];
+				do {
+					length++;
+					ptr = pack_hex_byte(ptr, *nptr++);
+				 } while (*nptr && length < 16);
+				/*
+				 * would like that 16 to be the size of
+				 * task_struct.comm but don't know the
+				 * syntax..
+				 */
+				*ptr = 0;
+			}
+			}
+			break;
+
+			/* task related */
+		case 'H':
+			switch (remcomInBuffer[1]) {
+			case 'g':
+				ptr = &remcomInBuffer[2];
+				hexToInt(&ptr, &threadid);
+				thread = getthread(threadid);
+				if (!thread) {
+					remcomOutBuffer[0] = 'E';
+					remcomOutBuffer[1] = '\0';
+					break;
+				}
+				/*
+				 * Just in case I forget what this is all about,
+				 * the "thread info" command to gdb causes it
+				 * to ask for a thread list.  It then switches
+				 * to each thread and asks for the registers.
+				 * For this (and only this) usage, we want to
+				 * fudge the registers of tasks not on the run
+				 * list (i.e. waiting) to show the routine that
+				 * called schedule. Also, gdb, is a minimalist
+				 * in that if the current thread is the last
+				 * it will not re-read the info when done.
+				 * This means that in this case we must show
+				 * the real registers. So here is how we do it:
+				 * Each entry we keep track of the min
+				 * thread in the list (the last that gdb will)
+				 * get info for.  We also keep track of the
+				 * starting thread.
+				 * "thread_list" is cleared when switching back
+				 * to the min thread if it is was current, or
+				 * if it was not current, thread_list is set
+				 * to 1.  When the switch to current comes,
+				 * if thread_list is 1, clear it, else do
+				 * nothing.
+				 */
+				usethread = thread;
+				if ((thread_list == 1) &&
+				    (thread == thread_list_start)) {
+					thread_list = 0;
+				}
+				if (thread_list && (threadid == thread_min)) {
+					if (thread == thread_list_start) {
+						thread_list = 0;
+					} else {
+						thread_list = 1;
+					}
+				}
+				/* follow through */
+			case 'c':
+				remcomOutBuffer[0] = 'O';
+				remcomOutBuffer[1] = 'K';
+				remcomOutBuffer[2] = '\0';
+				break;
+			}
+			break;
+
+			/* Query thread status */
+		case 'T':
+			ptr = &remcomInBuffer[1];
+			hexToInt(&ptr, &threadid);
+			thread = getthread(threadid);
+			if (thread) {
+				remcomOutBuffer[0] = 'O';
+				remcomOutBuffer[1] = 'K';
+				remcomOutBuffer[2] = '\0';
+				if (thread_min > threadid)
+					thread_min = threadid;
+			} else {
+				remcomOutBuffer[0] = 'E';
+				remcomOutBuffer[1] = '\0';
+			}
+			break;
+
+		case 'Y': /* set up a hardware breakpoint */
+			ptr = &remcomInBuffer[1];
+			hexToInt(&ptr, &breakno);
+			ptr++;
+			hexToInt(&ptr, &breaktype);
+			ptr++;
+			hexToInt(&ptr, &length);
+			ptr++;
+			hexToInt(&ptr, &addr);
+			if (set_hw_break(breakno & 0x3,
+					 breaktype & 0x3,
+					 length & 0x3, addr) == 0) {
+				strcpy(remcomOutBuffer, "OK");
+			} else {
+				strcpy(remcomOutBuffer, "ERROR");
+			}
+			break;
+
+			/* Remove hardware breakpoint */
+		case 'y':
+			ptr = &remcomInBuffer[1];
+			hexToInt(&ptr, &breakno);
+			if (remove_hw_break(breakno & 0x3) == 0) {
+				strcpy(remcomOutBuffer, "OK");
+			} else {
+				strcpy(remcomOutBuffer, "ERROR");
+			}
+			break;
+
+		case 'r':	/* reboot */
+			strcpy(remcomOutBuffer, "OK");
+			putpacket(remcomOutBuffer);
+			/*to_gdb("Rebooting\n"); */
+			/* triplefault	 no return from here */
+			{
+				static long no_idt[2];
+				__asm__ __volatile__("lidt %0"::"m"(no_idt[0]));
+				BREAKPOINT;
+			}
+
+		}		/* switch */
+
+		/* reply to the request */
+		putpacket(remcomOutBuffer);
+	}			/* while(1==1) */
+	/*
+	 *  reached by goto only.
+	 */
+      exit_kgdb:
+	/*
+	 * Here is where we set up to trap a gdb function call.	 NEW_esp
+	 * will be changed if we are trying to do this.	 We handle both
+	 * adding and subtracting, thus allowing gdb to put grung on
+	 * the stack which it removes later.
+	 */
+	if (NEW_esp != OLD_esp) {
+		int *ptr = END_OF_LOOKASIDE;
+		if (NEW_esp < OLD_esp)
+			ptr -= (OLD_esp - NEW_esp) / sizeof (int);
+		*--ptr = linux_regs->eflags;
+		*--ptr = linux_regs->xcs;
+		*--ptr = linux_regs->eip;
+		*--ptr = linux_regs->ecx;
+		*--ptr = linux_regs->ebx;
+		*--ptr = linux_regs->eax;
+		linux_regs->ecx = NEW_esp - (sizeof (int) * 6);
+		linux_regs->ebx = (unsigned int) END_OF_LOOKASIDE;
+		if (NEW_esp < OLD_esp) {
+			linux_regs->eip = (unsigned int) fn_call_stub;
+		} else {
+			linux_regs->eip = (unsigned int) fn_rtn_stub;
+			linux_regs->eax = NEW_esp;
+		}
+		linux_regs->eflags &= ~(IF_BIT | TF_BIT);
+	}
+#ifdef CONFIG_SMP
+	/*
+	 * Release gdb wait locks
+	 * Sanity check time.  Must have at least one cpu to run.  Also single
+	 * step must not be done if the current cpu is on hold.
+	 */
+	if (spinlock_count == 1) {
+		int ss_hold = (regs.eflags & 0x100) && kgdb_info.hold_on_sstep;
+		int cpu_avail = 0;
+		int i;
+
+		for (i = 0; i < MAX_NO_CPUS; i++) {
+			if (!cpu_online(i))
+				break;
+			if (!hold_cpu(i)) {
+				cpu_avail = 1;
+			}
+		}
+		/*
+		 * Early in the bring up there will be NO cpus on line...
+		 */
+		if (!cpu_avail && !cpus_empty(cpu_online_map)) {
+			to_gdb("No cpus unblocked, see 'kgdb_info.hold_cpu'\n");
+			goto once_again;
+		}
+		if (hold_cpu(smp_processor_id()) && (regs.eflags & 0x100)) {
+			to_gdb
+			    ("Current cpu must be unblocked to single step\n");
+			goto once_again;
+		}
+		if (!(ss_hold)) {
+			int i;
+			for (i = 0; i < MAX_NO_CPUS; i++) {
+				if (!hold_cpu(i)) {
+					spin_unlock(&waitlocks[i]);
+				}
+			}
+		} else {
+			spin_unlock(&waitlocks[smp_processor_id()]);
+		}
+		/* Release kgdb spinlock */
+		KGDB_SPIN_UNLOCK(&kgdb_spinlock);
+		/*
+		 * If this cpu is on hold, this is where we
+		 * do it.  Note, the NMI will pull us out of here,
+		 * but will return as the above lock is not held.
+		 * We will stay here till another cpu releases the lock for us.
+		 */
+		spin_unlock_wait(waitlocks + smp_processor_id());
+		kgdb_local_irq_restore(flags);
+		return (0);
+	}
+#if 0
+exit_just_unlock:
+#endif
+#endif
+	/* Release kgdb spinlock */
+	KGDB_SPIN_UNLOCK(&kgdb_spinlock);
+	kgdb_local_irq_restore(flags);
+	return (0);
+}
+
+/* this function is used to set up exception handlers for tracing and
+ * breakpoints.
+ * This function is not needed as the above line does all that is needed.
+ * We leave it for backward compatitability...
+ */
+void
+set_debug_traps(void)
+{
+	/*
+	 * linux_debug_hook is defined in traps.c.  We store a pointer
+	 * to our own exception handler into it.
+
+	 * But really folks, every hear of labeled common, an old Fortran
+	 * concept.  Lots of folks can reference it and it is define if
+	 * anyone does.	 Only one can initialize it at link time.  We do
+	 * this with the hook.	See the statement above.  No need for any
+	 * executable code and it is ready as soon as the kernel is
+	 * loaded.  Very desirable in kernel debugging.
+
+	 linux_debug_hook = handle_exception ;
+	 */
+
+	/* In case GDB is started before us, ack any packets (presumably
+	   "$?#xx") sitting there.
+	   putDebugChar ('+');
+
+	   initialized = 1;
+	 */
+}
+
+/* This function will generate a breakpoint exception.	It is used at the
+   beginning of a program to sync up with a debugger and can be used
+   otherwise as a quick means to stop program execution and "break" into
+   the debugger. */
+/* But really, just use the BREAKPOINT macro.  We will handle the int stuff
+ */
+
+#ifdef later
+/*
+ * possibly we should not go thru the traps.c code at all?  Someday.
+ */
+void
+do_kgdb_int3(struct pt_regs *regs, long error_code)
+{
+	kgdb_handle_exception(3, 5, error_code, regs);
+	return;
+}
+#endif
+#undef regs
+#ifdef CONFIG_TRAP_BAD_SYSCALL_EXITS
+asmlinkage void
+bad_sys_call_exit(int stuff)
+{
+	struct pt_regs *regs = (struct pt_regs *) &stuff;
+	printk("Sys call %d return with %x preempt_count\n",
+	       (int) regs->orig_eax, preempt_count());
+}
+#endif
+#ifdef CONFIG_STACK_OVERFLOW_TEST
+#include <asm/kgdb.h>
+asmlinkage void
+stack_overflow(void)
+{
+#ifdef BREAKPOINT
+	BREAKPOINT;
+#else
+	printk("Kernel stack overflow, looping forever\n");
+#endif
+	while (1) {
+	}
+}
+#endif
+
+#if defined(CONFIG_SMP) || defined(CONFIG_KGDB_CONSOLE)
+char gdbconbuf[BUFMAX];
+
+static void
+kgdb_gdb_message(const char *s, unsigned count)
+{
+	int i;
+	int wcount;
+	char *bufptr;
+	/*
+	 * This takes care of NMI while spining out chars to gdb
+	 */
+	IF_SMP(in_kgdb_console = 1);
+	gdbconbuf[0] = 'O';
+	bufptr = gdbconbuf + 1;
+	while (count > 0) {
+		if ((count << 1) > (BUFMAX - 2)) {
+			wcount = (BUFMAX - 2) >> 1;
+		} else {
+			wcount = count;
+		}
+		count -= wcount;
+		for (i = 0; i < wcount; i++) {
+			bufptr = pack_hex_byte(bufptr, s[i]);
+		}
+		*bufptr = '\0';
+		s += wcount;
+
+		putpacket(gdbconbuf);
+
+	}
+	IF_SMP(in_kgdb_console = 0);
+}
+#endif
+#ifdef CONFIG_SMP
+static void
+to_gdb(const char *s)
+{
+	int count = 0;
+	while (s[count] && (count++ < BUFMAX)) ;
+	kgdb_gdb_message(s, count);
+}
+#endif
+#ifdef CONFIG_KGDB_CONSOLE
+#include <linux/console.h>
+#include <linux/init.h>
+#include <linux/fs.h>
+#include <asm/uaccess.h>
+#include <asm/semaphore.h>
+
+void
+kgdb_console_write(struct console *co, const char *s, unsigned count)
+{
+
+	if (gdb_i386vector == -1) {
+		/*
+		 * We have not yet talked to gdb.  What to do...
+		 * lets break, on continue we can do the write.
+		 * But first tell him whats up. Uh, well no can do,
+		 * as this IS the console.  Oh well...
+		 * We do need to wait or the messages will be lost.
+		 * Other option would be to tell the above code to
+		 * ignore this breakpoint and do an auto return,
+		 * but that might confuse gdb.	Also this happens
+		 * early enough in boot up that we don't have the traps
+		 * set up yet, so...
+		 */
+		breakpoint();
+	}
+	kgdb_gdb_message(s, count);
+}
+
+/*
+ * ------------------------------------------------------------
+ * Serial KGDB driver
+ * ------------------------------------------------------------
+ */
+
+static struct console kgdbcons = {
+	name:"kgdb",
+	write:kgdb_console_write,
+#ifdef CONFIG_KGDB_USER_CONSOLE
+	device:kgdb_console_device,
+#endif
+	flags:CON_PRINTBUFFER | CON_ENABLED,
+	index:-1,
+};
+
+/*
+ * The trick here is that this file gets linked before printk.o
+ * That means we get to peer at the console info in the command
+ * line before it does.	 If we are up, we register, otherwise,
+ * do nothing.	By returning 0, we allow printk to look also.
+ */
+static int kgdb_console_enabled;
+
+int __init
+kgdb_console_init(char *str)
+{
+	if ((strncmp(str, "kgdb", 4) == 0) || (strncmp(str, "gdb", 3) == 0)) {
+		register_console(&kgdbcons);
+		kgdb_console_enabled = 1;
+	}
+	return 0;		/* let others look at the string */
+}
+
+__setup("console=", kgdb_console_init);
+
+#ifdef CONFIG_KGDB_USER_CONSOLE
+static kdev_t kgdb_console_device(struct console *c);
+/* This stuff sort of works, but it knocks out telnet devices
+ * we are leaving it here in case we (or you) find time to figure it out
+ * better..
+ */
+
+/*
+ * We need a real char device as well for when the console is opened for user
+ * space activities.
+ */
+
+static int
+kgdb_consdev_open(struct inode *inode, struct file *file)
+{
+	return 0;
+}
+
+static ssize_t
+kgdb_consdev_write(struct file *file, const char *buf,
+		   size_t count, loff_t * ppos)
+{
+	int size, ret = 0;
+	static char kbuf[128];
+	static DECLARE_MUTEX(sem);
+
+	/* We are not reentrant... */
+	if (down_interruptible(&sem))
+		return -ERESTARTSYS;
+
+	while (count > 0) {
+		/* need to copy the data from user space */
+		size = count;
+		if (size > sizeof (kbuf))
+			size = sizeof (kbuf);
+		if (copy_from_user(kbuf, buf, size)) {
+			ret = -EFAULT;
+			break;;
+		}
+		kgdb_console_write(&kgdbcons, kbuf, size);
+		count -= size;
+		ret += size;
+		buf += size;
+	}
+
+	up(&sem);
+
+	return ret;
+}
+
+struct file_operations kgdb_consdev_fops = {
+	open:kgdb_consdev_open,
+	write:kgdb_consdev_write
+};
+static kdev_t
+kgdb_console_device(struct console *c)
+{
+	return MKDEV(TTYAUX_MAJOR, 1);
+}
+
+/*
+ * This routine gets called from the serial stub in the i386/lib
+ * This is so it is done late in bring up (just before the console open).
+ */
+void
+kgdb_console_finit(void)
+{
+	if (kgdb_console_enabled) {
+		char *cptr = cdevname(MKDEV(TTYAUX_MAJOR, 1));
+		char *cp = cptr;
+		while (*cptr && *cptr != '(')
+			cptr++;
+		*cptr = 0;
+		unregister_chrdev(TTYAUX_MAJOR, cp);
+		register_chrdev(TTYAUX_MAJOR, "kgdb", &kgdb_consdev_fops);
+	}
+}
+#endif
+#endif
+#ifdef CONFIG_KGDB_TS
+#include <asm/msr.h>		/* time stamp code */
+#include <asm/hardirq.h>	/* in_interrupt */
+#ifdef CONFIG_KGDB_TS_64
+#define DATA_POINTS 64
+#endif
+#ifdef CONFIG_KGDB_TS_128
+#define DATA_POINTS 128
+#endif
+#ifdef CONFIG_KGDB_TS_256
+#define DATA_POINTS 256
+#endif
+#ifdef CONFIG_KGDB_TS_512
+#define DATA_POINTS 512
+#endif
+#ifdef CONFIG_KGDB_TS_1024
+#define DATA_POINTS 1024
+#endif
+#ifndef DATA_POINTS
+#define DATA_POINTS 128		/* must be a power of two */
+#endif
+#define INDEX_MASK (DATA_POINTS - 1)
+#if (INDEX_MASK & DATA_POINTS)
+#error "CONFIG_KGDB_TS_COUNT must be a power of 2"
+#endif
+struct kgdb_and_then_struct {
+#ifdef CONFIG_SMP
+	int on_cpu;
+#endif
+	struct task_struct *task;
+	long long at_time;
+	int from_ln;
+	char *in_src;
+	void *from;
+	int *with_shpf;
+	int data0;
+	int data1;
+};
+struct kgdb_and_then_struct2 {
+#ifdef CONFIG_SMP
+	int on_cpu;
+#endif
+	struct task_struct *task;
+	long long at_time;
+	int from_ln;
+	char *in_src;
+	void *from;
+	int *with_shpf;
+	struct task_struct *t1;
+	struct task_struct *t2;
+};
+struct kgdb_and_then_struct kgdb_data[DATA_POINTS];
+
+struct kgdb_and_then_struct *kgdb_and_then = &kgdb_data[0];
+int kgdb_and_then_count;
+
+void
+kgdb_tstamp(int line, char *source, int data0, int data1)
+{
+	static spinlock_t ts_spin = SPIN_LOCK_UNLOCKED;
+	int flags;
+	kgdb_local_irq_save(flags);
+	spin_lock(&ts_spin);
+	rdtscll(kgdb_and_then->at_time);
+#ifdef CONFIG_SMP
+	kgdb_and_then->on_cpu = smp_processor_id();
+#endif
+	kgdb_and_then->task = current;
+	kgdb_and_then->from_ln = line;
+	kgdb_and_then->in_src = source;
+	kgdb_and_then->from = __builtin_return_address(0);
+	kgdb_and_then->with_shpf = (int *) (((flags & IF_BIT) >> 9) |
+					    (preempt_count() << 8));
+	kgdb_and_then->data0 = data0;
+	kgdb_and_then->data1 = data1;
+	kgdb_and_then = &kgdb_data[++kgdb_and_then_count & INDEX_MASK];
+	spin_unlock(&ts_spin);
+	kgdb_local_irq_restore(flags);
+#ifdef CONFIG_PREEMPT
+
+#endif
+	return;
+}
+#endif
+typedef int gdb_debug_hook(int exceptionVector,
+			   int signo, int err_code, struct pt_regs *linux_regs);
+gdb_debug_hook *linux_debug_hook = &kgdb_handle_exception;	/* histerical reasons... */
+
+static int kgdb_need_breakpoint[NR_CPUS];
+
+void kgdb_schedule_breakpoint(void)
+{
+	kgdb_need_breakpoint[smp_processor_id()] = 1;
+}
+
+void kgdb_process_breakpoint(void)
+{
+	/*
+	 * Handle a breakpoint queued from inside network driver code
+         * to avoid reentrancy issues
+	 */
+	if (kgdb_need_breakpoint[smp_processor_id()]) {
+		kgdb_need_breakpoint[smp_processor_id()] = 0;
+		BREAKPOINT;
+	}
+}
+
--- diff/arch/i386/lib/bitops.c	1970-01-01 01:00:00.000000000 +0100
+++ source/arch/i386/lib/bitops.c	2004-06-11 19:21:57.000000000 +0100
@@ -0,0 +1,70 @@
+#include <linux/bitops.h>
+#include <linux/module.h>
+
+/**
+ * find_next_bit - find the first set bit in a memory region
+ * @addr: The address to base the search on
+ * @offset: The bitnumber to start searching at
+ * @size: The maximum size to search
+ */
+int find_next_bit(const unsigned long *addr, int size, int offset)
+{
+	const unsigned long *p = addr + (offset >> 5);
+	int set = 0, bit = offset & 31, res;
+
+	if (bit) {
+		/*
+		 * Look for nonzero in the first 32 bits:
+		 */
+		__asm__("bsfl %1,%0\n\t"
+			"jne 1f\n\t"
+			"movl $32, %0\n"
+			"1:"
+			: "=r" (set)
+			: "r" (*p >> bit));
+		if (set < (32 - bit))
+			return set + offset;
+		set = 32 - bit;
+		p++;
+	}
+	/*
+	 * No set bit yet, search remaining full words for a bit
+	 */
+	res = find_first_bit (p, size - 32 * (p - addr));
+	return (offset + set + res);
+}
+EXPORT_SYMBOL(find_next_bit);
+
+/**
+ * find_next_zero_bit - find the first zero bit in a memory region
+ * @addr: The address to base the search on
+ * @offset: The bitnumber to start searching at
+ * @size: The maximum size to search
+ */
+int find_next_zero_bit(const unsigned long *addr, int size, int offset)
+{
+	unsigned long * p = ((unsigned long *) addr) + (offset >> 5);
+	int set = 0, bit = offset & 31, res;
+
+	if (bit) {
+		/*
+		 * Look for zero in the first 32 bits.
+		 */
+		__asm__("bsfl %1,%0\n\t"
+			"jne 1f\n\t"
+			"movl $32, %0\n"
+			"1:"
+			: "=r" (set)
+			: "r" (~(*p >> bit)));
+		if (set < (32 - bit))
+			return set + offset;
+		set = 32 - bit;
+		p++;
+	}
+	/*
+	 * No zero yet, search remaining full bytes for a zero
+	 */
+	res = find_first_zero_bit (p, size - 32 * (p - (unsigned long *) addr));
+	return (offset + set + res);
+}
+EXPORT_SYMBOL(find_next_zero_bit);
--- diff/arch/i386/lib/kgdb_serial.c	1970-01-01 01:00:00.000000000 +0100
+++ source/arch/i386/lib/kgdb_serial.c	2004-06-11 19:21:57.000000000 +0100
@@ -0,0 +1,499 @@
+/*
+ * Serial interface GDB stub
+ *
+ * Written (hacked together) by David Grothe (dave@gcom.com)
+ * Modified to allow invokation early in boot see also
+ * kgdb.h for instructions by George Anzinger(george@mvista.com)
+ * Modified to handle debugging over ethernet by Robert Walsh
+ * <rjwalsh@durables.org> and wangdi <wangdi@clusterfs.com>, based on
+ * code by San Mehat.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/errno.h>
+#include <linux/signal.h>
+#include <linux/sched.h>
+#include <linux/timer.h>
+#include <linux/interrupt.h>
+#include <linux/tty.h>
+#include <linux/tty_flip.h>
+#include <linux/serial.h>
+#include <linux/serial_reg.h>
+#include <linux/config.h>
+#include <linux/major.h>
+#include <linux/string.h>
+#include <linux/fcntl.h>
+#include <linux/ptrace.h>
+#include <linux/ioport.h>
+#include <linux/mm.h>
+#include <linux/init.h>
+#include <linux/highmem.h>
+#include <asm/system.h>
+#include <asm/io.h>
+#include <asm/segment.h>
+#include <asm/bitops.h>
+#include <asm/system.h>
+#include <asm/kgdb_local.h>
+#ifdef CONFIG_KGDB_USER_CONSOLE
+extern void kgdb_console_finit(void);
+#endif
+#define PRNT_off
+#define TEST_EXISTANCE
+#ifdef PRNT
+#define dbprintk(s) printk s
+#else
+#define dbprintk(s)
+#endif
+#define TEST_INTERRUPT_off
+#ifdef TEST_INTERRUPT
+#define intprintk(s) printk s
+#else
+#define intprintk(s)
+#endif
+
+#define IRQ_T(info) ((info->flags & ASYNC_SHARE_IRQ) ? SA_SHIRQ : SA_INTERRUPT)
+
+#define	GDB_BUF_SIZE	512	/* power of 2, please */
+
+static char gdb_buf[GDB_BUF_SIZE];
+static int gdb_buf_in_inx;
+static atomic_t gdb_buf_in_cnt;
+static int gdb_buf_out_inx;
+
+struct async_struct *gdb_async_info;
+static int gdb_async_irq;
+
+#define outb_px(a,b) outb_p(b,a)
+
+static void program_uart(struct async_struct *info);
+static void write_char(struct async_struct *info, int chr);
+/*
+ * Get a byte from the hardware data buffer and return it
+ */
+static int
+read_data_bfr(struct async_struct *info)
+{
+	char it = inb_p(info->port + UART_LSR);
+
+	if (it & UART_LSR_DR)
+		return (inb_p(info->port + UART_RX));
+	/*
+	 * If we have a framing error assume somebody messed with
+	 * our uart.  Reprogram it and send '-' both ways...
+	 */
+	if (it & 0xc) {
+		program_uart(info);
+		write_char(info, '-');
+		return ('-');
+	}
+	return (-1);
+
+}				/* read_data_bfr */
+
+/*
+ * Get a char if available, return -1 if nothing available.
+ * Empty the receive buffer first, then look at the interface hardware.
+
+ * Locking here is a bit of a problem.	We MUST not lock out communication
+ * if we are trying to talk to gdb about a kgdb entry.	ON the other hand
+ * we can loose chars in the console pass thru if we don't lock.  It is also
+ * possible that we could hold the lock or be waiting for it when kgdb
+ * NEEDS to talk.  Since kgdb locks down the world, it does not need locks.
+ * We do, of course have possible issues with interrupting a uart operation,
+ * but we will just depend on the uart status to help keep that straight.
+
+ */
+static spinlock_t uart_interrupt_lock = SPIN_LOCK_UNLOCKED;
+#ifdef CONFIG_SMP
+extern spinlock_t kgdb_spinlock;
+#endif
+
+static int
+read_char(struct async_struct *info)
+{
+	int chr;
+	unsigned long flags;
+	local_irq_save(flags);
+#ifdef CONFIG_SMP
+	if (!spin_is_locked(&kgdb_spinlock)) {
+		spin_lock(&uart_interrupt_lock);
+	}
+#endif
+	if (atomic_read(&gdb_buf_in_cnt) != 0) {	/* intr routine has q'd chars */
+		chr = gdb_buf[gdb_buf_out_inx++];
+		gdb_buf_out_inx &= (GDB_BUF_SIZE - 1);
+		atomic_dec(&gdb_buf_in_cnt);
+	} else {
+		chr = read_data_bfr(info);
+	}
+#ifdef CONFIG_SMP
+	if (!spin_is_locked(&kgdb_spinlock)) {
+		spin_unlock(&uart_interrupt_lock);
+	}
+#endif
+	local_irq_restore(flags);
+	return (chr);
+}
+
+/*
+ * Wait until the interface can accept a char, then write it.
+ */
+static void
+write_char(struct async_struct *info, int chr)
+{
+	while (!(inb_p(info->port + UART_LSR) & UART_LSR_THRE)) ;
+
+	outb_p(chr, info->port + UART_TX);
+
+}				/* write_char */
+
+/*
+ * Mostly we don't need a spinlock, but since the console goes
+ * thru here with interrutps on, well, we need to catch those
+ * chars.
+ */
+/*
+ * This is the receiver interrupt routine for the GDB stub.
+ * It will receive a limited number of characters of input
+ * from the gdb  host machine and save them up in a buffer.
+ *
+ * When the gdb stub routine tty_getDebugChar() is called it
+ * draws characters out of the buffer until it is empty and
+ * then reads directly from the serial port.
+ *
+ * We do not attempt to write chars from the interrupt routine
+ * since the stubs do all of that via tty_putDebugChar() which
+ * writes one byte after waiting for the interface to become
+ * ready.
+ *
+ * The debug stubs like to run with interrupts disabled since,
+ * after all, they run as a consequence of a breakpoint in
+ * the kernel.
+ *
+ * Perhaps someone who knows more about the tty driver than I
+ * care to learn can make this work for any low level serial
+ * driver.
+ */
+static irqreturn_t
+gdb_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+	struct async_struct *info;
+	unsigned long flags;
+
+	info = gdb_async_info;
+	if (!info || !info->tty || irq != gdb_async_irq)
+		return IRQ_NONE;
+
+	local_irq_save(flags);
+	spin_lock(&uart_interrupt_lock);
+	do {
+		int chr = read_data_bfr(info);
+		intprintk(("Debug char on int: %x hex\n", chr));
+		if (chr < 0)
+			continue;
+
+		if (chr == 3) {	/* Ctrl-C means remote interrupt */
+			BREAKPOINT;
+			continue;
+		}
+
+		if (atomic_read(&gdb_buf_in_cnt) >= GDB_BUF_SIZE) {
+			/* buffer overflow tosses early char */
+			read_char(info);
+		}
+		gdb_buf[gdb_buf_in_inx++] = chr;
+		gdb_buf_in_inx &= (GDB_BUF_SIZE - 1);
+	} while (inb_p(info->port + UART_IIR) & UART_IIR_RDI);
+	spin_unlock(&uart_interrupt_lock);
+	local_irq_restore(flags);
+	return IRQ_HANDLED;
+}				/* gdb_interrupt */
+
+/*
+ * Just a NULL routine for testing.
+ */
+void
+gdb_null(void)
+{
+}				/* gdb_null */
+
+/* These structure are filled in with values defined in asm/kgdb_local.h
+ */
+static struct serial_state state = SB_STATE;
+static struct async_struct local_info = SB_INFO;
+static int ok_to_enable_ints = 0;
+static void kgdb_enable_ints_now(void);
+
+extern char *kgdb_version;
+/*
+ * Hook an IRQ for KGDB.
+ *
+ * This routine is called from tty_putDebugChar, below.
+ */
+static int ints_disabled = 1;
+int
+gdb_hook_interrupt(struct async_struct *info, int verb)
+{
+	struct serial_state *state = info->state;
+	unsigned long flags;
+	int port;
+#ifdef TEST_EXISTANCE
+	int scratch, scratch2;
+#endif
+
+	/* The above fails if memory managment is not set up yet.
+	 * Rather than fail the set up, just keep track of the fact
+	 * and pick up the interrupt thing later.
+	 */
+	gdb_async_info = info;
+	port = gdb_async_info->port;
+	gdb_async_irq = state->irq;
+	if (verb) {
+		printk("kgdb %s : port =%x, IRQ=%d, divisor =%d\n",
+		       kgdb_version,
+		       port,
+		       gdb_async_irq, gdb_async_info->state->custom_divisor);
+	}
+	local_irq_save(flags);
+#ifdef TEST_EXISTANCE
+	/* Existance test */
+	/* Should not need all this, but just in case.... */
+
+	scratch = inb_p(port + UART_IER);
+	outb_px(port + UART_IER, 0);
+	outb_px(0xff, 0x080);
+	scratch2 = inb_p(port + UART_IER);
+	outb_px(port + UART_IER, scratch);
+	if (scratch2) {
+		printk
+		    ("gdb_hook_interrupt: Could not clear IER, not a UART!\n");
+		local_irq_restore(flags);
+		return 1;	/* We failed; there's nothing here */
+	}
+	scratch2 = inb_p(port + UART_LCR);
+	outb_px(port + UART_LCR, 0xBF);	/* set up for StarTech test */
+	outb_px(port + UART_EFR, 0);	/* EFR is the same as FCR */
+	outb_px(port + UART_LCR, 0);
+	outb_px(port + UART_FCR, UART_FCR_ENABLE_FIFO);
+	scratch = inb_p(port + UART_IIR) >> 6;
+	if (scratch == 1) {
+		printk("gdb_hook_interrupt: Undefined UART type!"
+		       "  Not a UART! \n");
+		local_irq_restore(flags);
+		return 1;
+	} else {
+		dbprintk(("gdb_hook_interrupt: UART type "
+			  "is %d where 0=16450, 2=16550 3=16550A\n", scratch));
+	}
+	scratch = inb_p(port + UART_MCR);
+	outb_px(port + UART_MCR, UART_MCR_LOOP | scratch);
+	outb_px(port + UART_MCR, UART_MCR_LOOP | 0x0A);
+	scratch2 = inb_p(port + UART_MSR) & 0xF0;
+	outb_px(port + UART_MCR, scratch);
+	if (scratch2 != 0x90) {
+		printk("gdb_hook_interrupt: "
+		       "Loop back test failed! Not a UART!\n");
+		local_irq_restore(flags);
+		return scratch2 + 1000;	/* force 0 to fail */
+	}
+#endif				/* test existance */
+	program_uart(info);
+	local_irq_restore(flags);
+
+	return (0);
+
+}				/* gdb_hook_interrupt */
+
+static void
+program_uart(struct async_struct *info)
+{
+	int port = info->port;
+
+	(void) inb_p(port + UART_RX);
+	outb_px(port + UART_IER, 0);
+
+	(void) inb_p(port + UART_RX);	/* serial driver comments say */
+	(void) inb_p(port + UART_IIR);	/* this clears the interrupt regs */
+	(void) inb_p(port + UART_MSR);
+	outb_px(port + UART_LCR, UART_LCR_WLEN8 | UART_LCR_DLAB);
+	outb_px(port + UART_DLL, info->state->custom_divisor & 0xff);	/* LS */
+	outb_px(port + UART_DLM, info->state->custom_divisor >> 8);	/* MS  */
+	outb_px(port + UART_MCR, info->MCR);
+
+	outb_px(port + UART_FCR, UART_FCR_ENABLE_FIFO | UART_FCR_TRIGGER_1 | UART_FCR_CLEAR_XMIT | UART_FCR_CLEAR_RCVR);	/* set fcr */
+	outb_px(port + UART_LCR, UART_LCR_WLEN8);	/* reset DLAB */
+	outb_px(port + UART_FCR, UART_FCR_ENABLE_FIFO | UART_FCR_TRIGGER_1);	/* set fcr */
+	if (!ints_disabled) {
+		intprintk(("KGDB: Sending %d to port %x offset %d\n",
+			   gdb_async_info->IER,
+			   (int) gdb_async_info->port, UART_IER));
+		outb_px(gdb_async_info->port + UART_IER, gdb_async_info->IER);
+	}
+	return;
+}
+
+/*
+ * tty_getDebugChar
+ *
+ * This is a GDB stub routine.	It waits for a character from the
+ * serial interface and then returns it.  If there is no serial
+ * interface connection then it returns a bogus value which will
+ * almost certainly cause the system to hang.  In the
+ */
+int kgdb_in_isr = 0;
+int kgdb_in_lsr = 0;
+extern spinlock_t kgdb_spinlock;
+
+/* Caller takes needed protections */
+
+int
+tty_getDebugChar(void)
+{
+	volatile int chr, dum, time, end_time;
+
+	dbprintk(("tty_getDebugChar(port %x): ", gdb_async_info->port));
+
+	if (gdb_async_info == NULL) {
+		gdb_hook_interrupt(&local_info, 0);
+	}
+	/*
+	 * This trick says if we wait a very long time and get
+	 * no char, return the -1 and let the upper level deal
+	 * with it.
+	 */
+	rdtsc(dum, time);
+	end_time = time + 2;
+	while (((chr = read_char(gdb_async_info)) == -1) &&
+	       (end_time - time) > 0) {
+		rdtsc(dum, time);
+	};
+	/*
+	 * This covers our butts if some other code messes with
+	 * our uart, hay, it happens :o)
+	 */
+	if (chr == -1)
+		program_uart(gdb_async_info);
+
+	dbprintk(("%c\n", chr > ' ' && chr < 0x7F ? chr : ' '));
+	return (chr);
+
+}				/* tty_getDebugChar */
+
+static int count = 3;
+static spinlock_t one_at_atime = SPIN_LOCK_UNLOCKED;
+
+static int __init
+kgdb_enable_ints(void)
+{
+	if (kgdboe) {
+		return 0;
+	}
+	if (gdb_async_info == NULL) {
+		gdb_hook_interrupt(&local_info, 1);
+	}
+	ok_to_enable_ints = 1;
+	kgdb_enable_ints_now();
+#ifdef CONFIG_KGDB_USER_CONSOLE
+	kgdb_console_finit();
+#endif
+	return 0;
+}
+
+#ifdef CONFIG_SERIAL_8250
+void shutdown_for_kgdb(struct async_struct *gdb_async_info);
+#endif
+
+#ifdef CONFIG_DISCONTIGMEM
+static inline int kgdb_mem_init_done(void)
+{
+	return highmem_start_page != NULL;
+}
+#else
+static inline int kgdb_mem_init_done(void)
+{
+	return max_mapnr != 0;
+}
+#endif
+
+static void
+kgdb_enable_ints_now(void)
+{
+	if (!spin_trylock(&one_at_atime))
+		return;
+	if (!ints_disabled)
+		goto exit;
+	if (kgdb_mem_init_done() &&
+			ints_disabled) {	/* don't try till mem init */
+#ifdef CONFIG_SERIAL_8250
+		/*
+		 * The ifdef here allows the system to be configured
+		 * without the serial driver.
+		 * Don't make it a module, however, it will steal the port
+		 */
+		shutdown_for_kgdb(gdb_async_info);
+#endif
+		ints_disabled = request_irq(gdb_async_info->state->irq,
+					    gdb_interrupt,
+					    IRQ_T(gdb_async_info),
+					    "KGDB-stub", NULL);
+		intprintk(("KGDB: request_irq returned %d\n", ints_disabled));
+	}
+	if (!ints_disabled) {
+		intprintk(("KGDB: Sending %d to port %x offset %d\n",
+			   gdb_async_info->IER,
+			   (int) gdb_async_info->port, UART_IER));
+		outb_px(gdb_async_info->port + UART_IER, gdb_async_info->IER);
+	}
+      exit:
+	spin_unlock(&one_at_atime);
+}
+
+/*
+ * tty_putDebugChar
+ *
+ * This is a GDB stub routine.	It waits until the interface is ready
+ * to transmit a char and then sends it.  If there is no serial
+ * interface connection then it simply returns to its caller, having
+ * pretended to send the char.	Caller takes needed protections.
+ */
+void
+tty_putDebugChar(int chr)
+{
+	dbprintk(("tty_putDebugChar(port %x): chr=%02x '%c', ints_on=%d\n",
+		  gdb_async_info->port,
+		  chr,
+		  chr > ' ' && chr < 0x7F ? chr : ' ', ints_disabled ? 0 : 1));
+
+	if (gdb_async_info == NULL) {
+		gdb_hook_interrupt(&local_info, 0);
+	}
+
+	write_char(gdb_async_info, chr);	/* this routine will wait */
+	count = (chr == '#') ? 0 : count + 1;
+	if ((count == 2)) {	/* try to enable after */
+		if (ints_disabled & ok_to_enable_ints)
+			kgdb_enable_ints_now();	/* try to enable after */
+
+		/* We do this a lot because, well we really want to get these
+		 * interrupts.	The serial driver will clear these bits when it
+		 * initializes the chip.  Every thing else it does is ok,
+		 * but this.
+		 */
+		if (!ints_disabled) {
+			outb_px(gdb_async_info->port + UART_IER,
+				gdb_async_info->IER);
+		}
+	}
+
+}				/* tty_putDebugChar */
+
+/*
+ * This does nothing for the serial port, since it doesn't buffer.
+ */
+
+void tty_flushDebugChar(void)
+{
+}
+
+module_init(kgdb_enable_ints);
--- diff/arch/ia64/kernel/kgdb_stub.c	1970-01-01 01:00:00.000000000 +0100
+++ source/arch/ia64/kernel/kgdb_stub.c	2004-06-11 19:21:58.000000000 +0100
@@ -0,0 +1,3010 @@
+/*
+ *
+ * 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, 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.
+ *
+ */
+
+/*
+ * Copyright (c) 2000 VERITAS Software Corporation.
+ *
+ */
+/****************************************************************************
+ *  Header: remcom.c,v 1.34 91/03/09 12:29:49 glenne Exp $
+ *
+ *  Module name: remcom.c $
+ *  Revision: 1.34 $
+ *  Date: 91/03/09 12:29:49 $
+ *  Contributor:     Lake Stevens Instrument Division$
+ *
+ *  Description:     low level support for gdb debugger. $
+ *
+ *  Considerations:  only works on target hardware $
+ *
+ *  Written by:	     Glenn Engel $
+ *  Updated by:	     David Grothe <dave@gcom.com>
+ *  Updated by:	     Robert Walsh <rjwalsh@durables.org>
+ *  Updated by:	     wangdi <wangdi@clusterfs.com>
+ *  ModuleState:     Experimental $
+ *
+ *  NOTES:	     See Below $
+ *
+ *  Modified for 386 by Jim Kingdon, Cygnus Support.
+ *  Compatibility with 2.1.xx kernel by David Grothe <dave@gcom.com>
+ *
+ *  Changes to allow auto initilization.  All that is needed is that it
+ *  be linked with the kernel and a break point (int 3) be executed.
+ *  The header file <asm/kgdb.h> defines BREAKPOINT to allow one to do
+ *  this. It should also be possible, once the interrupt system is up, to
+ *  call putDebugChar("+").  Once this is done, the remote debugger should
+ *  get our attention by sending a ^C in a packet. George Anzinger
+ *  <george@mvista.com>
+ *  Integrated into 2.2.5 kernel by Tigran Aivazian <tigran@sco.com>
+ *  Added thread support, support for multiple processors,
+ *	support for ia-32(x86) hardware debugging.
+ *	Amit S. Kale ( akale@veritas.com )
+ *
+ *  Modified to support debugging over ethernet by Robert Walsh
+ *  <rjwalsh@durables.org> and wangdi <wangdi@clusterfs.com>, based on
+ *  code by San Mehat.
+ *
+ *
+ *  To enable debugger support, two things need to happen.  One, a
+ *  call to set_debug_traps() is necessary in order to allow any breakpoints
+ *  or error conditions to be properly intercepted and reported to gdb.
+ *  Two, a breakpoint needs to be generated to begin communication.  This
+ *  is most easily accomplished by a call to breakpoint().  Breakpoint()
+ *  simulates a breakpoint by executing an int 3.
+ *
+ *************
+ *
+ *    The following gdb commands are supported:
+ *
+ * command	    function				   Return value
+ *
+ *    g		    return the value of the CPU registers  hex data or ENN
+ *    G		    set the value of the CPU registers	   OK or ENN
+ *
+ *    mAA..AA,LLLL  Read LLLL bytes at address AA..AA	   hex data or ENN
+ *    MAA..AA,LLLL: Write LLLL bytes at address AA.AA	   OK or ENN
+ *
+ *    c		    Resume at current address		   SNN	 ( signal NN)
+ *    cAA..AA	    Continue at address AA..AA		   SNN
+ *
+ *    s		    Step one instruction		   SNN
+ *    sAA..AA	    Step one instruction from AA..AA	   SNN
+ *
+ *    k		    kill
+ *
+ *    ?		    What was the last sigval ?		   SNN	 (signal NN)
+ *
+ * All commands and responses are sent with a packet which includes a
+ * checksum.  A packet consists of
+ *
+ * $<packet info>#<checksum>.
+ *
+ * where
+ * <packet info> :: <characters representing the command or response>
+ * <checksum>	 :: < two hex digits computed as modulo 256 sum of <packetinfo>>
+ *
+ * When a packet is received, it is first acknowledged with either '+' or '-'.
+ * '+' indicates a successful transfer.	 '-' indicates a failed transfer.
+ *
+ * Example:
+ *
+ * Host:		  Reply:
+ * $m0,10#2a		   +$00010203040506070809101112131415#42
+ *
+ ****************************************************************************/
+#define KGDB_VERSION "<20030915.1651.33>"
+#include <linux/config.h>
+#include <linux/types.h>
+#include <asm/string.h>		/* for strcpy */
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <asm/system.h>
+#include <asm/ptrace.h>		/* for linux pt_regs struct */
+#include <asm/kgdb_local.h>
+#include <linux/list.h>
+#include <asm/atomic.h>
+#include <asm/processor.h>
+#include <asm/unwind.h>
+#include <asm/delay.h>
+#include <asm/sections.h>
+#include <linux/irq.h>
+#include <linux/reboot.h>
+#include <linux/inet.h>
+#include <linux/netpoll.h>
+
+/*
+ * IA64 ToDo:
+ *	1) more testing needs to be done when modifying registers.
+ *	2) probably could use cleanup in register get/put from unw_info but gdb work
+ *	   is on going (WIP) to reduce g-packet on wire for serial
+ *	3) until gdb work is complete and accepted by gdb folks, the serial interface
+ *	   isn't complete.  the current g-packet is over 10,000 bytes which is too
+ *	   large for a serial line. without a g-packet a delay is used with large putpacket
+	   requests.  however, this won't solve a gdb sent packet which is a g-packet.
+ *	4) NMI for hung machine.  Well we don't have real NMI!
+ */
+
+/************************************************************************
+ *
+ * external low-level support routines
+ */
+typedef void (*Function) (void);	/* pointer to a function */
+
+/* Thread reference */
+typedef unsigned char threadref[8];
+
+extern int tty_putDebugChar(int);     /* write a single character      */
+extern int tty_getDebugChar(void);    /* read and return a single char */
+extern void tty_flushDebugChar(void); /* flush pending characters      */
+extern int eth_putDebugChar(int);     /* write a single character      */
+extern int eth_getDebugChar(void);    /* read and return a single char */
+extern void eth_flushDebugChar(void); /* flush pending characters      */
+
+/************************************************************************/
+/* BUFMAX defines the maximum number of characters in inbound/outbound buffers*/
+/* at least NUMREGBYTES*2 are needed for register packets */
+/* Longer buffer is needed to list all threads */
+/* purloined from gdb ia64 config support */
+#define NUM_REGS 590
+#define REGISTER_BYTES (NUM_REGS*8+128*8)
+#define REGISTER_BYTE(N) (((N) * 8) \
+  + ((N) <= IA64_FR0_REGNUM ? 0 : 8 * (((N) > IA64_FR127_REGNUM) ? 128 : (N) - IA64_FR0_REGNUM)))
+#define	REGISTER_SIZE(N) (((N) >= IA64_FR0_REGNUM && (N) <= IA64_FR127_REGNUM) ? 16 : 8)
+#define IA64_GR0_REGNUM         0
+#define IA64_FR0_REGNUM         128
+#define IA64_FR127_REGNUM       (IA64_FR0_REGNUM+127)
+#define IA64_PR0_REGNUM         256
+#define IA64_BR0_REGNUM         320
+#define IA64_VFP_REGNUM         328
+#define IA64_PR_REGNUM          330
+#define IA64_IP_REGNUM          331
+#define IA64_PSR_REGNUM         332
+#define IA64_CFM_REGNUM         333
+#define IA64_AR0_REGNUM         334
+#define IA64_NAT0_REGNUM        462
+#define IA64_NAT31_REGNUM       (IA64_NAT0_REGNUM+31)
+#define IA64_NAT32_REGNUM       (IA64_NAT0_REGNUM+32)
+#define IA64_RSC_REGNUM		(IA64_AR0_REGNUM+16)
+#define IA64_BSP_REGNUM		(IA64_AR0_REGNUM+17)
+#define IA64_BSPSTORE_REGNUM	(IA64_AR0_REGNUM+18)
+#define IA64_RNAT_REGNUM	(IA64_AR0_REGNUM+19)
+#define IA64_FCR_REGNUM		(IA64_AR0_REGNUM+21)
+#define IA64_EFLAG_REGNUM	(IA64_AR0_REGNUM+24)
+#define IA64_CSD_REGNUM		(IA64_AR0_REGNUM+25)
+#define IA64_SSD_REGNUM		(IA64_AR0_REGNUM+26)
+#define IA64_CFLG_REGNUM	(IA64_AR0_REGNUM+27)
+#define IA64_FSR_REGNUM		(IA64_AR0_REGNUM+28)
+#define IA64_FIR_REGNUM		(IA64_AR0_REGNUM+29)
+#define IA64_FDR_REGNUM		(IA64_AR0_REGNUM+30)
+#define IA64_CCV_REGNUM		(IA64_AR0_REGNUM+32)
+#define IA64_UNAT_REGNUM	(IA64_AR0_REGNUM+36)
+#define IA64_FPSR_REGNUM	(IA64_AR0_REGNUM+40)
+#define IA64_ITC_REGNUM		(IA64_AR0_REGNUM+44)
+#define IA64_PFS_REGNUM		(IA64_AR0_REGNUM+64)
+#define IA64_LC_REGNUM		(IA64_AR0_REGNUM+65)
+#define IA64_EC_REGNUM		(IA64_AR0_REGNUM+66)
+
+#define	REGISTER_INDEX(N)	(REGISTER_BYTE(N) / sizeof (unsigned long))
+#define BUFMAX (REGISTER_BYTES*2+10)
+static char remcomInBuffer[BUFMAX];
+static char remcomOutBuffer[BUFMAX];
+static short error;
+
+
+char *kgdb_version = KGDB_VERSION;
+
+/*  debug >  0 prints ill-formed commands in valid packets & checksum errors */
+int debug_regs = 0;		/* set to non-zero to print registers */
+
+/* filled in by an external module */
+char *gdb_module_offsets;
+
+static const char hexchars[] = "0123456789abcdef";
+
+/* Number of bytes of registers.  */
+#define NUMREGBYTES 	REGISTER_BYTES
+#define	BREAKNUM	0x00003333300LL
+#define	KGDBBREAKNUM	0x6665UL
+
+static void inline
+kgdb_pc(struct pt_regs *regs, unsigned long pc)
+{
+	regs->cr_iip = pc & ~0xf;
+	ia64_psr(regs)->ri = pc & 0x3;
+	return;
+}
+
+void
+breakpoint(void)
+{
+	asm volatile ("break.m 0x6665");
+}
+
+/***************************  ASSEMBLY CODE MACROS *************************/
+/*
+ * Put the error code here just in case the user cares.
+ * Likewise, the vector number here (since GDB only gets the signal
+ * number through the usual means, and that's not very specific).
+ * The called_from is the return address so he can tell how we entered kgdb.
+ * This will allow him to seperate out the various possible entries.
+ */
+#define REMOTE_DEBUG 0		/* set != to turn on printing (also available in info) */
+
+#define PID_MAX PID_MAX_DEFAULT
+
+#ifdef CONFIG_SMP
+void smp_send_nmi_allbutself(void);
+#define IF_SMP(x) x
+#undef MAX_NO_CPUS
+#ifndef CONFIG_NO_KGDB_CPUS
+#define CONFIG_NO_KGDB_CPUS 2
+#endif
+#if CONFIG_NO_KGDB_CPUS > NR_CPUS
+#define MAX_NO_CPUS NR_CPUS
+#else
+#define MAX_NO_CPUS CONFIG_NO_KGDB_CPUS
+#endif
+#define hold_init hold_on_sstep: 1,
+#define MAX_CPU_MASK (unsigned long)((1LL << MAX_NO_CPUS) - 1LL)
+#define NUM_CPUS num_online_cpus()
+#else
+#define IF_SMP(x)
+#define hold_init
+#undef MAX_NO_CPUS
+#define MAX_NO_CPUS 1
+#define NUM_CPUS 1
+#endif
+#define NOCPU (struct task_struct *)0xbad1fbad
+struct kgdb_state {
+	int		exceptionVector;
+	int		signo;
+	unsigned long	err_code;
+	struct pt_regs *regs;
+	struct unw_frame_info
+			*unw;
+	int		ret;
+};
+/* *INDENT-OFF*	 */
+struct kgdb_info {
+	int used_malloc;
+	void *called_from;
+	long long entry_itc;
+	int errcode;
+	unsigned long vector;
+	int print_debug_info;
+	unsigned long ia64_regs[REGISTER_BYTES / sizeof(long)];
+#ifdef CONFIG_SMP
+	int hold_on_sstep;
+	struct {
+		volatile struct task_struct *task;
+		int pid;
+		int hold;
+		struct pt_regs *regs;
+		unsigned long ia64_regs[REGISTER_BYTES / sizeof(long)];
+	} cpus_waiting[MAX_NO_CPUS];
+#endif
+} kgdb_info = {hold_init print_debug_info:REMOTE_DEBUG, vector:-1UL};
+
+/* *INDENT-ON*	*/
+
+#define used_m kgdb_info.used_malloc
+/*
+ * This is little area we set aside to contain the stack we
+ * need to build to allow gdb to call functions.  We use one
+ * per cpu to avoid locking issues.  We will do all this work
+ * with interrupts off so that should take care of the protection
+ * issues.
+ */
+#define	MAX_HW_BREAKPOINT	(20)
+long hw_break_total_dbr, hw_break_total_ibr;
+#define	HW_BREAKPOINT	(hw_break_total_dbr + hw_break_total_ibr)
+#define	WATCH_INSTRUCTION	0x0
+#define WATCH_WRITE		0x1
+#define	WATCH_READ		0x2
+#define	WATCH_ACCESS		0x3
+
+#define	HWCAP_DBR	((1 << WATCH_WRITE) | (1 << WATCH_READ))
+#define	HWCAP_IBR	(1 << WATCH_INSTRUCTION)
+struct hw_breakpoint {
+	unsigned enabled;
+	unsigned long capable;
+	unsigned long type;
+	unsigned long mask;
+	unsigned long addr;
+} *breakinfo;
+
+#define LOOKASIDE_SIZE (200 + (sizeof(struct hw_breakpoint) * MAX_HW_BREAKPOINT))
+#define MALLOC_MAX   LOOKASIDE_SIZE	/* Max malloc size */
+struct {
+	unsigned int esp;
+	int array[LOOKASIDE_SIZE];
+} fn_call_lookaside[MAX_NO_CPUS];
+
+#define IF_BIT 0x200
+#define TF_BIT 0x100
+
+#define MALLOC_ROUND 8-1
+
+static char malloc_array[MALLOC_MAX];
+IF_SMP(static void to_gdb(const char *mess));
+void *
+malloc(int size)
+{
+
+	if (size <= (MALLOC_MAX - used_m)) {
+		int old_used = used_m;
+		used_m += ((size + MALLOC_ROUND) & (~MALLOC_ROUND));
+		return &malloc_array[old_used];
+	} else {
+		return NULL;
+	}
+}
+
+/*
+ * I/O dispatch functions...
+ * Based upon kgdboe, either call the ethernet
+ * handler or the serial one..
+ */
+void
+putDebugChar(int c)
+{
+	if (!kgdboe) {
+		tty_putDebugChar(c);
+	} else {
+		eth_putDebugChar(c);
+	}
+}
+
+int
+getDebugChar(void)
+{
+	if (!kgdboe) {
+		char ch;
+		while (1) {
+			ch = tty_getDebugChar() & 0x7f;
+			if (ch != 0x7f)
+				return ch;
+		}
+	} else {
+		return eth_getDebugChar();
+	}
+}
+
+void
+flushDebugChar(void)
+{
+	if (!kgdboe) {
+		tty_flushDebugChar();
+	} else {
+		eth_flushDebugChar();
+	}
+}
+
+/*
+ * Gdb calls functions by pushing agruments, including a return address
+ * on the stack and the adjusting EIP to point to the function.	 The
+ * whole assumption in GDB is that we are on a different stack than the
+ * one the "user" i.e. code that hit the break point, is on.  This, of
+ * course is not true in the kernel.  Thus various dodges are needed to
+ * do the call without directly messing with EIP (which we can not change
+ * as it is just a location and not a register.	 To adjust it would then
+ * require that we move every thing below EIP up or down as needed.  This
+ * will not work as we may well have stack relative pointer on the stack
+ * (such as the pointer to regs, for example).
+
+ * So here is what we do:
+ * We detect gdb attempting to store into the stack area and instead, store
+ * into the fn_call_lookaside.array at the same relative location as if it
+ * were the area ESP pointed at.  We also trap ESP modifications
+ * and uses these to adjust fn_call_lookaside.esp.  On entry
+ * fn_call_lookaside.esp will be set to point at the last entry in
+ * fn_call_lookaside.array.  This allows us to check if it has changed, and
+ * if so, on exit, we add the registers we will use to do the move and a
+ * trap/ interrupt return exit sequence.  We then adjust the eflags in the
+ * regs array (remember we now have a copy in the fn_call_lookaside.array) to
+ * kill the interrupt bit, AND we change EIP to point at our set up stub.
+ * As part of the register set up we preset the registers to point at the
+ * begining and end of the fn_call_lookaside.array, so all the stub needs to
+ * do is move words from the array to the stack until ESP= the desired value
+ * then do the rti.  This will then transfer to the desired function with
+ * all the correct registers.  Nifty huh?
+ */
+extern asmlinkage void fn_call_stub(void);
+extern asmlinkage void fn_rtn_stub(void);
+/*					   *INDENT-OFF*	 */
+/*__asm__("fn_rtn_stub:\n\t"
+	"movl %eax,%esp\n\t"
+	"fn_call_stub:\n\t"
+	"1:\n\t"
+	"addl $-4,%ebx\n\t"
+	"movl (%ebx), %eax\n\t"
+	"pushl %eax\n\t"
+	"cmpl %esp,%ecx\n\t"
+	"jne  1b\n\t"
+	"popl %eax\n\t"
+	"popl %ebx\n\t"
+	"popl %ecx\n\t"
+	"iret \n\t");
+*/
+/*					     *INDENT-ON*  */
+#define gdb_ia64vector	kgdb_info.vector
+#define gdb_ia64errcode kgdb_info.errcode
+#define waiting_cpus	kgdb_info.cpus_waiting
+#define remote_debug	kgdb_info.print_debug_info
+#define hold_cpu(cpu)	kgdb_info.cpus_waiting[cpu].hold
+/* gdb locks */
+
+#ifdef CONFIG_SMP
+static int in_kgdb_called;
+static spinlock_t waitlocks[MAX_NO_CPUS] =
+    {[0 ... MAX_NO_CPUS - 1] = SPIN_LOCK_UNLOCKED };
+/*
+ * The following array has the thread pointer of each of the "other"
+ * cpus.  We make it global so it can be seen by gdb.
+ */
+volatile int in_kgdb_entry_log[MAX_NO_CPUS];
+volatile struct pt_regs *in_kgdb_here_log[MAX_NO_CPUS];
+/*
+static spinlock_t continuelocks[MAX_NO_CPUS];
+*/
+spinlock_t kgdb_spinlock = SPIN_LOCK_UNLOCKED;
+/* waiters on our spinlock plus us */
+static atomic_t spinlock_waiters = ATOMIC_INIT(1);
+static int spinlock_count = 0;
+static int spinlock_cpu = 0;
+/*
+ * Note we use nested spin locks to account for the case where a break
+ * point is encountered when calling a function by user direction from
+ * kgdb. Also there is the memory exception recursion to account for.
+ * Well, yes, but this lets other cpus thru too.  Lets add a
+ * cpu id to the lock.
+ */
+#define KGDB_SPIN_LOCK(x) if( spinlock_count == 0 || \
+			      spinlock_cpu != smp_processor_id()){\
+				      atomic_inc(&spinlock_waiters); \
+				      while (! spin_trylock(x)) {\
+					    in_kgdb(linux_regs, unw_info);\
+				      }\
+				      atomic_dec(&spinlock_waiters); \
+				      spinlock_count = 1; \
+				      spinlock_cpu = smp_processor_id(); \
+			  }else{  \
+				      spinlock_count++; \
+			  }
+#define KGDB_SPIN_UNLOCK(x) if( --spinlock_count == 0) spin_unlock(x)
+#else
+unsigned kgdb_spinlock = 0;
+#define KGDB_SPIN_LOCK(x) --*x
+#define KGDB_SPIN_UNLOCK(x) ++*x
+#endif
+
+int
+hex(char ch)
+{
+	if ((ch >= 'a') && (ch <= 'f'))
+		return (ch - 'a' + 10);
+	if ((ch >= '0') && (ch <= '9'))
+		return (ch - '0');
+	if ((ch >= 'A') && (ch <= 'F'))
+		return (ch - 'A' + 10);
+	return (-1);
+}
+
+/* scan for the sequence $<data>#<checksum>	*/
+void
+getpacket(char *buffer)
+{
+	unsigned char checksum;
+	unsigned char xmitcsum;
+	int i;
+	int count;
+	char ch;
+
+	do {
+		/* wait around for the start character, ignore all other characters */
+		while ((ch = (getDebugChar() & 0x7f)) != '$') ;
+		checksum = 0;
+		xmitcsum = -1;
+
+		count = 0;
+
+		/* now, read until a # or end of buffer is found */
+		while (count < BUFMAX) {
+			ch = getDebugChar() & 0x7f;
+			if (ch == '#')
+				break;
+			checksum = checksum + ch;
+			buffer[count] = ch;
+			count = count + 1;
+		}
+		buffer[count] = 0;
+
+		if (ch == '#') {
+			xmitcsum = hex(getDebugChar() & 0x7f) << 4;
+			xmitcsum += hex(getDebugChar() & 0x7f);
+			if ((remote_debug) && (checksum != xmitcsum)) {
+				printk
+				    ("bad checksum.	My count = 0x%x, sent=0x%x. buf=%s\n",
+				     checksum, xmitcsum, buffer);
+			}
+
+			if (checksum != xmitcsum) {
+				putDebugChar('-');	/* failed checksum */
+			}
+			else {
+				putDebugChar('+');	/* successful transfer */
+				/* if a sequence char is present, reply the sequence ID */
+				if (buffer[2] == ':') {
+					putDebugChar(buffer[0]);
+					putDebugChar(buffer[1]);
+					/* remove sequence chars from buffer */
+					count = strlen(buffer);
+					for (i = 3; i <= count; i++)
+						buffer[i - 3] = buffer[i];
+				}
+			}
+		}
+	} while (checksum != xmitcsum);
+
+	if (remote_debug)
+		printk("R:%s\n", buffer);
+	flushDebugChar();
+}
+
+/* send the packet in buffer.  */
+
+void
+putpacket(char *buffer)
+{
+	unsigned char checksum;
+	int count;
+	char ch;
+
+	/*  $<packet info>#<checksum>. */
+
+	if (!kgdboe) {
+		do {
+			if (remote_debug)
+				printk("T:%s\n", buffer);
+			putDebugChar('$');
+			checksum = 0;
+			count = 0;
+
+			while ((ch = buffer[count])) {
+				putDebugChar(ch);
+				checksum += ch;
+				count += 1;
+			}
+
+			putDebugChar('#');
+			putDebugChar(hexchars[checksum >> 4]);
+			putDebugChar(hexchars[checksum % 16]);
+			flushDebugChar();
+
+		} while ((getDebugChar() & 0x7f) != '+');
+	} else {
+		/*
+		 * For udp, we can not transfer too much bytes once.
+		 * We only transfer MAX_SEND_COUNT size bytes each time
+		 */
+
+#define MAX_SEND_COUNT 30
+
+		int send_count = 0, i = 0;
+		char send_buf[MAX_SEND_COUNT];
+
+		do {
+			if (remote_debug)
+				printk("T:%s\n", buffer);
+			putDebugChar('$');
+			checksum = 0;
+			count = 0;
+			send_count = 0;
+			while ((ch = buffer[count])) {
+				if (send_count >= MAX_SEND_COUNT) {
+					for(i = 0; i < MAX_SEND_COUNT; i++) {
+						putDebugChar(send_buf[i]);
+					}
+					flushDebugChar();
+					send_count = 0;
+				} else {
+					send_buf[send_count] = ch;
+					checksum += ch;
+					count ++;
+					send_count++;
+				}
+			}
+			for(i = 0; i < send_count; i++)
+				putDebugChar(send_buf[i]);
+			putDebugChar('#');
+			putDebugChar(hexchars[checksum >> 4]);
+			putDebugChar(hexchars[checksum % 16]);
+			flushDebugChar();
+		} while ((getDebugChar() & 0x7f) != '+');
+	}
+}
+
+
+void
+debug_error(char *format, char *parm)
+{
+	if (remote_debug)
+		printk(format, parm);
+}
+
+static void
+print_regs(struct pt_regs *regs)
+{
+	printk("B0=0x%lx\n", regs->b0);
+	printk("IPSR=0x%lx\n", regs->cr_ipsr);
+	printk("IIP=0x%lx\n", regs->cr_iip);
+	printk("\n");
+
+}				/* print_regs */
+
+
+
+static void
+unw_ar_regs(struct unw_frame_info *unw, unsigned long *regs, int put)
+{
+	if (put)
+		unw_access_ar(unw, UNW_AR_BSP, &regs[REGISTER_INDEX(IA64_BSP_REGNUM)], put);
+	else
+		unw_get_bsp(unw, &regs[REGISTER_INDEX(IA64_BSP_REGNUM)]);
+	unw_access_ar(unw, UNW_AR_BSPSTORE, &regs[REGISTER_INDEX(IA64_BSPSTORE_REGNUM)], put);
+	unw_access_ar(unw, UNW_AR_PFS, &regs[REGISTER_INDEX(IA64_PFS_REGNUM)], put);
+	unw_access_ar(unw, UNW_AR_RNAT, &regs[REGISTER_INDEX(IA64_RNAT_REGNUM)], put);
+	unw_access_ar(unw, UNW_AR_UNAT, &regs[REGISTER_INDEX(IA64_UNAT_REGNUM)], put);
+	unw_access_ar(unw, UNW_AR_LC, &regs[REGISTER_INDEX(IA64_LC_REGNUM)], put);
+	unw_access_ar(unw, UNW_AR_EC, &regs[REGISTER_INDEX(IA64_EC_REGNUM)], put);
+	unw_access_ar(unw, UNW_AR_FPSR, &regs[REGISTER_INDEX(IA64_FPSR_REGNUM)], put);
+	unw_access_ar(unw, UNW_AR_RSC, &regs[REGISTER_INDEX(IA64_RSC_REGNUM)], put);
+	unw_access_ar(unw, UNW_AR_CCV, &regs[REGISTER_INDEX(IA64_CCV_REGNUM)], put);
+	unw_access_ar(unw, UNW_AR_CSD, &regs[REGISTER_INDEX(IA64_CSD_REGNUM)], put);
+	unw_access_ar(unw, UNW_AR_SSD, &regs[REGISTER_INDEX(IA64_SSD_REGNUM)], put);
+	return;
+}
+
+static void
+unw_get_regs(struct unw_frame_info *unw, unsigned long *regs, struct pt_regs *ptregs)
+{
+	int i, j;
+	char nat;
+	unsigned long *preg;
+	struct ia64_fpreg *fr, freg;
+
+	memset(regs, 0, sizeof (kgdb_info.ia64_regs));
+
+	for (i = 1; i < 32; i++) {
+		if (ptregs && ((i >= 8 && i <= 11) || (i >= 12 && i <= 15)))
+			continue;
+		unw_access_gr(unw, i, &regs[REGISTER_INDEX(IA64_GR0_REGNUM + i)], &nat, 0);
+		regs[REGISTER_INDEX(IA64_NAT0_REGNUM + i)] = nat;
+	}
+
+	if (ptregs) {
+		for (preg = &ptregs->r8, i = 8; i < 12; i++, preg++)
+			regs[REGISTER_INDEX(IA64_GR0_REGNUM + i)] = *preg;
+		regs[REGISTER_INDEX(IA64_GR0_REGNUM + 12)] = ptregs->r12;
+		regs[REGISTER_INDEX(IA64_GR0_REGNUM + 13)] = ptregs->r13;
+		regs[REGISTER_INDEX(IA64_GR0_REGNUM + 14)] = ptregs->r14;
+		regs[REGISTER_INDEX(IA64_GR0_REGNUM + 15)] = ptregs->r15;
+	}
+
+	for (i = 1; i < 8; i++) {
+		if (ptregs && (i == 6 || i == 7))
+			continue;
+		unw_access_br(unw, i, &regs[REGISTER_INDEX(IA64_BR0_REGNUM + i)], 0);
+	}
+
+	if (ptregs) {
+		regs[REGISTER_INDEX(IA64_BR0_REGNUM)] = ptregs->b0;
+		regs[REGISTER_INDEX(IA64_BR0_REGNUM + 6)] = ptregs->b6;
+		regs[REGISTER_INDEX(IA64_BR0_REGNUM + 7)] = ptregs->b7;
+	} else {
+		unw_access_br(unw, i, &regs[REGISTER_INDEX(IA64_BR0_REGNUM + 6)], 0);
+		unw_access_br(unw, i, &regs[REGISTER_INDEX(IA64_BR0_REGNUM + 7)], 0);
+		unw_access_br(unw, 0, &regs[REGISTER_INDEX(IA64_BR0_REGNUM)], 0);
+	}
+
+	if (ptregs)
+		fr = &ptregs->f6;
+	else
+		fr = &freg;
+
+	for (i = 6; i < 12; i++) {
+		if (!ptregs)
+			unw_access_fr(unw, i, fr, 0);
+		regs[REGISTER_INDEX(IA64_FR0_REGNUM + 6 + i)] = fr->u.bits[0];
+		regs[REGISTER_INDEX(IA64_FR0_REGNUM + 6 + i + 1)] = fr->u.bits[1];
+		if (ptregs)
+			fr++;
+	}
+
+	unw_ar_regs(unw, regs, 0);
+
+	unw_access_pr(unw, &regs[REGISTER_INDEX(IA64_PR_REGNUM)], 0);
+	for (j = 1, i = 0; i < 64; i++, j <<= 1, i++)
+		regs[REGISTER_INDEX(IA64_PR0_REGNUM + i)] =
+			(regs[REGISTER_INDEX(IA64_PR_REGNUM)] & j) ? 1 : 0;
+
+
+	if (!ptregs) {
+		unw_get_ip(unw, &regs[REGISTER_INDEX(IA64_IP_REGNUM)]);
+		unw_get_cfm(unw, &regs[REGISTER_INDEX(IA64_CFM_REGNUM)]);
+	} else {
+		regs[REGISTER_INDEX(IA64_IP_REGNUM)] = ptregs->cr_iip;
+		regs[REGISTER_INDEX(IA64_PSR_REGNUM)] = ptregs->cr_ipsr;
+		regs[REGISTER_INDEX(IA64_CFM_REGNUM)] = ptregs->cr_ifs;
+	}
+
+	return;
+}
+
+static void
+kgdb_get_block_task(struct task_struct *p, unsigned long *ia64regs)
+{
+	struct unw_frame_info info;
+	unsigned long ip;
+	int count = 0;
+
+	unw_init_from_blocked_task(&info, p);
+	ip = 0UL;
+	do {
+		if (unw_unwind(&info) < 0)
+			return;
+		unw_get_ip(&info, &ip);
+		if (!in_sched_functions(ip))
+			break;
+	} while (count++ < 16);
+
+	if (!ip)
+		return;
+
+	unw_get_regs(&info, ia64regs, (struct pt_regs *) 0);
+
+	return;
+}
+
+static void
+regs_to_gdb_regs(struct kgdb_state *state)
+{
+	unw_get_regs(state->unw, kgdb_info.ia64_regs, state->regs);
+	return;
+}				/* regs_to_gdb_regs */
+
+static void
+gdb_regs_to_regs(struct kgdb_state *state)
+{
+	int i;
+	char nat;
+	unsigned long *regs, *preg;
+	struct ia64_fpreg *fr;
+	struct unw_frame_info *unw;
+
+	unw = state->unw;
+	regs = kgdb_info.ia64_regs;
+
+	for (i = 1; i < 32; i++) {
+		if ((i >= 8 && i <= 11) || (i >= 12 && i <= 15))
+			continue;
+		nat = (char) regs[REGISTER_INDEX(IA64_NAT0_REGNUM + i)];
+		unw_access_gr(unw, i, &regs[REGISTER_INDEX(IA64_GR0_REGNUM + i)], &nat, 1);
+	}
+
+	for (preg = &state->regs->r8, i = 8; i < 12; i++, preg++)
+		regs[REGISTER_INDEX(IA64_GR0_REGNUM + i)] = *preg;
+	state->regs->r12 = regs[REGISTER_INDEX(IA64_GR0_REGNUM + 12)];
+	state->regs->r12 = regs[REGISTER_INDEX(IA64_GR0_REGNUM + 13)];
+	state->regs->r12 = regs[REGISTER_INDEX(IA64_GR0_REGNUM + 14)];
+	state->regs->r12 = regs[REGISTER_INDEX(IA64_GR0_REGNUM + 15)];
+
+	for (i = 1; i < 8; i++) {
+		if ((i == 6 || i == 7))
+			continue;
+		unw_access_br(unw, i, &regs[REGISTER_INDEX(IA64_BR0_REGNUM + i)], 1);
+	}
+	state->regs->b0 = regs[REGISTER_INDEX(IA64_BR0_REGNUM)];
+	state->regs->b6 = regs[REGISTER_INDEX(IA64_BR0_REGNUM + 6)];
+	state->regs->b7 = regs[REGISTER_INDEX(IA64_BR0_REGNUM + 7)];
+
+	for (fr = &state->regs->f6, i = 6; i < 12; i++, fr++) {
+		fr->u.bits[0] = regs[REGISTER_INDEX(IA64_FR0_REGNUM + 6 + i)];
+		fr->u.bits[1] = regs[REGISTER_INDEX(IA64_FR0_REGNUM + 6 + i + 1)];
+	}
+
+	unw_ar_regs(unw, regs, 1);
+
+	unw_access_pr(unw, &regs[IA64_PR_REGNUM], 1);
+
+	state->regs->cr_iip = regs[REGISTER_INDEX(IA64_IP_REGNUM)];
+	state->regs->cr_ipsr = regs[REGISTER_INDEX(IA64_PSR_REGNUM)];
+	state->regs->cr_ifs = regs[REGISTER_INDEX(IA64_CFM_REGNUM)];
+
+	return;
+
+}				/* gdb_regs_to_regs */
+
+int thread_list = 0;
+
+void
+get_gdb_regs(struct task_struct *p, struct kgdb_state *state)
+{
+	IF_SMP(int i);
+	if (!p || p == current) {
+		regs_to_gdb_regs(state);
+		return;
+	}
+#ifdef CONFIG_SMP
+	for (i = 0; i < MAX_NO_CPUS; i++) {
+		if (p == kgdb_info.cpus_waiting[i].task &&
+			!user_mode(kgdb_info.cpus_waiting[i].regs)){
+			memcpy(kgdb_info.ia64_regs, kgdb_info.cpus_waiting[i].ia64_regs,
+				sizeof(kgdb_info.ia64_regs));
+			return;
+		}
+	}
+#endif
+/*
+ * This code is to give a more informative notion of where a process
+ * is waiting.	It is used only when the user asks for a thread info
+ * list.  If he then switches to the thread, s/he will find the task
+ * is in schedule, but a back trace should show the same info we come
+ * up with. Some of this code was purloined from get_wchan;
+ */
+
+	if (!thread_list)
+		return;
+	else if (p->state == TASK_RUNNING)
+		return;
+
+	kgdb_get_block_task(p, kgdb_info.ia64_regs);
+
+	return;
+
+}
+
+/* Indicate to caller of mem2hex or hex2mem that there has been an
+   error.  */
+static volatile int mem_err = 0;
+static volatile int mem_err_expected = 0;
+static volatile int mem_err_cnt = 0;
+
+int
+get_char(char *addr, unsigned char *data)
+{
+	mm_segment_t fs;
+	int ret;
+
+	if ((unsigned long) addr < DEFAULT_TASK_SIZE)
+		return -EFAULT;
+
+	wmb();
+	fs = get_fs();
+	set_fs(KERNEL_DS);
+
+	if (get_user(*data, addr) != 0)
+		ret = -EFAULT;
+	else
+		ret = 0;
+
+	set_fs(fs);
+	return ret;
+}
+
+int
+set_char(char *addr, int val)
+{
+	mm_segment_t fs;
+	int ret;
+
+	if ((unsigned long) addr < DEFAULT_TASK_SIZE)
+		return -EFAULT;
+
+	wmb();
+	fs = get_fs();
+	set_fs(KERNEL_DS);
+
+	if (put_user(val, addr) != 0)
+		ret = -EFAULT;
+	else
+		ret = 0;
+
+	set_fs(fs);
+	return ret;
+}
+
+/* convert the memory pointed to by mem into hex, placing result in buf */
+/* return a pointer to the last char put in buf (null) */
+/* If MAY_FAULT is non-zero, then we should set mem_err in response to
+   a fault; if zero treat a fault like any other fault in the stub.  */
+char *
+mem2hex(char *mem, char *buf, int count, int may_fault)
+{
+	int i;
+	unsigned char ch;
+
+	if (may_fault) {
+		mem_err_expected = 1;
+		mem_err = 0;
+	}
+
+	for (i = 0; i < count; i++) {
+		/* printk("%lx = ", mem) ; */
+
+		if (get_char(mem++, &ch)) {
+			if (remote_debug)
+				printk("Mem fault fetching from addr %lx\n", (long) (mem - 1));
+			*buf = 0;	/* truncate buffer */
+			return buf;
+		}
+		*buf++ = hexchars[ch >> 4];
+		*buf++ = hexchars[ch % 16];
+	}
+	*buf = 0;
+	if (may_fault)
+		mem_err_expected = 0;
+	return (buf);
+}
+
+/* convert the hex array pointed to by buf into binary to be placed in mem */
+/* return a pointer to the character AFTER the last byte written */
+/* NOTE: We use the may fault flag to also indicate if the write is to
+ * the registers (0) or "other" memory (!=0)
+ */
+char *
+hex2mem(char *buf, char *mem, int count, int may_fault)
+{
+	int i;
+	unsigned char ch;
+
+	if (may_fault) {
+		mem_err_expected = 1;
+		mem_err = 0;
+	}
+	for (i = 0; i < count; i++) {
+		ch = hex(*buf++) << 4;
+		ch = ch + hex(*buf++);
+		if (set_char(mem++, ch)) {
+			if (remote_debug)
+				printk("Mem fault storing to addr %lx\n",
+				       (long) (mem - 1));
+			return (mem);
+		}
+	}
+	if (may_fault)
+		mem_err_expected = 0;
+	return (mem);
+}
+
+/**********************************************/
+/* WHILE WE FIND NICE HEX CHARS, BUILD AN INT */
+/* RETURN NUMBER OF CHARS PROCESSED	      */
+/**********************************************/
+int
+hexToLong(char **ptr, unsigned long *intValue)
+{
+	int numChars = 0;
+	int hexValue;
+
+	*intValue = 0UL;
+
+	while (**ptr) {
+		hexValue = hex(**ptr);
+		if (hexValue >= 0) {
+			*intValue = (*intValue << 4) | hexValue;
+			numChars++;
+		} else
+			break;
+
+		(*ptr)++;
+	}
+
+	return (numChars);
+}
+
+int
+hexToInt(char **ptr, int *intValue)
+{
+	int numChars = 0;
+	int hexValue;
+
+	*intValue = 0;
+
+	while (**ptr) {
+		hexValue = hex(**ptr);
+		if (hexValue >= 0) {
+			*intValue = (*intValue << 4) | hexValue;
+			numChars++;
+		} else
+			break;
+
+		(*ptr)++;
+	}
+
+	return (numChars);
+}
+
+#define stubhex(h) hex(h)
+#ifdef old_thread_list
+
+static int
+stub_unpack_int(char *buff, int fieldlength)
+{
+	int nibble;
+	int retval = 0;
+
+	while (fieldlength) {
+		nibble = stubhex(*buff++);
+		retval |= nibble;
+		fieldlength--;
+		if (fieldlength)
+			retval = retval << 4;
+	}
+	return retval;
+}
+#endif
+static char *
+pack_hex_byte(char *pkt, int byte)
+{
+	*pkt++ = hexchars[(byte >> 4) & 0xf];
+	*pkt++ = hexchars[(byte & 0xf)];
+	return pkt;
+}
+
+#define BUF_THREAD_ID_SIZE 16
+
+static char *
+pack_threadid(char *pkt, threadref * id)
+{
+	char *limit;
+	unsigned char *altid;
+
+	altid = (unsigned char *) id;
+	limit = pkt + BUF_THREAD_ID_SIZE;
+	while (pkt < limit)
+		pkt = pack_hex_byte(pkt, *altid++);
+	return pkt;
+}
+
+#ifdef old_thread_list
+static char *
+unpack_byte(char *buf, int *value)
+{
+	*value = stub_unpack_int(buf, 2);
+	return buf + 2;
+}
+
+static char *
+unpack_threadid(char *inbuf, threadref * id)
+{
+	char *altref;
+	char *limit = inbuf + BUF_THREAD_ID_SIZE;
+	int x, y;
+
+	altref = (char *) id;
+
+	while (inbuf < limit) {
+		x = stubhex(*inbuf++);
+		y = stubhex(*inbuf++);
+		*altref++ = (x << 4) | y;
+	}
+	return inbuf;
+}
+#endif
+void
+int_to_threadref(threadref * id, int value)
+{
+	unsigned char *scan;
+
+	scan = (unsigned char *) id;
+	{
+		int i = 4;
+		while (i--)
+			*scan++ = 0;
+	}
+	*scan++ = (value >> 24) & 0xff;
+	*scan++ = (value >> 16) & 0xff;
+	*scan++ = (value >> 8) & 0xff;
+	*scan++ = (value & 0xff);
+}
+int
+int_to_hex_v(unsigned char * id, int value)
+{
+	unsigned char *start = id;
+	int shift;
+	int ch;
+
+	for (shift = 28; shift >= 0; shift -= 4) {
+		if ((ch = (value >> shift) & 0xf) || (id != start)) {
+			*id = hexchars[ch];
+			id++;
+		}
+	}
+	if (id == start)
+		*id++ = '0';
+	return id - start;
+}
+#ifdef old_thread_list
+
+static int
+threadref_to_int(threadref * ref)
+{
+	int i, value = 0;
+	unsigned char *scan;
+
+	scan = (char *) ref;
+	scan += 4;
+	i = 4;
+	while (i-- > 0)
+		value = (value << 8) | ((*scan++) & 0xff);
+	return value;
+}
+#endif
+static int
+cmp_str(char *s1, char *s2, int count)
+{
+	while (count--) {
+		if (*s1++ != *s2++)
+			return 0;
+	}
+	return 1;
+}
+
+#if 1				/* this is a hold over from 2.4 where O(1) was "sometimes" */
+extern struct task_struct *kgdb_get_idle(int cpu);
+#define idle_task(cpu) kgdb_get_idle(cpu)
+#else
+#define idle_task(cpu) init_tasks[cpu]
+#endif
+
+extern int kgdb_pid_init_done;
+
+#ifdef	CONFIG_KGDB_EARLY
+struct task_struct kgdb_task = {.comm = "kgdb-dummy"};
+#endif
+
+struct task_struct *
+getthread(int pid)
+{
+	struct task_struct *thread;
+	if (pid >= PID_MAX && pid <= (PID_MAX + MAX_NO_CPUS)) {
+
+		return idle_task(pid - PID_MAX);
+	} else {
+		/*
+		 * find_task_by_pid is relatively safe all the time
+		 * Other pid functions require lock downs which imply
+		 * that we may be interrupting them (as we get here
+		 * in the middle of most any lock down).
+		 * Still we don't want to call until the table exists!
+		 */
+		if (kgdb_pid_init_done){
+			thread = find_task_by_pid(pid);
+			if (thread) {
+				return thread;
+			}
+		}
+	}
+#ifdef	CONFIG_KGDB_EARLY
+	if (!kgdb_pid_init_done)
+		return &kgdb_task;
+#endif
+	return NULL;
+}
+/* *INDENT-OFF*	 */
+
+enum instruction_type {A, I, M, F, B, L, X, u};
+
+static enum instruction_type bundle_encoding[32][3] = {
+  { M, I, I },				/* 00 */
+  { M, I, I },				/* 01 */
+  { M, I, I },				/* 02 */
+  { M, I, I },				/* 03 */
+  { M, L, X },				/* 04 */
+  { M, L, X },				/* 05 */
+  { u, u, u },  			/* 06 */
+  { u, u, u },  			/* 07 */
+  { M, M, I },				/* 08 */
+  { M, M, I },				/* 09 */
+  { M, M, I },				/* 0A */
+  { M, M, I },				/* 0B */
+  { M, F, I },				/* 0C */
+  { M, F, I },				/* 0D */
+  { M, M, F },				/* 0E */
+  { M, M, F },				/* 0F */
+  { M, I, B },				/* 10 */
+  { M, I, B },				/* 11 */
+  { M, B, B },				/* 12 */
+  { M, B, B },				/* 13 */
+  { u, u, u },  			/* 14 */
+  { u, u, u },  			/* 15 */
+  { B, B, B },				/* 16 */
+  { B, B, B },				/* 17 */
+  { M, M, B },				/* 18 */
+  { M, M, B },				/* 19 */
+  { u, u, u },  			/* 1A */
+  { u, u, u },  			/* 1B */
+  { M, F, B },				/* 1C */
+  { M, F, B },				/* 1D */
+  { u, u, u },  			/* 1E */
+  { u, u, u },  			/* 1F */
+};
+
+#define	MAX_BREAK_POINTS	(20)
+
+struct z0_break_point {
+	unsigned long addr;
+	unsigned long bundle[2];
+	unsigned int enabled;
+} z0_break_point[MAX_BREAK_POINTS];
+
+int kgdb_arch_set_breakpoint(unsigned long addr)
+{
+	unsigned long slot = addr & 0xf, bundle_addr;
+	unsigned long template;
+	struct bundle {
+		struct {
+			unsigned long long template : 5;
+			unsigned long long slot0 : 41;
+			unsigned long long slot1_p0 : 64-46;
+		} quad0;
+		struct {
+			unsigned long long slot1_p1 : 41 - (64-46);
+			unsigned long long slot2 : 41;
+		} quad1;
+	} bundle;
+	int i;
+	struct z0_break_point *z0 = NULL;
+	unsigned long valid;
+
+	asm volatile("probe.w %0 = %1, 0" : "=r" (valid) : "r" (addr) : "memory");
+	if (!valid)
+		return 0;
+	asm volatile("probe.w %0 = %1, 0" : "=r" (valid) : "r" (addr+8) : "memory");
+	if (!valid)
+		return 0;
+
+
+	for (i = 0; i < MAX_BREAK_POINTS; i++)
+		if (!z0_break_point[i].enabled) {
+			z0 = &z0_break_point[i];
+			break;
+		}
+
+	if (!z0)
+		return 0;
+
+	if (slot > 2)
+		slot = 0;
+
+	bundle_addr = addr & ~0xFULL;
+	memcpy(&bundle, (unsigned long *)bundle_addr, sizeof(bundle));
+	memcpy(z0->bundle, &bundle, sizeof(bundle));
+
+	template = bundle.quad0.template;
+	if (slot == 1 && bundle_encoding[template][1] == L)
+		slot = 2;
+	switch (slot) {
+	case 0:
+		bundle.quad0.slot0 = BREAKNUM;
+		break;
+	case 1:
+		bundle.quad0.slot1_p0 = BREAKNUM;
+		bundle.quad1.slot1_p1 = (BREAKNUM >> (64-46));
+		break;
+	case 2:
+		bundle.quad1.slot2 = BREAKNUM;
+		break;
+	}
+
+	memcpy((char *) bundle_addr, (char *) &bundle, sizeof(bundle));
+	flush_icache_range(bundle_addr, bundle_addr + sizeof(bundle));
+	z0->addr = addr;
+	z0->enabled = 1;
+
+	return 1;
+}
+
+int kgdb_arch_remove_breakpoint(unsigned long addr)
+{
+	struct z0_break_point *z0 = NULL;
+	int i;
+
+	for (i = 0; i < MAX_BREAK_POINTS; i++)
+		if (z0_break_point[i].enabled && z0_break_point[i].addr == addr) {
+			z0 = &z0_break_point[i];
+			break;
+		}
+
+	if (!z0)
+		return 0;
+
+	addr = addr & ~0xFULL;
+	(void) memcpy((char *) addr, (char *) z0->bundle, sizeof (z0->bundle));
+	flush_icache_range(addr, addr + sizeof(z0->bundle));
+	z0->enabled = 0;
+	return 1;
+}
+
+
+unsigned long hw_breakpoint_status;
+
+int hw_breakpoint_init;
+
+void
+do_init_hw_break(void)
+{
+	s64 status;
+	int i;
+
+	hw_breakpoint_init = 1;
+
+#ifdef	CONFIG_IA64_HP_SIM
+	hw_break_total_ibr = 8;
+	hw_break_total_dbr = 8;
+	status = 0;
+#else
+	status = ia64_pal_debug_info(&hw_break_total_ibr, &hw_break_total_dbr);
+#endif
+
+	if (status) {
+		printk(KERN_INFO "do_init_hw_break: pal call failed %d\n", (int) status);
+		return;
+	}
+
+	if (HW_BREAKPOINT > MAX_HW_BREAKPOINT) {
+		printk(KERN_INFO "do_init_hw_break: %d exceeds max %d\n", (int) HW_BREAKPOINT,
+			(int) MAX_HW_BREAKPOINT);
+
+		while ((HW_BREAKPOINT > MAX_HW_BREAKPOINT) && hw_break_total_ibr != 1)
+			hw_break_total_ibr--;
+		while (HW_BREAKPOINT > MAX_HW_BREAKPOINT)
+			hw_break_total_dbr--;
+	}
+
+	breakinfo = malloc(HW_BREAKPOINT * sizeof(struct hw_breakpoint));
+
+	if (!breakinfo) {
+		printk(KERN_INFO "Failed to allocate hardware break array\n");
+		return;
+	}
+
+	memset(breakinfo, 0, HW_BREAKPOINT * sizeof(struct hw_breakpoint));
+
+	for (i = 0; i < hw_break_total_dbr; i++)
+		breakinfo[i].capable = HWCAP_DBR;
+
+	for (; i < HW_BREAKPOINT; i++)
+		breakinfo[i].capable = HWCAP_IBR;
+
+	return;
+}
+
+void
+correct_hw_break(void)
+{
+	int breakno;
+
+	if (!breakinfo)
+		return;
+
+	for (breakno = 0; breakno < HW_BREAKPOINT; breakno++) {
+		if (breakinfo[breakno].enabled) {
+			if (breakinfo[breakno].capable & HWCAP_IBR) {
+				int ibreakno = breakno - hw_break_total_dbr;
+				ia64_set_ibr(ibreakno << 1, breakinfo[breakno].addr);
+				ia64_set_ibr((ibreakno << 1) + 1,
+					(~breakinfo[breakno].mask & ((1UL << 56UL) - 1)) |
+					(1UL << 56UL) | (1UL << 63UL));
+			}
+			else {
+				ia64_set_dbr(breakno << 1, breakinfo[breakno].addr);
+				ia64_set_dbr((breakno << 1) + 1,
+					(~breakinfo[breakno].mask & ((1UL << 56UL) - 1)) |
+					(1UL << 56UL) | (breakinfo[breakno].type << 62UL));
+			}
+		}
+		else  {
+			if (breakinfo[breakno].capable & HWCAP_IBR)
+				ia64_set_ibr(((breakno - hw_break_total_dbr) << 1) + 1, 0);
+			else
+				ia64_set_dbr((breakno << 1) + 1, 0);
+		}
+	}
+
+	return;
+}
+
+int
+hardware_breakpoint(unsigned long addr, int length, int type, int action)
+{
+	int breakno, found, watch;
+	unsigned long mask;
+	extern unsigned long _start[];
+
+	if (!hw_breakpoint_init)
+		do_init_hw_break();
+
+	if (!breakinfo)
+		return 0;
+	else if (addr == (unsigned long) _start)
+		return 1;
+
+	if (type == WATCH_ACCESS)
+		mask = HWCAP_DBR;
+	else
+		mask = 1UL << type;
+
+	for (watch = 0, found = 0, breakno = 0; breakno < HW_BREAKPOINT; breakno++) {
+		if (action) {
+			if (breakinfo[breakno].enabled || !(breakinfo[breakno].capable & mask))
+				continue;
+			breakinfo[breakno].enabled = 1;
+			breakinfo[breakno].type = type;
+			breakinfo[breakno].mask = length - 1;
+			breakinfo[breakno].addr = addr;
+			watch = breakno;
+		} else if (breakinfo[breakno].enabled &&
+			((length < 0 && breakinfo[breakno].addr == addr) ||
+			((breakinfo[breakno].capable & mask) &&
+			(breakinfo[breakno].mask == (length - 1)) &&
+			(breakinfo[breakno].addr == addr)))) {
+			breakinfo[breakno].enabled = 0;
+			breakinfo[breakno].type = 0UL;
+		}
+		else
+			continue;
+		found++;
+		if (type != WATCH_ACCESS)
+			break;
+		else if (found == 2)
+			break;
+		else
+			mask = HWCAP_IBR;
+	}
+
+	if (type == WATCH_ACCESS && found == 1) {
+		breakinfo[watch].enabled = 0;
+		found = 0;
+	}
+
+	return found;
+}
+
+#ifdef	oldbreak_protocol
+int
+remove_hw_break(unsigned breakno)
+{
+	if (!breakinfo[breakno].enabled)
+		return -1;
+
+	breakinfo[breakno].enabled = 0;
+
+	return 0;
+}
+
+int
+set_hw_break(unsigned breakno, unsigned type, unsigned len, unsigned addr)
+{
+	if (breakinfo[breakno].enabled)
+		return -1;
+
+	breakinfo[breakno].enabled = 1;
+	breakinfo[breakno].type = type;
+	breakinfo[breakno].mask = len - 1;
+	breakinfo[breakno].addr = addr;
+	return 0;
+}
+#endif
+
+static void inline
+normalize(struct unw_frame_info *running, struct pt_regs *regs)
+{
+	unsigned long sp;
+
+	/*
+	 * unwind to last frame before exception which will be an error
+	 * and then fetch the bsp at exception time.
+	 */
+
+	do {
+		unw_get_sp(running, &sp);
+		if ((sp + 0x10) >= (unsigned long) regs)
+			break;
+	} while (unw_unwind(running) >= 0);
+
+	return;
+}
+
+#ifdef CONFIG_SMP
+static int in_kgdb_console = 0;
+
+
+static void
+snap_regs(struct unw_frame_info *unw_info, void *data)
+{
+	struct pt_regs *regs;
+	int cpu;
+
+	regs = data;
+	normalize(unw_info, regs);
+	cpu = smp_processor_id();
+	unw_get_regs(unw_info, kgdb_info.cpus_waiting[cpu].ia64_regs, regs);
+
+	return;
+}
+
+int
+in_kgdb(struct pt_regs *regs, struct unw_frame_info *unw_info)
+{
+	unsigned flags;
+	int cpu = smp_processor_id();
+	in_kgdb_called = 1;
+
+	preempt_disable();
+
+	if (!spin_is_locked(&kgdb_spinlock)) {
+		if (in_kgdb_here_log[cpu] ||	/* we are holding this cpu */
+		    in_kgdb_console) {	/* or we are doing slow i/o */
+			preempt_enable_no_resched();
+			return 1;
+		}
+		preempt_enable_no_resched();
+		return 0;
+	}
+
+	/* As I see it the only reason not to let all cpus spin on
+	 * the same spin_lock is to allow selected ones to proceed.
+	 * This would be a good thing, so we leave it this way.
+	 * Maybe someday....  Done !
+
+	 * in_kgdb() is called from an NMI so we don't pretend
+	 * to have any resources, like printk() for example.
+	 */
+
+	kgdb_local_irq_save(flags);	/* only local here, to avoid hanging */
+	/*
+	 * log arival of this cpu
+	 * The NMI keeps on ticking.  Protect against recurring more
+	 * than once, and ignor the cpu that has the kgdb lock
+	 */
+	in_kgdb_entry_log[cpu]++;
+	in_kgdb_here_log[cpu] = regs;
+	if (cpu == spinlock_cpu || waiting_cpus[cpu].task)
+		goto exit_in_kgdb;
+
+	/*
+	 * For protection of the initilization of the spin locks by kgdb
+	 * it locks the kgdb spinlock before it gets the wait locks set
+	 * up.	We wait here for the wait lock to be taken.  If the
+	 * kgdb lock goes away first??	Well, it could be a slow exit
+	 * sequence where the wait lock is removed prior to the kgdb lock
+	 * so if kgdb gets unlocked, we just exit.
+	 */
+
+	while (spin_is_locked(&kgdb_spinlock) &&
+	       !spin_is_locked(waitlocks + cpu)) ;
+	if (!spin_is_locked(&kgdb_spinlock))
+		goto exit_in_kgdb;
+
+	if (unw_info)
+		unw_get_regs(unw_info, kgdb_info.cpus_waiting[cpu].ia64_regs, regs);
+	else if (!user_mode(regs)) {
+		if (current->state == TASK_RUNNING)
+			unw_init_running(snap_regs, regs);
+		else
+			kgdb_get_block_task(current, kgdb_info.cpus_waiting[cpu].ia64_regs);
+	}
+	waiting_cpus[cpu].task = current;
+	waiting_cpus[cpu].pid = (current->pid) ? : (PID_MAX + cpu);
+	waiting_cpus[cpu].regs = regs;
+
+	spin_unlock_wait(waitlocks + cpu);
+
+
+	/*
+	 * log departure of this cpu
+	 */
+	waiting_cpus[cpu].task = 0;
+	waiting_cpus[cpu].pid = 0;
+	waiting_cpus[cpu].regs = 0;
+	correct_hw_break();
+      exit_in_kgdb:
+	in_kgdb_here_log[cpu] = 0;
+	kgdb_local_irq_restore(flags);
+	preempt_enable_no_resched();
+	return 1;
+	/*
+	   spin_unlock(continuelocks + smp_processor_id());
+	 */
+}
+
+void
+smp__in_kgdb(struct pt_regs regs)
+{
+	in_kgdb(&regs, NULL);
+}
+#else
+int
+in_kgdb(struct pt_regs *regs, struct unw_frame_info *unw)
+{
+	return (kgdb_spinlock);
+}
+#endif
+
+void
+printexceptioninfo(int exceptionNo, int errorcode, char *buffer)
+{
+	switch (exceptionNo) {
+	case 1:		/* debug exception */
+		break;
+	case 3:		/* breakpoint */
+		sprintf(buffer, "Software breakpoint");
+		return;
+	default:
+		sprintf(buffer, "Details not available");
+		return;
+	}
+	sprintf(buffer, "Unknown trap");
+	return;
+}
+
+/*
+ * This function does all command procesing for interfacing to gdb.
+ *
+ * NOTE:  The INT nn instruction leaves the state of the interrupt
+ *	  enable flag UNCHANGED.  That means that when this routine
+ *	  is entered via a breakpoint (INT 3) instruction from code
+ *	  that has interrupts enabled, then interrupts will STILL BE
+ *	  enabled when this routine is entered.	 The first thing that
+ *	  we do here is disable interrupts so as to prevent recursive
+ *	  entries and bothersome serial interrupts while we are
+ *	  trying to run the serial port in polled mode.
+ *
+ * For kernel version 2.1.xx the kgdb_cli() actually gets a spin lock so
+ * it is always necessary to do a restore_flags before returning
+ * so as to let go of that lock.
+ */
+
+static void do_kgdb_handle_exception(struct unw_frame_info *, void *data);
+
+int
+kgdb_handle_exception(int exceptionVector, int signo, unsigned long err_code, struct pt_regs *linux_regs)
+{
+	struct kgdb_state info;
+
+	/*
+	 * If the entry is not from the kernel then return to the Linux
+	 * trap handler and let it process the interrupt normally.
+	 */
+	if (user_mode(linux_regs)) {
+		printk("ignoring non-kernel exception\n");
+		print_regs(linux_regs);
+		return (0);
+	}
+
+	preempt_disable();
+
+	kgdb_info.called_from = __builtin_return_address(0);
+
+	info.exceptionVector = exceptionVector;
+	info.signo = signo;
+	info.err_code = err_code;
+	info.regs = linux_regs;
+	info.unw = (void *) 0;
+	unw_init_running(do_kgdb_handle_exception, &info);
+
+	preempt_enable_no_resched();
+
+	return info.ret;
+}
+
+static int kgdb_dbregs_enabled;
+
+static void
+do_kgdb_handle_exception(struct unw_frame_info *unw_info, void *data)
+{
+	int exceptionVector, signo, have_regs = 0;
+	unsigned long err_code;
+	struct pt_regs *linux_regs;
+	struct kgdb_state *info;
+	struct task_struct *usethread = NULL;
+	struct task_struct *thread_list_start = 0, *thread = NULL;
+	int length;
+	unsigned long addr;
+	char *ptr;
+	int newPC;
+	threadref thref;
+	int threadid;
+	int thread_min = PID_MAX + MAX_NO_CPUS;
+#ifdef old_thread_list
+	int maxthreads;
+#endif
+	int nothreads;
+	unsigned long flags;
+#define	gdb_regs	kgdb_info.ia64_regs
+	IF_SMP(int entry_state = 0);	/* 0, ok, 1, no nmi, 2 sync failed */
+#define NO_NMI 1
+#define NO_SYNC 2
+#define	ptregs	(*linux_regs)
+#define NUMREGS NUM_REGS
+
+	info = data;
+	info->unw = unw_info;
+	exceptionVector = info->exceptionVector;
+	signo = info->signo;
+	err_code = info->err_code;
+	linux_regs = info->regs;
+
+	normalize(unw_info, linux_regs);
+
+	/*
+	 * If we're using eth mode, set the 'mode' in the netdevice.
+	 */
+	if (kgdboe)
+		netpoll_set_trap(1);
+
+	kgdb_local_irq_save(flags);
+
+	/* Get kgdb spinlock */
+
+	KGDB_SPIN_LOCK(&kgdb_spinlock);
+	kgdb_info.entry_itc = ia64_get_itc();
+	/*
+	 * We depend on this spinlock and the NMI watch dog to control the
+	 * other cpus.	They will arrive at "in_kgdb()" as a result of the
+	 * NMI and will wait there for the following spin locks to be
+	 * released.
+	 */
+#ifdef CONFIG_SMP
+
+#if 0
+	if (cpu_callout_map & ~MAX_CPU_MASK) {
+		printk("kgdb : too many cpus, possibly not mapped"
+		       " in contiguous space, change MAX_NO_CPUS"
+		       " in kgdb_stub and make new kernel.\n"
+		       " cpu_callout_map is %lx\n", cpu_callout_map);
+		goto exit_just_unlock;
+	}
+#endif
+	if (spinlock_count == 1) {
+		long time = 0, end_time;
+		int i;
+		int cpu_logged_in[MAX_NO_CPUS] = {[0 ... MAX_NO_CPUS - 1] = (0)
+		};
+		if (remote_debug) {
+			printk("kgdb : cpu %d entry, syncing others\n",
+			       smp_processor_id());
+		}
+		for (i = 0; i < MAX_NO_CPUS; i++) {
+			/*
+			 * Use trylock as we may already hold the lock if
+			 * we are holding the cpu.  Net result is all
+			 * locked.
+			 */
+			spin_trylock(&waitlocks[i]);
+		}
+		for (i = 0; i < MAX_NO_CPUS; i++)
+			cpu_logged_in[i] = 0;
+		/*
+		 * Wait for their arrival.  We know the watch dog is active if
+		 * in_kgdb() has ever been called, as it is always called on a
+		 * watchdog tick.
+		 */
+		time = ia64_get_itc();
+		end_time = time + 2;	/* Note: we use the High order bits! */
+		i = 1;
+		if (num_online_cpus() > 1) {
+			int me_in_kgdb = in_kgdb_entry_log[smp_processor_id()];
+			smp_send_nmi_allbutself();
+
+			while (i < num_online_cpus() && time != end_time) {
+				int j;
+				for (j = 0; j < MAX_NO_CPUS; j++) {
+					if (waiting_cpus[j].task &&
+					    waiting_cpus[j].task != NOCPU &&
+					    !cpu_logged_in[j]) {
+						i++;
+						cpu_logged_in[j] = 1;
+						if (remote_debug) {
+							printk
+							    ("kgdb : cpu %d arrived at kgdb\n",
+							     j);
+						}
+						break;
+					} else if (!waiting_cpus[j].task &&
+						   !cpu_online(j)) {
+						waiting_cpus[j].task = NOCPU;
+						cpu_logged_in[j] = 1;
+						waiting_cpus[j].hold = 1;
+						break;
+					}
+					if (!waiting_cpus[j].task && in_kgdb_here_log[j]) {
+						int wait = 100000;
+						while (wait-- && !waiting_cpus[j].task );
+						if (!waiting_cpus[j].task  &&
+							in_kgdb_here_log[j]) {
+							printk
+							    ("kgdb : cpu %d stall"
+							     " in in_kgdb\n",
+							     j);
+							i++;
+							cpu_logged_in[j] = 1;
+							waiting_cpus[j].task =
+								(struct task_struct *) 1;
+						}
+					}
+				}
+
+				if (in_kgdb_entry_log[smp_processor_id()] >
+				    (me_in_kgdb + 10)) {
+					break;
+				}
+
+				time = ia64_get_itc();
+			}
+			if (i < num_online_cpus()) {
+				printk
+				    ("kgdb : time out, proceeding without sync\n");
+#if 0
+				printk("kgdb : Waiting_cpus: 0 = %d, 1 = %d\n",
+				       waiting_cpus[0].task != 0,
+				       waiting_cpus[1].task != 0);
+				printk("kgdb : Cpu_logged in: 0 = %d, 1 = %d\n",
+				       cpu_logged_in[0], cpu_logged_in[1]);
+				printk
+				    ("kgdb : in_kgdb_here_log in: 0 = %d, 1 = %d\n",
+				     in_kgdb_here_log[0] != 0,
+				     in_kgdb_here_log[1] != 0);
+#endif
+				entry_state = NO_SYNC;
+			} else {
+#if 0
+				int ent =
+				    in_kgdb_entry_log[smp_processor_id()] -
+				    me_in_kgdb;
+				printk("kgdb : sync after %d entries\n", ent);
+#endif
+			}
+		} else {
+			if (remote_debug) {
+				printk
+				    ("kgdb : %ld cpus, but watchdog not active\n"
+				     "proceeding without locking down other cpus\n",
+				     num_online_cpus());
+				entry_state = NO_NMI;
+			}
+		}
+	}
+#endif
+
+	if (remote_debug) {
+		unsigned long *lp = (unsigned long *) &linux_regs;
+
+		printk("handle_exception(exceptionVector=%d, "
+		       "signo=%d, err_code=%ld, linux_regs=%p)\n",
+		       exceptionVector, signo, err_code, linux_regs);
+		if (debug_regs) {
+			print_regs(&ptregs);
+			printk("Stk: %8lx %8lx %8lx %8lx"
+			       "  %8lx %8lx %8lx %8lx\n",
+			       lp[0], lp[1], lp[2], lp[3],
+			       lp[4], lp[5], lp[6], lp[7]);
+			printk("     %8lx %8lx %8lx %8lx"
+			       "  %8lx %8lx %8lx %8lx\n",
+			       lp[8], lp[9], lp[10], lp[11],
+			       lp[12], lp[13], lp[14], lp[15]);
+			printk("     %8lx %8lx %8lx %8lx  "
+			       "%8lx %8lx %8lx %8lx\n",
+			       lp[16], lp[17], lp[18], lp[19],
+			       lp[20], lp[21], lp[22], lp[23]);
+			printk("     %8lx %8lx %8lx %8lx  "
+			       "%8lx %8lx %8lx %8lx\n",
+			       lp[24], lp[25], lp[26], lp[27],
+			       lp[28], lp[29], lp[30], lp[31]);
+		}
+	}
+
+	/* Disable hardware debugging while we are in kgdb */
+	/* Get the debug register status register */
+	hw_breakpoint_status = ia64_getreg(_IA64_REG_PSR);
+	if (hw_breakpoint_status & IA64_PSR_DB)
+		ia64_setreg(_IA64_REG_PSR_L, hw_breakpoint_status ^ IA64_PSR_DB);
+
+
+	switch (exceptionVector) {
+	case -1:	/* general death */
+	case 11:	/* break  fix signo */
+		switch (err_code) { 	/* break_num */
+		case BREAKNUM:
+			signo = SIGTRAP;
+			break;
+		case KGDBBREAKNUM:
+			signo = SIGTRAP;
+			if (ia64_psr(linux_regs)->ri < 2)
+				kgdb_pc(linux_regs, linux_regs->cr_iip +
+					ia64_psr(linux_regs)->ri + 1);
+			else
+				kgdb_pc(linux_regs, linux_regs->cr_iip + 16);
+			break;
+		}
+		break;
+	case 29:	/*  hardware breakpoint ibr/dbr fault */
+	case 36:	/* single step trap */
+		signo = SIGTRAP;
+		break;
+	case 6:		/* ikey_miss */
+	case 7:		/* dkey_miss */
+	case 24:	/* general exception */
+	case 31:	/*  unsupported data reference */
+		signo = SIGSEGV;
+		break;
+	case 13:	/* reserved  */
+	case 14:	/*  " ""     */
+	case 15:	/*  " ""     */
+	case 16:	/*  " ""     */
+	case 17:	/*  " ""     */
+	case 18:	/*  " ""     */
+	case 19:	/*  " ""     */
+	case 28:	/*  " ""     */
+	case 25:	/* disable fp */
+	case 32:	/* floating point */
+	case 33:	/* floating point trap */
+	case 34:	/* lower privilege fault */
+	case 35:	/* taken branch trap */
+	case 37:	/* reserved */
+	case 38:	/* reserved */
+	case 39:	/* reserved */
+	case 40:	/* reserved */
+	case 41:	/* reserved */
+	case 42:	/* reserved */
+	case 43:	/* reserved */
+	case 44:	/* reserved */
+	case 45:	/* ia32_exception */
+	case 47:	/* ia32 interrupt  */
+	default:	/* reserved and undefined */
+		signo = SIGILL;
+		break;
+	case 5:		/* kernel page fault */
+		if (mem_err_expected) {
+			/*
+			 * This fault occured because of the
+			 * get_char or set_char routines.  These
+			 * two routines use either eax of edx to
+			 * indirectly reference the location in
+			 * memory that they are working with.
+			 * For a page fault, when we return the
+			 * instruction will be retried, so we
+			 * have to make sure that these
+			 * registers point to valid memory.
+			 */
+			mem_err = 1;	/* set mem error flag */
+			mem_err_expected = 0;
+			mem_err_cnt++;	/* helps in debugging */
+			if (ia64_psr(linux_regs)->ri < 2)
+				kgdb_pc(linux_regs, linux_regs->cr_iip +
+					ia64_psr(linux_regs)->ri + 1);
+			else
+				kgdb_pc(linux_regs, linux_regs->cr_iip + 16);
+			if (remote_debug)
+				printk("Return after memory error: "
+				       "mem_err_cnt=%d\n", mem_err_cnt);
+			if (debug_regs)
+				print_regs(&ptregs);
+			goto exit_kgdb;
+		}
+		break;
+	}
+	if (remote_debug)
+		printk("kgdb : entered kgdb on cpu %d\n", smp_processor_id());
+
+	gdb_ia64vector = exceptionVector;
+	gdb_ia64errcode = err_code;
+#ifdef CONFIG_SMP
+	/*
+	 * OK, we can now communicate, lets tell gdb about the sync.
+	 * but only if we had a problem.
+	 */
+	switch (entry_state) {
+	case NO_NMI:
+		to_gdb("NMI not active, other cpus not stopped\n");
+		break;
+	case NO_SYNC:
+		to_gdb("Some cpus not stopped, see 'kgdb_info' for details\n");
+	default:;
+	}
+
+#endif
+/*
+ * Set up the gdb function call area.
+ */
+
+      IF_SMP(once_again:)
+	    /* reply to host that an exception has occurred */
+	remcomOutBuffer[0] = 'S';
+	remcomOutBuffer[1] = hexchars[signo >> 4];
+	remcomOutBuffer[2] = hexchars[signo % 16];
+	remcomOutBuffer[3] = 0;
+
+	putpacket(remcomOutBuffer);
+
+	while (1 == 1) {
+		error = 0;
+		remcomOutBuffer[0] = 0;
+		getpacket(remcomInBuffer);
+		switch (remcomInBuffer[0]) {
+		case '?':
+			remcomOutBuffer[0] = 'S';
+			remcomOutBuffer[1] = hexchars[signo >> 4];
+			remcomOutBuffer[2] = hexchars[signo % 16];
+			remcomOutBuffer[3] = 0;
+			break;
+		case 'd':
+			remote_debug = !(remote_debug);	/* toggle debug flag */
+			printk("Remote debug %s\n",
+			       remote_debug ? "on" : "off");
+			break;
+		case 'p':	/* fetch register */
+		{
+			int regnum;
+
+			if (!have_regs) {
+				get_gdb_regs(usethread, info);
+				have_regs = 1;
+			}
+
+			hex2mem(&remcomInBuffer[1], (char *) &regnum, sizeof(regnum), 0);
+			if (regnum >= NUMREGS) {
+				remcomOutBuffer[0] = 'E';
+				remcomOutBuffer[1] = 0;
+				break;
+			}
+			mem2hex((char *) &gdb_regs[REGISTER_INDEX(regnum)], remcomOutBuffer,
+				REGISTER_SIZE(regnum), 0);
+			remcomOutBuffer[REGISTER_SIZE(regnum) * 2] = 0;
+			break;
+		}
+		case 'g':	/* return the value of the CPU registers */
+			get_gdb_regs(usethread, info);
+			mem2hex((char *) gdb_regs, remcomOutBuffer, NUMREGBYTES, 0);
+			break;
+		case 'G':	/* set the value of the CPU registers - return OK */
+			hex2mem(&remcomInBuffer[1], (char *) gdb_regs, NUMREGBYTES, 0);
+			if (!usethread || usethread == current) {
+				gdb_regs_to_regs(info);
+				strcpy(remcomOutBuffer, "OK");
+			} else {
+				strcpy(remcomOutBuffer, "E00");
+			}
+			break;
+
+		case 'P':{	/* set the value of a single CPU register -
+				   return OK */
+				/*
+				 * For some reason, gdb wants to talk about psudo
+				 * registers (greater than 15).	 These may have
+				 * meaning for ptrace, but for us it is safe to
+				 * ignor them.	We do this by dumping them into
+				 * _GS which we also ignor, but do have memory for.
+				 */
+				int regno;
+
+				ptr = &remcomInBuffer[1];
+				regs_to_gdb_regs(info);
+				if ((!usethread || usethread == current) &&
+				    hexToInt(&ptr, &regno) &&
+				    *ptr++ == '=' && (regno >= 0)) {
+					regno =
+					    (regno >= NUMREGS ? 0 : regno);
+					hex2mem(ptr, (char *) &gdb_regs[REGISTER_INDEX(regno)],
+						4, 0);
+					gdb_regs_to_regs(info);
+					strcpy(remcomOutBuffer, "OK");
+					break;
+				}
+				strcpy(remcomOutBuffer, "E01");
+				break;
+			}
+
+			/* mAA..AA,LLLL	 Read LLLL bytes at address AA..AA */
+		case 'm':
+			/* TRY TO READ %x,%x.  IF SUCCEED, SET PTR = 0 */
+			ptr = &remcomInBuffer[1];
+			if (hexToLong(&ptr, &addr) &&
+			    (*(ptr++) == ',') && (hexToInt(&ptr, &length))) {
+				ptr = 0;
+				/*
+				 * hex doubles the byte count
+				 */
+				if (length > (BUFMAX / 2))
+					length = BUFMAX / 2;
+				mem2hex((char *) addr,
+					remcomOutBuffer, length, 1);
+				if (mem_err) {
+					strcpy(remcomOutBuffer, "E03");
+					debug_error("memory fault\n", NULL);
+				}
+			}
+
+			if (ptr) {
+				strcpy(remcomOutBuffer, "E01");
+				debug_error
+				    ("malformed read memory command: %s\n",
+				     remcomInBuffer);
+			}
+			break;
+
+			/* MAA..AA,LLLL:
+			   Write LLLL bytes at address AA.AA return OK */
+		case 'M':
+			/* TRY TO READ '%x,%x:'.  IF SUCCEED, SET PTR = 0 */
+			ptr = &remcomInBuffer[1];
+			if (hexToLong(&ptr, &addr) &&
+			    (*(ptr++) == ',') &&
+			    (hexToInt(&ptr, &length)) && (*(ptr++) == ':')) {
+				extern unsigned long _start[];
+
+				if (addr == (unsigned long) _start)
+					strcpy(remcomOutBuffer, "OK");
+
+				else {
+					hex2mem(ptr, (char *) addr, length, 1);
+
+					if (mem_err) {
+						strcpy(remcomOutBuffer, "E03");
+						debug_error("memory fault\n", NULL);
+					} else {
+						if (kernel_text_address(addr))
+							flush_icache_range(addr, addr + length);
+						strcpy(remcomOutBuffer, "OK");
+					}
+				}
+
+				ptr = 0;
+			}
+			if (ptr) {
+				strcpy(remcomOutBuffer, "E02");
+				debug_error
+				    ("malformed write memory command: %s\n",
+				     remcomInBuffer);
+			}
+			break;
+		case 'S':
+			remcomInBuffer[0] = 's';
+		case 'C':
+			/* Csig;AA..AA where ;AA..AA is optional
+			 * continue with signal
+			 * Since signals are meaning less to us, delete that
+			 * part and then fall into the 'c' code.
+			 */
+			ptr = &remcomInBuffer[1];
+			length = 2;
+			while (*ptr && *ptr != ';') {
+				length++;
+				ptr++;
+			}
+			if (*ptr) {
+				do {
+					ptr++;
+					*(ptr - length++) = *ptr;
+				} while (*ptr);
+			} else {
+				remcomInBuffer[1] = 0;
+			}
+
+			/* cAA..AA  Continue at address AA..AA(optional) */
+			/* sAA..AA  Step one instruction from AA..AA(optional) */
+			/* D	    detach, reply OK and then continue */
+		case 'c':
+		case 's':
+		case 'D':
+
+			/* try to read optional parameter,
+			   pc unchanged if no parm */
+			ptr = &remcomInBuffer[1];
+			if (hexToLong(&ptr, &addr)) {
+				if (remote_debug)
+					printk("Changing EIP to 0x%lx\n", addr);
+
+				ptregs.cr_iip = addr;
+			}
+
+			newPC = ptregs.cr_iip;
+
+			/* clear the trace bit */
+			ptregs.cr_ipsr &= ~IA64_PSR_SS;
+
+			/* set the trace bit if we're stepping */
+			if (remcomInBuffer[0] == 's')
+				ptregs.cr_ipsr |= IA64_PSR_SS;
+
+			/* detach is a friendly version of continue. Note that
+			   debugging is still enabled (e.g hit control C)
+			 */
+			if (remcomInBuffer[0] == 'D') {
+				strcpy(remcomOutBuffer, "OK");
+				putpacket(remcomOutBuffer);
+			}
+
+			if (remote_debug) {
+				printk("Resuming execution\n");
+				print_regs(&ptregs);
+			}
+
+			if (kgdboe)
+				netpoll_set_trap(0);
+
+			correct_hw_break();
+			ptregs.cr_ipsr |= IA64_PSR_DB;
+			goto exit_kgdb;
+
+			/* kill the program */
+		case 'k':	/* do nothing */
+			break;
+
+			/* query */
+		case 'q':
+			nothreads = 0;
+			switch (remcomInBuffer[1]) {
+			case 'f':
+				threadid = 1;
+				thread_list = 2;
+				thread_list_start = (usethread ? : current);
+			case 's':
+				if (!cmp_str(&remcomInBuffer[2],
+					     "ThreadInfo", 10))
+					break;
+
+				remcomOutBuffer[nothreads++] = 'm';
+				for (; threadid < PID_MAX + MAX_NO_CPUS;
+				     threadid++) {
+					thread = getthread(threadid);
+					if (thread) {
+						nothreads += int_to_hex_v(
+							&remcomOutBuffer[
+								nothreads],
+							threadid);
+						if (thread_min > threadid)
+							thread_min = threadid;
+						remcomOutBuffer[
+							nothreads] = ',';
+						nothreads++;
+						if (nothreads > BUFMAX - 10)
+							break;
+					}
+				}
+				if (remcomOutBuffer[nothreads - 1] == 'm') {
+					remcomOutBuffer[nothreads - 1] = 'l';
+				} else {
+					nothreads--;
+				}
+				remcomOutBuffer[nothreads] = 0;
+				break;
+
+#ifdef old_thread_list /* Old thread info request */
+			case 'L':
+				/* List threads */
+				thread_list = 2;
+				thread_list_start = (usethread ? : current);
+				unpack_byte(remcomInBuffer + 3, &maxthreads);
+				unpack_threadid(remcomInBuffer + 5, &thref);
+				do {
+					int buf_thread_limit =
+					    (BUFMAX - 22) / BUF_THREAD_ID_SIZE;
+					if (maxthreads > buf_thread_limit) {
+						maxthreads = buf_thread_limit;
+					}
+				} while (0);
+				remcomOutBuffer[0] = 'q';
+				remcomOutBuffer[1] = 'M';
+				remcomOutBuffer[4] = '0';
+				pack_threadid(remcomOutBuffer + 5, &thref);
+
+				threadid = threadref_to_int(&thref);
+				for (nothreads = 0;
+				     nothreads < maxthreads &&
+				     threadid < PID_MAX + MAX_NO_CPUS;
+				     threadid++) {
+					thread = getthread(threadid);
+					if (thread) {
+						int_to_threadref(&thref,
+								 threadid);
+						pack_threadid(remcomOutBuffer +
+							      21 +
+							      nothreads * 16,
+							      &thref);
+						nothreads++;
+						if (thread_min > threadid)
+							thread_min = threadid;
+					}
+				}
+
+				if (threadid == PID_MAX + MAX_NO_CPUS) {
+					remcomOutBuffer[4] = '1';
+				}
+				pack_hex_byte(remcomOutBuffer + 2, nothreads);
+				remcomOutBuffer[21 + nothreads * 16] = '\0';
+				break;
+#endif
+			case 'C':
+				/* Current thread id */
+				remcomOutBuffer[0] = 'Q';
+				remcomOutBuffer[1] = 'C';
+				threadid = current->pid;
+				if (!threadid) {
+					/*
+					 * idle thread
+					 */
+					for (threadid = PID_MAX;
+					     threadid < PID_MAX + MAX_NO_CPUS;
+					     threadid++) {
+						if (current ==
+						    idle_task(threadid -
+							      PID_MAX))
+							break;
+					}
+				}
+				int_to_threadref(&thref, threadid);
+				pack_threadid(remcomOutBuffer + 2, &thref);
+				remcomOutBuffer[18] = '\0';
+				break;
+
+			case 'E':
+				/* Print exception info */
+				printexceptioninfo(exceptionVector,
+						   err_code, remcomOutBuffer);
+				break;
+			case 'T':{
+				char * nptr;
+				/* Thread extra info */
+				if (!cmp_str(&remcomInBuffer[2],
+					    "hreadExtraInfo,", 15)) {
+					break;
+				}
+				ptr = &remcomInBuffer[17];
+				hexToInt(&ptr, &threadid);
+				thread = getthread(threadid);
+				nptr = &thread->comm[0];
+				length = 0;
+				ptr = &remcomOutBuffer[0];
+				do {
+					length++;
+					ptr = pack_hex_byte(ptr, *nptr++);
+				 } while (*nptr && length < 16);
+				/*
+				 * would like that 16 to be the size of
+				 * task_struct.comm but don't know the
+				 * syntax..
+				 */
+				*ptr = 0;
+			}
+			}
+			break;
+
+			/* task related */
+		case 'H':
+			switch (remcomInBuffer[1]) {
+			case 'g':
+				ptr = &remcomInBuffer[2];
+				hexToInt(&ptr, &threadid);
+				thread = getthread(threadid);
+				if (!thread) {
+					remcomOutBuffer[0] = 'E';
+					remcomOutBuffer[1] = '\0';
+					break;
+				}
+				/*
+				 * Just in case I forget what this is all about,
+				 * the "thread info" command to gdb causes it
+				 * to ask for a thread list.  It then switches
+				 * to each thread and asks for the registers.
+				 * For this (and only this) usage, we want to
+				 * fudge the registers of tasks not on the run
+				 * list (i.e. waiting) to show the routine that
+				 * called schedule. Also, gdb, is a minimalist
+				 * in that if the current thread is the last
+				 * it will not re-read the info when done.
+				 * This means that in this case we must show
+				 * the real registers. So here is how we do it:
+				 * Each entry we keep track of the min
+				 * thread in the list (the last that gdb will)
+				 * get info for.  We also keep track of the
+				 * starting thread.
+				 * "thread_list" is cleared when switching back
+				 * to the min thread if it is was current, or
+				 * if it was not current, thread_list is set
+				 * to 1.  When the switch to current comes,
+				 * if thread_list is 1, clear it, else do
+				 * nothing.
+				 */
+				usethread = thread;
+				have_regs = 0;
+				if ((thread_list == 1) &&
+				    (thread == thread_list_start)) {
+					thread_list = 0;
+				}
+				if (thread_list && (threadid == thread_min)) {
+					if (thread == thread_list_start) {
+						thread_list = 0;
+					} else {
+						thread_list = 1;
+					}
+				}
+				/* follow through */
+			case 'c':
+				remcomOutBuffer[0] = 'O';
+				remcomOutBuffer[1] = 'K';
+				remcomOutBuffer[2] = '\0';
+				break;
+			}
+			break;
+
+			/* Query thread status */
+		case 'T':
+			ptr = &remcomInBuffer[1];
+			hexToInt(&ptr, &threadid);
+			thread = getthread(threadid);
+			if (thread) {
+				remcomOutBuffer[0] = 'O';
+				remcomOutBuffer[1] = 'K';
+				remcomOutBuffer[2] = '\0';
+				if (thread_min > threadid)
+					thread_min = threadid;
+			} else {
+				remcomOutBuffer[0] = 'E';
+				remcomOutBuffer[1] = '\0';
+			}
+			break;
+
+#ifdef	oldbreak_protocol
+		case 'Y': /* set up a hardware breakpoint */
+			ptr = &remcomInBuffer[1];
+			hexToInt(&ptr, &breakno);
+			ptr++;
+			hexToInt(&ptr, &breaktype);
+			ptr++;
+			hexToInt(&ptr, &length);
+			ptr++;
+			hexToLong(&ptr, &addr);
+			if (set_hw_break(breakno & 0x3,
+					 breaktype & 0x3,
+					 length & 0x3, addr) == 0) {
+				strcpy(remcomOutBuffer, "OK");
+			} else {
+				strcpy(remcomOutBuffer, "ERROR");
+			}
+			break;
+
+			/* Remove hardware breakpoint */
+		case 'y':
+			ptr = &remcomInBuffer[1];
+			hexToInt(&ptr, &breakno);
+			if (remove_hw_break(breakno & 0x3) == 0) {
+				strcpy(remcomOutBuffer, "OK");
+			} else {
+				strcpy(remcomOutBuffer, "ERROR");
+			}
+			break;
+#endif
+		/*
+		 * Set/Remove watchpoint
+		 *
+		 */
+		case 'Z':
+		case 'z':
+			if (!kgdb_dbregs_enabled)
+				break;
+
+			switch (remcomInBuffer[1]) {
+			case '0':	/* insert hwd break */
+			case '1':	/* hardware breakpoint */
+			case '2':	/* write watchpoint */
+			case '3':	/* read watchpoint */
+			case '4':	/* access watchpoint */
+			{
+				int ret;
+				if (remcomInBuffer[2] != ',') {
+					strcpy(remcomOutBuffer, "ERROR");
+					break;
+				}
+				ptr = &remcomInBuffer[3];
+				if (hexToLong(&ptr, &addr)) {
+					ptr++;
+					if (!hexToInt(&ptr, &length)) {
+						strcpy(remcomOutBuffer, "ERROR");
+						break;
+					}
+				}
+				else {
+					strcpy(remcomOutBuffer, "ERROR");
+					break;
+				}
+
+				if (remcomInBuffer[1] == '0') {
+					if (remcomInBuffer[0] == 'z')
+						ret = kgdb_arch_remove_breakpoint(addr);
+					else
+						ret = kgdb_arch_set_breakpoint(addr);
+				}
+				else ret = hardware_breakpoint(addr, length,
+					remcomInBuffer[1] - '1',
+					remcomInBuffer[0] == 'Z');
+				if (ret)
+					strcpy(remcomOutBuffer, "OK");
+				else
+					strcpy(remcomOutBuffer, "ERROR");
+				break;
+			}
+			default:
+				strcpy(remcomOutBuffer, "ERROR");
+				break;
+			}
+			break;
+		case 'R':	/* reboot */
+			strcpy(remcomOutBuffer, "OK");
+			putpacket(remcomOutBuffer);
+			/*to_gdb("Rebooting\n"); */
+			machine_restart(NULL);
+
+		}		/* switch */
+
+		/* reply to the request */
+		putpacket(remcomOutBuffer);
+	}			/* while(1==1) */
+	/*
+	 *  reached by goto only.
+	 */
+      exit_kgdb:
+#ifdef CONFIG_SMP
+	/*
+	 * Release gdb wait locks
+	 * Sanity check time.  Must have at least one cpu to run.  Also single
+	 * step must not be done if the current cpu is on hold.
+	 */
+	if (spinlock_count == 1) {
+		int ss_hold = (ptregs.cr_ipsr & IA64_PSR_SS) && kgdb_info.hold_on_sstep;
+		int cpu_avail = 0;
+		int i;
+
+		for (i = 0; i < MAX_NO_CPUS; i++) {
+			if (!cpu_online(i))
+				break;
+			if (!hold_cpu(i)) {
+				cpu_avail = 1;
+			}
+		}
+		/*
+		 * Early in the bring up there will be NO cpus on line...
+		 */
+		if (!cpu_avail && !cpus_empty(cpu_online_map)) {
+			to_gdb("No cpus unblocked, see 'kgdb_info.hold_cpu'\n");
+			goto once_again;
+		}
+		if (hold_cpu(smp_processor_id()) && (ptregs.cr_ipsr & IA64_PSR_SS)) {
+			to_gdb
+			    ("Current cpu must be unblocked to single step\n");
+			goto once_again;
+		}
+
+		if (!ss_hold) {
+			int i;
+			for (i = 0; i < MAX_NO_CPUS; i++) {
+				if (!hold_cpu(i)) {
+					spin_unlock(&waitlocks[i]);
+				}
+			}
+		} else {
+			spin_unlock(&waitlocks[smp_processor_id()]);
+		}
+		/* Release kgdb spinlock */
+		KGDB_SPIN_UNLOCK(&kgdb_spinlock);
+		/*
+		 * If this cpu is on hold, this is where we
+		 * do it.  Note, the NMI will pull us out of here,
+		 * but will return as the above lock is not held.
+		 * We will stay here till another cpu releases the lock for us.
+		 */
+		spin_unlock_wait(waitlocks + smp_processor_id());
+		kgdb_local_irq_restore(flags);
+		info->ret = 0;
+		return;
+	}
+#if 0
+exit_just_unlock:
+#endif
+#endif
+	/* Release kgdb spinlock */
+	KGDB_SPIN_UNLOCK(&kgdb_spinlock);
+	kgdb_local_irq_restore(flags);
+	info->ret = 0;
+	return;
+}
+
+/* this function is used to set up exception handlers for tracing and
+ * breakpoints.
+ * This function is not needed as the above line does all that is needed.
+ * We leave it for backward compatitability...
+ */
+void
+set_debug_traps(void)
+{
+	/*
+	 * linux_debug_hook is defined in traps.c.  We store a pointer
+	 * to our own exception handler into it.
+
+	 * But really folks, every hear of labeled common, an old Fortran
+	 * concept.  Lots of folks can reference it and it is define if
+	 * anyone does.	 Only one can initialize it at link time.  We do
+	 * this with the hook.	See the statement above.  No need for any
+	 * executable code and it is ready as soon as the kernel is
+	 * loaded.  Very desirable in kernel debugging.
+
+	 linux_debug_hook = handle_exception ;
+	 */
+
+	/* In case GDB is started before us, ack any packets (presumably
+	   "$?#xx") sitting there.
+	   putDebugChar ('+');
+
+	   initialized = 1;
+	 */
+}
+
+/* This function will generate a breakpoint exception.	It is used at the
+   beginning of a program to sync up with a debugger and can be used
+   otherwise as a quick means to stop program execution and "break" into
+   the debugger. */
+/* But really, just use the BREAKPOINT macro.  We will handle the int stuff
+ */
+
+#ifdef later
+/*
+ * possibly we should not go thru the traps.c code at all?  Someday.
+ */
+void
+do_kgdb_int3(struct pt_regs *regs, long error_code)
+{
+	kgdb_handle_exception(3, 5, error_code, regs);
+	return;
+}
+#endif
+#undef regs
+#ifdef CONFIG_TRAP_BAD_SYSCALL_EXITS
+asmlinkage void
+bad_sys_call_exit(int stuff)
+{
+	struct pt_regs *regs = (struct pt_regs *) &stuff;
+	printk("Sys call %d return with %x preempt_count\n",
+	       (int) regs->orig_eax, preempt_count());
+}
+#endif
+#ifdef CONFIG_STACK_OVERFLOW_TEST
+#include <asm/kgdb.h>
+asmlinkage void
+stack_overflow(void)
+{
+#ifdef BREAKPOINT
+	BREAKPOINT;
+#else
+	printk("Kernel stack overflow, looping forever\n");
+#endif
+	while (1) {
+	}
+}
+#endif
+
+#if defined(CONFIG_SMP) || defined(CONFIG_KGDB_CONSOLE)
+char gdbconbuf[BUFMAX];
+
+static void
+kgdb_gdb_message(const char *s, unsigned count)
+{
+	int i;
+	int wcount;
+	char *bufptr;
+	/*
+	 * This takes care of NMI while spining out chars to gdb
+	 */
+	IF_SMP(in_kgdb_console = 1);
+	gdbconbuf[0] = 'O';
+	bufptr = gdbconbuf + 1;
+	while (count > 0) {
+		if ((count << 1) > (BUFMAX - 2)) {
+			wcount = (BUFMAX - 2) >> 1;
+		} else {
+			wcount = count;
+		}
+		count -= wcount;
+		for (i = 0; i < wcount; i++) {
+			bufptr = pack_hex_byte(bufptr, s[i]);
+		}
+		*bufptr = '\0';
+		s += wcount;
+
+		putpacket(gdbconbuf);
+
+	}
+	IF_SMP(in_kgdb_console = 0);
+}
+#endif
+#ifdef CONFIG_SMP
+static void
+to_gdb(const char *s)
+{
+	int count = 0;
+	while (s[count] && (count++ < BUFMAX)) ;
+	kgdb_gdb_message(s, count);
+}
+#endif
+#ifdef CONFIG_KGDB_CONSOLE
+#include <linux/console.h>
+#include <linux/init.h>
+#include <linux/fs.h>
+#include <asm/uaccess.h>
+#include <asm/semaphore.h>
+
+void
+kgdb_console_write(struct console *co, const char *s, unsigned count)
+{
+
+	if (gdb_ia64vector == -1) {
+		/*
+		 * We have not yet talked to gdb.  What to do...
+		 * lets break, on continue we can do the write.
+		 * But first tell him whats up. Uh, well no can do,
+		 * as this IS the console.  Oh well...
+		 * We do need to wait or the messages will be lost.
+		 * Other option would be to tell the above code to
+		 * ignore this breakpoint and do an auto return,
+		 * but that might confuse gdb.	Also this happens
+		 * early enough in boot up that we don't have the traps
+		 * set up yet, so...
+		 */
+		breakpoint();
+	}
+	kgdb_gdb_message(s, count);
+}
+
+/*
+ * ------------------------------------------------------------
+ * Serial KGDB driver
+ * ------------------------------------------------------------
+ */
+
+static struct console kgdbcons = {
+	name:"kgdb",
+	write:kgdb_console_write,
+#ifdef CONFIG_KGDB_USER_CONSOLE
+	device:kgdb_console_device,
+#endif
+	flags:CON_PRINTBUFFER | CON_ENABLED,
+	index:-1,
+};
+
+/*
+ * The trick here is that this file gets linked before printk.o
+ * That means we get to peer at the console info in the command
+ * line before it does.	 If we are up, we register, otherwise,
+ * do nothing.	By returning 0, we allow printk to look also.
+ */
+static int kgdb_console_enabled;
+
+int __init
+kgdb_console_init(char *str)
+{
+	if ((strncmp(str, "kgdb", 4) == 0) || (strncmp(str, "gdb", 3) == 0)) {
+		register_console(&kgdbcons);
+		kgdb_console_enabled = 1;
+	}
+	return 0;		/* let others look at the string */
+}
+
+__setup("console=", kgdb_console_init);
+
+int __init
+kgdb_enable_dbregs(char *str)
+{
+	kgdb_dbregs_enabled = 1;
+	return 1;
+}
+
+__setup("kgdb_debug_regs=", kgdb_enable_dbregs);
+
+#ifdef CONFIG_KGDB_USER_CONSOLE
+static kdev_t kgdb_console_device(struct console *c);
+/* This stuff sort of works, but it knocks out telnet devices
+ * we are leaving it here in case we (or you) find time to figure it out
+ * better..
+ */
+
+/*
+ * We need a real char device as well for when the console is opened for user
+ * space activities.
+ */
+
+static int
+kgdb_consdev_open(struct inode *inode, struct file *file)
+{
+	return 0;
+}
+
+static ssize_t
+kgdb_consdev_write(struct file *file, const char *buf,
+		   size_t count, loff_t * ppos)
+{
+	int size, ret = 0;
+	static char kbuf[128];
+	static DECLARE_MUTEX(sem);
+
+	/* We are not reentrant... */
+	if (down_interruptible(&sem))
+		return -ERESTARTSYS;
+
+	while (count > 0) {
+		/* need to copy the data from user space */
+		size = count;
+		if (size > sizeof (kbuf))
+			size = sizeof (kbuf);
+		if (copy_from_user(kbuf, buf, size)) {
+			ret = -EFAULT;
+			break;;
+		}
+		kgdb_console_write(&kgdbcons, kbuf, size);
+		count -= size;
+		ret += size;
+		buf += size;
+	}
+
+	up(&sem);
+
+	return ret;
+}
+
+struct file_operations kgdb_consdev_fops = {
+	open:kgdb_consdev_open,
+	write:kgdb_consdev_write
+};
+static kdev_t
+kgdb_console_device(struct console *c)
+{
+	return MKDEV(TTYAUX_MAJOR, 1);
+}
+
+/*
+ * This routine gets called from the serial stub in the i386/lib
+ * This is so it is done late in bring up (just before the console open).
+ */
+void
+kgdb_console_finit(void)
+{
+	if (kgdb_console_enabled) {
+		char *cptr = cdevname(MKDEV(TTYAUX_MAJOR, 1));
+		char *cp = cptr;
+		while (*cptr && *cptr != '(')
+			cptr++;
+		*cptr = 0;
+		unregister_chrdev(TTYAUX_MAJOR, cp);
+		register_chrdev(TTYAUX_MAJOR, "kgdb", &kgdb_consdev_fops);
+	}
+}
+#endif
+#endif
+#ifdef CONFIG_KGDB_TS
+#include <asm/msr.h>		/* time stamp code */
+#include <asm/hardirq.h>	/* in_interrupt */
+#ifdef CONFIG_KGDB_TS_64
+#define DATA_POINTS 64
+#endif
+#ifdef CONFIG_KGDB_TS_128
+#define DATA_POINTS 128
+#endif
+#ifdef CONFIG_KGDB_TS_256
+#define DATA_POINTS 256
+#endif
+#ifdef CONFIG_KGDB_TS_512
+#define DATA_POINTS 512
+#endif
+#ifdef CONFIG_KGDB_TS_1024
+#define DATA_POINTS 1024
+#endif
+#ifndef DATA_POINTS
+#define DATA_POINTS 128		/* must be a power of two */
+#endif
+#define INDEX_MASK (DATA_POINTS - 1)
+#if (INDEX_MASK & DATA_POINTS)
+#error "CONFIG_KGDB_TS_COUNT must be a power of 2"
+#endif
+struct kgdb_and_then_struct {
+#ifdef CONFIG_SMP
+	int on_cpu;
+#endif
+	struct task_struct *task;
+	long long at_time;
+	int from_ln;
+	char *in_src;
+	void *from;
+	int *with_shpf;
+	int data0;
+	int data1;
+};
+struct kgdb_and_then_struct2 {
+#ifdef CONFIG_SMP
+	int on_cpu;
+#endif
+	struct task_struct *task;
+	long long at_time;
+	int from_ln;
+	char *in_src;
+	void *from;
+	int *with_shpf;
+	struct task_struct *t1;
+	struct task_struct *t2;
+};
+struct kgdb_and_then_struct kgdb_data[DATA_POINTS];
+
+struct kgdb_and_then_struct *kgdb_and_then = &kgdb_data[0];
+int kgdb_and_then_count;
+
+void
+kgdb_tstamp(int line, char *source, int data0, int data1)
+{
+	static spinlock_t ts_spin = SPIN_LOCK_UNLOCKED;
+	int flags;
+	kgdb_local_irq_save(flags);
+	spin_lock(&ts_spin);
+	kgdb_and_then->at_time = ia64_get_itc();
+#ifdef CONFIG_SMP
+	kgdb_and_then->on_cpu = smp_processor_id();
+#endif
+	kgdb_and_then->task = current;
+	kgdb_and_then->from_ln = line;
+	kgdb_and_then->in_src = source;
+	kgdb_and_then->from = __builtin_return_address(0);
+	kgdb_and_then->with_shpf = (int *) (((flags & IF_BIT) >> 9) |
+					    (preempt_count() << 8));
+	kgdb_and_then->data0 = data0;
+	kgdb_and_then->data1 = data1;
+	kgdb_and_then = &kgdb_data[++kgdb_and_then_count & INDEX_MASK];
+	spin_unlock(&ts_spin);
+	kgdb_local_irq_restore(flags);
+#ifdef CONFIG_PREEMPT
+
+#endif
+	return;
+}
+#endif
+typedef int gdb_debug_hook(int exceptionVector,
+			   int signo, int err_code, struct pt_regs *linux_regs);
+gdb_debug_hook *linux_debug_hook = &kgdb_handle_exception;	/* histerical reasons... */
+
+static int kgdb_need_breakpoint[NR_CPUS];
+
+void kgdb_schedule_breakpoint(void)
+{
+	kgdb_need_breakpoint[smp_processor_id()] = 1;
+}
+
+void kgdb_process_breakpoint(void)
+{
+	/*
+	 * Handle a breakpoint queued from inside network driver code
+         * to avoid reentrancy issues
+	 */
+	if (kgdb_need_breakpoint[smp_processor_id()]) {
+		kgdb_need_breakpoint[smp_processor_id()] = 0;
+		BREAKPOINT;
+	}
+}
+
--- diff/arch/ia64/lib/kgdb_serial.c	1970-01-01 01:00:00.000000000 +0100
+++ source/arch/ia64/lib/kgdb_serial.c	2004-06-11 19:21:58.000000000 +0100
@@ -0,0 +1,606 @@
+/*
+ * Serial interface GDB stub
+ *
+ * Written (hacked together) by David Grothe (dave@gcom.com)
+ * Modified to allow invokation early in boot see also
+ * kgdb.h for instructions by George Anzinger(george@mvista.com)
+ * Modified to handle debugging over ethernet by Robert Walsh
+ * <rjwalsh@durables.org> and wangdi <wangdi@clusterfs.com>, based on
+ * code by San Mehat.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/errno.h>
+#include <linux/signal.h>
+#include <linux/sched.h>
+#include <linux/timer.h>
+#include <linux/interrupt.h>
+#include <linux/tty.h>
+#include <linux/tty_flip.h>
+#include <linux/serial.h>
+#include <linux/serial_reg.h>
+#include <linux/serial_core.h>
+#include <linux/config.h>
+#include <linux/major.h>
+#include <linux/string.h>
+#include <linux/fcntl.h>
+#include <linux/ptrace.h>
+#include <linux/ioport.h>
+#include <linux/mm.h>
+#include <linux/init.h>
+#include <linux/highmem.h>
+#include <asm/system.h>
+#include <asm/io.h>
+#include <asm/segment.h>
+#include <asm/bitops.h>
+#include <asm/system.h>
+#include <asm/kgdb_local.h>
+#include <asm/delay.h>
+#ifdef CONFIG_KGDB_USER_CONSOLE
+extern void kgdb_console_finit(void);
+#endif
+#define PRNT_off
+#define TEST_EXISTANCE
+#ifdef PRNT
+#define dbprintk(s) printk s
+#else
+#define dbprintk(s)
+#endif
+#define TEST_INTERRUPT_off
+#ifdef TEST_INTERRUPT
+#define intprintk(s) printk s
+#else
+#define intprintk(s)
+#endif
+
+#define IRQ_T(info) ((info->flags & ASYNC_SHARE_IRQ) ? SA_SHIRQ : SA_INTERRUPT)
+
+#define	GDB_BUF_SIZE	512	/* power of 2, please */
+
+static char gdb_buf[GDB_BUF_SIZE];
+static int gdb_buf_in_inx;
+static atomic_t gdb_buf_in_cnt;
+static int gdb_buf_out_inx;
+
+struct async_struct *gdb_async_info;
+static int gdb_async_irq;
+
+#define outb_px(a,b,c) 		kgdb_serial_out(a, b, c)
+#define	outb_py(a, b, c)	kgdb_serial_out(b, c, a)
+#define	inb_py(ASYNC, OFF)	kgdb_serial_in(ASYNC, OFF)
+
+static void inline
+kgdb_serial_out(struct async_struct *serial, unsigned long offset, char ch)
+{
+	offset <<= serial->iomem_reg_shift;
+
+	switch(serial->io_type) {
+	case SERIAL_IO_MEM:
+		writeb(ch, serial->iomem_base + offset);
+		break;
+	default:
+		outb(serial->port + offset, ch);
+		break;
+	}
+	return;
+}
+
+static inline unsigned int
+kgdb_serial_in(struct async_struct *serial, unsigned long offset)
+{
+	unsigned int ch;
+
+	offset <<= serial->iomem_reg_shift;
+
+	switch(serial->io_type) {
+	case SERIAL_IO_MEM:
+		ch = readb(serial->iomem_base + offset);
+		break;
+	default:
+		ch = inb(serial->port + offset);
+		break;
+	}
+
+	return ch;
+}
+
+static void program_uart(struct async_struct *info);
+static void write_char(struct async_struct *info, int chr);
+/*
+ * Get a byte from the hardware data buffer and return it
+ */
+static int
+read_data_bfr(struct async_struct *info)
+{
+	char it = inb_py(info, UART_LSR);
+
+	if (it & UART_LSR_DR)
+		return (inb_py(info, UART_RX));
+	/*
+	 * If we have a framing error assume somebody messed with
+	 * our uart.  Reprogram it and send '-' both ways...
+	 */
+	if (it & 0xc) {
+		program_uart(info);
+		write_char(info, '-');
+		return ('-');
+	}
+	return (-1);
+
+}				/* read_data_bfr */
+
+/*
+ * Get a char if available, return -1 if nothing available.
+ * Empty the receive buffer first, then look at the interface hardware.
+
+ * Locking here is a bit of a problem.	We MUST not lock out communication
+ * if we are trying to talk to gdb about a kgdb entry.	ON the other hand
+ * we can loose chars in the console pass thru if we don't lock.  It is also
+ * possible that we could hold the lock or be waiting for it when kgdb
+ * NEEDS to talk.  Since kgdb locks down the world, it does not need locks.
+ * We do, of course have possible issues with interrupting a uart operation,
+ * but we will just depend on the uart status to help keep that straight.
+
+ */
+static spinlock_t uart_interrupt_lock = SPIN_LOCK_UNLOCKED;
+#ifdef CONFIG_SMP
+extern spinlock_t kgdb_spinlock;
+#endif
+
+static int
+read_char(struct async_struct *info)
+{
+	int chr;
+	unsigned long flags;
+	local_irq_save(flags);
+#ifdef CONFIG_SMP
+	if (!spin_is_locked(&kgdb_spinlock)) {
+		spin_lock(&uart_interrupt_lock);
+	}
+#endif
+	if (atomic_read(&gdb_buf_in_cnt) != 0) {	/* intr routine has q'd chars */
+		chr = gdb_buf[gdb_buf_out_inx++];
+		gdb_buf_out_inx &= (GDB_BUF_SIZE - 1);
+		atomic_dec(&gdb_buf_in_cnt);
+	} else {
+		chr = read_data_bfr(info);
+	}
+#ifdef CONFIG_SMP
+	if (!spin_is_locked(&kgdb_spinlock)) {
+		spin_unlock(&uart_interrupt_lock);
+	}
+#endif
+	local_irq_restore(flags);
+	return (chr);
+}
+
+/*
+ * Wait until the interface can accept a char, then write it.
+ */
+static void
+write_char(struct async_struct *info, int chr)
+{
+	while (!(inb_py(info, UART_LSR) & UART_LSR_THRE)) ;
+
+	outb_py(chr, info, UART_TX);
+
+}				/* write_char */
+
+/*
+ * Mostly we don't need a spinlock, but since the console goes
+ * thru here with interrutps on, well, we need to catch those
+ * chars.
+ */
+/*
+ * This is the receiver interrupt routine for the GDB stub.
+ * It will receive a limited number of characters of input
+ * from the gdb  host machine and save them up in a buffer.
+ *
+ * When the gdb stub routine tty_getDebugChar() is called it
+ * draws characters out of the buffer until it is empty and
+ * then reads directly from the serial port.
+ *
+ * We do not attempt to write chars from the interrupt routine
+ * since the stubs do all of that via tty_putDebugChar() which
+ * writes one byte after waiting for the interface to become
+ * ready.
+ *
+ * The debug stubs like to run with interrupts disabled since,
+ * after all, they run as a consequence of a breakpoint in
+ * the kernel.
+ *
+ * Perhaps someone who knows more about the tty driver than I
+ * care to learn can make this work for any low level serial
+ * driver.
+ */
+static irqreturn_t
+gdb_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+	struct async_struct *info;
+	unsigned long flags;
+
+	info = gdb_async_info;
+	if (!info || !info->tty || irq != gdb_async_irq)
+		return IRQ_NONE;
+
+	local_irq_save(flags);
+	spin_lock(&uart_interrupt_lock);
+	do {
+		int chr = read_data_bfr(info);
+		intprintk(("Debug char on int: %x hex\n", chr));
+		if (chr < 0)
+			continue;
+
+		if (chr == 3) {	/* Ctrl-C means remote interrupt */
+			BREAKPOINT;
+			continue;
+		}
+
+		if (atomic_read(&gdb_buf_in_cnt) >= GDB_BUF_SIZE) {
+			/* buffer overflow tosses early char */
+			read_char(info);
+		}
+		gdb_buf[gdb_buf_in_inx++] = chr;
+		gdb_buf_in_inx &= (GDB_BUF_SIZE - 1);
+	} while (inb_py(info,  UART_IIR) & UART_IIR_RDI);
+	spin_unlock(&uart_interrupt_lock);
+	local_irq_restore(flags);
+	return IRQ_HANDLED;
+}				/* gdb_interrupt */
+
+/*
+ * Just a NULL routine for testing.
+ */
+void
+gdb_null(void)
+{
+}				/* gdb_null */
+
+/* These structure are filled in with values defined in asm/kgdb_local.h
+ */
+static struct serial_state state = SB_STATE;
+static struct async_struct local_info = SB_INFO;
+static int ok_to_enable_ints = 0;
+static void kgdb_enable_ints_now(void);
+
+extern char *kgdb_version;
+/*
+ * Hook an IRQ for KGDB.
+ *
+ * This routine is called from tty_putDebugChar, below.
+ */
+static int ints_disabled = 1;
+int
+gdb_hook_interrupt(struct async_struct *info, int verb)
+{
+	struct serial_state *state = info->state;
+	unsigned long flags;
+	int port;
+#ifdef TEST_EXISTANCE
+	int scratch, scratch2;
+#endif
+
+	/* The above fails if memory managment is not set up yet.
+	 * Rather than fail the set up, just keep track of the fact
+	 * and pick up the interrupt thing later.
+	 */
+	gdb_async_info = info;
+	port = gdb_async_info->port;
+	gdb_async_irq = state->irq;
+	if (verb) {
+		printk("kgdb %s : port =%x, IRQ=%d, divisor =%d\n",
+		       kgdb_version,
+		       port,
+		       gdb_async_irq, gdb_async_info->state->custom_divisor);
+	}
+	local_irq_save(flags);
+#ifdef TEST_EXISTANCE
+	/* Existance test */
+	/* Should not need all this, but just in case.... */
+
+	scratch = inb_py(info, UART_IER);
+	outb_px(info, UART_IER, 0);
+	scratch2 = inb_py(info, UART_IER);
+	outb_px(info, UART_IER, scratch);
+	if (scratch2) {
+		printk
+		    ("gdb_hook_interrupt: Could not clear IER, not a UART!\n");
+		local_irq_restore(flags);
+		return 1;	/* We failed; there's nothing here */
+	}
+	scratch2 = inb_py(info, UART_LCR);
+	outb_px(info, UART_LCR, 0xBF);	/* set up for StarTech test */
+	outb_px(info, UART_EFR, 0);	/* EFR is the same as FCR */
+	outb_px(info, UART_LCR, 0);
+	outb_px(info, UART_FCR, UART_FCR_ENABLE_FIFO);
+	scratch = inb_py(info, UART_IIR) >> 6;
+	if (scratch == 1) {
+		printk("gdb_hook_interrupt: Undefined UART type!"
+		       "  Not a UART! \n");
+		local_irq_restore(flags);
+		return 1;
+	} else {
+		dbprintk(("gdb_hook_interrupt: UART type "
+			  "is %d where 0=16450, 2=16550 3=16550A\n", scratch));
+	}
+	scratch = inb_py(info, UART_MCR);
+	outb_px(info, UART_MCR, UART_MCR_LOOP | scratch);
+	outb_px(info, UART_MCR, UART_MCR_LOOP | 0x0A);
+	scratch2 = inb_py(info, UART_MSR) & 0xF0;
+	outb_px(info, UART_MCR, scratch);
+#ifndef	CONFIG_SERIAL_8250_HCDP		/* HCDP seems to skip this test */
+	if (scratch2 != 0x90) {
+		printk("gdb_hook_interrupt: "
+		       "Loop back test failed! Not a UART!\n");
+		local_irq_restore(flags);
+		return scratch2 + 1000;	/* force 0 to fail */
+	}
+#endif
+#endif				/* test existance */
+	program_uart(info);
+	local_irq_restore(flags);
+
+	return (0);
+
+}				/* gdb_hook_interrupt */
+
+static void
+program_uart(struct async_struct *info)
+{
+	(void) inb_py(info, UART_RX);
+	outb_px(info, UART_IER, 0);
+
+	(void) inb_py(info, UART_RX);	/* serial driver comments say */
+	(void) inb_py(info, UART_IIR);	/* this clears the interrupt regs */
+	(void) inb_py(info, UART_MSR);
+	outb_px(info, UART_LCR, UART_LCR_WLEN8 | UART_LCR_DLAB);
+	outb_px(info, UART_DLL, info->state->custom_divisor & 0xff);	/* LS */
+	outb_px(info, UART_DLM, info->state->custom_divisor >> 8);	/* MS  */
+	outb_px(info, UART_MCR, info->MCR);
+	printk("UART_LCR = 0x%x\n", inb_py(info, UART_LCR));
+
+	outb_px(info, UART_FCR, UART_FCR_ENABLE_FIFO | UART_FCR_TRIGGER_1 | UART_FCR_CLEAR_XMIT | UART_FCR_CLEAR_RCVR);	/* set fcr */
+	outb_px(info, UART_LCR, UART_LCR_WLEN8);	/* reset DLAB */
+	outb_px(info, UART_FCR, UART_FCR_ENABLE_FIFO | UART_FCR_TRIGGER_1);	/* set fcr */
+	if (!ints_disabled) {
+		intprintk(("KGDB: Sending %d to port %x offset %d\n",
+			   gdb_async_info->IER,
+			   (int) gdb_async_info->port, UART_IER));
+		outb_px(gdb_async_info, UART_IER, gdb_async_info->IER);
+	}
+	return;
+}
+
+/*
+ * tty_getDebugChar
+ *
+ * This is a GDB stub routine.	It waits for a character from the
+ * serial interface and then returns it.  If there is no serial
+ * interface connection then it returns a bogus value which will
+ * almost certainly cause the system to hang.  In the
+ */
+int kgdb_in_isr = 0;
+int kgdb_in_lsr = 0;
+extern spinlock_t kgdb_spinlock;
+
+/* Caller takes needed protections */
+
+int
+tty_getDebugChar(void)
+{
+	volatile int chr;
+	volatile long time, end_time;
+
+	dbprintk(("tty_getDebugChar(port %x): ", gdb_async_info->port));
+
+	if (gdb_async_info == NULL) {
+		gdb_hook_interrupt(&local_info, 0);
+	}
+	/*
+	 * This trick says if we wait a very long time and get
+	 * no char, return the -1 and let the upper level deal
+	 * with it.
+	 */
+	time = ia64_get_itc();
+	end_time = time + local_cpu_data->itm_delta * (HZ / 10);
+	if (!local_cpu_data->itm_delta)
+		end_time = time + 500;
+	while (((chr = read_char(gdb_async_info)) == -1) &&
+	       (end_time - time) > 0) {
+		time = ia64_get_itc();
+	};
+	/*
+	 * This covers our butts if some other code messes with
+	 * our uart, hay, it happens :o)
+	 */
+	if (chr == -1)
+		udelay(10000);
+//		program_uart(gdb_async_info);
+
+	dbprintk(("%c\n", chr > ' ' && chr < 0x7F ? chr : ' '));
+	return (chr);
+
+}				/* tty_getDebugChar */
+
+static int count = 3;
+static spinlock_t one_at_atime = SPIN_LOCK_UNLOCKED;
+
+static int __init
+kgdb_enable_ints(void)
+{
+	if (kgdboe) {
+		return 0;
+	}
+	if (gdb_async_info == NULL) {
+		gdb_hook_interrupt(&local_info, 1);
+	}
+	ok_to_enable_ints = 1;
+	kgdb_enable_ints_now();
+#ifdef CONFIG_KGDB_USER_CONSOLE
+	kgdb_console_finit();
+#endif
+	return 0;
+}
+
+static int mem_init_done = 1;
+
+#ifdef CONFIG_SERIAL_8250
+void shutdown_for_kgdb(struct async_struct *gdb_async_info);
+#endif
+
+
+static inline int kgdb_mem_init_done(void)
+{
+	return mem_init_done;
+}
+
+#ifdef	CONFIG_KGDB_EARLY
+static struct irqaction kgdb_action;
+#endif
+
+static void
+kgdb_enable_ints_now(void)
+{
+	if (!spin_trylock(&one_at_atime))
+		return;
+	if (!ints_disabled)
+		goto exit;
+	if (kgdb_mem_init_done() &&
+			ints_disabled) {	/* don't try till mem init */
+#ifdef CONFIG_SERIAL_8250
+		/*
+		 * The ifdef here allows the system to be configured
+		 * without the serial driver.
+		 * Don't make it a module, however, it will steal the port
+		 */
+		shutdown_for_kgdb(gdb_async_info);
+#endif
+#ifndef	CONFIG_KGDB_EARLY
+		ints_disabled = request_irq(gdb_async_info->state->irq,
+					    gdb_interrupt,
+					    IRQ_T(gdb_async_info),
+					    "KGDB-stub", NULL);
+#else
+{
+		irq_desc_t *desc;
+		kgdb_action.handler = gdb_interrupt;
+		kgdb_action.flags = IRQ_T(gdb_async_info);
+		kgdb_action.mask = 0;
+		kgdb_action.name = "KGDB-stub";
+		kgdb_action.next = NULL;
+		kgdb_action.dev_id = NULL;
+		desc = irq_descp(gdb_async_info->state->irq);
+		if (desc->handler != &no_irq_type) {
+			desc->action = &kgdb_action;
+			ints_disabled = 0;
+			desc->depth = 0;
+			desc->status &= ~(IRQ_DISABLED | IRQ_AUTODETECT |
+				IRQ_WAITING | IRQ_INPROGRESS);
+			desc->handler->startup(gdb_async_info->state->irq);
+		}
+		if (ints_disabled)
+			printk("kgdb_enable_ints_now: setup_irq failed\n");
+		else
+			printk("kgdb early access enabled\n");
+}
+#endif
+		intprintk(("KGDB: request_irq returned %d\n", ints_disabled));
+	}
+	if (!ints_disabled) {
+		intprintk(("KGDB: Sending %d to port %x offset %d\n",
+			   gdb_async_info->IER,
+			   (int) gdb_async_info->port, UART_IER));
+		outb_px(gdb_async_info, UART_IER, gdb_async_info->IER);
+	}
+      exit:
+	spin_unlock(&one_at_atime);
+}
+
+/*
+ * tty_putDebugChar
+ *
+ * This is a GDB stub routine.	It waits until the interface is ready
+ * to transmit a char and then sends it.  If there is no serial
+ * interface connection then it simply returns to its caller, having
+ * pretended to send the char.	Caller takes needed protections.
+ */
+void
+tty_putDebugChar(int chr)
+{
+	dbprintk(("tty_putDebugChar(port %x): chr=%02x '%c', ints_on=%d\n",
+		  gdb_async_info->port,
+		  chr,
+		  chr > ' ' && chr < 0x7F ? chr : ' ', ints_disabled ? 0 : 1));
+
+	if (gdb_async_info == NULL) {
+		gdb_hook_interrupt(&local_info, 0);
+	}
+
+	write_char(gdb_async_info, chr);	/* this routine will wait */
+	count = (chr == '#') ? 0 : count + 1;
+	if ((count == 2)) {	/* try to enable after */
+		if (ints_disabled & ok_to_enable_ints)
+			kgdb_enable_ints_now();	/* try to enable after */
+
+		/* We do this a lot because, well we really want to get these
+		 * interrupts.	The serial driver will clear these bits when it
+		 * initializes the chip.  Every thing else it does is ok,
+		 * but this.
+		 */
+		if (!ints_disabled) {
+			outb_px(gdb_async_info, UART_IER,
+				gdb_async_info->IER);
+		}
+	}
+
+}				/* tty_putDebugChar */
+
+/*
+ * This does nothing for the serial port, since it doesn't buffer.
+ */
+
+void tty_flushDebugChar(void)
+{
+}
+
+void __init
+kgdb_serial_init(void)
+{
+	extern char saved_command_line[];
+	char *cp, *str;
+	int kgdbbreak = 0;
+
+	for (cp = saved_command_line; *cp; cp++) {
+		if (memcmp(cp, "kgdb=1", 6) == 0) {
+			kgdbbreak = 1;
+		}
+		else if (memcmp(cp,"kgdbio=", 7) == 0) {
+			int baud;
+
+			cp += 7;
+			baud = simple_strtoul(cp, &str, 10);
+			state.custom_divisor = SB_BASE/baud;
+			if (*str == ',') {
+				str++;
+				state.irq = simple_strtoul(str, &str, 10);
+				if (*str == ',') {
+					str++;
+					local_info.iomem_base = state.iomem_base = (char *)
+						simple_strtoul(str, &str, 0);
+					local_info.io_type = state.io_type = SERIAL_IO_MEM;
+				}
+			}
+			printk("kgdb_serial_init: irq = %d iomem_base = 0x%lx baud = %d\n",
+				state.irq, state.iomem_base, baud);
+		}
+	}
+
+	kgdb_enable_ints();
+	if (!ints_disabled && kgdbbreak)
+		BREAKPOINT;
+}
+
+#ifndef	CONFIG_IA64_HP_SIM
+late_initcall(kgdb_enable_ints);
+#endif
--- diff/arch/ppc/kernel/head_e500.S	1970-01-01 01:00:00.000000000 +0100
+++ source/arch/ppc/kernel/head_e500.S	2004-06-11 19:21:59.000000000 +0100
@@ -0,0 +1,1329 @@
+/*
+ * arch/ppc/kernel/head_e500.S
+ *
+ * Kernel execution entry point code.
+ *
+ *    Copyright (c) 1995-1996 Gary Thomas <gdt@linuxppc.org>
+ *      Initial PowerPC version.
+ *    Copyright (c) 1996 Cort Dougan <cort@cs.nmt.edu>
+ *      Rewritten for PReP
+ *    Copyright (c) 1996 Paul Mackerras <paulus@cs.anu.edu.au>
+ *      Low-level exception handers, MMU support, and rewrite.
+ *    Copyright (c) 1997 Dan Malek <dmalek@jlc.net>
+ *      PowerPC 8xx modifications.
+ *    Copyright (c) 1998-1999 TiVo, Inc.
+ *      PowerPC 403GCX modifications.
+ *    Copyright (c) 1999 Grant Erickson <grant@lcse.umn.edu>
+ *      PowerPC 403GCX/405GP modifications.
+ *    Copyright 2000 MontaVista Software Inc.
+ *	PPC405 modifications
+ *      PowerPC 403GCX/405GP modifications.
+ * 	Author: MontaVista Software, Inc.
+ *         	frank_rowand@mvista.com or source@mvista.com
+ * 	   	debbie_chu@mvista.com
+ *    Copyright 2002-2004 MontaVista Software, Inc.
+ *      PowerPC 44x support, Matt Porter <mporter@kernel.crashing.org>
+ *    Copyright 2004 Freescale Semiconductor, Inc
+ *      PowerPC e500 modifications, Kumar Gala <kumar.gala@freescale.com>
+ *
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of  the GNU General  Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ */
+
+#include <linux/config.h>
+#include <asm/processor.h>
+#include <asm/page.h>
+#include <asm/mmu.h>
+#include <asm/pgtable.h>
+#include <asm/cputable.h>
+#include <asm/thread_info.h>
+#include <asm/ppc_asm.h>
+#include <asm/offsets.h>
+
+/*
+ * Macros
+ */
+
+#define SET_IVOR(vector_number, vector_label)		\
+		li	r26,vector_label@l; 		\
+		mtspr	SPRN_IVOR##vector_number,r26;	\
+		sync
+
+/* As with the other PowerPC ports, it is expected that when code
+ * execution begins here, the following registers contain valid, yet
+ * optional, information:
+ *
+ *   r3 - Board info structure pointer (DRAM, frequency, MAC address, etc.)
+ *   r4 - Starting address of the init RAM disk
+ *   r5 - Ending address of the init RAM disk
+ *   r6 - Start of kernel command line string (e.g. "mem=128")
+ *   r7 - End of kernel command line string
+ *
+ */
+	.text
+_GLOBAL(_stext)
+_GLOBAL(_start)
+	/*
+	 * Reserve a word at a fixed location to store the address
+	 * of abatron_pteptrs
+	 */
+	nop
+/*
+ * Save parameters we are passed
+ */
+	mr	r31,r3
+	mr	r30,r4
+	mr	r29,r5
+	mr	r28,r6
+	mr	r27,r7
+	li	r24,0		/* CPU number */
+
+/* We try to not make any assumptions about how the boot loader
+ * setup or used the TLBs.  We invalidate all mappings from the
+ * boot loader and load a single entry in TLB1[0] to map the
+ * first 16M of kernel memory.  Any boot info passed from the
+ * bootloader needs to live in this first 16M.
+ *
+ * Requirement on bootloader:
+ *  - The page we're executing in needs to reside in TLB1 and
+ *    have IPROT=1.  If not an invalidate broadcast could
+ *    evict the entry we're currently executing in.
+ *
+ *  r3 = Index of TLB1 were executing in
+ *  r4 = Current MSR[IS]
+ *  r5 = Index of TLB1 temp mapping
+ *
+ * Later in mapin_ram we will correctly map lowmem, and resize TLB1[0]
+ * if needed
+ */
+
+/* 1. Find the index of the entry we're executing in */
+	bl	invstr				/* Find our address */
+invstr:	mflr	r6				/* Make it accessible */
+	mfmsr	r7
+	rlwinm	r4,r7,27,31,31			/* extract MSR[IS] */
+	mfspr	r7, SPRN_PID0
+	slwi	r7,r7,16
+	or	r7,r7,r4
+	mtspr	SPRN_MAS6,r7
+	tlbsx	0,r6				/* search MSR[IS], SPID=PID0 */
+	mfspr	r7,SPRN_MAS1
+	andis.	r7,r7,MAS1_VALID@h
+	bne	match_TLB
+	mfspr	r7,SPRN_PID1
+	slwi	r7,r7,16
+	or	r7,r7,r4
+	mtspr	SPRN_MAS6,r7
+	tlbsx	0,r6				/* search MSR[IS], SPID=PID1 */
+	mfspr	r7,SPRN_MAS1
+	andis.	r7,r7,MAS1_VALID@h
+	bne	match_TLB
+	mfspr	r7, SPRN_PID2
+	slwi	r7,r7,16
+	or	r7,r7,r4
+	mtspr	SPRN_MAS6,r7
+	tlbsx	0,r6				/* Fall through, we had to match */
+match_TLB:
+	mfspr	r7,SPRN_MAS0
+	rlwinm	r3,r7,16,28,31			/* Extract MAS0(Entry) */
+
+	mfspr	r7,SPRN_MAS1			/* Insure IPROT set */
+	oris	r7,r7,MAS1_IPROT@h
+	mtspr	SPRN_MAS1,r7
+	tlbwe
+
+/* 2. Invalidate all entries except the entry we're executing in */
+	mfspr	r9,SPRN_TLB1CFG
+	andi.	r9,r9,0xfff
+	li	r6,0				/* Set Entry counter to 0 */
+1:	lis	r7,0x1000			/* Set MAS0(TLBSEL) = 1 */
+	rlwimi	r7,r6,16,12,15			/* Setup MAS0 = TLBSEL | ESEL(r6) */
+	mtspr	SPRN_MAS0,r7
+	tlbre
+	mfspr	r7,SPRN_MAS1
+	rlwinm	r7,r7,0,2,31			/* Clear MAS1 Valid and IPROT */
+	cmpw	r3,r6
+	beq	skpinv				/* Dont update the current execution TLB */
+	mtspr	SPRN_MAS1,r7
+	tlbwe
+	isync
+skpinv:	addi	r6,r6,1				/* Increment */
+	cmpw	r6,r9				/* Are we done? */
+	bne	1b				/* If not, repeat */
+
+	/* Invalidate TLB0 */
+	li      r6,0x04
+	tlbivax 0,r6
+#ifdef CONFIG_SMP
+	tlbsync
+#endif
+	/* Invalidate TLB1 */
+	li      r6,0x0c
+	tlbivax 0,r6
+#ifdef CONFIG_SMP
+	tlbsync
+#endif
+	msync
+
+/* 3. Setup a temp mapping and jump to it */
+	andi.	r5, r3, 0x1	/* Find an entry not used and is non-zero */
+	addi	r5, r5, 0x1
+	lis	r7,0x1000	/* Set MAS0(TLBSEL) = 1 */
+	rlwimi	r7,r3,16,12,15	/* Setup MAS0 = TLBSEL | ESEL(r3) */
+	mtspr	SPRN_MAS0,r7
+	tlbre
+
+	/* Just modify the entry ID and EPN for the temp mapping */
+	lis	r7,0x1000	/* Set MAS0(TLBSEL) = 1 */
+	rlwimi	r7,r5,16,12,15	/* Setup MAS0 = TLBSEL | ESEL(r5) */
+	mtspr	SPRN_MAS0,r7
+	xori	r6,r4,1		/* Setup TMP mapping in the other Address space */
+	slwi	r6,r6,12
+	oris	r6,r6,(MAS1_VALID|MAS1_IPROT)@h
+	ori	r6,r6,(MAS1_TSIZE(BOOKE_PAGESZ_4K))@l
+	mtspr	SPRN_MAS1,r6
+	mfspr	r6,SPRN_MAS2
+	li	r7,0		/* temp EPN = 0 */
+	rlwimi	r7,r6,0,20,31
+	mtspr	SPRN_MAS2,r7
+	tlbwe
+
+	xori	r6,r4,1
+	slwi	r6,r6,5		/* setup new context with other address space */
+	bl	1f		/* Find our address */
+1:	mflr	r9
+	rlwimi	r7,r9,0,20,31
+	addi	r7,r7,24
+	mtspr	SRR0,r7
+	mtspr	SRR1,r6
+	rfi
+
+/* 4. Clear out PIDs & Search info */
+	li	r6,0
+	mtspr	SPRN_PID0,r6
+	mtspr	SPRN_PID1,r6
+	mtspr	SPRN_PID2,r6
+	mtspr	SPRN_MAS6,r6
+
+/* 5. Invalidate mapping we started in */
+	lis	r7,0x1000	/* Set MAS0(TLBSEL) = 1 */
+	rlwimi	r7,r3,16,12,15	/* Setup MAS0 = TLBSEL | ESEL(r3) */
+	mtspr	SPRN_MAS0,r7
+	tlbre
+	li	r6,0
+	mtspr	SPRN_MAS1,r6
+	tlbwe
+	/* Invalidate TLB1 */
+	li      r9,0x0c
+	tlbivax 0,r9
+#ifdef CONFIG_SMP
+	tlbsync
+#endif
+	msync
+
+/* 6. Setup KERNELBASE mapping in TLB1[0] */
+	lis	r6,0x1000		/* Set MAS0(TLBSEL) = TLB1(1), ESEL = 0 */
+	mtspr	SPRN_MAS0,r6
+	lis	r6,(MAS1_VALID|MAS1_IPROT)@h
+	ori	r6,r6,(MAS1_TSIZE(BOOKE_PAGESZ_16M))@l
+	mtspr	SPRN_MAS1,r6
+	li	r7,0
+	lis	r6,KERNELBASE@h
+	ori	r6,r6,KERNELBASE@l
+	rlwimi	r6,r7,0,20,31
+	mtspr	SPRN_MAS2,r6
+	li	r7,(MAS3_SX|MAS3_SW|MAS3_SR)
+	mtspr	SPRN_MAS3,r7
+	tlbwe
+
+/* 7. Jump to KERNELBASE mapping */
+	li	r7,0
+	bl	1f			/* Find our address */
+1:	mflr	r9
+	rlwimi	r6,r9,0,20,31
+	addi	r6,r6,24
+	mtspr	SRR0,r6
+	mtspr	SRR1,r7
+	rfi				/* start execution out of TLB1[0] entry */
+
+/* 8. Clear out the temp mapping */
+	lis	r7,0x1000	/* Set MAS0(TLBSEL) = 1 */
+	rlwimi	r7,r5,16,12,15	/* Setup MAS0 = TLBSEL | ESEL(r5) */
+	mtspr	SPRN_MAS0,r7
+	tlbre
+	mtspr	SPRN_MAS1,r8
+	tlbwe
+	/* Invalidate TLB1 */
+	li      r9,0x0c
+	tlbivax 0,r9
+#ifdef CONFIG_SMP
+	tlbsync
+#endif
+	msync
+
+	/* Establish the interrupt vector offsets */
+	SET_IVOR(0,  CriticalInput);
+	SET_IVOR(1,  MachineCheck);
+	SET_IVOR(2,  DataStorage);
+	SET_IVOR(3,  InstructionStorage);
+	SET_IVOR(4,  ExternalInput);
+	SET_IVOR(5,  Alignment);
+	SET_IVOR(6,  Program);
+	SET_IVOR(7,  FloatingPointUnavailable);
+	SET_IVOR(8,  SystemCall);
+	SET_IVOR(9,  AuxillaryProcessorUnavailable);
+	SET_IVOR(10, Decrementer);
+	SET_IVOR(11, FixedIntervalTimer);
+	SET_IVOR(12, WatchdogTimer);
+	SET_IVOR(13, DataTLBError);
+	SET_IVOR(14, InstructionTLBError);
+	SET_IVOR(15, Debug);
+	SET_IVOR(32, SPEUnavailable);
+	SET_IVOR(33, SPEFloatingPointData);
+	SET_IVOR(34, SPEFloatingPointRound);
+	SET_IVOR(35, PerformanceMonitor);
+
+	/* Establish the interrupt vector base */
+	lis	r4,interrupt_base@h	/* IVPR only uses the high 16-bits */
+	mtspr	SPRN_IVPR,r4
+
+	/* Setup the defaults for TLB entries */
+	li	r2,MAS4_TSIZED(BOOKE_PAGESZ_4K)
+   	mtspr	SPRN_MAS4, r2
+
+#if 0
+	/* Enable DOZE */
+	mfspr	r2,SPRN_HID0
+	oris	r2,r2,HID0_DOZE@h
+	mtspr	SPRN_HID0, r2
+#endif
+
+	/*
+	 * This is where the main kernel code starts.
+	 */
+
+	/* ptr to current */
+	lis	r2,init_task@h
+	ori	r2,r2,init_task@l
+
+	/* ptr to current thread */
+	addi	r4,r2,THREAD	/* init task's THREAD */
+	mtspr	SPRG3,r4
+
+	/* stack */
+	lis	r1,init_thread_union@h
+	ori	r1,r1,init_thread_union@l
+	li	r0,0
+	stwu	r0,THREAD_SIZE-STACK_FRAME_OVERHEAD(r1)
+
+	bl	early_init
+
+	mfspr	r3,SPRN_TLB1CFG
+	andi.	r3,r3,0xfff
+	lis	r4,num_tlbcam_entries@ha
+	stw	r3,num_tlbcam_entries@l(r4)
+/*
+ * Decide what sort of machine this is and initialize the MMU.
+ */
+	mr	r3,r31
+	mr	r4,r30
+	mr	r5,r29
+	mr	r6,r28
+	mr	r7,r27
+	bl	machine_init
+	bl	MMU_init
+
+	/* Setup PTE pointers for the Abatron bdiGDB */
+	lis	r6, swapper_pg_dir@h
+	ori	r6, r6, swapper_pg_dir@l
+	lis	r5, abatron_pteptrs@h
+	ori	r5, r5, abatron_pteptrs@l
+	lis	r4, KERNELBASE@h
+	ori	r4, r4, KERNELBASE@l
+	stw	r5, 0(r4)	/* Save abatron_pteptrs at a fixed location */
+	stw	r6, 0(r5)
+
+	/* Let's move on */
+	lis	r4,start_kernel@h
+	ori	r4,r4,start_kernel@l
+	lis	r3,MSR_KERNEL@h
+	ori	r3,r3,MSR_KERNEL@l
+	mtspr	SRR0,r4
+	mtspr	SRR1,r3
+	rfi			/* change context and jump to start_kernel */
+
+/*
+ * Interrupt vector entry code
+ *
+ * The Book E MMUs are always on so we don't need to handle
+ * interrupts in real mode as with previous PPC processors. In
+ * this case we handle interrupts in the kernel virtual address
+ * space.
+ *
+ * Interrupt vectors are dynamically placed relative to the
+ * interrupt prefix as determined by the address of interrupt_base.
+ * The interrupt vectors offsets are programmed using the labels
+ * for each interrupt vector entry.
+ *
+ * Interrupt vectors must be aligned on a 16 byte boundary.
+ * We align on a 32 byte cache line boundary for good measure.
+ */
+
+#define NORMAL_EXCEPTION_PROLOG						     \
+	mtspr	SPRN_SPRG0,r10;		/* save two registers to work with */\
+	mtspr	SPRN_SPRG1,r11;						     \
+	mtspr	SPRN_SPRG4W,r1;						     \
+	mfcr	r10;			/* save CR in r10 for now	   */\
+	mfspr	r11,SPRN_SRR1;		/* check whether user or kernel    */\
+	andi.	r11,r11,MSR_PR;						     \
+	beq	1f;							     \
+	mfspr	r1,SPRG3;		/* if from user, start at top of   */\
+	lwz	r1,THREAD_INFO-THREAD(r1); /* this thread's kernel stack   */\
+	addi	r1,r1,THREAD_SIZE;					     \
+1:	subi	r1,r1,INT_FRAME_SIZE;	/* Allocate an exception frame     */\
+	tophys(r11,r1);							     \
+	stw	r10,_CCR(r11);          /* save various registers	   */\
+	stw	r12,GPR12(r11);						     \
+	stw	r9,GPR9(r11);						     \
+	mfspr	r10,SPRG0;						     \
+	stw	r10,GPR10(r11);						     \
+	mfspr	r12,SPRG1;						     \
+	stw	r12,GPR11(r11);						     \
+	mflr	r10;							     \
+	stw	r10,_LINK(r11);						     \
+	mfspr	r10,SPRG4R;						     \
+	mfspr	r12,SRR0;						     \
+	stw	r10,GPR1(r11);						     \
+	mfspr	r9,SRR1;						     \
+	stw	r10,0(r11);						     \
+	rlwinm	r9,r9,0,14,12;		/* clear MSR_WE (necessary?)	   */\
+	stw	r0,GPR0(r11);						     \
+	SAVE_4GPRS(3, r11);						     \
+	SAVE_2GPRS(7, r11)
+
+/*
+ * Exception prolog for critical exceptions.  This is a little different
+ * from the normal exception prolog above since a critical exception
+ * can potentially occur at any point during normal exception processing.
+ * Thus we cannot use the same SPRG registers as the normal prolog above.
+ * Instead we use a couple of words of memory at low physical addresses.
+ * This is OK since we don't support SMP on these processors. For Book E
+ * processors, we also have a reserved register (SPRG2) that is only used
+ * in critical exceptions so we can free up a GPR to use as the base for
+ * indirect access to the critical exception save area.  This is necessary
+ * since the MMU is always on and the save area is offset from KERNELBASE.
+ */
+#define CRITICAL_EXCEPTION_PROLOG					     \
+	mtspr	SPRG2,r8;		/* SPRG2 only used in criticals */   \
+	lis	r8,crit_save@ha;					     \
+	stw	r10,crit_r10@l(r8);					     \
+	stw	r11,crit_r11@l(r8);					     \
+	mfspr	r10,SPRG0;						     \
+	stw	r10,crit_sprg0@l(r8);					     \
+	mfspr	r10,SPRG1;						     \
+	stw	r10,crit_sprg1@l(r8);					     \
+	mfspr	r10,SPRG4R;						     \
+	stw	r10,crit_sprg4@l(r8);					     \
+	mfspr	r10,SPRG5R;						     \
+	stw	r10,crit_sprg5@l(r8);					     \
+	mfspr	r10,SPRG7R;						     \
+	stw	r10,crit_sprg7@l(r8);					     \
+	mfspr	r10,SPRN_PID;						     \
+	stw	r10,crit_pid@l(r8);					     \
+	mfspr	r10,SRR0;						     \
+	stw	r10,crit_srr0@l(r8);					     \
+	mfspr	r10,SRR1;						     \
+	stw	r10,crit_srr1@l(r8);					     \
+	mfspr	r8,SPRG2;		/* SPRG2 only used in criticals */   \
+	mfcr	r10;			/* save CR in r10 for now	   */\
+	mfspr	r11,SPRN_CSRR1;		/* check whether user or kernel    */\
+	andi.	r11,r11,MSR_PR;						     \
+	lis	r11,critical_stack_top@h;				     \
+	ori	r11,r11,critical_stack_top@l;				     \
+	beq	1f;							     \
+	/* COMING FROM USER MODE */					     \
+	mfspr	r11,SPRG3;		/* if from user, start at top of   */\
+	lwz	r11,THREAD_INFO-THREAD(r11); /* this thread's kernel stack */\
+	addi	r11,r11,THREAD_SIZE;					     \
+1:	subi	r11,r11,INT_FRAME_SIZE;	/* Allocate an exception frame     */\
+	stw	r10,_CCR(r11);          /* save various registers	   */\
+	stw	r12,GPR12(r11);						     \
+	stw	r9,GPR9(r11);						     \
+	mflr	r10;							     \
+	stw	r10,_LINK(r11);						     \
+	mfspr	r12,SPRN_DEAR;		/* save DEAR and ESR in the frame  */\
+	stw	r12,_DEAR(r11);		/* since they may have had stuff   */\
+	mfspr	r9,SPRN_ESR;		/* in them at the point where the  */\
+	stw	r9,_ESR(r11);		/* exception was taken		   */\
+	mfspr	r12,CSRR0;						     \
+	stw	r1,GPR1(r11);						     \
+	mfspr	r9,CSRR1;						     \
+	stw	r1,0(r11);						     \
+	tovirt(r1,r11);							     \
+	rlwinm	r9,r9,0,14,12;		/* clear MSR_WE (necessary?)	   */\
+	stw	r0,GPR0(r11);						     \
+	SAVE_4GPRS(3, r11);						     \
+	SAVE_2GPRS(7, r11)
+
+/*
+ * Exception prolog for machine check exceptions.  This is similar to
+ * the critical exception prolog, except that machine check exceptions
+ * have their own save area.  For Book E processors, we also have a
+ * reserved register (SPRG6) that is only used in machine check exceptions
+ * so we can free up a GPR to use as the base for indirect access to the
+ * machine check exception save area.  This is necessary since the MMU
+ * is always on and the save area is offset from KERNELBASE.
+ */
+#define MCHECK_EXCEPTION_PROLOG					     \
+	mtspr	SPRG6W,r8;		/* SPRG6 used in machine checks */   \
+	lis	r8,mcheck_save@ha;					     \
+	stw	r10,mcheck_r10@l(r8);					     \
+	stw	r11,mcheck_r11@l(r8);					     \
+	mfspr	r10,SPRG0;						     \
+	stw	r10,mcheck_sprg0@l(r8);					     \
+	mfspr	r10,SPRG1;						     \
+	stw	r10,mcheck_sprg1@l(r8);					     \
+	mfspr	r10,SPRG4R;						     \
+	stw	r10,mcheck_sprg4@l(r8);					     \
+	mfspr	r10,SPRG5R;						     \
+	stw	r10,mcheck_sprg5@l(r8);					     \
+	mfspr	r10,SPRG7R;						     \
+	stw	r10,mcheck_sprg7@l(r8);					     \
+	mfspr	r10,SPRN_PID;						     \
+	stw	r10,mcheck_pid@l(r8);					     \
+	mfspr	r10,SRR0;						     \
+	stw	r10,mcheck_srr0@l(r8);					     \
+	mfspr	r10,SRR1;						     \
+	stw	r10,mcheck_srr1@l(r8);					     \
+	mfspr	r10,CSRR0;						     \
+	stw	r10,mcheck_csrr0@l(r8);					     \
+	mfspr	r10,CSRR1;						     \
+	stw	r10,mcheck_csrr1@l(r8);					     \
+	mfspr	r8,SPRG6R;		/* SPRG6 used in machine checks */   \
+	mfcr	r10;			/* save CR in r10 for now	   */\
+	mfspr	r11,SPRN_MCSRR1;	/* check whether user or kernel    */\
+	andi.	r11,r11,MSR_PR;						     \
+	lis	r11,mcheck_stack_top@h;					     \
+	ori	r11,r11,mcheck_stack_top@l;				     \
+	beq	1f;							     \
+	/* COMING FROM USER MODE */					     \
+	mfspr	r11,SPRG3;		/* if from user, start at top of   */\
+	lwz	r11,THREAD_INFO-THREAD(r11); /* this thread's kernel stack */\
+	addi	r11,r11,THREAD_SIZE;					     \
+1:	subi	r11,r11,INT_FRAME_SIZE;	/* Allocate an exception frame     */\
+	stw	r10,_CCR(r11);          /* save various registers	   */\
+	stw	r12,GPR12(r11);						     \
+	stw	r9,GPR9(r11);						     \
+	mflr	r10;							     \
+	stw	r10,_LINK(r11);						     \
+	mfspr	r12,SPRN_DEAR;		/* save DEAR and ESR in the frame  */\
+	stw	r12,_DEAR(r11);		/* since they may have had stuff   */\
+	mfspr	r9,SPRN_ESR;		/* in them at the point where the  */\
+	stw	r9,_ESR(r11);		/* exception was taken		   */\
+	mfspr	r12,MCSRR0;						     \
+	stw	r1,GPR1(r11);						     \
+	mfspr	r9,MCSRR1;						     \
+	stw	r1,0(r11);						     \
+	tovirt(r1,r11);							     \
+	rlwinm	r9,r9,0,14,12;		/* clear MSR_WE (necessary?)	   */\
+	stw	r0,GPR0(r11);						     \
+	SAVE_4GPRS(3, r11);						     \
+	SAVE_2GPRS(7, r11)
+
+/*
+ * Exception vectors.
+ */
+#define	START_EXCEPTION(label)						     \
+        .align 5;              						     \
+label:
+
+#define FINISH_EXCEPTION(func)					\
+	bl	transfer_to_handler_full;			\
+	.long	func;						\
+	.long	ret_from_except_full
+
+#define EXCEPTION(n, label, hdlr, xfer)				\
+	START_EXCEPTION(label);					\
+	NORMAL_EXCEPTION_PROLOG;				\
+	addi	r3,r1,STACK_FRAME_OVERHEAD;			\
+	xfer(n, hdlr)
+
+#define CRITICAL_EXCEPTION(n, label, hdlr)			\
+	START_EXCEPTION(label);					\
+	CRITICAL_EXCEPTION_PROLOG;				\
+	addi	r3,r1,STACK_FRAME_OVERHEAD;			\
+	EXC_XFER_TEMPLATE(hdlr, n+2, (MSR_KERNEL & ~(MSR_ME|MSR_DE|MSR_CE)), \
+			  NOCOPY, transfer_to_handler_full, \
+			  ret_from_except_full)
+
+#define MCHECK_EXCEPTION(n, label, hdlr)			\
+	START_EXCEPTION(label);					\
+	MCHECK_EXCEPTION_PROLOG;				\
+	mfspr	r5,SPRN_ESR;					\
+	stw	r5,_ESR(r11);					\
+	addi	r3,r1,STACK_FRAME_OVERHEAD;			\
+	EXC_XFER_TEMPLATE(hdlr, n+2, (MSR_KERNEL & ~(MSR_ME|MSR_DE|MSR_CE)), \
+			  NOCOPY, mcheck_transfer_to_handler,   \
+			  ret_from_mcheck_exc)
+
+#define EXC_XFER_TEMPLATE(hdlr, trap, msr, copyee, tfer, ret)	\
+	li	r10,trap;					\
+	stw	r10,TRAP(r11);					\
+	lis	r10,msr@h;					\
+	ori	r10,r10,msr@l;					\
+	copyee(r10, r9);					\
+	bl	tfer;		 				\
+	.long	hdlr;						\
+	.long	ret
+
+#define COPY_EE(d, s)		rlwimi d,s,0,16,16
+#define NOCOPY(d, s)
+
+#define EXC_XFER_STD(n, hdlr)		\
+	EXC_XFER_TEMPLATE(hdlr, n, MSR_KERNEL, NOCOPY, transfer_to_handler_full, \
+			  ret_from_except_full)
+
+#define EXC_XFER_LITE(n, hdlr)		\
+	EXC_XFER_TEMPLATE(hdlr, n+1, MSR_KERNEL, NOCOPY, transfer_to_handler, \
+			  ret_from_except)
+
+#define EXC_XFER_EE(n, hdlr)		\
+	EXC_XFER_TEMPLATE(hdlr, n, MSR_KERNEL, COPY_EE, transfer_to_handler_full, \
+			  ret_from_except_full)
+
+#define EXC_XFER_EE_LITE(n, hdlr)	\
+	EXC_XFER_TEMPLATE(hdlr, n+1, MSR_KERNEL, COPY_EE, transfer_to_handler, \
+			  ret_from_except)
+
+interrupt_base:
+	/* Critical Input Interrupt */
+	CRITICAL_EXCEPTION(0x0100, CriticalInput, UnknownException)
+
+	/* Machine Check Interrupt */
+	MCHECK_EXCEPTION(0x0200, MachineCheck, MachineCheckException)
+
+	/* Data Storage Interrupt */
+	START_EXCEPTION(DataStorage)
+	mtspr	SPRG0, r10		/* Save some working registers */
+	mtspr	SPRG1, r11
+	mtspr	SPRG4W, r12
+	mtspr	SPRG5W, r13
+	mfcr	r11
+	mtspr	SPRG7W, r11
+
+	/*
+	 * Check if it was a store fault, if not then bail
+	 * because a user tried to access a kernel or
+	 * read-protected page.  Otherwise, get the
+	 * offending address and handle it.
+	 */
+	mfspr	r10, SPRN_ESR
+	andis.	r10, r10, ESR_ST@h
+	beq	2f
+
+	mfspr	r10, SPRN_DEAR		/* Get faulting address */
+
+	/* If we are faulting a kernel address, we have to use the
+	 * kernel page tables.
+	 */
+	lis	r11, TASK_SIZE@h
+	ori	r11, r11, TASK_SIZE@l
+	cmplw	0, r10, r11
+	bge	2f
+
+	/* Get the PGD for the current thread */
+3:
+	mfspr	r11,SPRG3
+	lwz	r11,PGDIR(r11)
+4:
+	rlwimi	r11, r10, 12, 20, 29	/* Create L1 (pgdir/pmd) address */
+	lwz	r11, 0(r11)		/* Get L1 entry */
+	rlwinm.	r12, r11, 0, 0, 19	/* Extract L2 (pte) base address */
+	beq	2f			/* Bail if no table */
+
+	rlwimi	r12, r10, 22, 20, 29	/* Compute PTE address */
+	lwz	r11, 0(r12)		/* Get Linux PTE */
+
+	/* Are _PAGE_USER & _PAGE_RW set & _PAGE_HWWRITE not? */
+	andi.	r13, r11, _PAGE_RW|_PAGE_USER|_PAGE_HWWRITE
+	cmpwi	0, r13, _PAGE_RW|_PAGE_USER
+	bne	2f			/* Bail if not */
+
+	/* Update 'changed'. */
+	ori	r11, r11, _PAGE_DIRTY|_PAGE_ACCESSED|_PAGE_HWWRITE
+	stw	r11, 0(r12)		/* Update Linux page table */
+
+	/* MAS2 not updated as the entry does exist in the tlb, this
+	   fault taken to detect state transition (eg: COW -> DIRTY)
+	 */
+	lis	r12, MAS3_RPN@h
+	ori	r12, r12, _PAGE_HWEXEC | MAS3_RPN@l
+	and	r11, r11, r12
+	rlwimi	r11, r11, 31, 27, 27	/* SX <- _PAGE_HWEXEC */
+	ori     r11, r11, (MAS3_UW|MAS3_SW|MAS3_UR|MAS3_SR)@l /* set static perms */
+
+	/* update search PID in MAS6, AS = 0 */
+	mfspr	r12, SPRN_PID0
+	slwi	r12, r12, 16
+	mtspr	SPRN_MAS6, r12
+
+	/* find the TLB index that caused the fault.  It has to be here. */
+	tlbsx	0, r10
+
+	mtspr	SPRN_MAS3,r11
+	tlbwe
+
+	/* Done...restore registers and get out of here.  */
+	mfspr	r11, SPRG7R
+	mtcr	r11
+	mfspr	r13, SPRG5R
+	mfspr	r12, SPRG4R
+	mfspr	r11, SPRG1
+	mfspr	r10, SPRG0
+	rfi			/* Force context change */
+
+2:
+	/*
+	 * The bailout.  Restore registers to pre-exception conditions
+	 * and call the heavyweights to help us out.
+	 */
+	mfspr	r11, SPRG7R
+	mtcr	r11
+	mfspr	r13, SPRG5R
+	mfspr	r12, SPRG4R
+	mfspr	r11, SPRG1
+	mfspr	r10, SPRG0
+	b	data_access
+
+	/* Instruction Storage Interrupt */
+	START_EXCEPTION(InstructionStorage)
+	NORMAL_EXCEPTION_PROLOG
+	mfspr	r5,SPRN_ESR		/* Grab the ESR and save it */
+	stw	r5,_ESR(r11)
+	mr      r4,r12                  /* Pass SRR0 as arg2 */
+	li      r5,0                    /* Pass zero as arg3 */
+	EXC_XFER_EE_LITE(0x0400, handle_page_fault)
+
+	/* External Input Interrupt */
+	EXCEPTION(0x0500, ExternalInput, do_IRQ, EXC_XFER_LITE)
+
+	/* Alignment Interrupt */
+	START_EXCEPTION(Alignment)
+	NORMAL_EXCEPTION_PROLOG
+	mfspr   r4,SPRN_DEAR            /* Grab the DEAR and save it */
+	stw     r4,_DEAR(r11)
+	addi    r3,r1,STACK_FRAME_OVERHEAD
+	EXC_XFER_EE(0x0600, AlignmentException)
+
+	/* Program Interrupt */
+	START_EXCEPTION(Program)
+	NORMAL_EXCEPTION_PROLOG
+	mfspr	r4,SPRN_ESR		/* Grab the ESR and save it */
+	stw	r4,_ESR(r11)
+	addi	r3,r1,STACK_FRAME_OVERHEAD
+	EXC_XFER_STD(0x0700, ProgramCheckException)
+
+	/* Floating Point Unavailable Interrupt */
+	EXCEPTION(0x0800, FloatingPointUnavailable, UnknownException, EXC_XFER_EE)
+
+	/* System Call Interrupt */
+	START_EXCEPTION(SystemCall)
+	NORMAL_EXCEPTION_PROLOG
+	EXC_XFER_EE_LITE(0x0c00, DoSyscall)
+
+	/* Auxillary Processor Unavailable Interrupt */
+	EXCEPTION(0x2900, AuxillaryProcessorUnavailable, UnknownException, EXC_XFER_EE)
+
+	/* Decrementer Interrupt */
+	START_EXCEPTION(Decrementer)
+	NORMAL_EXCEPTION_PROLOG
+	lis     r0,TSR_DIS@h            /* Setup the DEC interrupt mask */
+	mtspr   SPRN_TSR,r0		/* Clear the DEC interrupt */
+	addi    r3,r1,STACK_FRAME_OVERHEAD
+	EXC_XFER_LITE(0x0900, timer_interrupt)
+
+	/* Fixed Internal Timer Interrupt */
+	/* TODO: Add FIT support */
+	EXCEPTION(0x3100, FixedIntervalTimer, UnknownException, EXC_XFER_EE)
+
+	/* Watchdog Timer Interrupt */
+	/* TODO: Add watchdog support */
+	CRITICAL_EXCEPTION(0x3200, WatchdogTimer, UnknownException)
+
+	/* Data TLB Error Interrupt */
+	START_EXCEPTION(DataTLBError)
+	mtspr	SPRG0, r10		/* Save some working registers */
+	mtspr	SPRG1, r11
+	mtspr	SPRG4W, r12
+	mtspr	SPRG5W, r13
+	mfcr	r11
+	mtspr	SPRG7W, r11
+	mfspr	r10, SPRN_DEAR		/* Get faulting address */
+
+	/* If we are faulting a kernel address, we have to use the
+	 * kernel page tables.
+	 */
+	lis	r11, TASK_SIZE@h
+	ori	r11, r11, TASK_SIZE@l
+	cmplw	5, r10, r11
+	blt	5, 3f
+	lis	r11, swapper_pg_dir@h
+	ori	r11, r11, swapper_pg_dir@l
+
+	mfspr	r12,SPRN_MAS1		/* Set TID to 0 */
+	li	r13,MAS1_TID@l
+	andc	r12,r12,r13
+	mtspr	SPRN_MAS1,r12
+
+	b	4f
+
+	/* Get the PGD for the current thread */
+3:
+	mfspr	r11,SPRG3
+	lwz	r11,PGDIR(r11)
+
+4:
+	rlwimi	r11, r10, 12, 20, 29	/* Create L1 (pgdir/pmd) address */
+	lwz	r11, 0(r11)		/* Get L1 entry */
+	rlwinm.	r12, r11, 0, 0, 19	/* Extract L2 (pte) base address */
+	beq	2f			/* Bail if no table */
+
+	rlwimi	r12, r10, 22, 20, 29	/* Compute PTE address */
+	lwz	r11, 0(r12)		/* Get Linux PTE */
+	andi.	r13, r11, _PAGE_PRESENT
+	beq	2f
+
+	ori	r11, r11, _PAGE_ACCESSED
+	stw	r11, 0(r12)
+
+	 /* Jump to common tlb load */
+	b	finish_tlb_load
+2:
+	/* The bailout.  Restore registers to pre-exception conditions
+	 * and call the heavyweights to help us out.
+	 */
+	mfspr	r11, SPRG7R
+	mtcr	r11
+	mfspr	r13, SPRG5R
+	mfspr	r12, SPRG4R
+	mfspr	r11, SPRG1
+	mfspr	r10, SPRG0
+	b	data_access
+
+	/* Instruction TLB Error Interrupt */
+	/*
+	 * Nearly the same as above, except we get our
+	 * information from different registers and bailout
+	 * to a different point.
+	 */
+	START_EXCEPTION(InstructionTLBError)
+	mtspr	SPRG0, r10		/* Save some working registers */
+	mtspr	SPRG1, r11
+	mtspr	SPRG4W, r12
+	mtspr	SPRG5W, r13
+	mfcr	r11
+	mtspr	SPRG7W, r11
+	mfspr	r10, SRR0		/* Get faulting address */
+
+	/* If we are faulting a kernel address, we have to use the
+	 * kernel page tables.
+	 */
+	lis	r11, TASK_SIZE@h
+	ori	r11, r11, TASK_SIZE@l
+	cmplw	5, r10, r11
+	blt	5, 3f
+	lis	r11, swapper_pg_dir@h
+	ori	r11, r11, swapper_pg_dir@l
+
+	mfspr	r12,SPRN_MAS1		/* Set TID to 0 */
+	li	r13,MAS1_TID@l
+	andc	r12,r12,r13
+	mtspr	SPRN_MAS1,r12
+
+	b	4f
+
+	/* Get the PGD for the current thread */
+3:
+	mfspr	r11,SPRG3
+	lwz	r11,PGDIR(r11)
+
+4:
+	rlwimi	r11, r10, 12, 20, 29	/* Create L1 (pgdir/pmd) address */
+	lwz	r11, 0(r11)		/* Get L1 entry */
+	rlwinm.	r12, r11, 0, 0, 19	/* Extract L2 (pte) base address */
+	beq	2f			/* Bail if no table */
+
+	rlwimi	r12, r10, 22, 20, 29	/* Compute PTE address */
+	lwz	r11, 0(r12)		/* Get Linux PTE */
+	andi.	r13, r11, _PAGE_PRESENT
+	beq	2f
+
+	ori	r11, r11, _PAGE_ACCESSED
+	stw	r11, 0(r12)
+
+	/* Jump to common TLB load point */
+	b	finish_tlb_load
+
+2:
+	/* The bailout.  Restore registers to pre-exception conditions
+	 * and call the heavyweights to help us out.
+	 */
+	mfspr	r11, SPRG7R
+	mtcr	r11
+	mfspr	r13, SPRG5R
+	mfspr	r12, SPRG4R
+	mfspr	r11, SPRG1
+	mfspr	r10, SPRG0
+	b	InstructionStorage
+
+#ifdef CONFIG_SPE
+	/* SPE Unavailable */
+	START_EXCEPTION(SPEUnavailable)
+	NORMAL_EXCEPTION_PROLOG
+	bne	load_up_spe
+	addi    r3,r1,STACK_FRAME_OVERHEAD
+	EXC_XFER_EE_LITE(0x2010, KernelSPE)
+#else
+	EXCEPTION(0x2020, SPEUnavailable, UnknownException, EXC_XFER_EE)
+#endif /* CONFIG_SPE */
+
+	/* SPE Floating Point Data */
+#ifdef CONFIG_SPE
+	EXCEPTION(0x2030, SPEFloatingPointData, SPEFloatingPointException, EXC_XFER_EE);
+#else
+	EXCEPTION(0x2040, SPEFloatingPointData, UnknownException, EXC_XFER_EE)
+#endif /* CONFIG_SPE */
+
+	/* SPE Floating Point Round */
+	EXCEPTION(0x2050, SPEFloatingPointRound, UnknownException, EXC_XFER_EE)
+
+	/* Performance Monitor */
+	EXCEPTION(0x2060, PerformanceMonitor, UnknownException, EXC_XFER_EE)
+
+/* Check for a single step debug exception while in an exception
+ * handler before state has been saved.  This is to catch the case
+ * where an instruction that we are trying to single step causes
+ * an exception (eg ITLB/DTLB miss) and thus the first instruction of
+ * the exception handler generates a single step debug exception.
+ *
+ * If we get a debug trap on the first instruction of an exception handler,
+ * we reset the MSR_DE in the _exception handler's_ MSR (the debug trap is
+ * a critical exception, so we are using SPRN_CSRR1 to manipulate the MSR).
+ * The exception handler was handling a non-critical interrupt, so it will
+ * save (and later restore) the MSR via SPRN_SRR1, which will still have
+ * the MSR_DE bit set.
+ */
+	/* Debug Interrupt */
+	START_EXCEPTION(Debug)
+	CRITICAL_EXCEPTION_PROLOG
+
+	/*
+	 * If this is a single step or branch-taken exception in an
+	 * exception entry sequence, it was probably meant to apply to
+	 * the code where the exception occurred (since exception entry
+	 * doesn't turn off DE automatically).  We simulate the effect
+	 * of turning off DE on entry to an exception handler by turning
+	 * off DE in the CSRR1 value and clearing the debug status.
+	 */
+	mfspr	r10,SPRN_DBSR		/* check single-step/branch taken */
+	andis.	r10,r10,(DBSR_IC|DBSR_BT)@h
+	beq+	1f
+	andi.	r0,r9,MSR_PR		/* check supervisor */
+	beq	2f			/* branch if we need to fix it up... */
+
+	/* continue normal handling for a critical exception... */
+1:	mfspr	r4,SPRN_DBSR
+	addi	r3,r1,STACK_FRAME_OVERHEAD
+	EXC_XFER_TEMPLATE(DebugException, 0x2002, \
+		(MSR_KERNEL & ~(MSR_ME|MSR_DE|MSR_CE)), \
+		NOCOPY, crit_transfer_to_handler, ret_from_crit_exc)
+
+	/* here it looks like we got an inappropriate debug exception. */
+2:	rlwinm	r9,r9,0,~MSR_DE		/* clear DE in the CSRR1 value */
+	mtspr	SPRN_DBSR,r10		/* clear the IC/BT debug intr status */
+	/* restore state and get out */
+	lwz	r10,_CCR(r11)
+	lwz	r0,GPR0(r11)
+	lwz	r1,GPR1(r11)
+	mtcrf	0x80,r10
+	mtspr	CSRR0,r12
+	mtspr	CSRR1,r9
+	lwz	r9,GPR9(r11)
+
+	mtspr	SPRG2,r8;		/* SPRG2 only used in criticals */
+	lis	r8,crit_save@ha;
+	lwz	r10,crit_r10@l(r8)
+	lwz	r11,crit_r11@l(r8)
+	mfspr	r8,SPRG2
+
+	rfci
+	b	.
+
+/*
+ * Local functions
+ */
+	/*
+	 * Data TLB exceptions will bail out to this point
+	 * if they can't resolve the lightweight TLB fault.
+	 */
+data_access:
+	NORMAL_EXCEPTION_PROLOG
+	mfspr	r5,SPRN_ESR		/* Grab the ESR, save it, pass arg3 */
+	stw	r5,_ESR(r11)
+	mfspr	r4,SPRN_DEAR		/* Grab the DEAR, save it, pass arg2 */
+	andis.	r10,r5,(ESR_ILK|ESR_DLK)@h
+	bne	1f
+	EXC_XFER_EE_LITE(0x0300, handle_page_fault)
+1:
+	addi	r3,r1,STACK_FRAME_OVERHEAD
+	EXC_XFER_EE_LITE(0x0300, CacheLockingException)
+
+/*
+
+ * Both the instruction and data TLB miss get to this
+ * point to load the TLB.
+ * 	r10 - EA of fault
+ * 	r11 - TLB (info from Linux PTE)
+ * 	r12, r13 - available to use
+ * 	CR5 - results of addr < TASK_SIZE
+ *	MAS0, MAS1 - loaded with proper value when we get here
+ *	MAS2, MAS3 - will need additional info from Linux PTE
+ *	Upon exit, we reload everything and RFI.
+ */
+finish_tlb_load:
+	/*
+	 * We set execute, because we don't have the granularity to
+	 * properly set this at the page level (Linux problem).
+	 * Many of these bits are software only.  Bits we don't set
+	 * here we (properly should) assume have the appropriate value.
+	 */
+
+	mfspr	r12, SPRN_MAS2
+	rlwimi	r12, r11, 26, 27, 31	/* extract WIMGE from pte */
+	mtspr	SPRN_MAS2, r12
+
+	bge	5, 1f
+
+	/* addr > TASK_SIZE */
+	li	r10, (MAS3_UX | MAS3_UW | MAS3_UR)
+	andi.	r13, r11, (_PAGE_USER | _PAGE_HWWRITE | _PAGE_HWEXEC)
+	andi.	r12, r11, _PAGE_USER	/* Test for _PAGE_USER */
+	iseleq	r12, 0, r10
+	and	r10, r12, r13
+	srwi	r12, r10, 1
+	or	r12, r12, r10	/* Copy user perms into supervisor */
+	b	2f
+
+	/* addr <= TASK_SIZE */
+1:	rlwinm	r12, r11, 31, 29, 29	/* Extract _PAGE_HWWRITE into SW */
+	ori	r12, r12, (MAS3_SX | MAS3_SR)
+
+2:	rlwimi	r11, r12, 0, 20, 31	/* Extract RPN from PTE and merge with perms */
+	mtspr	SPRN_MAS3, r11
+	tlbwe
+
+	/* Done...restore registers and get out of here.  */
+	mfspr	r11, SPRG7R
+	mtcr	r11
+	mfspr	r13, SPRG5R
+	mfspr	r12, SPRG4R
+	mfspr	r11, SPRG1
+	mfspr	r10, SPRG0
+	rfi					/* Force context change */
+
+#ifdef CONFIG_SPE
+/* Note that the SPE support is closely modeled after the AltiVec
+ * support.  Changes to one are likely to be applicable to the
+ * other!  */
+load_up_spe:
+/*
+ * Disable SPE for the task which had SPE previously,
+ * and save its SPE registers in its thread_struct.
+ * Enables SPE for use in the kernel on return.
+ * On SMP we know the SPE units are free, since we give it up every
+ * switch.  -- Kumar
+ */
+	mfmsr	r5
+	oris	r5,r5,MSR_SPE@h
+	mtmsr	r5			/* enable use of SPE now */
+	isync
+/*
+ * For SMP, we don't do lazy SPE switching because it just gets too
+ * horrendously complex, especially when a task switches from one CPU
+ * to another.  Instead we call giveup_spe in switch_to.
+ */
+#ifndef CONFIG_SMP
+	lis	r3,last_task_used_spe@ha
+	lwz	r4,last_task_used_spe@l(r3)
+	cmpi	0,r4,0
+	beq	1f
+	addi	r4,r4,THREAD	/* want THREAD of last_task_used_spe */
+	SAVE_32EVR(0,r10,r4)
+   	evxor	evr10, evr10, evr10	/* clear out evr10 */
+	evmwumiaa evr10, evr10, evr10	/* evr10 <- ACC = 0 * 0 + ACC */
+	li	r5,THREAD_ACC
+   	evstddx	evr10, r4, r5		/* save off accumulator */
+	lwz	r5,PT_REGS(r4)
+	lwz	r4,_MSR-STACK_FRAME_OVERHEAD(r5)
+	lis	r10,MSR_SPE@h
+	andc	r4,r4,r10	/* disable SPE for previous task */
+	stw	r4,_MSR-STACK_FRAME_OVERHEAD(r5)
+1:
+#endif /* CONFIG_SMP */
+	/* enable use of SPE after return */
+	oris	r9,r9,MSR_SPE@h
+	mfspr	r5,SPRG3		/* current task's THREAD (phys) */
+	li	r4,1
+	li	r10,THREAD_ACC
+	stw	r4,THREAD_USED_SPE(r5)
+	evlddx	evr4,r10,r5
+	evmra	evr4,evr4
+	REST_32EVR(0,r10,r5)
+#ifndef CONFIG_SMP
+	subi	r4,r5,THREAD
+	stw	r4,last_task_used_spe@l(r3)
+#endif /* CONFIG_SMP */
+	/* restore registers and return */
+2:	REST_4GPRS(3, r11)
+	lwz	r10,_CCR(r11)
+	REST_GPR(1, r11)
+	mtcr	r10
+	lwz	r10,_LINK(r11)
+	mtlr	r10
+	REST_GPR(10, r11)
+	mtspr	SRR1,r9
+	mtspr	SRR0,r12
+	REST_GPR(9, r11)
+	REST_GPR(12, r11)
+	lwz	r11,GPR11(r11)
+	SYNC
+	rfi
+
+
+
+/*
+ * SPE unavailable trap from kernel - print a message, but let
+ * the task use SPE in the kernel until it returns to user mode.
+ */
+KernelSPE:
+	lwz	r3,_MSR(r1)
+	oris	r3,r3,MSR_SPE@h
+	stw	r3,_MSR(r1)	/* enable use of SPE after return */
+	lis	r3,87f@h
+	ori	r3,r3,87f@l
+	mr	r4,r2		/* current */
+	lwz	r5,_NIP(r1)
+	bl	printk
+	b	ret_from_except
+87:	.string	"SPE used in kernel  (task=%p, pc=%x)  \n"
+	.align	4,0
+
+#endif /* CONFIG_SPE */
+
+/*
+ * Global functions
+ */
+
+/*
+ * extern void loadcam_entry(unsigned int index)
+ *
+ * Load TLBCAM[index] entry in to the L2 CAM MMU
+ */
+_GLOBAL(loadcam_entry)
+	lis	r4,TLBCAM@ha
+	addi	r4,r4,TLBCAM@l
+	mulli	r5,r3,20
+	add	r3,r5,r4
+	lwz	r4,0(r3)
+	mtspr	SPRN_MAS0,r4
+	lwz	r4,4(r3)
+	mtspr	SPRN_MAS1,r4
+	lwz	r4,8(r3)
+	mtspr	SPRN_MAS2,r4
+	lwz	r4,12(r3)
+	mtspr	SPRN_MAS3,r4
+	tlbwe
+	isync
+	blr
+
+/*
+ * extern void giveup_altivec(struct task_struct *prev)
+ *
+ * The e500 core does not have an AltiVec unit.
+ */
+_GLOBAL(giveup_altivec)
+	blr
+
+#ifdef CONFIG_SPE
+/*
+ * extern void giveup_spe(struct task_struct *prev)
+ *
+ */
+_GLOBAL(giveup_spe)
+	mfmsr	r5
+	oris	r5,r5,MSR_SPE@h
+	SYNC
+	mtmsr	r5			/* enable use of SPE now */
+	isync
+	cmpi	0,r3,0
+	beqlr-				/* if no previous owner, done */
+	addi	r3,r3,THREAD		/* want THREAD of task */
+	lwz	r5,PT_REGS(r3)
+	cmpi	0,r5,0
+	SAVE_32EVR(0, r4, r3)
+   	evxor	evr6, evr6, evr6	/* clear out evr6 */
+	evmwumiaa evr6, evr6, evr6	/* evr6 <- ACC = 0 * 0 + ACC */
+	li	r4,THREAD_ACC
+   	evstddx	evr6, r4, r3		/* save off accumulator */
+	beq	1f
+	lwz	r4,_MSR-STACK_FRAME_OVERHEAD(r5)
+	lis	r3,MSR_SPE@h
+	andc	r4,r4,r3		/* disable SPE for previous task */
+	stw	r4,_MSR-STACK_FRAME_OVERHEAD(r5)
+1:
+#ifndef CONFIG_SMP
+	li	r5,0
+	lis	r4,last_task_used_spe@ha
+	stw	r5,last_task_used_spe@l(r4)
+#endif /* CONFIG_SMP */
+	blr
+#endif /* CONFIG_SPE */
+
+/*
+ * extern void giveup_fpu(struct task_struct *prev)
+ *
+ * The e500 core does not have an FPU.
+ */
+_GLOBAL(giveup_fpu)
+	blr
+
+/*
+ * extern void abort(void)
+ *
+ * At present, this routine just applies a system reset.
+ */
+_GLOBAL(abort)
+	li	r13,0
+        mtspr   SPRN_DBCR0,r13		/* disable all debug events */
+	mfmsr	r13
+	ori	r13,r13,MSR_DE@l	/* Enable Debug Events */
+	mtmsr	r13
+        mfspr   r13,SPRN_DBCR0
+        lis	r13,(DBCR0_IDM|DBCR0_RST_CHIP)@h
+        mtspr   SPRN_DBCR0,r13
+
+_GLOBAL(set_context)
+
+#ifdef CONFIG_BDI_SWITCH
+	/* Context switch the PTE pointer for the Abatron BDI2000.
+	 * The PGDIR is the second parameter.
+	 */
+	lis	r5, abatron_pteptrs@h
+	ori	r5, r5, abatron_pteptrs@l
+	stw	r4, 0x4(r5)
+#endif
+	mtspr	SPRN_PID,r3
+	isync			/* Force context change */
+	blr
+
+/*
+ * We put a few things here that have to be page-aligned. This stuff
+ * goes at the beginning of the data segment, which is page-aligned.
+ */
+	.data
+_GLOBAL(sdata)
+_GLOBAL(empty_zero_page)
+	.space	4096
+_GLOBAL(swapper_pg_dir)
+	.space	4096
+
+	.section .bss
+/* Stack for handling critical exceptions from kernel mode */
+critical_stack_bottom:
+	.space 4096
+critical_stack_top:
+	.previous
+
+/* Stack for handling machine check exceptions from kernel mode */
+mcheck_stack_bottom:
+	.space 4096
+mcheck_stack_top:
+	.previous
+
+/*
+ * This area is used for temporarily saving registers during the
+ * critical and machine check exception prologs. It must always
+ * follow the page aligned allocations, so it starts on a page
+ * boundary, ensuring that all crit_save areas are in a single
+ * page.
+ */
+
+/* crit_save */
+_GLOBAL(crit_save)
+	.space  4
+_GLOBAL(crit_r10)
+	.space	4
+_GLOBAL(crit_r11)
+	.space	4
+_GLOBAL(crit_sprg0)
+	.space	4
+_GLOBAL(crit_sprg1)
+	.space	4
+_GLOBAL(crit_sprg4)
+	.space	4
+_GLOBAL(crit_sprg5)
+	.space	4
+_GLOBAL(crit_sprg7)
+	.space	4
+_GLOBAL(crit_pid)
+	.space	4
+_GLOBAL(crit_srr0)
+	.space	4
+_GLOBAL(crit_srr1)
+	.space	4
+
+/* mcheck_save */
+_GLOBAL(mcheck_save)
+	.space  4
+_GLOBAL(mcheck_r10)
+	.space	4
+_GLOBAL(mcheck_r11)
+	.space	4
+_GLOBAL(mcheck_sprg0)
+	.space	4
+_GLOBAL(mcheck_sprg1)
+	.space	4
+_GLOBAL(mcheck_sprg4)
+	.space	4
+_GLOBAL(mcheck_sprg5)
+	.space	4
+_GLOBAL(mcheck_sprg7)
+	.space	4
+_GLOBAL(mcheck_pid)
+	.space	4
+_GLOBAL(mcheck_srr0)
+	.space	4
+_GLOBAL(mcheck_srr1)
+	.space	4
+_GLOBAL(mcheck_csrr0)
+	.space	4
+_GLOBAL(mcheck_csrr1)
+	.space	4
+
+/*
+ * This space gets a copy of optional info passed to us by the bootstrap
+ * which is used to pass parameters into the kernel like root=/dev/sda1, etc.
+ */
+_GLOBAL(cmd_line)
+	.space	512
+
+/*
+ * Room for two PTE pointers, usually the kernel and current user pointers
+ * to their respective root page table.
+ */
+abatron_pteptrs:
+	.space	8
+
+
--- diff/arch/ppc/mm/fsl_booke_mmu.c	1970-01-01 01:00:00.000000000 +0100
+++ source/arch/ppc/mm/fsl_booke_mmu.c	2004-06-11 19:21:59.000000000 +0100
@@ -0,0 +1,236 @@
+/*
+ * Modifications by Kumar Gala (kumar.gala@freescale.com) to support
+ * E500 Book E processors.
+ *
+ * Copyright 2004 Freescale Semiconductor, Inc
+ *
+ * This file contains the routines for initializing the MMU
+ * on the 4xx series of chips.
+ *  -- paulus
+ *
+ *  Derived from arch/ppc/mm/init.c:
+ *    Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org)
+ *
+ *  Modifications by Paul Mackerras (PowerMac) (paulus@cs.anu.edu.au)
+ *  and Cort Dougan (PReP) (cort@cs.nmt.edu)
+ *    Copyright (C) 1996 Paul Mackerras
+ *  Amiga/APUS changes by Jesper Skov (jskov@cygnus.co.uk).
+ *
+ *  Derived from "arch/i386/mm/init.c"
+ *    Copyright (C) 1991, 1992, 1993, 1994  Linus Torvalds
+ *
+ *  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.
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/signal.h>
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/string.h>
+#include <linux/types.h>
+#include <linux/ptrace.h>
+#include <linux/mman.h>
+#include <linux/mm.h>
+#include <linux/swap.h>
+#include <linux/stddef.h>
+#include <linux/vmalloc.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/bootmem.h>
+#include <linux/highmem.h>
+
+#include <asm/pgalloc.h>
+#include <asm/prom.h>
+#include <asm/io.h>
+#include <asm/mmu_context.h>
+#include <asm/pgtable.h>
+#include <asm/mmu.h>
+#include <asm/uaccess.h>
+#include <asm/smp.h>
+#include <asm/bootx.h>
+#include <asm/machdep.h>
+#include <asm/setup.h>
+
+extern void loadcam_entry(unsigned int index);
+unsigned int tlbcam_index;
+unsigned int num_tlbcam_entries;
+static unsigned long __cam0, __cam1, __cam2;
+extern unsigned long total_lowmem;
+extern unsigned long __max_low_memory;
+#define MAX_LOW_MEM	CONFIG_LOWMEM_SIZE
+
+struct tlbcam {
+   	u32	MAS0;
+	u32	MAS1;
+	u32	MAS2;
+	u32	MAS3;
+	u32	MAS7;
+} TLBCAM[NUM_TLBCAMS];
+
+struct tlbcamrange {
+   	unsigned long start;
+	unsigned long limit;
+	phys_addr_t phys;
+} tlbcam_addrs[NUM_TLBCAMS];
+
+extern unsigned int tlbcam_index;
+
+/*
+ * Return PA for this VA if it is mapped by a CAM, or 0
+ */
+unsigned long v_mapped_by_tlbcam(unsigned long va)
+{
+	int b;
+	for (b = 0; b < tlbcam_index; ++b)
+		if (va >= tlbcam_addrs[b].start && va < tlbcam_addrs[b].limit)
+			return tlbcam_addrs[b].phys + (va - tlbcam_addrs[b].start);
+	return 0;
+}
+
+/*
+ * Return VA for a given PA or 0 if not mapped
+ */
+unsigned long p_mapped_by_tlbcam(unsigned long pa)
+{
+	int b;
+	for (b = 0; b < tlbcam_index; ++b)
+		if (pa >= tlbcam_addrs[b].phys
+	    	    && pa < (tlbcam_addrs[b].limit-tlbcam_addrs[b].start)
+		              +tlbcam_addrs[b].phys)
+			return tlbcam_addrs[b].start+(pa-tlbcam_addrs[b].phys);
+	return 0;
+}
+
+/*
+ * Set up one of the I/D BAT (block address translation) register pairs.
+ * The parameters are not checked; in particular size must be a power
+ * of 4 between 4k and 256M.
+ */
+void settlbcam(int index, unsigned long virt, phys_addr_t phys,
+		unsigned int size, int flags, unsigned int pid)
+{
+	unsigned int tsize, lz;
+
+	asm ("cntlzw %0,%1" : "=r" (lz) : "r" (size));
+	tsize = (21 - lz) / 2;
+
+#ifdef CONFIG_SMP
+	if ((flags & _PAGE_NO_CACHE) == 0)
+		flags |= _PAGE_COHERENT;
+#endif
+
+	TLBCAM[index].MAS0 = MAS0_TLBSEL | (index << 16);
+	TLBCAM[index].MAS1 = MAS1_VALID | MAS1_IPROT | MAS1_TSIZE(tsize) | ((pid << 16) & MAS1_TID);
+	TLBCAM[index].MAS2 = virt & PAGE_MASK;
+
+	TLBCAM[index].MAS2 |= (flags & _PAGE_WRITETHRU) ? MAS2_W : 0;
+	TLBCAM[index].MAS2 |= (flags & _PAGE_NO_CACHE) ? MAS2_I : 0;
+	TLBCAM[index].MAS2 |= (flags & _PAGE_COHERENT) ? MAS2_M : 0;
+	TLBCAM[index].MAS2 |= (flags & _PAGE_GUARDED) ? MAS2_G : 0;
+	TLBCAM[index].MAS2 |= (flags & _PAGE_ENDIAN) ? MAS2_E : 0;
+
+	TLBCAM[index].MAS3 = (phys & PAGE_MASK) | MAS3_SX | MAS3_SR;
+	TLBCAM[index].MAS3 |= ((flags & _PAGE_RW) ? MAS3_SW : 0);
+
+#ifndef CONFIG_KGDB /* want user access for breakpoints */
+	if (flags & _PAGE_USER) {
+	   TLBCAM[index].MAS3 |= MAS3_UX | MAS3_UR;
+	   TLBCAM[index].MAS3 |= ((flags & _PAGE_RW) ? MAS3_UW : 0);
+	}
+#else
+	TLBCAM[index].MAS3 |= MAS3_UX | MAS3_UR;
+	TLBCAM[index].MAS3 |= ((flags & _PAGE_RW) ? MAS3_UW : 0);
+#endif
+
+	tlbcam_addrs[index].start = virt;
+	tlbcam_addrs[index].limit = virt + size - 1;
+	tlbcam_addrs[index].phys = phys;
+
+	loadcam_entry(index);
+}
+
+void invalidate_tlbcam_entry(int index)
+{
+	TLBCAM[index].MAS0 = MAS0_TLBSEL | (index << 16);
+	TLBCAM[index].MAS1 = ~MAS1_VALID;
+
+	loadcam_entry(index);
+}
+
+void __init cam_mapin_ram(unsigned long cam0, unsigned long cam1,
+		unsigned long cam2)
+{
+	settlbcam(0, KERNELBASE, PPC_MEMSTART, cam0, _PAGE_KERNEL, 0);
+	tlbcam_index++;
+	if (cam1) {
+		tlbcam_index++;
+		settlbcam(1, KERNELBASE+cam0, PPC_MEMSTART+cam0, cam1, _PAGE_KERNEL, 0);
+	}
+	if (cam2) {
+		tlbcam_index++;
+		settlbcam(2, KERNELBASE+cam0+cam1, PPC_MEMSTART+cam0+cam1, cam2, _PAGE_KERNEL, 0);
+	}
+}
+
+/*
+ * MMU_init_hw does the chip-specific initialization of the MMU hardware.
+ */
+void __init MMU_init_hw(void)
+{
+	flush_instruction_cache();
+}
+
+unsigned long __init mmu_mapin_ram(void)
+{
+	cam_mapin_ram(__cam0, __cam1, __cam2);
+
+	return __cam0 + __cam1 + __cam2;
+}
+
+
+void __init
+adjust_total_lowmem(void)
+{
+	unsigned long max_low_mem = MAX_LOW_MEM;
+	unsigned long cam_max = 0x10000000;
+	unsigned long ram;
+
+	/* adjust CAM size to max_low_mem */
+	if (max_low_mem < cam_max)
+		cam_max = max_low_mem;
+
+	/* adjust lowmem size to max_low_mem */
+	if (max_low_mem < total_lowmem)
+		ram = max_low_mem;
+	else
+		ram = total_lowmem;
+
+	/* Calculate CAM values */
+	__cam0 = 1UL << 2 * (__ilog2(ram) / 2);
+	if (__cam0 > cam_max)
+		__cam0 = cam_max;
+	ram -= __cam0;
+	if (ram) {
+		__cam1 = 1UL << 2 * (__ilog2(ram) / 2);
+		if (__cam1 > cam_max)
+			__cam1 = cam_max;
+		ram -= __cam1;
+	}
+	if (ram) {
+		__cam2 = 1UL << 2 * (__ilog2(ram) / 2);
+		if (__cam2 > cam_max)
+			__cam2 = cam_max;
+		ram -= __cam2;
+	}
+
+	printk(KERN_INFO "Memory CAM mapping: CAM0=%ldMb, CAM1=%ldMb,"
+			" CAM2=%ldMb residual: %ldMb\n",
+			__cam0 >> 20, __cam1 >> 20, __cam2 >> 20,
+			(total_lowmem - __cam0 - __cam1 - __cam2) >> 20);
+	__max_low_memory = max_low_mem = __cam0 + __cam1 + __cam2;
+}
--- diff/arch/ppc/platforms/85xx/Kconfig	1970-01-01 01:00:00.000000000 +0100
+++ source/arch/ppc/platforms/85xx/Kconfig	2004-06-11 19:21:59.000000000 +0100
@@ -0,0 +1,44 @@
+config 85xx
+	bool
+	depends on E500
+	default y
+
+config PPC_INDIRECT_PCI_BE
+	bool
+	depends on 85xx
+	default y
+
+menu "Freescale 85xx options"
+	depends on E500
+
+choice
+	prompt "Machine Type"
+	depends on 85xx
+	default MPC8540_ADS
+
+config MPC8540_ADS
+	bool "MPC8540ADS"
+	help
+	  This option enables support for the MPC 8540 ADS evaluation board.
+
+endchoice
+
+# It's often necessary to know the specific 85xx processor type.
+# Fortunately, it is implied (so far) from the board type, so we
+# don't need to ask more redundant questions.
+config MPC8540
+	bool
+	depends on MPC8540_ADS
+	default y
+
+config FSL_OCP
+	bool
+	depends on 85xx
+	default y
+
+config PPC_GEN550
+	bool
+	depends on MPC8540
+	default y
+
+endmenu
--- diff/arch/ppc/platforms/85xx/Makefile	1970-01-01 01:00:00.000000000 +0100
+++ source/arch/ppc/platforms/85xx/Makefile	2004-06-11 19:21:59.000000000 +0100
@@ -0,0 +1,7 @@
+#
+# Makefile for the PowerPC 85xx linux kernel.
+#
+
+obj-$(CONFIG_MPC8540_ADS)	+= mpc85xx_ads_common.o mpc8540_ads.o
+
+obj-$(CONFIG_MPC8540)		+= mpc8540.o
--- diff/arch/ppc/platforms/85xx/mpc8540.c	1970-01-01 01:00:00.000000000 +0100
+++ source/arch/ppc/platforms/85xx/mpc8540.c	2004-06-11 19:21:59.000000000 +0100
@@ -0,0 +1,97 @@
+/*
+ * arch/ppc/platforms/85xx/mpc8540.c
+ *
+ * MPC8540 I/O descriptions
+ *
+ * Maintainer: Kumar Gala <kumar.gala@freescale.com>
+ *
+ * Copyright 2004 Freescale Semiconductor Inc.
+ *
+ * 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.
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <asm/mpc85xx.h>
+#include <asm/ocp.h>
+
+/* These should be defined in platform code */
+extern struct ocp_gfar_data mpc85xx_tsec1_def;
+extern struct ocp_gfar_data mpc85xx_tsec2_def;
+extern struct ocp_gfar_data mpc85xx_fec_def;
+extern struct ocp_mpc_i2c_data mpc85xx_i2c1_def;
+
+/* We use offsets for paddr since we do not know at compile time
+ * what CCSRBAR is, platform code should fix this up in
+ * setup_arch
+ *
+ * Only the first IRQ is given even if a device has
+ * multiple lines associated with ita
+ */
+struct ocp_def core_ocp[] = {
+        { .vendor       = OCP_VENDOR_FREESCALE,
+          .function     = OCP_FUNC_IIC,
+          .index        = 0,
+          .paddr        = MPC85xx_IIC1_OFFSET,
+          .irq          = MPC85xx_IRQ_IIC1,
+          .pm           = OCP_CPM_NA,
+          .additions    = &mpc85xx_i2c1_def,
+        },
+        { .vendor       = OCP_VENDOR_FREESCALE,
+          .function     = OCP_FUNC_16550,
+          .index        = 0,
+          .paddr        = MPC85xx_UART0_OFFSET,
+          .irq          = MPC85xx_IRQ_DUART,
+          .pm           = OCP_CPM_NA,
+        },
+        { .vendor       = OCP_VENDOR_FREESCALE,
+          .function     = OCP_FUNC_16550,
+          .index        = 1,
+          .paddr        = MPC85xx_UART1_OFFSET,
+          .irq          = MPC85xx_IRQ_DUART,
+          .pm           = OCP_CPM_NA,
+        },
+        { .vendor       = OCP_VENDOR_FREESCALE,
+          .function     = OCP_FUNC_GFAR,
+          .index        = 0,
+          .paddr        = MPC85xx_ENET1_OFFSET,
+          .irq          = MPC85xx_IRQ_TSEC1_TX,
+          .pm           = OCP_CPM_NA,
+          .additions    = &mpc85xx_tsec1_def,
+        },
+        { .vendor       = OCP_VENDOR_FREESCALE,
+          .function     = OCP_FUNC_GFAR,
+          .index        = 1,
+          .paddr        = MPC85xx_ENET2_OFFSET,
+          .irq          = MPC85xx_IRQ_TSEC2_TX,
+          .pm           = OCP_CPM_NA,
+          .additions    = &mpc85xx_tsec2_def,
+        },
+        { .vendor       = OCP_VENDOR_FREESCALE,
+          .function     = OCP_FUNC_GFAR,
+          .index        = 2,
+          .paddr        = MPC85xx_ENET3_OFFSET,
+          .irq          = MPC85xx_IRQ_FEC,
+          .pm           = OCP_CPM_NA,
+          .additions    = &mpc85xx_fec_def,
+        },
+        { .vendor       = OCP_VENDOR_FREESCALE,
+          .function     = OCP_FUNC_DMA,
+          .index        = 0,
+          .paddr        = MPC85xx_DMA_OFFSET,
+          .irq          = MPC85xx_IRQ_DMA0,
+          .pm           = OCP_CPM_NA,
+        },
+        { .vendor       = OCP_VENDOR_FREESCALE,
+          .function     = OCP_FUNC_PERFMON,
+          .index        = 0,
+          .paddr        = MPC85xx_PERFMON_OFFSET,
+          .irq          = MPC85xx_IRQ_PERFMON,
+          .pm           = OCP_CPM_NA,
+        },
+        { .vendor       = OCP_VENDOR_INVALID
+        }
+};
--- diff/arch/ppc/platforms/85xx/mpc8540_ads.c	1970-01-01 01:00:00.000000000 +0100
+++ source/arch/ppc/platforms/85xx/mpc8540_ads.c	2004-06-11 19:21:59.000000000 +0100
@@ -0,0 +1,238 @@
+/*
+ * arch/ppc/platforms/85xx/mpc8540_ads.c
+ *
+ * MPC8540ADS board specific routines
+ *
+ * Maintainer: Kumar Gala <kumar.gala@freescale.com>
+ *
+ * Copyright 2004 Freescale Semiconductor Inc.
+ *
+ * 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.
+ */
+
+#include <linux/config.h>
+#include <linux/stddef.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/errno.h>
+#include <linux/reboot.h>
+#include <linux/pci.h>
+#include <linux/kdev_t.h>
+#include <linux/major.h>
+#include <linux/console.h>
+#include <linux/delay.h>
+#include <linux/irq.h>
+#include <linux/seq_file.h>
+#include <linux/root_dev.h>
+#include <linux/serial.h>
+#include <linux/tty.h>	/* for linux/serial_core.h */
+#include <linux/serial_core.h>
+#include <linux/module.h>
+
+#include <asm/system.h>
+#include <asm/pgtable.h>
+#include <asm/page.h>
+#include <asm/atomic.h>
+#include <asm/time.h>
+#include <asm/io.h>
+#include <asm/machdep.h>
+#include <asm/prom.h>
+#include <asm/open_pic.h>
+#include <asm/bootinfo.h>
+#include <asm/pci-bridge.h>
+#include <asm/mpc85xx.h>
+#include <asm/irq.h>
+#include <asm/immap_85xx.h>
+#include <asm/kgdb.h>
+#include <asm/ocp.h>
+#include <mm/mmu_decl.h>
+
+#include <syslib/ppc85xx_common.h>
+#include <syslib/ppc85xx_setup.h>
+
+struct ocp_gfar_data mpc85xx_tsec1_def = {
+	.interruptTransmit = MPC85xx_IRQ_TSEC1_TX,
+	.interruptError = MPC85xx_IRQ_TSEC1_ERROR,
+	.interruptReceive = MPC85xx_IRQ_TSEC1_RX,
+	.interruptPHY = MPC85xx_IRQ_EXT5,
+	.flags = (GFAR_HAS_GIGABIT | GFAR_HAS_MULTI_INTR
+			| GFAR_HAS_RMON
+			| GFAR_HAS_PHY_INTR | GFAR_HAS_COALESCE),
+	.phyid = 0,
+	.phyregidx = 0,
+};
+
+struct ocp_gfar_data mpc85xx_tsec2_def = {
+	.interruptTransmit = MPC85xx_IRQ_TSEC2_TX,
+	.interruptError = MPC85xx_IRQ_TSEC2_ERROR,
+	.interruptReceive = MPC85xx_IRQ_TSEC2_RX,
+	.interruptPHY = MPC85xx_IRQ_EXT5,
+	.flags = (GFAR_HAS_GIGABIT | GFAR_HAS_MULTI_INTR
+			| GFAR_HAS_RMON
+			| GFAR_HAS_PHY_INTR | GFAR_HAS_COALESCE),
+	.phyid = 1,
+	.phyregidx = 0,
+};
+
+struct ocp_gfar_data mpc85xx_fec_def = {
+	.interruptTransmit = MPC85xx_IRQ_FEC,
+	.interruptError = MPC85xx_IRQ_FEC,
+	.interruptReceive = MPC85xx_IRQ_FEC,
+	.interruptPHY = MPC85xx_IRQ_EXT5,
+	.flags = 0,
+	.phyid = 3,
+	.phyregidx = 0,
+};
+
+struct ocp_fs_i2c_data mpc85xx_i2c1_def = {
+	.flags = FS_I2C_SEPARATE_DFSRR,
+};
+
+/* ************************************************************************
+ *
+ * Setup the architecture
+ *
+ */
+static void __init
+mpc8540ads_setup_arch(void)
+{
+	struct ocp_def *def;
+	struct ocp_gfar_data *einfo;
+	bd_t *binfo = (bd_t *) __res;
+	unsigned int freq;
+
+	/* get the core frequency */
+	freq = binfo->bi_intfreq;
+
+	if (ppc_md.progress)
+		ppc_md.progress("mpc8540ads_setup_arch()", 0);
+
+	/* Set loops_per_jiffy to a half-way reasonable value,
+	   for use until calibrate_delay gets called. */
+	loops_per_jiffy = freq / HZ;
+
+#ifdef CONFIG_PCI
+	/* setup PCI host bridges */
+	mpc85xx_setup_hose();
+#endif
+
+#ifdef CONFIG_DUMMY_CONSOLE
+	conswitchp = &dummy_con;
+#endif
+
+#ifdef CONFIG_SERIAL_8250
+	mpc85xx_early_serial_map();
+#endif
+
+#ifdef CONFIG_SERIAL_TEXT_DEBUG
+	/* Invalidate the entry we stole earlier the serial ports
+	 * should be properly mapped */
+	invalidate_tlbcam_entry(NUM_TLBCAMS - 1);
+#endif
+
+	def = ocp_get_one_device(OCP_VENDOR_FREESCALE, OCP_FUNC_GFAR, 0);
+	if (def) {
+		einfo = (struct ocp_gfar_data *) def->additions;
+		memcpy(einfo->mac_addr, binfo->bi_enetaddr, 6);
+	}
+
+	def = ocp_get_one_device(OCP_VENDOR_FREESCALE, OCP_FUNC_GFAR, 1);
+	if (def) {
+		einfo = (struct ocp_gfar_data *) def->additions;
+		memcpy(einfo->mac_addr, binfo->bi_enet1addr, 6);
+	}
+
+	def = ocp_get_one_device(OCP_VENDOR_FREESCALE, OCP_FUNC_GFAR, 2);
+	if (def) {
+		einfo = (struct ocp_gfar_data *) def->additions;
+		memcpy(einfo->mac_addr, binfo->bi_enet2addr, 6);
+	}
+
+#ifdef CONFIG_BLK_DEV_INITRD
+	if (initrd_start)
+		ROOT_DEV = Root_RAM0;
+	else
+#endif
+#ifdef  CONFIG_ROOT_NFS
+		ROOT_DEV = Root_NFS;
+#else
+		ROOT_DEV = Root_HDA1;
+#endif
+
+	ocp_for_each_device(mpc85xx_update_paddr_ocp, &(binfo->bi_immr_base));
+}
+
+/* ************************************************************************ */
+void __init
+platform_init(unsigned long r3, unsigned long r4, unsigned long r5,
+	      unsigned long r6, unsigned long r7)
+{
+	/* parse_bootinfo must always be called first */
+	parse_bootinfo(find_bootinfo());
+
+	/*
+	 * If we were passed in a board information, copy it into the
+	 * residual data area.
+	 */
+	if (r3) {
+		memcpy((void *) __res, (void *) (r3 + KERNELBASE),
+		       sizeof (bd_t));
+	}
+#ifdef CONFIG_SERIAL_TEXT_DEBUG
+	{
+		bd_t *binfo = (bd_t *) __res;
+
+		/* Use the last TLB entry to map CCSRBAR to allow access to DUART regs */
+		settlbcam(NUM_TLBCAMS - 1, binfo->bi_immr_base,
+			  binfo->bi_immr_base, MPC85xx_CCSRBAR_SIZE, _PAGE_IO, 0);
+	}
+#endif
+
+#if defined(CONFIG_BLK_DEV_INITRD)
+	/*
+	 * If the init RAM disk has been configured in, and there's a valid
+	 * starting address for it, set it up.
+	 */
+	if (r4) {
+		initrd_start = r4 + KERNELBASE;
+		initrd_end = r5 + KERNELBASE;
+	}
+#endif				/* CONFIG_BLK_DEV_INITRD */
+
+	/* Copy the kernel command line arguments to a safe place. */
+
+	if (r6) {
+		*(char *) (r7 + KERNELBASE) = 0;
+		strcpy(cmd_line, (char *) (r6 + KERNELBASE));
+	}
+
+	/* setup the PowerPC module struct */
+	ppc_md.setup_arch = mpc8540ads_setup_arch;
+	ppc_md.show_cpuinfo = mpc85xx_ads_show_cpuinfo;
+
+	ppc_md.init_IRQ = mpc85xx_ads_init_IRQ;
+	ppc_md.get_irq = openpic_get_irq;
+
+	ppc_md.restart = mpc85xx_restart;
+	ppc_md.power_off = mpc85xx_power_off;
+	ppc_md.halt = mpc85xx_halt;
+
+	ppc_md.find_end_of_memory = mpc85xx_find_end_of_memory;
+
+	ppc_md.time_init = NULL;
+	ppc_md.set_rtc_time = NULL;
+	ppc_md.get_rtc_time = NULL;
+	ppc_md.calibrate_decr = mpc85xx_calibrate_decr;
+
+#if defined(CONFIG_SERIAL_8250) && defined(CONFIG_SERIAL_TEXT_DEBUG)
+	ppc_md.progress = gen550_progress;
+#endif	/* CONFIG_SERIAL_8250 && CONFIG_SERIAL_TEXT_DEBUG */
+
+	if (ppc_md.progress)
+		ppc_md.progress("mpc8540ads_init(): exit", 0);
+
+	return;
+}
--- diff/arch/ppc/platforms/85xx/mpc8540_ads.h	1970-01-01 01:00:00.000000000 +0100
+++ source/arch/ppc/platforms/85xx/mpc8540_ads.h	2004-06-11 19:21:59.000000000 +0100
@@ -0,0 +1,30 @@
+/*
+ * arch/ppc/platforms/85xx/mpc8540_ads.h
+ *
+ * MPC8540ADS board definitions
+ *
+ * Maintainer: Kumar Gala <kumar.gala@freescale.com>
+ *
+ * Copyright 2004 Freescale Semiconductor Inc.
+ *
+ * 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.
+ *
+ */
+
+#ifndef __MACH_MPC8540ADS_H__
+#define __MACH_MPC8540ADS_H__
+
+#include <linux/config.h>
+#include <linux/serial.h>
+#include <linux/initrd.h>
+#include <syslib/ppc85xx_setup.h>
+#include <platforms/85xx/mpc85xx_ads_common.h>
+
+#define SERIAL_PORT_DFNS	\
+	STD_UART_OP(0)		\
+	STD_UART_OP(1)
+
+#endif /* __MACH_MPC8540ADS_H__ */
--- diff/arch/ppc/platforms/85xx/mpc85xx_ads_common.c	1970-01-01 01:00:00.000000000 +0100
+++ source/arch/ppc/platforms/85xx/mpc85xx_ads_common.c	2004-06-11 19:21:59.000000000 +0100
@@ -0,0 +1,237 @@
+/*
+ * arch/ppc/platforms/85xx/mpc85xx_ads_common.c
+ *
+ * MPC85xx ADS board common routines
+ *
+ * Maintainer: Kumar Gala <kumar.gala@freescale.com>
+ *
+ * Copyright 2004 Freescale Semiconductor Inc.
+ *
+ * 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.
+ */
+
+#include <linux/config.h>
+#include <linux/stddef.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/errno.h>
+#include <linux/reboot.h>
+#include <linux/pci.h>
+#include <linux/kdev_t.h>
+#include <linux/major.h>
+#include <linux/console.h>
+#include <linux/delay.h>
+#include <linux/irq.h>
+#include <linux/seq_file.h>
+#include <linux/serial.h>
+#include <linux/module.h>
+
+#include <asm/system.h>
+#include <asm/pgtable.h>
+#include <asm/page.h>
+#include <asm/atomic.h>
+#include <asm/time.h>
+#include <asm/io.h>
+#include <asm/machdep.h>
+#include <asm/prom.h>
+#include <asm/open_pic.h>
+#include <asm/bootinfo.h>
+#include <asm/pci-bridge.h>
+#include <asm/mpc85xx.h>
+#include <asm/irq.h>
+#include <asm/immap_85xx.h>
+#include <asm/ocp.h>
+
+#include <mm/mmu_decl.h>
+
+#include <platforms/85xx/mpc85xx_ads_common.h>
+
+#ifndef CONFIG_PCI
+unsigned long isa_io_base = 0;
+unsigned long isa_mem_base = 0;
+#endif
+
+extern unsigned long total_memory;	/* in mm/init */
+
+unsigned char __res[sizeof (bd_t)];
+
+/* Internal interrupts are all Level Sensitive, and Positive Polarity */
+
+static u_char mpc85xx_ads_openpic_initsenses[] __initdata = {
+	(IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE),	/* Internal  0: L2 Cache */
+	(IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE),	/* Internal  1: ECM */
+	(IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE),	/* Internal  2: DDR DRAM */
+	(IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE),	/* Internal  3: LBIU */
+	(IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE),	/* Internal  4: DMA 0 */
+	(IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE),	/* Internal  5: DMA 1 */
+	(IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE),	/* Internal  6: DMA 2 */
+	(IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE),	/* Internal  7: DMA 3 */
+	(IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE),	/* Internal  8: PCI/PCI-X */
+	(IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE),	/* Internal  9: RIO Inbound Port Write Error */
+	(IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE),	/* Internal 10: RIO Doorbell Inbound */
+	(IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE),	/* Internal 11: RIO Outbound Message */
+	(IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE),	/* Internal 12: RIO Inbound Message */
+	(IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE),	/* Internal 13: TSEC 0 Transmit */
+	(IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE),	/* Internal 14: TSEC 0 Receive */
+	(IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE),	/* Internal 15: Unused */
+	(IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE),	/* Internal 16: Unused */
+	(IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE),	/* Internal 17: Unused */
+	(IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE),	/* Internal 18: TSEC 0 Receive/Transmit Error */
+	(IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE),	/* Internal 19: TSEC 1 Transmit */
+	(IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE),	/* Internal 20: TSEC 1 Receive */
+	(IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE),	/* Internal 21: Unused */
+	(IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE),	/* Internal 22: Unused */
+	(IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE),	/* Internal 23: Unused */
+	(IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE),	/* Internal 24: TSEC 1 Receive/Transmit Error */
+	(IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE),	/* Internal 25: Fast Ethernet */
+	(IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE),	/* Internal 26: DUART */
+	(IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE),	/* Internal 27: I2C */
+	(IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE),	/* Internal 28: Performance Monitor */
+	(IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE),	/* Internal 29: Unused */
+	(IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE),	/* Internal 30: CPM */
+	(IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE),	/* Internal 31: Unused */
+	0x0,						/* External  0: */
+#if defined(CONFIG_PCI)
+	(IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE),	/* External 1: PCI slot 0 */
+	(IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE),	/* External 2: PCI slot 1 */
+	(IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE),	/* External 3: PCI slot 2 */
+	(IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE),	/* External 4: PCI slot 3 */
+#else
+	0x0,				/* External  1: */
+	0x0,				/* External  2: */
+	0x0,				/* External  3: */
+	0x0,				/* External  4: */
+#endif
+	(IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE),	/* External 5: PHY */
+	0x0,				/* External  6: */
+	(IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE),	/* External 7: PHY */
+	0x0,				/* External  8: */
+	0x0,				/* External  9: */
+	0x0,				/* External 10: */
+	0x0,				/* External 11: */
+};
+
+/* ************************************************************************ */
+int
+mpc85xx_ads_show_cpuinfo(struct seq_file *m)
+{
+	uint pvid, svid, phid1;
+	uint memsize = total_memory;
+	bd_t *binfo = (bd_t *) __res;
+	unsigned int freq;
+
+	/* get the core frequency */
+	freq = binfo->bi_intfreq;
+
+	pvid = mfspr(PVR);
+	svid = mfspr(SVR);
+
+	seq_printf(m, "Vendor\t\t: Freescale Semiconductor\n");
+
+	switch (svid & 0xffff0000) {
+	case SVR_8540:
+		seq_printf(m, "Machine\t\t: mpc8540ads\n");
+		break;
+	case SVR_8560:
+		seq_printf(m, "Machine\t\t: mpc8560ads\n");
+		break;
+	default:
+		seq_printf(m, "Machine\t\t: unknown\n");
+		break;
+	}
+	seq_printf(m, "bus freq\t: %u.%.6u MHz\n", freq / 1000000,
+		   freq % 1000000);
+	seq_printf(m, "PVR\t\t: 0x%x\n", pvid);
+	seq_printf(m, "SVR\t\t: 0x%x\n", svid);
+
+	/* Display cpu Pll setting */
+	phid1 = mfspr(HID1);
+	seq_printf(m, "PLL setting\t: 0x%x\n", ((phid1 >> 24) & 0x3f));
+
+	/* Display the amount of memory */
+	seq_printf(m, "Memory\t\t: %d MB\n", memsize / (1024 * 1024));
+
+	return 0;
+}
+
+void __init
+mpc85xx_ads_init_IRQ(void)
+{
+	bd_t *binfo = (bd_t *) __res;
+	/* Determine the Physical Address of the OpenPIC regs */
+	phys_addr_t OpenPIC_PAddr =
+	    binfo->bi_immr_base + MPC85xx_OPENPIC_OFFSET;
+	OpenPIC_Addr = ioremap(OpenPIC_PAddr, MPC85xx_OPENPIC_SIZE);
+	OpenPIC_InitSenses = mpc85xx_ads_openpic_initsenses;
+	OpenPIC_NumInitSenses = sizeof (mpc85xx_ads_openpic_initsenses);
+
+	/* Skip reserved space and internal sources */
+	openpic_set_sources(0, 32, OpenPIC_Addr + 0x10200);
+	/* Map PIC IRQs 0-11 */
+	openpic_set_sources(32, 12, OpenPIC_Addr + 0x10000);
+
+	/* we let openpic interrupts starting from an offset, to
+	 * leave space for cascading interrupts underneath.
+	 */
+	openpic_init(MPC85xx_OPENPIC_IRQ_OFFSET);
+
+	return;
+}
+
+#ifdef CONFIG_PCI
+/*
+ * interrupt routing
+ */
+
+int
+mpc85xx_map_irq(struct pci_dev *dev, unsigned char idsel, unsigned char pin)
+{
+	static char pci_irq_table[][4] =
+	    /*
+	     * This is little evil, but works around the fact
+	     * that revA boards have IDSEL starting at 18
+	     * and others boards (older) start at 12
+	     *
+	     *      PCI IDSEL/INTPIN->INTLINE
+	     *       A      B      C      D
+	     */
+	{
+		{PIRQA, PIRQB, PIRQC, PIRQD},	/* IDSEL 2 */
+		{PIRQD, PIRQA, PIRQB, PIRQC},
+		{PIRQC, PIRQD, PIRQA, PIRQB},
+		{PIRQB, PIRQC, PIRQD, PIRQA},	/* IDSEL 5 */
+		{0, 0, 0, 0},	/* -- */
+		{0, 0, 0, 0},	/* -- */
+		{0, 0, 0, 0},	/* -- */
+		{0, 0, 0, 0},	/* -- */
+		{0, 0, 0, 0},	/* -- */
+		{0, 0, 0, 0},	/* -- */
+		{PIRQA, PIRQB, PIRQC, PIRQD},	/* IDSEL 12 */
+		{PIRQD, PIRQA, PIRQB, PIRQC},
+		{PIRQC, PIRQD, PIRQA, PIRQB},
+		{PIRQB, PIRQC, PIRQD, PIRQA},	/* IDSEL 15 */
+		{0, 0, 0, 0},	/* -- */
+		{0, 0, 0, 0},	/* -- */
+		{PIRQA, PIRQB, PIRQC, PIRQD},	/* IDSEL 18 */
+		{PIRQD, PIRQA, PIRQB, PIRQC},
+		{PIRQC, PIRQD, PIRQA, PIRQB},
+		{PIRQB, PIRQC, PIRQD, PIRQA},	/* IDSEL 21 */
+	};
+
+	const long min_idsel = 2, max_idsel = 21, irqs_per_slot = 4;
+	return PCI_IRQ_TABLE_LOOKUP;
+}
+
+int
+mpc85xx_exclude_device(u_char bus, u_char devfn)
+{
+	if (bus == 0 && PCI_SLOT(devfn) == 0)
+		return PCIBIOS_DEVICE_NOT_FOUND;
+	else
+		return PCIBIOS_SUCCESSFUL;
+}
+
+#endif /* CONFIG_PCI */
--- diff/arch/ppc/platforms/85xx/mpc85xx_ads_common.h	1970-01-01 01:00:00.000000000 +0100
+++ source/arch/ppc/platforms/85xx/mpc85xx_ads_common.h	2004-06-11 19:21:59.000000000 +0100
@@ -0,0 +1,50 @@
+/*
+ * arch/ppc/platforms/85xx/mpc85xx_ads_common.h
+ *
+ * MPC85XX ADS common board definitions
+ *
+ * Maintainer: Kumar Gala <kumar.gala@freescale.com>
+ *
+ * Copyright 2004 Freescale Semiconductor Inc.
+ *
+ * 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.
+ *
+ */
+
+#ifndef __MACH_MPC85XX_ADS_H__
+#define __MACH_MPC85XX_ADS_H__
+
+#include <linux/config.h>
+#include <linux/init.h>
+#include <linux/seq_file.h>
+#include <asm/ppcboot.h>
+
+#define BOARD_CCSRBAR		((uint)0xe0000000)
+#define BCSR_ADDR		((uint)0xf8000000)
+#define BCSR_SIZE		((uint)(32 * 1024))
+
+extern int mpc85xx_ads_show_cpuinfo(struct seq_file *m);
+extern void mpc85xx_ads_init_IRQ(void) __init;
+extern void mpc85xx_ads_map_io(void) __init;
+
+/* PCI interrupt controller */
+#define PIRQA		MPC85xx_IRQ_EXT1
+#define PIRQB		MPC85xx_IRQ_EXT2
+#define PIRQC		MPC85xx_IRQ_EXT3
+#define PIRQD		MPC85xx_IRQ_EXT4
+
+#define MPC85XX_PCI1_LOWER_IO	0x00000000
+#define MPC85XX_PCI1_UPPER_IO	0x00ffffff
+
+#define MPC85XX_PCI1_LOWER_MEM	0x80000000
+#define MPC85XX_PCI1_UPPER_MEM	0x9fffffff
+
+#define MPC85XX_PCI1_IO_BASE	0xe2000000
+#define MPC85XX_PCI1_MEM_OFFSET	0x00000000
+
+#define MPC85XX_PCI1_IO_SIZE	0x01000000
+
+#endif				/* __MACH_MPC85XX_ADS_H__ */
--- diff/arch/ppc/platforms/sbc82xx.c	1970-01-01 01:00:00.000000000 +0100
+++ source/arch/ppc/platforms/sbc82xx.c	2004-06-11 19:21:59.000000000 +0100
@@ -0,0 +1,113 @@
+/*
+ * arch/ppc/platforms/sbc82xx.c
+ *
+ * SBC82XX platform support
+ *
+ * Author: Guy Streeter <streeter@redhat.com>
+ *
+ * Derived from: est8260_setup.c by Allen Curtis, ONZ
+ *
+ * Copyright 2004 Red Hat, Inc.
+ *
+ * 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.
+ */
+
+#include <linux/config.h>
+#include <linux/seq_file.h>
+#include <linux/stddef.h>
+
+#include <asm/mpc8260.h>
+#include <asm/machdep.h>
+#include <asm/io.h>
+#include <asm/todc.h>
+#include <asm/immap_8260.h>
+
+static void (*callback_setup_arch)(void);
+
+extern unsigned char __res[sizeof(bd_t)];
+
+extern void m8260_init(unsigned long r3, unsigned long r4,
+	unsigned long r5, unsigned long r6, unsigned long r7);
+
+extern void (*late_time_init)(void);
+
+static int
+sbc82xx_show_cpuinfo(struct seq_file *m)
+{
+	bd_t	*binfo = (bd_t *)__res;
+
+	seq_printf(m, "vendor\t\t: Wind River\n"
+		      "machine\t\t: SBC PowerQUICC II\n"
+		      "\n"
+		      "mem size\t\t: 0x%08lx\n"
+		      "console baud\t\t: %ld\n"
+		      "\n",
+		      binfo->bi_memsize,
+		      binfo->bi_baudrate);
+	return 0;
+}
+
+static void __init
+sbc82xx_setup_arch(void)
+{
+	printk("SBC PowerQUICC II Port\n");
+	callback_setup_arch();
+}
+
+TODC_ALLOC();
+
+/*
+ * Timer init happens before mem_init but after paging init, so we cannot
+ * directly use ioremap() at that time.
+ * late_time_init() is call after paging init.
+ */
+#ifdef CONFIG_GEN_RTC
+static void sbc82xx_time_init(void)
+{
+	volatile memctl8260_t *mc = &immr->im_memctl;
+	TODC_INIT(TODC_TYPE_MK48T59, 0, 0, SBC82xx_TODC_NVRAM_ADDR, 0);
+
+	/* Set up CS11 for RTC chip */
+	mc->memc_br11=0;
+	mc->memc_or11=0xffff0836;
+	mc->memc_br11=0x80000801;
+
+	todc_info->nvram_data =
+		(unsigned int)ioremap(todc_info->nvram_data, 0x2000);
+	BUG_ON(!todc_info->nvram_data);
+	ppc_md.get_rtc_time	= todc_get_rtc_time;
+	ppc_md.set_rtc_time	= todc_set_rtc_time;
+	ppc_md.nvram_read_val	= todc_direct_read_val;
+	ppc_md.nvram_write_val	= todc_direct_write_val;
+	todc_time_init();
+}
+#endif /* CONFIG_GEN_RTC */
+
+void __init
+platform_init(unsigned long r3, unsigned long r4, unsigned long r5,
+	      unsigned long r6, unsigned long r7)
+{
+	/* Generic 8260 platform initialization */
+	m8260_init(r3, r4, r5, r6, r7);
+
+	/* u-boot may be using one of the FCC Ethernet devices.
+	   Use the MAC address to the SCC. */
+	__res[offsetof(bd_t, bi_enetaddr[5])] &= ~3;
+
+	/* Anything special for this platform */
+	ppc_md.show_cpuinfo	= sbc82xx_show_cpuinfo;
+
+	callback_setup_arch	= ppc_md.setup_arch;
+	ppc_md.setup_arch	= sbc82xx_setup_arch;
+#ifdef CONFIG_GEN_RTC
+	ppc_md.time_init        = NULL;
+	ppc_md.get_rtc_time     = NULL;
+	ppc_md.set_rtc_time     = NULL;
+	ppc_md.nvram_read_val   = NULL;
+	ppc_md.nvram_write_val  = NULL;
+	late_time_init		= sbc82xx_time_init;
+#endif /* CONFIG_GEN_RTC */
+}
--- diff/arch/ppc/platforms/sbc82xx.h	1970-01-01 01:00:00.000000000 +0100
+++ source/arch/ppc/platforms/sbc82xx.h	2004-06-11 19:21:59.000000000 +0100
@@ -0,0 +1,24 @@
+/* Board information for the SBCPowerQUICCII, which should be generic for
+ * all 8260 boards.  The IMMR is now given to us so the hard define
+ * will soon be removed.  All of the clock values are computed from
+ * the configuration SCMR and the Power-On-Reset word.
+ */
+
+#ifndef __PPC_SBC82xx_H__
+#define __PPC_SBC82xx_H__
+
+#include <asm/ppcboot.h>
+
+#define IMAP_ADDR			0xf0000000
+#define CPM_MAP_ADDR			0xf0000000
+
+#define SBC82xx_TODC_NVRAM_ADDR		0x80000000
+
+#define SBC82xx_MACADDR_NVRAM_FCC1	0x220000c9	/* JP6B */
+#define SBC82xx_MACADDR_NVRAM_SCC1	0x220000cf	/* JP6A */
+#define SBC82xx_MACADDR_NVRAM_FCC2	0x220000d5	/* JP7A */
+#define SBC82xx_MACADDR_NVRAM_FCC3	0x220000db	/* JP7B */
+
+#define BOOTROM_RESTART_ADDR      ((uint)0x40000104)
+
+#endif /* __PPC_SBC82xx_H__ */
--- diff/arch/ppc/syslib/ppc85xx_common.c	1970-01-01 01:00:00.000000000 +0100
+++ source/arch/ppc/syslib/ppc85xx_common.c	2004-06-11 19:21:59.000000000 +0100
@@ -0,0 +1,46 @@
+/*
+ * arch/ppc/syslib/ppc85xx_common.c
+ *
+ * MPC85xx support routines
+ *
+ * Maintainer: Kumar Gala <kumar.gala@freescale.com>
+ *
+ * Copyright 2004 Freescale Semiconductor Inc.
+ *
+ * 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.
+ */
+
+#include <linux/config.h>
+#include <linux/types.h>
+#include <linux/module.h>
+#include <linux/init.h>
+
+#include <asm/mpc85xx.h>
+#include <asm/mmu.h>
+#include <asm/ocp.h>
+
+/* ************************************************************************ */
+/* Return the value of CCSRBAR for the current board */
+
+phys_addr_t
+get_ccsrbar(void)
+{
+        return BOARD_CCSRBAR;
+}
+
+/* ************************************************************************ */
+/* Update the 85xx OCP tables paddr field */
+void
+mpc85xx_update_paddr_ocp(struct ocp_device *dev, void *arg)
+{
+	phys_addr_t ccsrbar;
+	if (arg) {
+		ccsrbar = *(phys_addr_t *)arg;
+		dev->def->paddr += ccsrbar;
+	}
+}
+
+EXPORT_SYMBOL(get_ccsrbar);
--- diff/arch/ppc/syslib/ppc85xx_common.h	1970-01-01 01:00:00.000000000 +0100
+++ source/arch/ppc/syslib/ppc85xx_common.h	2004-06-11 19:21:59.000000000 +0100
@@ -0,0 +1,29 @@
+/*
+ * arch/ppc/syslib/ppc85xx_common.h
+ *
+ * MPC85xx support routines
+ *
+ * Maintainer: Kumar Gala <kumar.gala@freescale.com>
+ *
+ * Copyright 2004 Freescale Semiconductor Inc.
+ *
+ * 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.
+ */
+
+#ifndef __PPC_SYSLIB_PPC85XX_COMMON_H
+#define __PPC_SYSLIB_PPC85XX_COMMON_H
+
+#include <linux/config.h>
+#include <linux/init.h>
+#include <asm/ocp.h>
+
+/* Provide access to ccsrbar for any modules, etc */
+phys_addr_t get_ccsrbar(void);
+
+/* Update the 85xx OCP tables paddr field */
+void mpc85xx_update_paddr_ocp(struct ocp_device *dev, void *ccsrbar);
+
+#endif /* __PPC_SYSLIB_PPC85XX_COMMON_H */
--- diff/arch/ppc/syslib/ppc85xx_setup.c	1970-01-01 01:00:00.000000000 +0100
+++ source/arch/ppc/syslib/ppc85xx_setup.c	2004-06-11 19:21:59.000000000 +0100
@@ -0,0 +1,341 @@
+/*
+ * arch/ppc/syslib/ppc85xx_setup.c
+ *
+ * MPC85XX common board code
+ *
+ * Maintainer: Kumar Gala <kumar.gala@freescale.com>
+ *
+ * Copyright 2004 Freescale Semiconductor Inc.
+ *
+ * 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.
+ */
+
+#include <linux/config.h>
+#include <linux/types.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/pci.h>
+#include <linux/serial.h>
+#include <linux/tty.h>	/* for linux/serial_core.h */
+#include <linux/serial_core.h>
+
+#include <asm/prom.h>
+#include <asm/time.h>
+#include <asm/mpc85xx.h>
+#include <asm/immap_85xx.h>
+#include <asm/mmu.h>
+#include <asm/ocp.h>
+#include <asm/kgdb.h>
+
+/* Return the amount of memory */
+unsigned long __init
+mpc85xx_find_end_of_memory(void)
+{
+        bd_t *binfo;
+
+        binfo = (bd_t *) __res;
+
+        return binfo->bi_memsize;
+}
+
+/* The decrementer counts at the system (internal) clock freq divided by 8 */
+void __init
+mpc85xx_calibrate_decr(void)
+{
+        bd_t *binfo = (bd_t *) __res;
+        unsigned int freq, divisor;
+
+        /* get the core frequency */
+        freq = binfo->bi_busfreq;
+
+        /* The timebase is updated every 8 bus clocks, HID0[SEL_TBCLK] = 0 */
+        divisor = 8;
+        tb_ticks_per_jiffy = freq / divisor / HZ;
+        tb_to_us = mulhwu_scale_factor(freq / divisor, 1000000);
+
+	/* Set the time base to zero */
+	mtspr(SPRN_TBWL, 0);
+	mtspr(SPRN_TBWU, 0);
+
+	/* Clear any pending timer interrupts */
+	mtspr(SPRN_TSR, TSR_ENW | TSR_WIS | TSR_DIS | TSR_FIS);
+
+	/* Enable decrementer interrupt */
+	mtspr(SPRN_TCR, TCR_DIE);
+}
+
+#ifdef CONFIG_SERIAL_8250
+void __init
+mpc85xx_early_serial_map(void)
+{
+	struct uart_port serial_req;
+	bd_t *binfo = (bd_t *) __res;
+	phys_addr_t duart_paddr = binfo->bi_immr_base + MPC85xx_UART0_OFFSET;
+
+	/* Setup serial port access */
+	memset(&serial_req, 0, sizeof (serial_req));
+	serial_req.uartclk = binfo->bi_busfreq;
+	serial_req.line = 0;
+	serial_req.irq = MPC85xx_IRQ_DUART;
+	serial_req.flags = ASYNC_BOOT_AUTOCONF | ASYNC_SKIP_TEST;
+	serial_req.iotype = SERIAL_IO_MEM;
+	serial_req.membase = ioremap(duart_paddr, MPC85xx_UART0_SIZE);
+	serial_req.mapbase = duart_paddr;
+	serial_req.regshift = 0;
+
+#if defined(CONFIG_SERIAL_TEXT_DEBUG) || defined(CONFIG_KGDB)
+	gen550_init(0, &serial_req);
+#endif
+
+	if (early_serial_setup(&serial_req) != 0)
+		printk("Early serial init of port 0 failed\n");
+
+	/* Assume early_serial_setup() doesn't modify serial_req */
+	duart_paddr = binfo->bi_immr_base + MPC85xx_UART1_OFFSET;
+	serial_req.line = 1;
+	serial_req.mapbase = duart_paddr;
+	serial_req.membase = ioremap(duart_paddr, MPC85xx_UART1_SIZE);
+
+#if defined(CONFIG_SERIAL_TEXT_DEBUG) || defined(CONFIG_KGDB)
+	gen550_init(1, &serial_req);
+#endif
+
+	if (early_serial_setup(&serial_req) != 0)
+		printk("Early serial init of port 1 failed\n");
+}
+#endif
+
+void
+mpc85xx_restart(char *cmd)
+{
+	local_irq_disable();
+	abort();
+}
+
+void
+mpc85xx_power_off(void)
+{
+	local_irq_disable();
+	for(;;);
+}
+
+void
+mpc85xx_halt(void)
+{
+	local_irq_disable();
+	for(;;);
+}
+
+#ifdef CONFIG_PCI
+static void __init
+mpc85xx_setup_pci1(struct pci_controller *hose)
+{
+	volatile struct ccsr_pci *pci;
+	volatile struct ccsr_guts *guts;
+	unsigned short temps;
+	bd_t *binfo = (bd_t *) __res;
+
+	pci = ioremap(binfo->bi_immr_base + MPC85xx_PCI1_OFFSET,
+		    MPC85xx_PCI1_SIZE);
+
+	guts = ioremap(binfo->bi_immr_base + MPC85xx_GUTS_OFFSET,
+		    MPC85xx_GUTS_SIZE);
+
+	early_read_config_word(hose, 0, 0, PCI_COMMAND, &temps);
+	temps |= PCI_COMMAND_SERR | PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY;
+	early_write_config_word(hose, 0, 0, PCI_COMMAND, temps);
+
+#define PORDEVSR_PCI	(0x00800000)	/* PCI Mode */
+	if (guts->pordevsr & PORDEVSR_PCI) {
+ 		early_write_config_byte(hose, 0, 0, PCI_LATENCY_TIMER, 0x80);
+ 	} else {
+		/* PCI-X init */
+		temps = PCI_X_CMD_MAX_SPLIT | PCI_X_CMD_MAX_READ
+			| PCI_X_CMD_ERO | PCI_X_CMD_DPERR_E;
+		early_write_config_word(hose, 0, 0, PCIX_COMMAND, temps);
+	}
+
+	/* Disable all windows (except powar0 since its ignored) */
+	pci->powar1 = 0;
+	pci->powar2 = 0;
+	pci->powar3 = 0;
+	pci->powar4 = 0;
+	pci->piwar1 = 0;
+	pci->piwar2 = 0;
+	pci->piwar3 = 0;
+
+	/* Setup 512M Phys:PCI 1:1 outbound mem window @ 0x80000000 */
+	pci->potar1 = (MPC85XX_PCI1_LOWER_MEM >> 12) & 0x000fffff;
+	pci->potear1 = 0x00000000;
+	pci->powbar1 = (MPC85XX_PCI1_LOWER_MEM >> 12) & 0x000fffff;
+	pci->powar1 = 0x8004401c;	/* Enable, Mem R/W, 512M */
+
+	/* Setup 16M outboud IO windows @ 0xe2000000 */
+	pci->potar2 = 0x00000000;
+	pci->potear2 = 0x00000000;
+	pci->powbar2 = (MPC85XX_PCI1_IO_BASE >> 12) & 0x000fffff;
+	pci->powar2 = 0x80088017;	/* Enable, IO R/W, 16M */
+
+	/* Setup 2G inbound Memory Window @ 0 */
+	pci->pitar1 = 0x00000000;
+	pci->piwbar1 = 0x00000000;
+	pci->piwar1 = 0xa0f5501e;	/* Enable, Prefetch, Local
+					   Mem, Snoop R/W, 2G */
+}
+
+
+extern int mpc85xx_map_irq(struct pci_dev *dev, unsigned char idsel, unsigned char pin);
+extern int mpc85xx_exclude_device(u_char bus, u_char devfn);
+
+#if CONFIG_85xx_PCI2
+static void __init
+mpc85xx_setup_pci2(struct pci_controller *hose)
+{
+	volatile struct ccsr_pci *pci;
+	unsigned short temps;
+	bd_t *binfo = (bd_t *) __res;
+
+	pci = ioremap(binfo->bi_immr_base + MPC85xx_PCI2_OFFSET,
+		    MPC85xx_PCI2_SIZE);
+
+	early_read_config_word(hose, 0, 0, PCI_COMMAND, &temps);
+	temps |= PCI_COMMAND_SERR | PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY;
+	early_write_config_word(hose, 0, 0, PCI_COMMAND, temps);
+	early_write_config_byte(hose, 0, 0, PCI_LATENCY_TIMER, 0x80);
+
+	/* Disable all windows (except powar0 since its ignored) */
+	pci->powar1 = 0;
+	pci->powar2 = 0;
+	pci->powar3 = 0;
+	pci->powar4 = 0;
+	pci->piwar1 = 0;
+	pci->piwar2 = 0;
+	pci->piwar3 = 0;
+
+	/* Setup 512M Phys:PCI 1:1 outbound mem window @ 0xa0000000 */
+	pci->potar1 = (MPC85XX_PCI2_LOWER_MEM >> 12) & 0x000fffff;
+	pci->potear1 = 0x00000000;
+	pci->powbar1 = (MPC85XX_PCI2_LOWER_MEM >> 12) & 0x000fffff;
+	pci->powar1 = 0x8004401c;	/* Enable, Mem R/W, 512M */
+
+	/* Setup 16M outboud IO windows @ 0xe3000000 */
+	pci->potar2 = 0x00000000;
+	pci->potear2 = 0x00000000;
+	pci->powbar2 = (MPC85XX_PCI2_IO_BASE >> 12) & 0x000fffff;
+	pci->powar2 = 0x80088017;	/* Enable, IO R/W, 16M */
+
+	/* Setup 2G inbound Memory Window @ 0 */
+	pci->pitar1 = 0x00000000;
+	pci->piwbar1 = 0x00000000;
+	pci->piwar1 = 0xa0f5501e;	/* Enable, Prefetch, Local
+					   Mem, Snoop R/W, 2G */
+}
+#endif /* CONFIG_85xx_PCI2 */
+
+void __init
+mpc85xx_setup_hose(void)
+{
+	struct pci_controller *hose_a;
+#ifdef CONFIG_85xx_PCI2
+	struct pci_controller *hose_b;
+#endif
+	bd_t *binfo = (bd_t *) __res;
+
+	hose_a = pcibios_alloc_controller();
+
+	if (!hose_a)
+		return;
+
+	ppc_md.pci_swizzle = common_swizzle;
+	ppc_md.pci_map_irq = mpc85xx_map_irq;
+
+	hose_a->first_busno = 0;
+	hose_a->bus_offset = 0;
+	hose_a->last_busno = 0xff;
+
+	setup_indirect_pci(hose_a, binfo->bi_immr_base + PCI1_CFG_ADDR_OFFSET,
+			   binfo->bi_immr_base + PCI1_CFG_DATA_OFFSET);
+	hose_a->set_cfg_type = 1;
+
+	mpc85xx_setup_pci1(hose_a);
+
+	hose_a->pci_mem_offset = MPC85XX_PCI1_MEM_OFFSET;
+	hose_a->mem_space.start = MPC85XX_PCI1_LOWER_MEM;
+	hose_a->mem_space.end = MPC85XX_PCI1_UPPER_MEM;
+
+	hose_a->io_space.start = MPC85XX_PCI1_LOWER_IO;
+	hose_a->io_space.end = MPC85XX_PCI1_UPPER_IO;
+	hose_a->io_base_phys = MPC85XX_PCI1_IO_BASE;
+#if CONFIG_85xx_PCI2
+	isa_io_base =
+		(unsigned long) ioremap(MPC85XX_PCI1_IO_BASE,
+					MPC85XX_PCI1_IO_SIZE +
+					MPC85XX_PCI2_IO_SIZE);
+#else
+	isa_io_base =
+		(unsigned long) ioremap(MPC85XX_PCI1_IO_BASE,
+					MPC85XX_PCI1_IO_SIZE);
+#endif
+	hose_a->io_base_virt = (void *) isa_io_base;
+
+	/* setup resources */
+	pci_init_resource(&hose_a->mem_resources[0],
+			MPC85XX_PCI1_LOWER_MEM,
+			MPC85XX_PCI1_UPPER_MEM,
+			IORESOURCE_MEM, "PCI1 host bridge");
+
+	pci_init_resource(&hose_a->io_resource,
+			MPC85XX_PCI1_LOWER_IO,
+			MPC85XX_PCI1_UPPER_IO,
+			IORESOURCE_IO, "PCI1 host bridge");
+
+	ppc_md.pci_exclude_device = mpc85xx_exclude_device;
+
+	hose_a->last_busno = pciauto_bus_scan(hose_a, hose_a->first_busno);
+
+#if CONFIG_85xx_PCI2
+	hose_b = pcibios_alloc_controller();
+
+	if (!hose_b)
+		return;
+
+	hose_b->bus_offset = hose_a->last_busno + 1;
+	hose_b->first_busno = hose_a->last_busno + 1;
+	hose_b->last_busno = 0xff;
+
+	setup_indirect_pci(hose_b, binfo->bi_immr_base + PCI2_CFG_ADDR_OFFSET,
+			   binfo->bi_immr_base + PCI2_CFG_DATA_OFFSET);
+	hose_b->set_cfg_type = 1;
+
+	mpc85xx_setup_pci2(hose_b);
+
+	hose_b->pci_mem_offset = MPC85XX_PCI2_MEM_OFFSET;
+	hose_b->mem_space.start = MPC85XX_PCI2_LOWER_MEM;
+	hose_b->mem_space.end = MPC85XX_PCI2_UPPER_MEM;
+
+	hose_b->io_space.start = MPC85XX_PCI2_LOWER_IO;
+	hose_b->io_space.end = MPC85XX_PCI2_UPPER_IO;
+	hose_b->io_base_phys = MPC85XX_PCI2_IO_BASE;
+	hose_b->io_base_virt = (void *) isa_io_base + MPC85XX_PCI1_IO_SIZE;
+
+	/* setup resources */
+	pci_init_resource(&hose_b->mem_resources[0],
+			MPC85XX_PCI2_LOWER_MEM,
+			MPC85XX_PCI2_UPPER_MEM,
+			IORESOURCE_MEM, "PCI2 host bridge");
+
+	pci_init_resource(&hose_b->io_resource,
+			MPC85XX_PCI2_LOWER_IO,
+			MPC85XX_PCI2_UPPER_IO,
+			IORESOURCE_IO, "PCI2 host bridge");
+
+	hose_b->last_busno = pciauto_bus_scan(hose_b, hose_b->first_busno);
+#endif
+	return;
+}
+#endif /* CONFIG_PCI */
+
+
--- diff/arch/ppc/syslib/ppc85xx_setup.h	1970-01-01 01:00:00.000000000 +0100
+++ source/arch/ppc/syslib/ppc85xx_setup.h	2004-06-11 19:21:59.000000000 +0100
@@ -0,0 +1,67 @@
+/*
+ * arch/ppc/syslib/ppc85xx_setup.h
+ *
+ * MPC85XX common board definitions
+ *
+ * Maintainer: Kumar Gala <kumar.gala@freescale.com>
+ *
+ * Copyright 2004 Freescale Semiconductor Inc.
+ *
+ * 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.
+ *
+ */
+
+#ifndef __PPC_SYSLIB_PPC85XX_SETUP_H
+#define __PPC_SYSLIB_PPC85XX_SETUP_H
+
+#include <linux/config.h>
+#include <linux/serial.h>
+#include <linux/init.h>
+#include <asm/ppcboot.h>
+
+extern unsigned long mpc85xx_find_end_of_memory(void) __init;
+extern void mpc85xx_calibrate_decr(void) __init;
+extern void mpc85xx_early_serial_map(void) __init;
+extern void mpc85xx_restart(char *cmd);
+extern void mpc85xx_power_off(void);
+extern void mpc85xx_halt(void);
+extern void mpc85xx_setup_hose(void) __init;
+
+/* PCI config */
+#define PCI1_CFG_ADDR_OFFSET	(0x8000)
+#define PCI1_CFG_DATA_OFFSET	(0x8004)
+
+#define PCI2_CFG_ADDR_OFFSET	(0x9000)
+#define PCI2_CFG_DATA_OFFSET	(0x9004)
+
+/* Additional register for PCI-X configuration */
+#define PCIX_NEXT_CAP	0x60
+#define PCIX_CAP_ID	0x61
+#define PCIX_COMMAND	0x62
+#define PCIX_STATUS	0x64
+
+/* Serial Config */
+#define MPC85XX_0_SERIAL                (CCSRBAR + 0x4500)
+#define MPC85XX_1_SERIAL                (CCSRBAR + 0x4600)
+
+#ifdef CONFIG_SERIAL_MANY_PORTS
+#define RS_TABLE_SIZE  64
+#else
+#define RS_TABLE_SIZE  2
+#endif
+
+#define BASE_BAUD 0
+
+#define STD_UART_OP(num)					\
+	{ 0, BASE_BAUD, num, MPC85xx_IRQ_DUART,			\
+		(ASYNC_BOOT_AUTOCONF | ASYNC_SKIP_TEST),	\
+		iomem_base: (u8 *)MPC85XX_##num##_SERIAL,	\
+		io_type: SERIAL_IO_MEM},
+
+/* Offset of CPM register space */
+#define CPM_MAP_ADDR	(CCSRBAR + MPC85xx_CPM_OFFSET)
+
+#endif /* __PPC_SYSLIB_PPC85XX_SETUP_H */
--- diff/arch/x86_64/Kconfig.kgdb	1970-01-01 01:00:00.000000000 +0100
+++ source/arch/x86_64/Kconfig.kgdb	2004-06-11 19:22:00.000000000 +0100
@@ -0,0 +1,176 @@
+config KGDB
+	bool "Include kgdb kernel debugger"
+	depends on DEBUG_KERNEL
+	select DEBUG_INFO
+	help
+	  If you say Y here, the system will be compiled with the debug
+	  option (-g) and a debugging stub will be included in the
+	  kernel.  This stub communicates with gdb on another (host)
+	  computer via a serial port.  The host computer should have
+	  access to the kernel binary file (vmlinux) and a serial port
+	  that is connected to the target machine.  Gdb can be made to
+	  configure the serial port or you can use stty and setserial to
+	  do this. See the 'target' command in gdb. This option also
+	  configures in the ability to request a breakpoint early in the
+	  boot process.  To request the breakpoint just include 'kgdb'
+	  as a boot option when booting the target machine.  The system
+	  will then break as soon as it looks at the boot options.  This
+	  option also installs a breakpoint in panic and sends any
+	  kernel faults to the debugger. For more information see the
+	  Documentation/i386/kgdb.txt file.
+
+choice
+	depends on KGDB
+    	prompt "Debug serial port BAUD"
+	default KGDB_115200BAUD
+	help
+	  Gdb and the kernel stub need to agree on the baud rate to be
+	  used.  Some systems (x86 family at this writing) allow this to
+	  be configured.
+
+config KGDB_9600BAUD
+	bool "9600"
+
+config KGDB_19200BAUD
+	bool "19200"
+
+config KGDB_38400BAUD
+	bool "38400"
+
+config KGDB_57600BAUD
+	bool "57600"
+
+config KGDB_115200BAUD
+	bool "115200"
+endchoice
+
+config KGDB_PORT
+	hex "hex I/O port address of the debug serial port"
+	depends on KGDB
+	default  3f8
+	help
+	  Some systems (x86 family at this writing) allow the port
+	  address to be configured.  The number entered is assumed to be
+	  hex, don't put 0x in front of it.  The standard address are:
+	  COM1 3f8 , irq 4 and COM2 2f8 irq 3.  Setserial /dev/ttySx
+	  will tell you what you have.  It is good to test the serial
+	  connection with a live system before trying to debug.
+
+config KGDB_IRQ
+	int "IRQ of the debug serial port"
+	depends on KGDB
+	default 4
+	help
+	  This is the irq for the debug port.  If everything is working
+	  correctly and the kernel has interrupts on a control C to the
+	  port should cause a break into the kernel debug stub.
+
+config DEBUG_INFO
+	bool
+	depends on KGDB
+	default y
+
+config KGDB_MORE
+	bool "Add any additional compile options"
+	depends on KGDB
+	default n
+	help
+	  Saying yes here turns on the ability to enter additional
+	  compile options.
+
+
+config KGDB_OPTIONS
+	depends on KGDB_MORE
+	string "Additional compile arguments"
+	default "-O1"
+	help
+	  This option allows you enter additional compile options for
+	  the whole kernel compile.  Each platform will have a default
+	  that seems right for it.  For example on PPC "-ggdb -O1", and
+	  for i386 "-O1".  Note that by configuring KGDB "-g" is already
+	  turned on.  In addition, on i386 platforms
+	  "-fomit-frame-pointer" is deleted from the standard compile
+	  options.
+
+config NO_KGDB_CPUS
+	int "Number of CPUs"
+	depends on KGDB && SMP
+	default NR_CPUS
+	help
+
+	  This option sets the number of cpus for kgdb ONLY.  It is used
+	  to prune some internal structures so they look "nice" when
+	  displayed with gdb.  This is to overcome possibly larger
+	  numbers that may have been entered above.  Enter the real
+	  number to get nice clean kgdb_info displays.
+
+config KGDB_TS
+	bool "Enable kgdb time stamp macros?"
+	depends on KGDB
+	default n
+	help
+	  Kgdb event macros allow you to instrument your code with calls
+	  to the kgdb event recording function.  The event log may be
+	  examined with gdb at a break point.  Turning on this
+	  capability also allows you to choose how many events to
+	  keep. Kgdb always keeps the lastest events.
+
+choice
+	depends on KGDB_TS
+	prompt "Max number of time stamps to save?"
+	default KGDB_TS_128
+
+config KGDB_TS_64
+	bool "64"
+
+config KGDB_TS_128
+	bool "128"
+
+config KGDB_TS_256
+	bool "256"
+
+config KGDB_TS_512
+	bool "512"
+
+config KGDB_TS_1024
+	bool "1024"
+
+endchoice
+
+config STACK_OVERFLOW_TEST
+	bool "Turn on kernel stack overflow testing?"
+	depends on KGDB
+	default n
+	help
+	  This option enables code in the front line interrupt handlers
+	  to check for kernel stack overflow on interrupts and system
+	  calls.  This is part of the kgdb code on x86 systems.
+
+config KGDB_CONSOLE
+	bool "Enable serial console thru kgdb port"
+	depends on KGDB
+	default n
+	help
+	  This option enables the command line "console=kgdb" option.
+	  When the system is booted with this option in the command line
+	  all kernel printk output is sent to gdb (as well as to other
+	  consoles).  For this to work gdb must be connected.  For this
+	  reason, this command line option will generate a breakpoint if
+	  gdb has not yet connected.  After the gdb continue command is
+	  given all pent up console output will be printed by gdb on the
+	  host machine.  Neither this option, nor KGDB require the
+	  serial driver to be configured.
+
+config KGDB_SYSRQ
+	bool "Turn on SysRq 'G' command to do a break?"
+	depends on KGDB
+	default y
+	help
+	  This option includes an option in the SysRq code that allows
+	  you to enter SysRq G which generates a breakpoint to the KGDB
+	  stub.  This will work if the keyboard is alive and can
+	  interrupt the system.  Because of constraints on when the
+	  serial port interrupt can be enabled, this code may allow you
+	  to interrupt the system before the serial port control C is
+	  available.  Just say yes here.
+
--- diff/arch/x86_64/kernel/kgdb_stub.c	1970-01-01 01:00:00.000000000 +0100
+++ source/arch/x86_64/kernel/kgdb_stub.c	2004-06-11 19:22:00.000000000 +0100
@@ -0,0 +1,2591 @@
+/*
+ *
+ * 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, 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.
+ *
+ */
+
+/*
+ * Copyright (c) 2000 VERITAS Software Corporation.
+ *
+ */
+/****************************************************************************
+ *  Header: remcom.c,v 1.34 91/03/09 12:29:49 glenne Exp $
+ *
+ *  Module name: remcom.c $
+ *  Revision: 1.34 $
+ *  Date: 91/03/09 12:29:49 $
+ *  Contributor:     Lake Stevens Instrument Division$
+ *
+ *  Description:     low level support for gdb debugger. $
+ *
+ *  Considerations:  only works on target hardware $
+ *
+ *  Written by:	     Glenn Engel $
+ *  Updated by:	     David Grothe <dave@gcom.com>
+ *  Updated by:	     Robert Walsh <rjwalsh@durables.org>
+ *  Updated by:	     wangdi <wangdi@clusterfs.com>
+ *  ModuleState:     Experimental $
+ *
+ *  NOTES:	     See Below $
+ *
+ *  Modified for 386 by Jim Kingdon, Cygnus Support.
+ *  Compatibility with 2.1.xx kernel by David Grothe <dave@gcom.com>
+ *
+ *  Changes to allow auto initilization.  All that is needed is that it
+ *  be linked with the kernel and a break point (int 3) be executed.
+ *  The header file <asm/kgdb.h> defines BREAKPOINT to allow one to do
+ *  this. It should also be possible, once the interrupt system is up, to
+ *  call putDebugChar("+").  Once this is done, the remote debugger should
+ *  get our attention by sending a ^C in a packet. George Anzinger
+ *  <george@mvista.com>
+ *  Integrated into 2.2.5 kernel by Tigran Aivazian <tigran@sco.com>
+ *  Added thread support, support for multiple processors,
+ *	support for ia-32(x86) hardware debugging.
+ *	Amit S. Kale ( akale@veritas.com )
+ *
+ *  Modified to support debugging over ethernet by Robert Walsh
+ *  <rjwalsh@durables.org> and wangdi <wangdi@clusterfs.com>, based on
+ *  code by San Mehat.
+ *
+ *  X86_64 changes from Andi Kleen's patch merged by Jim Houston
+ * 	(jim.houston@ccur.com).  If it works thank Andi if its broken
+ * 	blame me.
+ *
+ *  To enable debugger support, two things need to happen.  One, a
+ *  call to set_debug_traps() is necessary in order to allow any breakpoints
+ *  or error conditions to be properly intercepted and reported to gdb.
+ *  Two, a breakpoint needs to be generated to begin communication.  This
+ *  is most easily accomplished by a call to breakpoint().  Breakpoint()
+ *  simulates a breakpoint by executing an int 3.
+ *
+ *************
+ *
+ *    The following gdb commands are supported:
+ *
+ * command	    function				   Return value
+ *
+ *    g		    return the value of the CPU registers  hex data or ENN
+ *    G		    set the value of the CPU registers	   OK or ENN
+ *
+ *    mAA..AA,LLLL  Read LLLL bytes at address AA..AA	   hex data or ENN
+ *    MAA..AA,LLLL: Write LLLL bytes at address AA.AA	   OK or ENN
+ *
+ *    c		    Resume at current address		   SNN	 ( signal NN)
+ *    cAA..AA	    Continue at address AA..AA		   SNN
+ *
+ *    s		    Step one instruction		   SNN
+ *    sAA..AA	    Step one instruction from AA..AA	   SNN
+ *
+ *    k		    kill
+ *
+ *    ?		    What was the last sigval ?		   SNN	 (signal NN)
+ *
+ * All commands and responses are sent with a packet which includes a
+ * checksum.  A packet consists of
+ *
+ * $<packet info>#<checksum>.
+ *
+ * where
+ * <packet info> :: <characters representing the command or response>
+ * <checksum>	 :: < two hex digits computed as modulo 256 sum of <packetinfo>>
+ *
+ * When a packet is received, it is first acknowledged with either '+' or '-'.
+ * '+' indicates a successful transfer.	 '-' indicates a failed transfer.
+ *
+ * Example:
+ *
+ * Host:		  Reply:
+ * $m0,10#2a		   +$00010203040506070809101112131415#42
+ *
+ ****************************************************************************/
+#define KGDB_VERSION "<20030915.1651.33>"
+#include <linux/config.h>
+#include <linux/types.h>
+#include <asm/string.h>		/* for strcpy */
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <asm/system.h>
+#include <asm/ptrace.h>		/* for linux pt_regs struct */
+#include <asm/kgdb_local.h>
+#include <linux/list.h>
+#include <asm/atomic.h>
+#include <asm/processor.h>
+#include <linux/irq.h>
+#include <asm/desc.h>
+#include <linux/inet.h>
+#include <linux/netpoll.h>
+#include <linux/cpumask.h>
+#include <linux/bitops.h>
+#include <linux/notifier.h>
+#include <asm/kdebug.h>
+#include <asm/uaccess.h>
+#include <linux/ptrace.h>
+
+#define Dearly_printk(x...)
+int kgdb_enabled = 0;
+
+/************************************************************************
+ *
+ * external low-level support routines
+ */
+typedef void (*Function) (void);	/* pointer to a function */
+
+/* Thread reference */
+typedef unsigned char threadref[8];
+
+extern int tty_putDebugChar(int);     /* write a single character      */
+extern int tty_getDebugChar(void);    /* read and return a single char */
+extern void tty_flushDebugChar(void); /* flush pending characters      */
+extern int eth_putDebugChar(int);     /* write a single character      */
+extern int eth_getDebugChar(void);    /* read and return a single char */
+extern void eth_flushDebugChar(void); /* flush pending characters      */
+
+/************************************************************************/
+/* BUFMAX defines the maximum number of characters in inbound/outbound buffers*/
+/* at least NUMREGBYTES*2 are needed for register packets */
+/* Longer buffer is needed to list all threads */
+#define BUFMAX 400
+
+char *kgdb_version = KGDB_VERSION;
+
+/*  debug >  0 prints ill-formed commands in valid packets & checksum errors */
+int debug_regs = 0;		/* set to non-zero to print registers */
+
+/* filled in by an external module */
+char *gdb_module_offsets;
+
+static const char hexchars[] = "0123456789abcdef";
+
+/* Number of bytes of registers.  */
+#define NUMREGBYTES (NUMREGS * sizeof(unsigned long))
+/*
+ * Note that this register image is in a different order than
+ * the register image that Linux produces at interrupt time.
+ *
+ * Linux's register image is defined by struct pt_regs in ptrace.h.
+ * Just why GDB uses a different order is a historical mystery.
+ *
+ * Could add XMM and segment registers here.
+ */
+enum regnames {_RAX,
+	       _RBX,
+	       _RCX,
+	       _RDX,
+	       _RSI,
+	       _RDI,
+	       _RBP,
+	       _RSP,
+	       _R8,
+	       _R9,
+	       _R10,
+	       _R11,
+	       _R12,
+	       _R13,
+	       _R14,
+	       _R15,
+	       _PC,
+	       _PS,
+	       NUMREGS };
+
+
+/***************************  ASSEMBLY CODE MACROS *************************/
+/*
+ * Put the error code here just in case the user cares.
+ * Likewise, the vector number here (since GDB only gets the signal
+ * number through the usual means, and that's not very specific).
+ * The called_from is the return address so he can tell how we entered kgdb.
+ * This will allow him to seperate out the various possible entries.
+ */
+#define REMOTE_DEBUG 0		/* set != to turn on printing (also available in info) */
+
+#define PID_MAX PID_MAX_DEFAULT
+
+#ifdef CONFIG_SMP
+void smp_send_nmi_allbutself(void);
+#define IF_SMP(x) x
+#undef MAX_NO_CPUS
+#ifndef CONFIG_NO_KGDB_CPUS
+#define CONFIG_NO_KGDB_CPUS 2
+#endif
+#if CONFIG_NO_KGDB_CPUS > NR_CPUS
+#define MAX_NO_CPUS NR_CPUS
+#else
+#define MAX_NO_CPUS CONFIG_NO_KGDB_CPUS
+#endif
+#define hold_init hold_on_sstep: 1,
+#define MAX_CPU_MASK (unsigned long)((1LL << MAX_NO_CPUS) - 1LL)
+#define NUM_CPUS num_online_cpus()
+#else
+#define IF_SMP(x)
+#define hold_init
+#undef MAX_NO_CPUS
+#define MAX_NO_CPUS 1
+#define NUM_CPUS 1
+#endif
+#define NOCPU (struct task_struct *)0xbad1fbad
+/* *INDENT-OFF*	 */
+struct kgdb_info {
+	int used_malloc;
+	void *called_from;
+	long long entry_tsc;
+	int errcode;
+	int vector;
+	int print_debug_info;
+#ifdef CONFIG_SMP
+	int hold_on_sstep;
+	struct {
+		volatile struct task_struct *task;
+		int pid;
+		int hold;
+		struct pt_regs *regs;
+	} cpus_waiting[MAX_NO_CPUS];
+#endif
+} kgdb_info = {hold_init print_debug_info:REMOTE_DEBUG, vector:-1};
+
+/* *INDENT-ON*	*/
+
+#define used_m kgdb_info.used_malloc
+/*
+ * This is little area we set aside to contain the stack we
+ * need to build to allow gdb to call functions.  We use one
+ * per cpu to avoid locking issues.  We will do all this work
+ * with interrupts off so that should take care of the protection
+ * issues.
+ */
+#define LOOKASIDE_SIZE 200	/* should be more than enough */
+#define MALLOC_MAX   200	/* Max malloc size */
+struct {
+	unsigned long rsp;
+	unsigned long array[LOOKASIDE_SIZE];
+} fn_call_lookaside[MAX_NO_CPUS];
+
+static int trap_cpu;
+static unsigned long OLD_esp;
+
+#define END_OF_LOOKASIDE  &fn_call_lookaside[trap_cpu].array[LOOKASIDE_SIZE]
+#define IF_BIT 0x200
+#define TF_BIT 0x100
+
+#define MALLOC_ROUND 8-1
+
+static char malloc_array[MALLOC_MAX];
+IF_SMP(static void to_gdb(const char *mess));
+void *
+malloc(int size)
+{
+
+	if (size <= (MALLOC_MAX - used_m)) {
+		int old_used = used_m;
+		used_m += ((size + MALLOC_ROUND) & (~MALLOC_ROUND));
+		return &malloc_array[old_used];
+	} else {
+		return NULL;
+	}
+}
+
+/*
+ * I/O dispatch functions...
+ * Based upon kgdboe, either call the ethernet
+ * handler or the serial one..
+ */
+void
+putDebugChar(int c)
+{
+	if (!kgdboe) {
+		tty_putDebugChar(c);
+	} else {
+		eth_putDebugChar(c);
+	}
+}
+
+int
+getDebugChar(void)
+{
+	if (!kgdboe) {
+		return tty_getDebugChar();
+	} else {
+		return eth_getDebugChar();
+	}
+}
+
+void
+flushDebugChar(void)
+{
+	if (!kgdboe) {
+		tty_flushDebugChar();
+	} else {
+		eth_flushDebugChar();
+	}
+}
+
+/*
+ * Gdb calls functions by pushing agruments, including a return address
+ * on the stack and the adjusting EIP to point to the function.	 The
+ * whole assumption in GDB is that we are on a different stack than the
+ * one the "user" i.e. code that hit the break point, is on.  This, of
+ * course is not true in the kernel.  Thus various dodges are needed to
+ * do the call without directly messing with EIP (which we can not change
+ * as it is just a location and not a register.	 To adjust it would then
+ * require that we move every thing below EIP up or down as needed.  This
+ * will not work as we may well have stack relative pointer on the stack
+ * (such as the pointer to regs, for example).
+
+ * So here is what we do:
+ * We detect gdb attempting to store into the stack area and instead, store
+ * into the fn_call_lookaside.array at the same relative location as if it
+ * were the area ESP pointed at.  We also trap ESP modifications
+ * and uses these to adjust fn_call_lookaside.esp.  On entry
+ * fn_call_lookaside.esp will be set to point at the last entry in
+ * fn_call_lookaside.array.  This allows us to check if it has changed, and
+ * if so, on exit, we add the registers we will use to do the move and a
+ * trap/ interrupt return exit sequence.  We then adjust the eflags in the
+ * regs array (remember we now have a copy in the fn_call_lookaside.array) to
+ * kill the interrupt bit, AND we change EIP to point at our set up stub.
+ * As part of the register set up we preset the registers to point at the
+ * begining and end of the fn_call_lookaside.array, so all the stub needs to
+ * do is move words from the array to the stack until ESP= the desired value
+ * then do the rti.  This will then transfer to the desired function with
+ * all the correct registers.  Nifty huh?
+ */
+extern asmlinkage void fn_call_stub(void);
+extern asmlinkage void fn_rtn_stub(void);
+/*					   *INDENT-OFF*	 */
+__asm__("fn_rtn_stub:\n\t"
+	"movq %rax,%rsp\n\t"
+	"fn_call_stub:\n\t"
+	"1:\n\t"
+	"addq $-8,%rbx\n\t"
+	"movq (%rbx), %rax\n\t"
+	"pushq %rax\n\t"
+	"cmpq %rsp,%rcx\n\t"
+	"jne  1b\n\t"
+	"popq %rax\n\t"
+	"popq %rbx\n\t"
+	"popq %rcx\n\t"
+	"iret \n\t");
+/*					     *INDENT-ON*  */
+#define gdb_i386vector	kgdb_info.vector
+#define gdb_i386errcode kgdb_info.errcode
+#define waiting_cpus	kgdb_info.cpus_waiting
+#define remote_debug	kgdb_info.print_debug_info
+#define hold_cpu(cpu)	kgdb_info.cpus_waiting[cpu].hold
+/* gdb locks */
+
+#ifdef CONFIG_SMP
+static int in_kgdb_called;
+static spinlock_t waitlocks[MAX_NO_CPUS] =
+    {[0 ... MAX_NO_CPUS - 1] = SPIN_LOCK_UNLOCKED };
+/*
+ * The following array has the thread pointer of each of the "other"
+ * cpus.  We make it global so it can be seen by gdb.
+ */
+volatile int in_kgdb_entry_log[MAX_NO_CPUS];
+volatile struct pt_regs *in_kgdb_here_log[MAX_NO_CPUS];
+/*
+static spinlock_t continuelocks[MAX_NO_CPUS];
+*/
+spinlock_t kgdb_spinlock = SPIN_LOCK_UNLOCKED;
+/* waiters on our spinlock plus us */
+static atomic_t spinlock_waiters = ATOMIC_INIT(1);
+static int spinlock_count = 0;
+static int spinlock_cpu = 0;
+/*
+ * Note we use nested spin locks to account for the case where a break
+ * point is encountered when calling a function by user direction from
+ * kgdb. Also there is the memory exception recursion to account for.
+ * Well, yes, but this lets other cpus thru too.  Lets add a
+ * cpu id to the lock.
+ */
+#define KGDB_SPIN_LOCK(x) if( spinlock_count == 0 || \
+			      spinlock_cpu != smp_processor_id()){\
+				      atomic_inc(&spinlock_waiters); \
+				      while (! spin_trylock(x)) {\
+					    in_kgdb(&regs);\
+				      }\
+				      atomic_dec(&spinlock_waiters); \
+				      spinlock_count = 1; \
+				      spinlock_cpu = smp_processor_id(); \
+			  }else{  \
+				      spinlock_count++; \
+			  }
+#define KGDB_SPIN_UNLOCK(x) if( --spinlock_count == 0) spin_unlock(x)
+#else
+unsigned kgdb_spinlock = 0;
+#define KGDB_SPIN_LOCK(x) --*x
+#define KGDB_SPIN_UNLOCK(x) ++*x
+#endif
+
+int
+hex(char ch)
+{
+	if ((ch >= 'a') && (ch <= 'f'))
+		return (ch - 'a' + 10);
+	if ((ch >= '0') && (ch <= '9'))
+		return (ch - '0');
+	if ((ch >= 'A') && (ch <= 'F'))
+		return (ch - 'A' + 10);
+	return (-1);
+}
+
+/* scan for the sequence $<data>#<checksum>	*/
+void
+getpacket(char *buffer)
+{
+	unsigned char checksum;
+	unsigned char xmitcsum;
+	int i;
+	int count;
+	char ch;
+
+	do {
+		/* wait around for the start character, ignore all other characters */
+		while ((ch = (getDebugChar() & 0x7f)) != '$') ;
+		checksum = 0;
+		xmitcsum = -1;
+
+		count = 0;
+
+		/* now, read until a # or end of buffer is found */
+		while (count < BUFMAX) {
+			ch = getDebugChar() & 0x7f;
+			if (ch == '#')
+				break;
+			checksum = checksum + ch;
+			buffer[count] = ch;
+			count = count + 1;
+		}
+		buffer[count] = 0;
+
+		if (ch == '#') {
+			xmitcsum = hex(getDebugChar() & 0x7f) << 4;
+			xmitcsum += hex(getDebugChar() & 0x7f);
+			if ((remote_debug) && (checksum != xmitcsum)) {
+				printk
+				    ("bad checksum.	My count = 0x%x, sent=0x%x. buf=%s\n",
+				     checksum, xmitcsum, buffer);
+			}
+
+			if (checksum != xmitcsum)
+				putDebugChar('-');	/* failed checksum */
+			else {
+				putDebugChar('+');	/* successful transfer */
+				/* if a sequence char is present, reply the sequence ID */
+				if (buffer[2] == ':') {
+					putDebugChar(buffer[0]);
+					putDebugChar(buffer[1]);
+					/* remove sequence chars from buffer */
+					count = strlen(buffer);
+					for (i = 3; i <= count; i++)
+						buffer[i - 3] = buffer[i];
+				}
+			}
+		}
+	} while (checksum != xmitcsum);
+
+	if (remote_debug)
+		printk("R:%s\n", buffer);
+	flushDebugChar();
+}
+
+/* send the packet in buffer.  */
+
+void
+putpacket(char *buffer)
+{
+	unsigned char checksum;
+	int count;
+	char ch;
+
+	/*  $<packet info>#<checksum>. */
+
+	if (!kgdboe) {
+		do {
+			if (remote_debug)
+				printk("T:%s\n", buffer);
+			putDebugChar('$');
+			checksum = 0;
+			count = 0;
+
+			while ((ch = buffer[count])) {
+				putDebugChar(ch);
+				checksum += ch;
+				count += 1;
+			}
+
+			putDebugChar('#');
+			putDebugChar(hexchars[checksum >> 4]);
+			putDebugChar(hexchars[checksum % 16]);
+			flushDebugChar();
+
+		} while ((getDebugChar() & 0x7f) != '+');
+	} else {
+		/*
+		 * For udp, we can not transfer too much bytes once.
+		 * We only transfer MAX_SEND_COUNT size bytes each time
+		 */
+
+#define MAX_SEND_COUNT 30
+
+		int send_count = 0, i = 0;
+		char send_buf[MAX_SEND_COUNT];
+
+		do {
+			if (remote_debug)
+				printk("T:%s\n", buffer);
+			putDebugChar('$');
+			checksum = 0;
+			count = 0;
+			send_count = 0;
+			while ((ch = buffer[count])) {
+				if (send_count >= MAX_SEND_COUNT) {
+					for(i = 0; i < MAX_SEND_COUNT; i++) {
+						putDebugChar(send_buf[i]);
+					}
+					flushDebugChar();
+					send_count = 0;
+				} else {
+					send_buf[send_count] = ch;
+					checksum += ch;
+					count ++;
+					send_count++;
+				}
+			}
+			for(i = 0; i < send_count; i++)
+				putDebugChar(send_buf[i]);
+			putDebugChar('#');
+			putDebugChar(hexchars[checksum >> 4]);
+			putDebugChar(hexchars[checksum % 16]);
+			flushDebugChar();
+		} while ((getDebugChar() & 0x7f) != '+');
+	}
+}
+
+static char remcomInBuffer[BUFMAX];
+static char remcomOutBuffer[BUFMAX];
+static char lbuf[BUFMAX];
+static short error;
+
+void
+debug_error(char *format, char *parm)
+{
+	if (remote_debug)
+		printk(format, parm);
+}
+
+static void
+print_regs(struct pt_regs *regs)
+{
+	printk("RAX=%016lx RBX=%016lx RCX=%016lx\n",
+		regs->rax, regs->rbx, regs->rcx);
+	printk("RDX=%016lx RSI=%016lx RDI=%016lx\n",
+		regs->rdx, regs->rsi, regs->rdi);
+	printk("RBP=%016lx PS=%016lx PC=%016lx\n",
+		regs->rbp, regs->eflags, regs->rip);
+ 	printk("R8=%016lx R9=%016lx R10=%016lx\n",
+		regs->r8, regs->r9, regs->r10);
+	printk("R11=%016lx R12=%016lx R13=%016lx\n",
+		regs->r11, regs->r12, regs->r13);
+	printk("R14=%016lx R15=%016lx RSP=%016lx\n",
+		regs->r14, regs->r15, regs->rsp);
+}
+
+#define NEW_esp fn_call_lookaside[trap_cpu].rsp
+
+static void
+regs_to_gdb_regs(unsigned long *gdb_regs, struct pt_regs *regs)
+{
+	gdb_regs[_RAX] =  regs->rax;
+	gdb_regs[_RBX] =  regs->rbx;
+	gdb_regs[_RCX] =  regs->rcx;
+	gdb_regs[_RDX] =  regs->rdx;
+	gdb_regs[_RSI] =  regs->rsi;
+	gdb_regs[_RDI] =  regs->rdi;
+	gdb_regs[_RBP] =  regs->rbp;
+	gdb_regs[ _PS] =  regs->eflags;
+	gdb_regs[ _PC] =  regs->rip;
+	gdb_regs[ _R8] =  regs->r8;
+	gdb_regs[ _R9] =  regs->r9;
+	gdb_regs[_R10] = regs->r10;
+	gdb_regs[_R11] = regs->r11;
+	gdb_regs[_R12] = regs->r12;
+	gdb_regs[_R13] = regs->r13;
+	gdb_regs[_R14] = regs->r14;
+	gdb_regs[_R15] = regs->r15;
+	gdb_regs[_RSP] =  regs->rsp;
+
+	/* Note, as we are a debugging the kernel, we will always
+	 * trap in kernel code, this means no priviledge change,
+	 * and so the pt_regs structure is not completely valid.  In a non
+	 * privilege change trap, only EFLAGS, CS and EIP are put on the stack,
+	 * SS and ESP are not stacked, this means that the last 2 elements of
+	 * pt_regs is not valid (they would normally refer to the user stack)
+	 * also, using regs+1 is no good because you end up will a value that is
+	 * 2 longs (8) too high.  This used to cause stepping over functions
+	 * to fail, so my fix is to use the address of regs->esp, which
+	 * should point at the end of the stack frame.	Note I have ignored
+	 * completely exceptions that cause an error code to be stacked, such
+	 * as double fault.  Stuart Hughes, Zentropix.
+	 * original code: gdb_regs[_ESP] =  (int) (regs + 1) ;
+
+	 * this is now done on entry and moved to OLD_esp (as well as NEW_esp).
+	 */
+}
+
+static void
+gdb_regs_to_regs(unsigned long *gdb_regs, struct pt_regs *regs)
+{
+	regs->rax	=     gdb_regs[_RAX] ;
+	regs->rbx	=     gdb_regs[_RBX] ;
+	regs->rcx	=     gdb_regs[_RCX] ;
+	regs->rdx	=     gdb_regs[_RDX] ;
+	regs->rsi	=     gdb_regs[_RSI] ;
+	regs->rdi	=     gdb_regs[_RDI] ;
+	regs->rbp	=     gdb_regs[_RBP] ;
+	regs->eflags	=     gdb_regs[ _PS] ;
+	regs->rip	=     gdb_regs[ _PC] ;
+	regs->r8	=     gdb_regs[ _R8] ;
+	regs->r9	=     gdb_regs[ _R9] ;
+	regs->r10	=     gdb_regs[ _R10] ;
+	regs->r11	=     gdb_regs[ _R11] ;
+	regs->r12	=     gdb_regs[ _R12] ;
+	regs->r13	=     gdb_regs[ _R13] ;
+	regs->r14	=     gdb_regs[ _R14] ;
+	regs->r15	=     gdb_regs[ _R15] ;
+ #if 0					/* can't change these */
+	regs->rsp	=     gdb_regs[_RSP] ;
+	regs->ss	=     gdb_regs[ _SS] ;
+	regs->fs = gdb_regs[_FS];
+	regs->gs = gdb_regs[_GS];
+#endif
+}				/* gdb_regs_to_regs */
+
+int thread_list = 0;
+extern void thread_return(void);
+
+void
+get_gdb_regs(struct task_struct *p, struct pt_regs *regs, unsigned long *gdb_regs)
+{
+	unsigned long **rbp, *rsp, *rsp0, pc;
+	int count = 0;
+	IF_SMP(int i);
+	if (!p || p == current) {
+		regs_to_gdb_regs(gdb_regs, regs);
+		return;
+	}
+#ifdef CONFIG_SMP
+	for (i = 0; i < MAX_NO_CPUS; i++) {
+		if (p == kgdb_info.cpus_waiting[i].task) {
+			regs_to_gdb_regs(gdb_regs,
+					 kgdb_info.cpus_waiting[i].regs);
+			gdb_regs[_RSP] =
+			    (unsigned long)&kgdb_info.cpus_waiting[i].regs->rsp;
+
+			return;
+		}
+	}
+#endif
+	memset(gdb_regs, 0, NUMREGBYTES);
+	rsp = (unsigned long *)p->thread.rsp;
+	rbp = (unsigned long **)rsp[0];
+	rsp += 2;
+	gdb_regs[_PC] =  (unsigned long)thread_return;
+	gdb_regs[_RBP] = (unsigned long)rbp;
+	gdb_regs[_RSP] = (unsigned long)rsp;
+
+/*
+ * This code is to give a more informative notion of where a process
+ * is waiting.	It is used only when the user asks for a thread info
+ * list.  If he then switches to the thread, s/he will find the task
+ * is in schedule, but a back trace should show the same info we come
+ * up with.  This code was shamelessly purloined from process.c.  It was
+ * then enhanced to provide more registers than simply the program
+ * counter.
+ */
+
+	if (!thread_list) {
+		return;
+	}
+
+	if (p->state == TASK_RUNNING)
+		return;
+	rsp0 = (unsigned long *)p->thread.rsp0;
+	if (rsp < (unsigned long *) p->thread_info || rsp > rsp0)
+		return;
+	/* include/asm-i386/system.h:switch_to() pushes ebp last. */
+	do {
+		if (*rbp < rsp || *rbp > rsp0)
+			break;
+		rbp = (unsigned long **)*rbp;
+		rsp = (unsigned long *)rbp;
+		pc = rsp[1];
+
+		if (!in_sched_functions(pc))
+			break;
+		gdb_regs[_PC] = (unsigned long)pc;
+		gdb_regs[_RSP] = (unsigned long)rsp;
+		gdb_regs[_RBP] = (unsigned long)rbp;
+	} while (count++ < 16);
+	return;
+}
+
+/* convert the memory pointed to by mem into hex, placing result in buf */
+/* returns nonzero if any memory access fails. */
+int mem2hex( char* mem, char* buf, int   count)
+{
+	int i;
+	unsigned char ch;
+	int ret = 0;
+
+	for (i=0;i<count;i++) {
+		ch = 0;
+		ret |= __get_user(ch, mem);
+		mem++;
+		*buf++ = hexchars[ch >> 4];
+		*buf++ = hexchars[ch % 16];
+	}
+	*buf = 0;
+	if (ret) {
+		Dearly_printk("mem2hex: fault at accessing %p\n", mem);
+	}
+	return(ret);
+}
+
+/* convert the hex array pointed to by buf into binary to be placed in mem */
+/* return nonzero if any memory access fails. */
+int hex2mem( char* buf, char* mem, int count)
+{
+	int i;
+	unsigned char ch;
+	int ret = 0;
+
+	for (i=0;i<count;i++) {
+		ch = hex(*buf++) << 4;
+		ch = ch + hex(*buf++);
+		ret |= __put_user(ch, mem);
+		mem++;
+	}
+	if (ret) {
+		Dearly_printk("hex2mem: fault at %p\n", mem);
+	}
+	return(ret);
+}
+
+#if 0
+/* Indicate to caller of mem2hex or hex2mem that there has been an
+   error.  */
+static volatile int mem_err = 0;
+static volatile int mem_err_expected = 0;
+static volatile int mem_err_cnt = 0;
+static int garbage_loc = -1;
+
+int
+get_char(char *addr)
+{
+	return *addr;
+}
+
+void
+set_char(char *addr, int val, int may_fault)
+{
+	/*
+	 * This code traps references to the area mapped to the kernel
+	 * stack as given by the regs and, instead, stores to the
+	 * fn_call_lookaside[cpu].array
+	 */
+	if (may_fault &&
+	    (unsigned int) addr < OLD_esp &&
+	    ((unsigned int) addr > (OLD_esp - (unsigned int) LOOKASIDE_SIZE))) {
+		addr = (char *) END_OF_LOOKASIDE - ((char *) OLD_esp - addr);
+	}
+	*addr = val;
+}
+
+/* convert the memory pointed to by mem into hex, placing result in buf */
+/* return a pointer to the last char put in buf (null) */
+/* If MAY_FAULT is non-zero, then we should set mem_err in response to
+   a fault; if zero treat a fault like any other fault in the stub.  */
+char *
+mem2hex(char *mem, char *buf, int count, int may_fault)
+{
+	int i;
+	unsigned char ch;
+
+	if (may_fault) {
+		mem_err_expected = 1;
+		mem_err = 0;
+	}
+	for (i = 0; i < count; i++) {
+		/* printk("%lx = ", mem) ; */
+
+		ch = get_char(mem++);
+
+		/* printk("%02x\n", ch & 0xFF) ; */
+		if (may_fault && mem_err) {
+			if (remote_debug)
+				printk("Mem fault fetching from addr %lx\n",
+				       (long) (mem - 1));
+			*buf = 0;	/* truncate buffer */
+			return (buf);
+		}
+		*buf++ = hexchars[ch >> 4];
+		*buf++ = hexchars[ch % 16];
+	}
+	*buf = 0;
+	if (may_fault)
+		mem_err_expected = 0;
+	return (buf);
+}
+
+/* convert the hex array pointed to by buf into binary to be placed in mem */
+/* return a pointer to the character AFTER the last byte written */
+/* NOTE: We use the may fault flag to also indicate if the write is to
+ * the registers (0) or "other" memory (!=0)
+ */
+char *
+hex2mem(char *buf, char *mem, int count, int may_fault)
+{
+	int i;
+	unsigned char ch;
+
+	if (may_fault) {
+		mem_err_expected = 1;
+		mem_err = 0;
+	}
+	for (i = 0; i < count; i++) {
+		ch = hex(*buf++) << 4;
+		ch = ch + hex(*buf++);
+		set_char(mem++, ch, may_fault);
+
+		if (may_fault && mem_err) {
+			if (remote_debug)
+				printk("Mem fault storing to addr %lx\n",
+				       (long) (mem - 1));
+			return (mem);
+		}
+	}
+	if (may_fault)
+		mem_err_expected = 0;
+	return (mem);
+}
+#endif
+
+/**********************************************/
+/* WHILE WE FIND NICE HEX CHARS, BUILD AN INT */
+/* RETURN NUMBER OF CHARS PROCESSED	      */
+/**********************************************/
+int
+hexToLong(char **ptr, unsigned long *value)
+{
+	int numChars = 0;
+	int hexValue;
+
+	*value = 0;
+
+	while (**ptr) {
+		hexValue = hex(**ptr);
+		if (hexValue >= 0) {
+			*value = (*value << 4) | hexValue;
+			numChars++;
+		} else
+			break;
+
+		(*ptr)++;
+	}
+
+	return (numChars);
+}
+
+#define stubhex(h) hex(h)
+#ifdef old_thread_list
+
+static int
+stub_unpack_int(char *buff, int fieldlength)
+{
+	int nibble;
+	int retval = 0;
+
+	while (fieldlength) {
+		nibble = stubhex(*buff++);
+		retval |= nibble;
+		fieldlength--;
+		if (fieldlength)
+			retval = retval << 4;
+	}
+	return retval;
+}
+#endif
+static char *
+pack_hex_byte(char *pkt, int byte)
+{
+	*pkt++ = hexchars[(byte >> 4) & 0xf];
+	*pkt++ = hexchars[(byte & 0xf)];
+	return pkt;
+}
+
+#define BUF_THREAD_ID_SIZE 16
+
+static char *
+pack_threadid(char *pkt, threadref * id)
+{
+	char *limit;
+	unsigned char *altid;
+
+	altid = (unsigned char *) id;
+	limit = pkt + BUF_THREAD_ID_SIZE;
+	while (pkt < limit)
+		pkt = pack_hex_byte(pkt, *altid++);
+	return pkt;
+}
+
+#ifdef old_thread_list
+static char *
+unpack_byte(char *buf, int *value)
+{
+	*value = stub_unpack_int(buf, 2);
+	return buf + 2;
+}
+
+static char *
+unpack_threadid(char *inbuf, threadref * id)
+{
+	char *altref;
+	char *limit = inbuf + BUF_THREAD_ID_SIZE;
+	int x, y;
+
+	altref = (char *) id;
+
+	while (inbuf < limit) {
+		x = stubhex(*inbuf++);
+		y = stubhex(*inbuf++);
+		*altref++ = (x << 4) | y;
+	}
+	return inbuf;
+}
+#endif
+void
+int_to_threadref(threadref * id, int value)
+{
+	unsigned char *scan;
+
+	scan = (unsigned char *) id;
+	{
+		int i = 4;
+		while (i--)
+			*scan++ = 0;
+	}
+	*scan++ = (value >> 24) & 0xff;
+	*scan++ = (value >> 16) & 0xff;
+	*scan++ = (value >> 8) & 0xff;
+	*scan++ = (value & 0xff);
+}
+int
+int_to_hex_v(unsigned char * id, int value)
+{
+	unsigned char *start = id;
+	int shift;
+	int ch;
+
+	for (shift = 28; shift >= 0; shift -= 4) {
+		if ((ch = (value >> shift) & 0xf) || (id != start)) {
+			*id = hexchars[ch];
+			id++;
+		}
+	}
+	if (id == start)
+		*id++ = '0';
+	return id - start;
+}
+#ifdef old_thread_list
+
+static int
+threadref_to_int(threadref * ref)
+{
+	int i, value = 0;
+	unsigned char *scan;
+
+	scan = (char *) ref;
+	scan += 4;
+	i = 4;
+	while (i-- > 0)
+		value = (value << 8) | ((*scan++) & 0xff);
+	return value;
+}
+#endif
+static int
+cmp_str(char *s1, char *s2, int count)
+{
+	while (count--) {
+		if (*s1++ != *s2++)
+			return 0;
+	}
+	return 1;
+}
+
+#if 1				/* this is a hold over from 2.4 where O(1) was "sometimes" */
+extern struct task_struct *kgdb_get_idle(int cpu);
+#define idle_task(cpu) kgdb_get_idle(cpu)
+#else
+#define idle_task(cpu) init_tasks[cpu]
+#endif
+
+extern int kgdb_pid_init_done;
+
+struct task_struct *
+getthread(int pid)
+{
+	struct task_struct *thread;
+	if (pid >= PID_MAX && pid <= (PID_MAX + MAX_NO_CPUS)) {
+		if (!cpu_online(pid - PID_MAX))
+			return NULL;
+
+		return idle_task(pid - PID_MAX);
+	} else {
+		/*
+		 * find_task_by_pid is relatively safe all the time
+		 * Other pid functions require lock downs which imply
+		 * that we may be interrupting them (as we get here
+		 * in the middle of most any lock down).
+		 * Still we don't want to call until the table exists!
+		 */
+		if (kgdb_pid_init_done){
+			thread = find_task_by_pid(pid);
+			if (thread) {
+				return thread;
+			}
+		}
+	}
+	return NULL;
+}
+/* *INDENT-OFF*	 */
+struct hw_breakpoint {
+	unsigned enabled;
+	unsigned type;
+	unsigned len;
+	unsigned long addr;
+} breakinfo[4] = { {enabled:0},
+		   {enabled:0},
+		   {enabled:0},
+		   {enabled:0}};
+/* *INDENT-ON*	*/
+unsigned long hw_breakpoint_status;
+void
+correct_hw_break(void)
+{
+	int breakno;
+	int correctit;
+	int breakbit;
+	unsigned long dr7;
+
+	asm volatile ("movq %%db7, %0\n":"=r" (dr7)
+		      :);
+	/* *INDENT-OFF*	 */
+	do {
+		unsigned long addr0, addr1, addr2, addr3;
+		asm volatile ("movq %%db0, %0\n"
+			      "movq %%db1, %1\n"
+			      "movq %%db2, %2\n"
+			      "movq %%db3, %3\n"
+			      :"=r" (addr0), "=r"(addr1),
+			      "=r"(addr2), "=r"(addr3)
+			      :);
+	} while (0);
+	/* *INDENT-ON*	*/
+	correctit = 0;
+	for (breakno = 0; breakno < 3; breakno++) {
+		breakbit = 2 << (breakno << 1);
+		if (!(dr7 & breakbit) && breakinfo[breakno].enabled) {
+			correctit = 1;
+			dr7 |= breakbit;
+			dr7 &= ~(0xf0000 << (breakno << 2));
+			dr7 |= (((breakinfo[breakno].len << 2) |
+				 breakinfo[breakno].type) << 16) <<
+			    (breakno << 2);
+			switch (breakno) {
+			case 0:
+				asm volatile ("movq %0, %%dr0\n"::"r"
+					      (breakinfo[breakno].addr));
+				break;
+
+			case 1:
+				asm volatile ("movq %0, %%dr1\n"::"r"
+					      (breakinfo[breakno].addr));
+				break;
+
+			case 2:
+				asm volatile ("movq %0, %%dr2\n"::"r"
+					      (breakinfo[breakno].addr));
+				break;
+
+			case 3:
+				asm volatile ("movq %0, %%dr3\n"::"r"
+					      (breakinfo[breakno].addr));
+				break;
+			}
+		} else if ((dr7 & breakbit) && !breakinfo[breakno].enabled) {
+			correctit = 1;
+			dr7 &= ~breakbit;
+			dr7 &= ~(0xf0000 << (breakno << 2));
+		}
+	}
+	if (correctit) {
+		asm volatile ("movq %0, %%db7\n"::"r" (dr7));
+	}
+}
+
+int
+remove_hw_break(unsigned breakno)
+{
+	if (!breakinfo[breakno].enabled) {
+		return -1;
+	}
+	breakinfo[breakno].enabled = 0;
+	return 0;
+}
+
+int
+set_hw_break(unsigned breakno, unsigned type, unsigned len, unsigned addr)
+{
+	if (breakinfo[breakno].enabled) {
+		return -1;
+	}
+	breakinfo[breakno].enabled = 1;
+	breakinfo[breakno].type = type;
+	breakinfo[breakno].len = len;
+	breakinfo[breakno].addr = addr;
+	return 0;
+}
+
+#ifdef CONFIG_SMP
+static int in_kgdb_console = 0;
+
+int
+in_kgdb(struct pt_regs *regs)
+{
+	unsigned long flags;
+	int cpu;
+	if (!kgdb_enabled)
+		return 0;
+	cpu = smp_processor_id();
+	in_kgdb_called = 1;
+	if (!spin_is_locked(&kgdb_spinlock)) {
+		if (in_kgdb_here_log[cpu] ||	/* we are holding this cpu */
+		    in_kgdb_console) {	/* or we are doing slow i/o */
+			return 1;
+		}
+		return 0;
+	}
+
+	/* As I see it the only reason not to let all cpus spin on
+	 * the same spin_lock is to allow selected ones to proceed.
+	 * This would be a good thing, so we leave it this way.
+	 * Maybe someday....  Done !
+
+	 * in_kgdb() is called from an NMI so we don't pretend
+	 * to have any resources, like printk() for example.
+	 */
+
+	local_irq_save(flags);	/* only local here, to avoid hanging */
+	/*
+	 * log arival of this cpu
+	 * The NMI keeps on ticking.  Protect against recurring more
+	 * than once, and ignor the cpu that has the kgdb lock
+	 */
+	in_kgdb_entry_log[cpu]++;
+	in_kgdb_here_log[cpu] = regs;
+	if (cpu == spinlock_cpu || waiting_cpus[cpu].task)
+		goto exit_in_kgdb;
+
+	/*
+	 * For protection of the initilization of the spin locks by kgdb
+	 * it locks the kgdb spinlock before it gets the wait locks set
+	 * up.	We wait here for the wait lock to be taken.  If the
+	 * kgdb lock goes away first??	Well, it could be a slow exit
+	 * sequence where the wait lock is removed prior to the kgdb lock
+	 * so if kgdb gets unlocked, we just exit.
+	 */
+
+	while (spin_is_locked(&kgdb_spinlock) &&
+	       !spin_is_locked(waitlocks + cpu)) ;
+	if (!spin_is_locked(&kgdb_spinlock))
+		goto exit_in_kgdb;
+
+	waiting_cpus[cpu].task = current;
+	waiting_cpus[cpu].pid = (current->pid) ? : (PID_MAX + cpu);
+	waiting_cpus[cpu].regs = regs;
+
+	spin_unlock_wait(waitlocks + cpu);
+
+	/*
+	 * log departure of this cpu
+	 */
+	waiting_cpus[cpu].task = 0;
+	waiting_cpus[cpu].pid = 0;
+	waiting_cpus[cpu].regs = 0;
+	correct_hw_break();
+      exit_in_kgdb:
+	in_kgdb_here_log[cpu] = 0;
+	local_irq_restore(flags);
+	return 1;
+	/*
+	   spin_unlock(continuelocks + smp_processor_id());
+	 */
+}
+
+void
+smp__in_kgdb(struct pt_regs regs)
+{
+	ack_APIC_irq();
+	in_kgdb(&regs);
+}
+#else
+int
+in_kgdb(struct pt_regs *regs)
+{
+	return (kgdb_spinlock);
+}
+#endif
+
+void
+printexceptioninfo(int exceptionNo, int errorcode, char *buffer)
+{
+	unsigned long dr6;
+	int i;
+	switch (exceptionNo) {
+	case 1:		/* debug exception */
+		break;
+	case 3:		/* breakpoint */
+		sprintf(buffer, "Software breakpoint");
+		return;
+	default:
+		sprintf(buffer, "Details not available");
+		return;
+	}
+	asm volatile ("movq %%db6, %0\n":"=r" (dr6)
+		      :);
+	if (dr6 & 0x4000) {
+		sprintf(buffer, "Single step");
+		return;
+	}
+	for (i = 0; i < 4; ++i) {
+		if (dr6 & (1 << i)) {
+			sprintf(buffer, "Hardware breakpoint %d", i);
+			return;
+		}
+	}
+	sprintf(buffer, "Unknown trap");
+	return;
+}
+
+/*
+ * The ThreadExtraInfo query allows us to pass an arbitrary string
+ * for display with the "info threads" command.
+ */
+
+void
+print_extra_info(task_t *p, char *buf)
+{
+	if (!p) {
+		sprintf(buf, "Invalid thread");
+		return;
+	}
+	sprintf(buf, "0x%p %8d %4d  %c  %s",
+		   (void *)p,  p->parent->pid,
+		   task_cpu(p),
+		   (p->state == 0) ? (task_curr(p)?'R':'r') :
+		     (p->state < 0) ? 'U' :
+		     (p->state & TASK_UNINTERRUPTIBLE) ? 'D' :
+		     (p->state & TASK_STOPPED || p->ptrace & PT_PTRACED) ? 'T' :
+		     (p->state & (TASK_ZOMBIE | TASK_DEAD)) ? 'Z' :
+		     (p->state & TASK_INTERRUPTIBLE) ? 'S' : '?',
+		   p->comm);
+}
+
+/*
+ * This function does all command procesing for interfacing to gdb.
+ *
+ * NOTE:  The INT nn instruction leaves the state of the interrupt
+ *	  enable flag UNCHANGED.  That means that when this routine
+ *	  is entered via a breakpoint (INT 3) instruction from code
+ *	  that has interrupts enabled, then interrupts will STILL BE
+ *	  enabled when this routine is entered.	 The first thing that
+ *	  we do here is disable interrupts so as to prevent recursive
+ *	  entries and bothersome serial interrupts while we are
+ *	  trying to run the serial port in polled mode.
+ *
+ * For kernel version 2.1.xx the kgdb_cli() actually gets a spin lock so
+ * it is always necessary to do a restore_flags before returning
+ * so as to let go of that lock.
+ */
+int
+kgdb_handle_exception(int exceptionVector,
+		      int signo, int err_code, struct pt_regs *linux_regs)
+{
+	struct task_struct *usethread = NULL;
+	struct task_struct *thread_list_start = 0, *thread = NULL;
+	struct task_struct *p;
+	unsigned long addr, length;
+	unsigned long breakno, breaktype;
+	char *ptr;
+	unsigned long newPC;
+	threadref thref;
+	unsigned long threadid, tmpid;
+	int thread_min = PID_MAX + MAX_NO_CPUS;
+#ifdef old_thread_list
+	int maxthreads;
+#endif
+	int nothreads;
+	unsigned long flags;
+	unsigned long gdb_regs[NUMREGS];
+	unsigned long dr6;
+	IF_SMP(int entry_state = 0);	/* 0, ok, 1, no nmi, 2 sync failed */
+#define NO_NMI 1
+#define NO_SYNC 2
+#define	regs	(*linux_regs)
+	/*
+	 * If the entry is not from the kernel then return to the Linux
+	 * trap handler and let it process the interrupt normally.
+	 */
+	if ((linux_regs->eflags & VM_MASK) || (3 & linux_regs->cs)) {
+		printk("ignoring non-kernel exception\n");
+		print_regs(&regs);
+		return (0);
+	}
+	/*
+	 * If we're using eth mode, set the 'mode' in the netdevice.
+	 */
+
+	if (kgdboe)
+		netpoll_set_trap(1);
+
+	local_irq_save(flags);
+
+	/* Get kgdb spinlock */
+
+	KGDB_SPIN_LOCK(&kgdb_spinlock);
+	rdtscll(kgdb_info.entry_tsc);
+	/*
+	 * We depend on this spinlock and the NMI watch dog to control the
+	 * other cpus.	They will arrive at "in_kgdb()" as a result of the
+	 * NMI and will wait there for the following spin locks to be
+	 * released.
+	 */
+#ifdef CONFIG_SMP
+
+#if 0
+	if (cpu_callout_map & ~MAX_CPU_MASK) {
+		printk("kgdb : too many cpus, possibly not mapped"
+		       " in contiguous space, change MAX_NO_CPUS"
+		       " in kgdb_stub and make new kernel.\n"
+		       " cpu_callout_map is %lx\n", cpu_callout_map);
+		goto exit_just_unlock;
+	}
+#endif
+	if (spinlock_count == 1) {
+		int time, end_time, dum;
+		int i;
+		int cpu_logged_in[MAX_NO_CPUS] = {[0 ... MAX_NO_CPUS - 1] = (0)
+		};
+		if (remote_debug) {
+			printk("kgdb : cpu %d entry, syncing others\n",
+			       smp_processor_id());
+		}
+		for (i = 0; i < MAX_NO_CPUS; i++) {
+			/*
+			 * Use trylock as we may already hold the lock if
+			 * we are holding the cpu.  Net result is all
+			 * locked.
+			 */
+			spin_trylock(&waitlocks[i]);
+		}
+		for (i = 0; i < MAX_NO_CPUS; i++)
+			cpu_logged_in[i] = 0;
+		/*
+		 * Wait for their arrival.  We know the watch dog is active if
+		 * in_kgdb() has ever been called, as it is always called on a
+		 * watchdog tick.
+		 */
+		rdtsc(dum, time);
+		end_time = time + 2;	/* Note: we use the High order bits! */
+		i = 1;
+		if (num_online_cpus() > 1) {
+			int me_in_kgdb = in_kgdb_entry_log[smp_processor_id()];
+			smp_send_nmi_allbutself();
+
+			while (i < num_online_cpus() && time != end_time) {
+				int j;
+				for (j = 0; j < MAX_NO_CPUS; j++) {
+					if (waiting_cpus[j].task &&
+					    waiting_cpus[j].task != NOCPU &&
+					    !cpu_logged_in[j]) {
+						i++;
+						cpu_logged_in[j] = 1;
+						if (remote_debug) {
+							printk
+							    ("kgdb : cpu %d arrived at kgdb\n",
+							     j);
+						}
+						break;
+					} else if (!waiting_cpus[j].task &&
+						   !cpu_online(j)) {
+						waiting_cpus[j].task = NOCPU;
+						cpu_logged_in[j] = 1;
+						waiting_cpus[j].hold = 1;
+						break;
+					}
+					if (!waiting_cpus[j].task &&
+					    in_kgdb_here_log[j]) {
+
+						int wait = 100000;
+						while (wait--) ;
+						if (!waiting_cpus[j].task &&
+						    in_kgdb_here_log[j]) {
+							printk
+							    ("kgdb : cpu %d stall"
+							     " in in_kgdb\n",
+							     j);
+							i++;
+							cpu_logged_in[j] = 1;
+							waiting_cpus[j].task =
+							    (struct task_struct
+							     *) 1;
+						}
+					}
+				}
+
+				if (in_kgdb_entry_log[smp_processor_id()] >
+				    (me_in_kgdb + 10)) {
+					break;
+				}
+
+				rdtsc(dum, time);
+			}
+			if (i < num_online_cpus()) {
+				printk
+				    ("kgdb : time out, proceeding without sync\n");
+#if 0
+				printk("kgdb : Waiting_cpus: 0 = %d, 1 = %d\n",
+				       waiting_cpus[0].task != 0,
+				       waiting_cpus[1].task != 0);
+				printk("kgdb : Cpu_logged in: 0 = %d, 1 = %d\n",
+				       cpu_logged_in[0], cpu_logged_in[1]);
+				printk
+				    ("kgdb : in_kgdb_here_log in: 0 = %d, 1 = %d\n",
+				     in_kgdb_here_log[0] != 0,
+				     in_kgdb_here_log[1] != 0);
+#endif
+				entry_state = NO_SYNC;
+			} else {
+#if 0
+				int ent =
+				    in_kgdb_entry_log[smp_processor_id()] -
+				    me_in_kgdb;
+				printk("kgdb : sync after %d entries\n", ent);
+#endif
+			}
+		} else {
+			if (remote_debug) {
+				printk
+				    ("kgdb : %d cpus, but watchdog not active\n"
+				     "proceeding without locking down other cpus\n",
+				     (int)num_online_cpus());
+				entry_state = NO_NMI;
+			}
+		}
+	}
+#endif
+
+	if (remote_debug) {
+		unsigned long *lp = (unsigned long *) &linux_regs;
+
+		printk("handle_exception(exceptionVector=%d, "
+		       "signo=%d, err_code=%d, linux_regs=%p)\n",
+		       exceptionVector, signo, err_code, linux_regs);
+		if (debug_regs) {
+			print_regs(&regs);
+			printk("Stk: %8lx %8lx %8lx %8lx"
+			       "  %8lx %8lx %8lx %8lx\n",
+			       lp[0], lp[1], lp[2], lp[3],
+			       lp[4], lp[5], lp[6], lp[7]);
+			printk("     %8lx %8lx %8lx %8lx"
+			       "  %8lx %8lx %8lx %8lx\n",
+			       lp[8], lp[9], lp[10], lp[11],
+			       lp[12], lp[13], lp[14], lp[15]);
+			printk("     %8lx %8lx %8lx %8lx  "
+			       "%8lx %8lx %8lx %8lx\n",
+			       lp[16], lp[17], lp[18], lp[19],
+			       lp[20], lp[21], lp[22], lp[23]);
+			printk("     %8lx %8lx %8lx %8lx  "
+			       "%8lx %8lx %8lx %8lx\n",
+			       lp[24], lp[25], lp[26], lp[27],
+			       lp[28], lp[29], lp[30], lp[31]);
+		}
+	}
+
+	/* Disable hardware debugging while we are in kgdb */
+	/* Get the debug register status register */
+/*				       *INDENT-OFF*  */
+      __asm__("movq %0,%%db7"
+	      :	/* no output */
+	      :"r"(0UL));
+
+	asm volatile ("movq %%db6, %0\n"
+		      :"=r" (hw_breakpoint_status)
+		      :);
+
+#if 0
+/*				       *INDENT-ON*  */
+	switch (exceptionVector) {
+	case 0:		/* divide error */
+	case 1:		/* debug exception */
+	case 2:		/* NMI */
+	case 3:		/* breakpoint */
+	case 4:		/* overflow */
+	case 5:		/* bounds check */
+	case 6:		/* invalid opcode */
+	case 7:		/* device not available */
+	case 8:		/* double fault (errcode) */
+	case 10:		/* invalid TSS (errcode) */
+	case 12:		/* stack fault (errcode) */
+	case 16:		/* floating point error */
+	case 17:		/* alignment check (errcode) */
+	default:		/* any undocumented */
+		break;
+	case 11:		/* segment not present (errcode) */
+	case 13:		/* general protection (errcode) */
+	case 14:		/* page fault (special errcode) */
+	case 19:		/* cache flush denied */
+		if (mem_err_expected) {
+			/*
+			 * This fault occured because of the
+			 * get_char or set_char routines.  These
+			 * two routines use either eax of edx to
+			 * indirectly reference the location in
+			 * memory that they are working with.
+			 * For a page fault, when we return the
+			 * instruction will be retried, so we
+			 * have to make sure that these
+			 * registers point to valid memory.
+			 */
+			mem_err = 1;	/* set mem error flag */
+			mem_err_expected = 0;
+			mem_err_cnt++;	/* helps in debugging */
+			/* make valid address */
+			regs.eax = (long) &garbage_loc;
+			/* make valid address */
+			regs.edx = (long) &garbage_loc;
+			if (remote_debug)
+				printk("Return after memory error: "
+				       "mem_err_cnt=%d\n", mem_err_cnt);
+			if (debug_regs)
+				print_regs(&regs);
+			goto exit_kgdb;
+		}
+		break;
+	}
+#endif
+	if (remote_debug)
+		printk("kgdb : entered kgdb on cpu %d\n", smp_processor_id());
+
+	gdb_i386vector = exceptionVector;
+	gdb_i386errcode = err_code;
+	kgdb_info.called_from = __builtin_return_address(0);
+#ifdef CONFIG_SMP
+	/*
+	 * OK, we can now communicate, lets tell gdb about the sync.
+	 * but only if we had a problem.
+	 */
+	switch (entry_state) {
+	case NO_NMI:
+		to_gdb("NMI not active, other cpus not stopped\n");
+		break;
+	case NO_SYNC:
+		to_gdb("Some cpus not stopped, see 'kgdb_info' for details\n");
+	default:;
+	}
+
+#endif
+/*
+ * Set up the gdb function call area.
+ */
+	trap_cpu = smp_processor_id();
+	OLD_esp = NEW_esp = (unsigned long) (&linux_regs->rsp);
+
+      IF_SMP(once_again:)
+	    /* reply to host that an exception has occurred */
+	    remcomOutBuffer[0] = 'S';
+	remcomOutBuffer[1] = hexchars[signo >> 4];
+	remcomOutBuffer[2] = hexchars[signo % 16];
+	remcomOutBuffer[3] = 0;
+
+	putpacket(remcomOutBuffer);
+
+	while (1 == 1) {
+		error = 0;
+		remcomOutBuffer[0] = 0;
+		getpacket(remcomInBuffer);
+		switch (remcomInBuffer[0]) {
+		case '?':
+			remcomOutBuffer[0] = 'S';
+			remcomOutBuffer[1] = hexchars[signo >> 4];
+			remcomOutBuffer[2] = hexchars[signo % 16];
+			remcomOutBuffer[3] = 0;
+			break;
+		case 'd':
+			remote_debug = !(remote_debug);	/* toggle debug flag */
+			printk("Remote debug %s\n",
+			       remote_debug ? "on" : "off");
+			break;
+		case 'g':	/* return the value of the CPU registers */
+			get_gdb_regs(usethread, &regs, gdb_regs);
+			mem2hex((char *) gdb_regs,
+				remcomOutBuffer, NUMREGBYTES);
+			break;
+		case 'G':	/* set the value of the CPU registers - return OK */
+			hex2mem(&remcomInBuffer[1],
+				(char *) gdb_regs, NUMREGBYTES);
+			if (!usethread || usethread == current) {
+				gdb_regs_to_regs(gdb_regs, &regs);
+				strcpy(remcomOutBuffer, "OK");
+			} else {
+				strcpy(remcomOutBuffer, "E00");
+			}
+			break;
+
+		case 'P':{	/* set the value of a single CPU register -
+				   return OK */
+				/*
+				 * For some reason, gdb wants to talk about psudo
+				 * registers (greater than 15).
+				 */
+				unsigned long regno;
+
+				ptr = &remcomInBuffer[1];
+				regs_to_gdb_regs(gdb_regs, &regs);
+				if ((!usethread || usethread == current) &&
+				    hexToLong(&ptr, &regno) &&
+				    *ptr++ == '=' && (regno >= 0)) {
+					if (regno >= NUMREGS)
+						break;
+					hex2mem(ptr, (char *) &gdb_regs[regno],
+						8);
+					gdb_regs_to_regs(gdb_regs, &regs);
+					strcpy(remcomOutBuffer, "OK");
+					break;
+				}
+				strcpy(remcomOutBuffer, "E01");
+				break;
+			}
+
+			/* mAA..AA,LLLL	 Read LLLL bytes at address AA..AA */
+		case 'm':
+			/* TRY TO READ %x,%x.  IF SUCCEED, SET PTR = 0 */
+			ptr = &remcomInBuffer[1];
+			if (hexToLong(&ptr, &addr) &&
+			    (*(ptr++) == ',') && (hexToLong(&ptr, &length))) {
+				ptr = 0;
+				/*
+				 * hex doubles the byte count
+				 */
+				if (length > (BUFMAX / 2))
+					length = BUFMAX / 2;
+				if (mem2hex((char *) addr,
+					remcomOutBuffer, length)) {
+					strcpy(remcomOutBuffer, "E03");
+					debug_error("memory fault\n", NULL);
+				}
+			}
+
+			if (ptr) {
+				strcpy(remcomOutBuffer, "E01");
+				debug_error
+				    ("malformed read memory command: %s\n",
+				     remcomInBuffer);
+			}
+			break;
+
+			/* MAA..AA,LLLL:
+			   Write LLLL bytes at address AA.AA return OK */
+		case 'M':
+			/* TRY TO READ '%x,%x:'.  IF SUCCEED, SET PTR = 0 */
+			ptr = &remcomInBuffer[1];
+			if (hexToLong(&ptr, &addr) &&
+			    (*(ptr++) == ',') &&
+			    (hexToLong(&ptr, &length)) && (*(ptr++) == ':')) {
+				if (hex2mem(ptr, (char *) addr, length)) {
+					strcpy(remcomOutBuffer, "E03");
+					debug_error("memory fault\n", NULL);
+				} else {
+					strcpy(remcomOutBuffer, "OK");
+				}
+
+				ptr = 0;
+			}
+			if (ptr) {
+				strcpy(remcomOutBuffer, "E02");
+				debug_error
+				    ("malformed write memory command: %s\n",
+				     remcomInBuffer);
+			}
+			break;
+		case 'S':
+			remcomInBuffer[0] = 's';
+		case 'C':
+			/* Csig;AA..AA where ;AA..AA is optional
+			 * continue with signal
+			 * Since signals are meaning less to us, delete that
+			 * part and then fall into the 'c' code.
+			 */
+			ptr = &remcomInBuffer[1];
+			length = 2;
+			while (*ptr && *ptr != ';') {
+				length++;
+				ptr++;
+			}
+			if (*ptr) {
+				do {
+					ptr++;
+					*(ptr - length++) = *ptr;
+				} while (*ptr);
+			} else {
+				remcomInBuffer[1] = 0;
+			}
+
+			/* cAA..AA  Continue at address AA..AA(optional) */
+			/* sAA..AA  Step one instruction from AA..AA(optional) */
+			/* D	    detach, reply OK and then continue */
+		case 'c':
+		case 's':
+		case 'D':
+
+			/* try to read optional parameter,
+			   pc unchanged if no parm */
+			ptr = &remcomInBuffer[1];
+			if (hexToLong(&ptr, &addr)) {
+				if (remote_debug)
+					printk("Changing EIP to 0x%lx\n", addr);
+
+				regs.rip = addr;
+			}
+
+			newPC = regs.rip;
+
+			/* clear the trace bit */
+			regs.eflags &= 0xfffffeff;
+
+			/* set the trace bit if we're stepping */
+			if (remcomInBuffer[0] == 's')
+				regs.eflags |= 0x100;
+
+			/* detach is a friendly version of continue. Note that
+			   debugging is still enabled (e.g hit control C)
+			 */
+			if (remcomInBuffer[0] == 'D') {
+				strcpy(remcomOutBuffer, "OK");
+				putpacket(remcomOutBuffer);
+			}
+
+			if (remote_debug) {
+				printk("Resuming execution\n");
+				print_regs(&regs);
+			}
+			asm volatile ("movq %%db6, %0\n":"=r" (dr6)
+				      :);
+			if (!(dr6 & 0x4000)) {
+				for (breakno = 0; breakno < 4; ++breakno) {
+					if (dr6 & (1 << breakno) &&
+					    (breakinfo[breakno].type == 0)) {
+						/* Set restore flag */
+						regs.eflags |= 0x10000;
+						break;
+					}
+				}
+			}
+
+			if (kgdboe)
+				netpoll_set_trap(0);
+
+			correct_hw_break();
+			asm volatile ("movq %0, %%db6\n"::"r" (0UL));
+			goto exit_kgdb;
+
+			/* kill the program */
+		case 'k':	/* do nothing */
+			break;
+
+			/* query */
+		case 'q':
+			nothreads = 0;
+			switch (remcomInBuffer[1]) {
+			case 'f':
+				threadid = 1;
+				thread_list = 2;
+				thread_list_start = (usethread ? : current);
+			case 's':
+				if (!cmp_str(&remcomInBuffer[2],
+					     "ThreadInfo", 10))
+					break;
+
+				remcomOutBuffer[nothreads++] = 'm';
+				for (; threadid < PID_MAX + MAX_NO_CPUS;
+				     threadid++) {
+					thread = getthread(threadid);
+					if (thread) {
+						nothreads += int_to_hex_v(
+							&remcomOutBuffer[
+								nothreads],
+							threadid);
+						if (thread_min > threadid)
+							thread_min = threadid;
+						remcomOutBuffer[
+							nothreads] = ',';
+						nothreads++;
+						if (nothreads > BUFMAX - 10)
+							break;
+					}
+				}
+				if (remcomOutBuffer[nothreads - 1] == 'm') {
+					remcomOutBuffer[nothreads - 1] = 'l';
+				} else {
+					nothreads--;
+				}
+				remcomOutBuffer[nothreads] = 0;
+				break;
+
+#ifdef old_thread_list /* Old thread info request */
+			case 'L':
+				/* List threads */
+				thread_list = 2;
+				thread_list_start = (usethread ? : current);
+				unpack_byte(remcomInBuffer + 3, &maxthreads);
+				unpack_threadid(remcomInBuffer + 5, &thref);
+				do {
+					int buf_thread_limit =
+					    (BUFMAX - 22) / BUF_THREAD_ID_SIZE;
+					if (maxthreads > buf_thread_limit) {
+						maxthreads = buf_thread_limit;
+					}
+				} while (0);
+				remcomOutBuffer[0] = 'q';
+				remcomOutBuffer[1] = 'M';
+				remcomOutBuffer[4] = '0';
+				pack_threadid(remcomOutBuffer + 5, &thref);
+
+				/* If start flag set start at 0. */
+				if (remcomInBuffer[2] == '1')
+					threadid = 0;
+				else
+					threadid = threadref_to_int(&thref);
+				for (nothreads = 0;
+				     nothreads < maxthreads &&
+				     threadid < PID_MAX + MAX_NO_CPUS;
+				     threadid++) {
+					thread = getthread(threadid);
+					if (thread) {
+						int_to_threadref(&thref,
+								 threadid);
+						pack_threadid(remcomOutBuffer +
+							      21 +
+							      nothreads * 16,
+							      &thref);
+						nothreads++;
+						if (thread_min > threadid)
+							thread_min = threadid;
+					}
+				}
+
+				if (threadid == PID_MAX + MAX_NO_CPUS) {
+					remcomOutBuffer[4] = '1';
+				}
+				pack_hex_byte(remcomOutBuffer + 2, nothreads);
+				remcomOutBuffer[21 + nothreads * 16] = '\0';
+				break;
+#endif
+			case 'C':
+				/* Current thread id */
+				remcomOutBuffer[0] = 'Q';
+				remcomOutBuffer[1] = 'C';
+				threadid = current->pid;
+				if (!threadid) {
+					/*
+					 * idle thread
+					 */
+					for (threadid = PID_MAX;
+					     threadid < PID_MAX + MAX_NO_CPUS;
+					     threadid++) {
+						if (current ==
+						    idle_task(threadid -
+							      PID_MAX))
+							break;
+					}
+				}
+				int_to_threadref(&thref, threadid);
+				pack_threadid(remcomOutBuffer + 2, &thref);
+				remcomOutBuffer[18] = '\0';
+				break;
+
+			case 'E':
+				/* Print exception info */
+				printexceptioninfo(exceptionVector,
+						   err_code, remcomOutBuffer);
+				break;
+			case 'T':
+				ptr = &remcomInBuffer[0];
+				if (strncmp(ptr, "qThreadExtraInfo,",
+					strlen("qThreadExtraInfo,")) == 0) {
+					ptr += strlen("qThreadExtraInfo,");
+					hexToLong(&ptr, &tmpid);
+					p = getthread(tmpid);
+					print_extra_info(p, lbuf);
+					mem2hex(lbuf, remcomOutBuffer,
+						strlen(lbuf));
+				}
+				break;
+#if 0
+			case 'T':{
+				char * nptr;
+				/* Thread extra info */
+				if (!cmp_str(&remcomInBuffer[2],
+					    "hreadExtraInfo,", 15)) {
+					break;
+				}
+				ptr = &remcomInBuffer[17];
+				hexToLong(&ptr, &threadid);
+				thread = getthread(threadid);
+				nptr = &thread->comm[0];
+				length = 0;
+				ptr = &remcomOutBuffer[0];
+				do {
+					length++;
+					ptr = pack_hex_byte(ptr, *nptr++);
+				 } while (*nptr && length < 16);
+				/*
+				 * would like that 16 to be the size of
+				 * task_struct.comm but don't know the
+				 * syntax..
+				 */
+				*ptr = 0;
+			}
+#endif
+			}
+			break;
+
+			/* task related */
+		case 'H':
+			switch (remcomInBuffer[1]) {
+			case 'g':
+				ptr = &remcomInBuffer[2];
+				hexToLong(&ptr, &threadid);
+				thread = getthread(threadid);
+				if (!thread) {
+					remcomOutBuffer[0] = 'E';
+					remcomOutBuffer[1] = '\0';
+					break;
+				}
+				/*
+				 * Just in case I forget what this is all about,
+				 * the "thread info" command to gdb causes it
+				 * to ask for a thread list.  It then switches
+				 * to each thread and asks for the registers.
+				 * For this (and only this) usage, we want to
+				 * fudge the registers of tasks not on the run
+				 * list (i.e. waiting) to show the routine that
+				 * called schedule. Also, gdb, is a minimalist
+				 * in that if the current thread is the last
+				 * it will not re-read the info when done.
+				 * This means that in this case we must show
+				 * the real registers. So here is how we do it:
+				 * Each entry we keep track of the min
+				 * thread in the list (the last that gdb will)
+				 * get info for.  We also keep track of the
+				 * starting thread.
+				 * "thread_list" is cleared when switching back
+				 * to the min thread if it is was current, or
+				 * if it was not current, thread_list is set
+				 * to 1.  When the switch to current comes,
+				 * if thread_list is 1, clear it, else do
+				 * nothing.
+				 */
+				usethread = thread;
+				if ((thread_list == 1) &&
+				    (thread == thread_list_start)) {
+					thread_list = 0;
+				}
+				if (thread_list && (threadid == thread_min)) {
+					if (thread == thread_list_start) {
+						thread_list = 0;
+					} else {
+						thread_list = 1;
+					}
+				}
+				/* follow through */
+			case 'c':
+				remcomOutBuffer[0] = 'O';
+				remcomOutBuffer[1] = 'K';
+				remcomOutBuffer[2] = '\0';
+				break;
+			}
+			break;
+
+			/* Query thread status */
+		case 'T':
+			ptr = &remcomInBuffer[1];
+			hexToLong(&ptr, &threadid);
+			thread = getthread(threadid);
+			if (thread) {
+				remcomOutBuffer[0] = 'O';
+				remcomOutBuffer[1] = 'K';
+				remcomOutBuffer[2] = '\0';
+				if (thread_min > threadid)
+					thread_min = threadid;
+			} else {
+				remcomOutBuffer[0] = 'E';
+				remcomOutBuffer[1] = '\0';
+			}
+			break;
+
+		case 'Y': /* set up a hardware breakpoint */
+			ptr = &remcomInBuffer[1];
+			hexToLong(&ptr, &breakno);
+			ptr++;
+			hexToLong(&ptr, &breaktype);
+			ptr++;
+			hexToLong(&ptr, &length);
+			ptr++;
+			hexToLong(&ptr, &addr);
+			if (set_hw_break(breakno & 0x3,
+					 breaktype & 0x3,
+					 length & 0x3, addr) == 0) {
+				strcpy(remcomOutBuffer, "OK");
+			} else {
+				strcpy(remcomOutBuffer, "ERROR");
+			}
+			break;
+
+			/* Remove hardware breakpoint */
+		case 'y':
+			ptr = &remcomInBuffer[1];
+			hexToLong(&ptr, &breakno);
+			if (remove_hw_break(breakno & 0x3) == 0) {
+				strcpy(remcomOutBuffer, "OK");
+			} else {
+				strcpy(remcomOutBuffer, "ERROR");
+			}
+			break;
+
+		case 'r':	/* reboot */
+			strcpy(remcomOutBuffer, "OK");
+			putpacket(remcomOutBuffer);
+			/*to_gdb("Rebooting\n"); */
+			/* triplefault	 no return from here */
+			{
+				static long no_idt[2];
+				__asm__ __volatile__("lidt %0"::"m"(no_idt[0]));
+				BREAKPOINT;
+			}
+
+		}		/* switch */
+
+		/* reply to the request */
+		putpacket(remcomOutBuffer);
+	}			/* while(1==1) */
+	/*
+	 *  reached by goto only.
+	 */
+      exit_kgdb:
+	/*
+	 * Here is where we set up to trap a gdb function call.	 NEW_esp
+	 * will be changed if we are trying to do this.	 We handle both
+	 * adding and subtracting, thus allowing gdb to put grung on
+	 * the stack which it removes later.
+	 */
+	if (NEW_esp != OLD_esp) {
+		unsigned long *ptr = END_OF_LOOKASIDE;
+		if (NEW_esp < OLD_esp)
+			ptr -= (OLD_esp - NEW_esp) / sizeof (unsigned long);
+		*--ptr = linux_regs->eflags;
+		*--ptr = linux_regs->cs;
+		*--ptr = linux_regs->rip;
+		*--ptr = linux_regs->rcx;
+		*--ptr = linux_regs->rbx;
+		*--ptr = linux_regs->rax;
+		linux_regs->rcx = NEW_esp - (sizeof (unsigned long) * 6);
+		linux_regs->rbx = (unsigned long) END_OF_LOOKASIDE;
+		if (NEW_esp < OLD_esp) {
+			linux_regs->rip = (unsigned long) fn_call_stub;
+		} else {
+			linux_regs->rip = (unsigned long) fn_rtn_stub;
+			linux_regs->rax = NEW_esp;
+		}
+		linux_regs->eflags &= ~(IF_BIT | TF_BIT);
+	}
+#ifdef CONFIG_SMP
+	/*
+	 * Release gdb wait locks
+	 * Sanity check time.  Must have at least one cpu to run.  Also single
+	 * step must not be done if the current cpu is on hold.
+	 */
+	if (spinlock_count == 1) {
+		int ss_hold = (regs.eflags & 0x100) && kgdb_info.hold_on_sstep;
+		int cpu_avail = 0;
+		int i;
+
+		for (i = 0; i < MAX_NO_CPUS; i++) {
+			if (!cpu_online(i))
+				break;
+			if (!hold_cpu(i)) {
+				cpu_avail = 1;
+			}
+		}
+		/*
+		 * Early in the bring up there will be NO cpus on line...
+		 */
+		if (!cpu_avail && !cpus_empty(cpu_online_map)) {
+			to_gdb("No cpus unblocked, see 'kgdb_info.hold_cpu'\n");
+			goto once_again;
+		}
+		if (hold_cpu(smp_processor_id()) && (regs.eflags & 0x100)) {
+			to_gdb
+			    ("Current cpu must be unblocked to single step\n");
+			goto once_again;
+		}
+		if (!(ss_hold)) {
+			int i;
+			for (i = 0; i < MAX_NO_CPUS; i++) {
+				if (!hold_cpu(i)) {
+					spin_unlock(&waitlocks[i]);
+				}
+			}
+		} else {
+			spin_unlock(&waitlocks[smp_processor_id()]);
+		}
+		/* Release kgdb spinlock */
+		KGDB_SPIN_UNLOCK(&kgdb_spinlock);
+		/*
+		 * If this cpu is on hold, this is where we
+		 * do it.  Note, the NMI will pull us out of here,
+		 * but will return as the above lock is not held.
+		 * We will stay here till another cpu releases the lock for us.
+		 */
+		spin_unlock_wait(waitlocks + smp_processor_id());
+		local_irq_restore(flags);
+		return (1);
+	}
+#if 0
+exit_just_unlock:
+#endif
+#endif
+	/* Release kgdb spinlock */
+	KGDB_SPIN_UNLOCK(&kgdb_spinlock);
+	local_irq_restore(flags);
+	return (1);
+}
+
+#undef regs
+static int kgdb_notify(struct notifier_block *self, unsigned long cmd, void *ptr)
+{
+	struct die_args *d = ptr;
+
+	if (!kgdb_enabled || (cmd == DIE_DEBUG && user_mode(d->regs)))
+		return NOTIFY_DONE;
+	if (cmd == DIE_NMI_IPI) {
+		if (in_kgdb(d->regs))
+			return NOTIFY_BAD;
+	} else if (kgdb_handle_exception(d->trapnr, d->signr, d->err, d->regs))
+		return NOTIFY_BAD; /* skip */
+
+	return NOTIFY_DONE;
+}
+
+static struct notifier_block kgdb_notifier = {
+	.notifier_call = kgdb_notify,
+	.priority = 0,
+};
+
+void set_debug_traps(void)
+{
+	static int initialized = 0;
+
+	if (!initialized) {
+		initialized = 1;
+		notifier_chain_register(&die_chain, &kgdb_notifier);
+	}
+}
+
+/*
+ * Provide the command line "gdb" initial break
+ */
+int __init kgdb_initial_break(char * str)
+{
+	if (*str == '\0'){
+		breakpoint();
+		return 1;
+	}
+	return 0;
+}
+__setup("gdb",kgdb_initial_break);
+
+/* This function will generate a breakpoint exception.	It is used at the
+   beginning of a program to sync up with a debugger and can be used
+   otherwise as a quick means to stop program execution and "break" into
+   the debugger. */
+/* But really, just use the BREAKPOINT macro.  We will handle the int stuff
+ */
+
+void breakpoint(void)
+{
+
+	set_debug_traps();
+	kgdb_enabled = 1;
+#if 0
+	/*
+	 * These calls were not enough to allow breakpoint to be
+	 * called before trap_init().  I moved the argument parsing
+	 * after trap_init() and it seems to work.
+	 */
+	set_intr_usr_gate(3,&int3); /* disable ints on trap */
+	set_intr_gate(1,&debug);
+	set_intr_gate(14,&page_fault);
+#endif
+
+        BREAKPOINT;
+}
+
+#ifdef later
+/*
+ * possibly we should not go thru the traps.c code at all?  Someday.
+ */
+void
+do_kgdb_int3(struct pt_regs *regs, long error_code)
+{
+	kgdb_handle_exception(3, 5, error_code, regs);
+	return;
+}
+#endif
+#undef regs
+#ifdef CONFIG_TRAP_BAD_SYSCALL_EXITS
+asmlinkage void
+bad_sys_call_exit(int stuff)
+{
+	struct pt_regs *regs = (struct pt_regs *) &stuff;
+	printk("Sys call %d return with %x preempt_count\n",
+	       (int) regs->orig_eax, preempt_count());
+}
+#endif
+#ifdef CONFIG_STACK_OVERFLOW_TEST
+#include <asm/kgdb.h>
+asmlinkage void
+stack_overflow(void)
+{
+#ifdef BREAKPOINT
+	BREAKPOINT;
+#else
+	printk("Kernel stack overflow, looping forever\n");
+#endif
+	while (1) {
+	}
+}
+#endif
+
+#if defined(CONFIG_SMP) || defined(CONFIG_KGDB_CONSOLE)
+char gdbconbuf[BUFMAX];
+
+static void
+kgdb_gdb_message(const char *s, unsigned count)
+{
+	int i;
+	int wcount;
+	char *bufptr;
+	/*
+	 * This takes care of NMI while spining out chars to gdb
+	 */
+	IF_SMP(in_kgdb_console = 1);
+	gdbconbuf[0] = 'O';
+	bufptr = gdbconbuf + 1;
+	while (count > 0) {
+		if ((count << 1) > (BUFMAX - 2)) {
+			wcount = (BUFMAX - 2) >> 1;
+		} else {
+			wcount = count;
+		}
+		count -= wcount;
+		for (i = 0; i < wcount; i++) {
+			bufptr = pack_hex_byte(bufptr, s[i]);
+		}
+		*bufptr = '\0';
+		s += wcount;
+
+		putpacket(gdbconbuf);
+
+	}
+	IF_SMP(in_kgdb_console = 0);
+}
+#endif
+#ifdef CONFIG_SMP
+static void
+to_gdb(const char *s)
+{
+	int count = 0;
+	while (s[count] && (count++ < BUFMAX)) ;
+	kgdb_gdb_message(s, count);
+}
+#endif
+#ifdef CONFIG_KGDB_CONSOLE
+#include <linux/console.h>
+#include <linux/init.h>
+#include <linux/fs.h>
+#include <asm/semaphore.h>
+
+void
+kgdb_console_write(struct console *co, const char *s, unsigned count)
+{
+
+	if (gdb_i386vector == -1) {
+		/*
+		 * We have not yet talked to gdb.  What to do...
+		 * lets break, on continue we can do the write.
+		 * But first tell him whats up. Uh, well no can do,
+		 * as this IS the console.  Oh well...
+		 * We do need to wait or the messages will be lost.
+		 * Other option would be to tell the above code to
+		 * ignore this breakpoint and do an auto return,
+		 * but that might confuse gdb.	Also this happens
+		 * early enough in boot up that we don't have the traps
+		 * set up yet, so...
+		 */
+		breakpoint();
+	}
+	kgdb_gdb_message(s, count);
+}
+
+/*
+ * ------------------------------------------------------------
+ * Serial KGDB driver
+ * ------------------------------------------------------------
+ */
+
+static struct console kgdbcons = {
+	name:"kgdb",
+	write:kgdb_console_write,
+#ifdef CONFIG_KGDB_USER_CONSOLE
+	device:kgdb_console_device,
+#endif
+	flags:CON_PRINTBUFFER | CON_ENABLED,
+	index:-1,
+};
+
+/*
+ * The trick here is that this file gets linked before printk.o
+ * That means we get to peer at the console info in the command
+ * line before it does.	 If we are up, we register, otherwise,
+ * do nothing.	By returning 0, we allow printk to look also.
+ */
+static int kgdb_console_enabled;
+
+int __init
+kgdb_console_init(char *str)
+{
+	if ((strncmp(str, "kgdb", 4) == 0) || (strncmp(str, "gdb", 3) == 0)) {
+		register_console(&kgdbcons);
+		kgdb_console_enabled = 1;
+	}
+	return 0;		/* let others look at the string */
+}
+
+__setup("console=", kgdb_console_init);
+
+#ifdef CONFIG_KGDB_USER_CONSOLE
+static kdev_t kgdb_console_device(struct console *c);
+/* This stuff sort of works, but it knocks out telnet devices
+ * we are leaving it here in case we (or you) find time to figure it out
+ * better..
+ */
+
+/*
+ * We need a real char device as well for when the console is opened for user
+ * space activities.
+ */
+
+static int
+kgdb_consdev_open(struct inode *inode, struct file *file)
+{
+	return 0;
+}
+
+static ssize_t
+kgdb_consdev_write(struct file *file, const char *buf,
+		   size_t count, loff_t * ppos)
+{
+	int size, ret = 0;
+	static char kbuf[128];
+	static DECLARE_MUTEX(sem);
+
+	/* We are not reentrant... */
+	if (down_interruptible(&sem))
+		return -ERESTARTSYS;
+
+	while (count > 0) {
+		/* need to copy the data from user space */
+		size = count;
+		if (size > sizeof (kbuf))
+			size = sizeof (kbuf);
+		if (copy_from_user(kbuf, buf, size)) {
+			ret = -EFAULT;
+			break;;
+		}
+		kgdb_console_write(&kgdbcons, kbuf, size);
+		count -= size;
+		ret += size;
+		buf += size;
+	}
+
+	up(&sem);
+
+	return ret;
+}
+
+struct file_operations kgdb_consdev_fops = {
+	open:kgdb_consdev_open,
+	write:kgdb_consdev_write
+};
+static kdev_t
+kgdb_console_device(struct console *c)
+{
+	return MKDEV(TTYAUX_MAJOR, 1);
+}
+
+/*
+ * This routine gets called from the serial stub in the i386/lib
+ * This is so it is done late in bring up (just before the console open).
+ */
+void
+kgdb_console_finit(void)
+{
+	if (kgdb_console_enabled) {
+		char *cptr = cdevname(MKDEV(TTYAUX_MAJOR, 1));
+		char *cp = cptr;
+		while (*cptr && *cptr != '(')
+			cptr++;
+		*cptr = 0;
+		unregister_chrdev(TTYAUX_MAJOR, cp);
+		register_chrdev(TTYAUX_MAJOR, "kgdb", &kgdb_consdev_fops);
+	}
+}
+#endif
+#endif
+#ifdef CONFIG_KGDB_TS
+#include <asm/msr.h>		/* time stamp code */
+#include <asm/hardirq.h>	/* in_interrupt */
+#ifdef CONFIG_KGDB_TS_64
+#define DATA_POINTS 64
+#endif
+#ifdef CONFIG_KGDB_TS_128
+#define DATA_POINTS 128
+#endif
+#ifdef CONFIG_KGDB_TS_256
+#define DATA_POINTS 256
+#endif
+#ifdef CONFIG_KGDB_TS_512
+#define DATA_POINTS 512
+#endif
+#ifdef CONFIG_KGDB_TS_1024
+#define DATA_POINTS 1024
+#endif
+#ifndef DATA_POINTS
+#define DATA_POINTS 128		/* must be a power of two */
+#endif
+#define INDEX_MASK (DATA_POINTS - 1)
+#if (INDEX_MASK & DATA_POINTS)
+#error "CONFIG_KGDB_TS_COUNT must be a power of 2"
+#endif
+struct kgdb_and_then_struct {
+#ifdef CONFIG_SMP
+	int on_cpu;
+#endif
+	struct task_struct *task;
+	long long at_time;
+	int from_ln;
+	char *in_src;
+	void *from;
+	int *with_shpf;
+	int data0;
+	int data1;
+};
+struct kgdb_and_then_struct2 {
+#ifdef CONFIG_SMP
+	int on_cpu;
+#endif
+	struct task_struct *task;
+	long long at_time;
+	int from_ln;
+	char *in_src;
+	void *from;
+	int *with_shpf;
+	struct task_struct *t1;
+	struct task_struct *t2;
+};
+struct kgdb_and_then_struct kgdb_data[DATA_POINTS];
+
+struct kgdb_and_then_struct *kgdb_and_then = &kgdb_data[0];
+int kgdb_and_then_count;
+
+void
+kgdb_tstamp(int line, char *source, int data0, int data1)
+{
+	static spinlock_t ts_spin = SPIN_LOCK_UNLOCKED;
+	unsigned long flags;
+
+	local_irq_save(flags);
+	spin_lock(&ts_spin);
+	rdtscll(kgdb_and_then->at_time);
+#ifdef CONFIG_SMP
+	kgdb_and_then->on_cpu = smp_processor_id();
+#endif
+	kgdb_and_then->task = current;
+	kgdb_and_then->from_ln = line;
+	kgdb_and_then->in_src = source;
+	kgdb_and_then->from = __builtin_return_address(0);
+	kgdb_and_then->with_shpf = (int *)(long)(((flags & IF_BIT) >> 9) |
+					    (preempt_count() << 8));
+	kgdb_and_then->data0 = data0;
+	kgdb_and_then->data1 = data1;
+	kgdb_and_then = &kgdb_data[++kgdb_and_then_count & INDEX_MASK];
+	spin_unlock(&ts_spin);
+	local_irq_restore(flags);
+#ifdef CONFIG_PREEMPT
+
+#endif
+	return;
+}
+#endif
+typedef int gdb_debug_hook(int exceptionVector,
+			   int signo, int err_code, struct pt_regs *linux_regs);
+gdb_debug_hook *linux_debug_hook = &kgdb_handle_exception;	/* histerical reasons... */
+
+static int kgdb_need_breakpoint[NR_CPUS];
+
+void kgdb_schedule_breakpoint(void)
+{
+	kgdb_need_breakpoint[smp_processor_id()] = 1;
+}
+
+void kgdb_process_breakpoint(void)
+{
+	/*
+	 * Handle a breakpoint queued from inside network driver code
+         * to avoid reentrancy issues
+	 */
+	if (kgdb_need_breakpoint[smp_processor_id()]) {
+		kgdb_need_breakpoint[smp_processor_id()] = 0;
+		kgdb_enabled = 1;
+		BREAKPOINT;
+	}
+}
+
--- diff/arch/x86_64/lib/kgdb_serial.c	1970-01-01 01:00:00.000000000 +0100
+++ source/arch/x86_64/lib/kgdb_serial.c	2004-06-11 19:22:00.000000000 +0100
@@ -0,0 +1,490 @@
+/*
+ * Serial interface GDB stub
+ *
+ * Written (hacked together) by David Grothe (dave@gcom.com)
+ * Modified to allow invokation early in boot see also
+ * kgdb.h for instructions by George Anzinger(george@mvista.com)
+ * Modified to handle debugging over ethernet by Robert Walsh
+ * <rjwalsh@durables.org> and wangdi <wangdi@clusterfs.com>, based on
+ * code by San Mehat.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/errno.h>
+#include <linux/signal.h>
+#include <linux/sched.h>
+#include <linux/timer.h>
+#include <linux/interrupt.h>
+#include <linux/tty.h>
+#include <linux/tty_flip.h>
+#include <linux/serial.h>
+#include <linux/serial_reg.h>
+#include <linux/config.h>
+#include <linux/major.h>
+#include <linux/string.h>
+#include <linux/fcntl.h>
+#include <linux/ptrace.h>
+#include <linux/ioport.h>
+#include <linux/mm.h>
+#include <linux/init.h>
+#include <linux/highmem.h>
+#include <asm/system.h>
+#include <asm/io.h>
+#include <asm/segment.h>
+#include <asm/bitops.h>
+#include <asm/system.h>
+#include <asm/kgdb_local.h>
+#ifdef CONFIG_KGDB_USER_CONSOLE
+extern void kgdb_console_finit(void);
+#endif
+#define PRNT_off
+#define TEST_EXISTANCE
+#ifdef PRNT
+#define dbprintk(s) printk s
+#else
+#define dbprintk(s)
+#endif
+#define TEST_INTERRUPT_off
+#ifdef TEST_INTERRUPT
+#define intprintk(s) printk s
+#else
+#define intprintk(s)
+#endif
+
+#define IRQ_T(info) ((info->flags & ASYNC_SHARE_IRQ) ? SA_SHIRQ : SA_INTERRUPT)
+
+#define	GDB_BUF_SIZE	512	/* power of 2, please */
+
+static char gdb_buf[GDB_BUF_SIZE];
+static int gdb_buf_in_inx;
+static atomic_t gdb_buf_in_cnt;
+static int gdb_buf_out_inx;
+
+struct async_struct *gdb_async_info;
+static int gdb_async_irq;
+
+#define outb_px(a,b) outb_p(b,a)
+
+static void program_uart(struct async_struct *info);
+static void write_char(struct async_struct *info, int chr);
+/*
+ * Get a byte from the hardware data buffer and return it
+ */
+static int
+read_data_bfr(struct async_struct *info)
+{
+	char it = inb_p(info->port + UART_LSR);
+
+	if (it & UART_LSR_DR)
+		return (inb_p(info->port + UART_RX));
+	/*
+	 * If we have a framing error assume somebody messed with
+	 * our uart.  Reprogram it and send '-' both ways...
+	 */
+	if (it & 0xc) {
+		program_uart(info);
+		write_char(info, '-');
+		return ('-');
+	}
+	return (-1);
+
+}				/* read_data_bfr */
+
+/*
+ * Get a char if available, return -1 if nothing available.
+ * Empty the receive buffer first, then look at the interface hardware.
+
+ * Locking here is a bit of a problem.	We MUST not lock out communication
+ * if we are trying to talk to gdb about a kgdb entry.	ON the other hand
+ * we can loose chars in the console pass thru if we don't lock.  It is also
+ * possible that we could hold the lock or be waiting for it when kgdb
+ * NEEDS to talk.  Since kgdb locks down the world, it does not need locks.
+ * We do, of course have possible issues with interrupting a uart operation,
+ * but we will just depend on the uart status to help keep that straight.
+
+ */
+static spinlock_t uart_interrupt_lock = SPIN_LOCK_UNLOCKED;
+#ifdef CONFIG_SMP
+extern spinlock_t kgdb_spinlock;
+#endif
+
+static int
+read_char(struct async_struct *info)
+{
+	int chr;
+	unsigned long flags;
+	local_irq_save(flags);
+#ifdef CONFIG_SMP
+	if (!spin_is_locked(&kgdb_spinlock)) {
+		spin_lock(&uart_interrupt_lock);
+	}
+#endif
+	if (atomic_read(&gdb_buf_in_cnt) != 0) {	/* intr routine has q'd chars */
+		chr = gdb_buf[gdb_buf_out_inx++];
+		gdb_buf_out_inx &= (GDB_BUF_SIZE - 1);
+		atomic_dec(&gdb_buf_in_cnt);
+	} else {
+		chr = read_data_bfr(info);
+	}
+#ifdef CONFIG_SMP
+	if (!spin_is_locked(&kgdb_spinlock)) {
+		spin_unlock(&uart_interrupt_lock);
+	}
+#endif
+	local_irq_restore(flags);
+	return (chr);
+}
+
+/*
+ * Wait until the interface can accept a char, then write it.
+ */
+static void
+write_char(struct async_struct *info, int chr)
+{
+	while (!(inb_p(info->port + UART_LSR) & UART_LSR_THRE)) ;
+
+	outb_p(chr, info->port + UART_TX);
+
+}				/* write_char */
+
+/*
+ * Mostly we don't need a spinlock, but since the console goes
+ * thru here with interrutps on, well, we need to catch those
+ * chars.
+ */
+/*
+ * This is the receiver interrupt routine for the GDB stub.
+ * It will receive a limited number of characters of input
+ * from the gdb  host machine and save them up in a buffer.
+ *
+ * When the gdb stub routine tty_getDebugChar() is called it
+ * draws characters out of the buffer until it is empty and
+ * then reads directly from the serial port.
+ *
+ * We do not attempt to write chars from the interrupt routine
+ * since the stubs do all of that via tty_putDebugChar() which
+ * writes one byte after waiting for the interface to become
+ * ready.
+ *
+ * The debug stubs like to run with interrupts disabled since,
+ * after all, they run as a consequence of a breakpoint in
+ * the kernel.
+ *
+ * Perhaps someone who knows more about the tty driver than I
+ * care to learn can make this work for any low level serial
+ * driver.
+ */
+static irqreturn_t
+gdb_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+	struct async_struct *info;
+	unsigned long flags;
+
+	info = gdb_async_info;
+	if (!info || !info->tty || irq != gdb_async_irq)
+		return IRQ_NONE;
+
+	local_irq_save(flags);
+	spin_lock(&uart_interrupt_lock);
+	do {
+		int chr = read_data_bfr(info);
+		intprintk(("Debug char on int: %x hex\n", chr));
+		if (chr < 0)
+			continue;
+
+		if (chr == 3) {	/* Ctrl-C means remote interrupt */
+			BREAKPOINT;
+			continue;
+		}
+
+		if (atomic_read(&gdb_buf_in_cnt) >= GDB_BUF_SIZE) {
+			/* buffer overflow tosses early char */
+			read_char(info);
+		}
+		gdb_buf[gdb_buf_in_inx++] = chr;
+		gdb_buf_in_inx &= (GDB_BUF_SIZE - 1);
+	} while (inb_p(info->port + UART_IIR) & UART_IIR_RDI);
+	spin_unlock(&uart_interrupt_lock);
+	local_irq_restore(flags);
+	return IRQ_HANDLED;
+}				/* gdb_interrupt */
+
+/*
+ * Just a NULL routine for testing.
+ */
+void
+gdb_null(void)
+{
+}				/* gdb_null */
+
+/* These structure are filled in with values defined in asm/kgdb_local.h
+ */
+static struct serial_state state = SB_STATE;
+static struct async_struct local_info = SB_INFO;
+static int ok_to_enable_ints = 0;
+static void kgdb_enable_ints_now(void);
+
+extern char *kgdb_version;
+/*
+ * Hook an IRQ for KGDB.
+ *
+ * This routine is called from tty_putDebugChar, below.
+ */
+static int ints_disabled = 1;
+int
+gdb_hook_interrupt(struct async_struct *info, int verb)
+{
+	struct serial_state *state = info->state;
+	unsigned long flags;
+	int port;
+#ifdef TEST_EXISTANCE
+	int scratch, scratch2;
+#endif
+
+	/* The above fails if memory managment is not set up yet.
+	 * Rather than fail the set up, just keep track of the fact
+	 * and pick up the interrupt thing later.
+	 */
+	gdb_async_info = info;
+	port = gdb_async_info->port;
+	gdb_async_irq = state->irq;
+	if (verb) {
+		printk("kgdb %s : port =%x, IRQ=%d, divisor =%d\n",
+		       kgdb_version,
+		       port,
+		       gdb_async_irq, gdb_async_info->state->custom_divisor);
+	}
+	local_irq_save(flags);
+#ifdef TEST_EXISTANCE
+	/* Existance test */
+	/* Should not need all this, but just in case.... */
+
+	scratch = inb_p(port + UART_IER);
+	outb_px(port + UART_IER, 0);
+	outb_px(0xff, 0x080);
+	scratch2 = inb_p(port + UART_IER);
+	outb_px(port + UART_IER, scratch);
+	if (scratch2) {
+		printk
+		    ("gdb_hook_interrupt: Could not clear IER, not a UART!\n");
+		local_irq_restore(flags);
+		return 1;	/* We failed; there's nothing here */
+	}
+	scratch2 = inb_p(port + UART_LCR);
+	outb_px(port + UART_LCR, 0xBF);	/* set up for StarTech test */
+	outb_px(port + UART_EFR, 0);	/* EFR is the same as FCR */
+	outb_px(port + UART_LCR, 0);
+	outb_px(port + UART_FCR, UART_FCR_ENABLE_FIFO);
+	scratch = inb_p(port + UART_IIR) >> 6;
+	if (scratch == 1) {
+		printk("gdb_hook_interrupt: Undefined UART type!"
+		       "  Not a UART! \n");
+		local_irq_restore(flags);
+		return 1;
+	} else {
+		dbprintk(("gdb_hook_interrupt: UART type "
+			  "is %d where 0=16450, 2=16550 3=16550A\n", scratch));
+	}
+	scratch = inb_p(port + UART_MCR);
+	outb_px(port + UART_MCR, UART_MCR_LOOP | scratch);
+	outb_px(port + UART_MCR, UART_MCR_LOOP | 0x0A);
+	scratch2 = inb_p(port + UART_MSR) & 0xF0;
+	outb_px(port + UART_MCR, scratch);
+	if (scratch2 != 0x90) {
+		printk("gdb_hook_interrupt: "
+		       "Loop back test failed! Not a UART!\n");
+		local_irq_restore(flags);
+		return scratch2 + 1000;	/* force 0 to fail */
+	}
+#endif				/* test existance */
+	program_uart(info);
+	local_irq_restore(flags);
+
+	return (0);
+
+}				/* gdb_hook_interrupt */
+
+static void
+program_uart(struct async_struct *info)
+{
+	int port = info->port;
+
+	(void) inb_p(port + UART_RX);
+	outb_px(port + UART_IER, 0);
+
+	(void) inb_p(port + UART_RX);	/* serial driver comments say */
+	(void) inb_p(port + UART_IIR);	/* this clears the interrupt regs */
+	(void) inb_p(port + UART_MSR);
+	outb_px(port + UART_LCR, UART_LCR_WLEN8 | UART_LCR_DLAB);
+	outb_px(port + UART_DLL, info->state->custom_divisor & 0xff);	/* LS */
+	outb_px(port + UART_DLM, info->state->custom_divisor >> 8);	/* MS  */
+	outb_px(port + UART_MCR, info->MCR);
+
+	outb_px(port + UART_FCR, UART_FCR_ENABLE_FIFO | UART_FCR_TRIGGER_1 | UART_FCR_CLEAR_XMIT | UART_FCR_CLEAR_RCVR);	/* set fcr */
+	outb_px(port + UART_LCR, UART_LCR_WLEN8);	/* reset DLAB */
+	outb_px(port + UART_FCR, UART_FCR_ENABLE_FIFO | UART_FCR_TRIGGER_1);	/* set fcr */
+	if (!ints_disabled) {
+		intprintk(("KGDB: Sending %d to port %x offset %d\n",
+			   gdb_async_info->IER,
+			   (int) gdb_async_info->port, UART_IER));
+		outb_px(gdb_async_info->port + UART_IER, gdb_async_info->IER);
+	}
+	return;
+}
+
+/*
+ * tty_getDebugChar
+ *
+ * This is a GDB stub routine.	It waits for a character from the
+ * serial interface and then returns it.  If there is no serial
+ * interface connection then it returns a bogus value which will
+ * almost certainly cause the system to hang.  In the
+ */
+int kgdb_in_isr = 0;
+int kgdb_in_lsr = 0;
+extern spinlock_t kgdb_spinlock;
+
+/* Caller takes needed protections */
+
+int
+tty_getDebugChar(void)
+{
+	volatile int chr, dum, time, end_time;
+
+	dbprintk(("tty_getDebugChar(port %x): ", gdb_async_info->port));
+
+	if (gdb_async_info == NULL) {
+		gdb_hook_interrupt(&local_info, 0);
+	}
+	/*
+	 * This trick says if we wait a very long time and get
+	 * no char, return the -1 and let the upper level deal
+	 * with it.
+	 */
+	rdtsc(dum, time);
+	end_time = time + 2;
+	while (((chr = read_char(gdb_async_info)) == -1) &&
+	       (end_time - time) > 0) {
+		rdtsc(dum, time);
+	};
+	/*
+	 * This covers our butts if some other code messes with
+	 * our uart, hay, it happens :o)
+	 */
+	if (chr == -1)
+		program_uart(gdb_async_info);
+
+	dbprintk(("%c\n", chr > ' ' && chr < 0x7F ? chr : ' '));
+	return (chr);
+
+}				/* tty_getDebugChar */
+
+static int count = 3;
+static spinlock_t one_at_atime = SPIN_LOCK_UNLOCKED;
+
+static int __init
+kgdb_enable_ints(void)
+{
+	set_debug_traps();
+	if (kgdboe) {
+		return 0;
+	}
+	if (gdb_async_info == NULL) {
+		gdb_hook_interrupt(&local_info, 1);
+	}
+	ok_to_enable_ints = 1;
+	kgdb_enable_ints_now();
+#ifdef CONFIG_KGDB_USER_CONSOLE
+	kgdb_console_finit();
+#endif
+	return 0;
+}
+
+#ifdef CONFIG_SERIAL_8250
+void shutdown_for_kgdb(struct async_struct *gdb_async_info);
+#endif
+
+#define kgdb_mem_init_done()    (1)
+
+static void
+kgdb_enable_ints_now(void)
+{
+	if (!spin_trylock(&one_at_atime))
+		return;
+	if (!ints_disabled)
+		goto exit;
+	if (kgdb_mem_init_done() &&
+			ints_disabled) {	/* don't try till mem init */
+#ifdef CONFIG_SERIAL_8250
+		/*
+		 * The ifdef here allows the system to be configured
+		 * without the serial driver.
+		 * Don't make it a module, however, it will steal the port
+		 */
+		shutdown_for_kgdb(gdb_async_info);
+#endif
+		ints_disabled = request_irq(gdb_async_info->state->irq,
+					    gdb_interrupt,
+					    IRQ_T(gdb_async_info),
+					    "KGDB-stub", NULL);
+		intprintk(("KGDB: request_irq returned %d\n", ints_disabled));
+	}
+	if (!ints_disabled) {
+		intprintk(("KGDB: Sending %d to port %x offset %d\n",
+			   gdb_async_info->IER,
+			   (int) gdb_async_info->port, UART_IER));
+		outb_px(gdb_async_info->port + UART_IER, gdb_async_info->IER);
+	}
+      exit:
+	spin_unlock(&one_at_atime);
+}
+
+/*
+ * tty_putDebugChar
+ *
+ * This is a GDB stub routine.	It waits until the interface is ready
+ * to transmit a char and then sends it.  If there is no serial
+ * interface connection then it simply returns to its caller, having
+ * pretended to send the char.	Caller takes needed protections.
+ */
+void
+tty_putDebugChar(int chr)
+{
+	dbprintk(("tty_putDebugChar(port %x): chr=%02x '%c', ints_on=%d\n",
+		  gdb_async_info->port,
+		  chr,
+		  chr > ' ' && chr < 0x7F ? chr : ' ', ints_disabled ? 0 : 1));
+
+	if (gdb_async_info == NULL) {
+		gdb_hook_interrupt(&local_info, 0);
+	}
+
+	write_char(gdb_async_info, chr);	/* this routine will wait */
+	count = (chr == '#') ? 0 : count + 1;
+	if ((count == 2)) {	/* try to enable after */
+		if (ints_disabled & ok_to_enable_ints)
+			kgdb_enable_ints_now();	/* try to enable after */
+
+		/* We do this a lot because, well we really want to get these
+		 * interrupts.	The serial driver will clear these bits when it
+		 * initializes the chip.  Every thing else it does is ok,
+		 * but this.
+		 */
+		if (!ints_disabled) {
+			outb_px(gdb_async_info->port + UART_IER,
+				gdb_async_info->IER);
+		}
+	}
+
+}				/* tty_putDebugChar */
+
+/*
+ * This does nothing for the serial port, since it doesn't buffer.
+ */
+
+void tty_flushDebugChar(void)
+{
+}
+
+module_init(kgdb_enable_ints);
--- diff/drivers/char/hpet.c	1970-01-01 01:00:00.000000000 +0100
+++ source/drivers/char/hpet.c	2004-06-11 19:22:01.000000000 +0100
@@ -0,0 +1,1061 @@
+/*
+ * Intel & MS High Precision Event Timer Implementation.
+ * Contributors:
+ *	Venki Pallipadi
+ * 	Bob Picco
+ */
+
+#include <linux/config.h>
+#include <linux/interrupt.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/miscdevice.h>
+#include <linux/major.h>
+#include <linux/ioport.h>
+#include <linux/fcntl.h>
+#include <linux/init.h>
+#include <linux/poll.h>
+#include <linux/proc_fs.h>
+#include <linux/spinlock.h>
+#include <linux/sysctl.h>
+#include <linux/wait.h>
+#include <linux/bcd.h>
+#include <linux/seq_file.h>
+
+#include <asm/current.h>
+#include <asm/uaccess.h>
+#include <asm/system.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/bitops.h>
+#include <asm/div64.h>
+
+#include <linux/acpi.h>
+#include <acpi/acpi_bus.h>
+#include <linux/hpet.h>
+
+/*
+ * The High Precision Event Timer driver.
+ * This driver is closely modelled after the rtc.c driver.
+ * http://www.intel.com/labs/platcomp/hpet/hpetspec.htm
+ */
+#define	HPET_USER_FREQ	(64)
+#define	HPET_DRIFT	(500)
+
+static u32 hpet_ntimer, hpet_nhpet, hpet_max_freq = HPET_USER_FREQ;
+
+/* A lock for concurrent access by app and isr hpet activity. */
+static spinlock_t hpet_lock = SPIN_LOCK_UNLOCKED;
+/* A lock for concurrent intermodule access to hpet and isr hpet activity. */
+static spinlock_t hpet_task_lock = SPIN_LOCK_UNLOCKED;
+
+struct hpet_dev {
+	struct hpets *hd_hpets;
+	struct hpet *hd_hpet;
+	struct hpet_timer *hd_timer;
+	unsigned long hd_ireqfreq;
+	unsigned long hd_irqdata;
+	wait_queue_head_t hd_waitqueue;
+	struct fasync_struct *hd_async_queue;
+	struct hpet_task *hd_task;
+	unsigned int hd_flags;
+	unsigned int hd_irq;
+	unsigned int hd_hdwirq;
+};
+
+struct hpets {
+	struct hpets *hp_next;
+	struct hpet *hp_hpet;
+	unsigned long hp_period;
+	unsigned long hp_delta;
+	unsigned int hp_ntimer;
+	unsigned int hp_which;
+	struct hpet_dev hp_dev[1];
+};
+
+static struct hpets *hpets;
+
+#define	HPET_OPEN		0x0001
+#define	HPET_IE			0x0002	/* interrupt enabled */
+#define	HPET_PERIODIC		0x0004
+
+#if BITS_PER_LONG == 64
+#define	write_counter(V, MC)	writeq(V, MC)
+#define	read_counter(MC)	readq(MC)
+#else
+#define	write_counter(V, MC) 	writel(V, MC)
+#define	read_counter(MC)	readl(MC)
+#endif
+
+static irqreturn_t hpet_interrupt(int irq, void *data, struct pt_regs *regs)
+{
+	struct hpet_dev *devp;
+	unsigned long isr;
+
+	devp = data;
+
+	spin_lock(&hpet_lock);
+	devp->hd_irqdata++;
+
+	/*
+	 * For non-periodic timers, increment the accumulator.
+	 * This has the effect of treating non-periodic like periodic.
+	 */
+	if ((devp->hd_flags & (HPET_IE | HPET_PERIODIC)) == HPET_IE) {
+		unsigned long m, t;
+
+		t = devp->hd_ireqfreq;
+		m = read_counter(&devp->hd_hpet->hpet_mc);
+		write_counter(t + m + devp->hd_hpets->hp_delta,
+			      &devp->hd_timer->hpet_compare);
+	}
+
+	isr = (1 << (devp - devp->hd_hpets->hp_dev));
+	writeq(isr, &devp->hd_hpet->hpet_isr);
+	spin_unlock(&hpet_lock);
+
+	spin_lock(&hpet_task_lock);
+	if (devp->hd_task)
+		devp->hd_task->ht_func(devp->hd_task->ht_data);
+	spin_unlock(&hpet_task_lock);
+
+	wake_up_interruptible(&devp->hd_waitqueue);
+
+	kill_fasync(&devp->hd_async_queue, SIGIO, POLL_IN);
+
+	return IRQ_HANDLED;
+}
+
+static int hpet_open(struct inode *inode, struct file *file)
+{
+	struct hpet_dev *devp;
+	struct hpets *hpetp;
+	int i;
+
+	spin_lock_irq(&hpet_lock);
+
+	for (devp = NULL, hpetp = hpets; hpetp && !devp; hpetp = hpetp->hp_next)
+		for (i = 0; i < hpetp->hp_ntimer; i++)
+			if (hpetp->hp_dev[i].hd_flags & HPET_OPEN
+			    || hpetp->hp_dev[i].hd_task)
+				continue;
+			else {
+				devp = &hpetp->hp_dev[i];
+				break;
+			}
+
+	if (!devp) {
+		spin_unlock_irq(&hpet_lock);
+		return -EBUSY;
+	}
+
+	file->private_data = devp;
+	devp->hd_irqdata = 0;
+	devp->hd_flags |= HPET_OPEN;
+	spin_unlock_irq(&hpet_lock);
+
+	return 0;
+}
+
+static ssize_t
+hpet_read(struct file *file, char *buf, size_t count, loff_t * ppos)
+{
+	DECLARE_WAITQUEUE(wait, current);
+	unsigned long data;
+	ssize_t retval;
+	struct hpet_dev *devp;
+
+	devp = file->private_data;
+	if (!devp->hd_ireqfreq)
+		return -EIO;
+
+	if (count < sizeof(unsigned long))
+		return -EINVAL;
+
+	add_wait_queue(&devp->hd_waitqueue, &wait);
+
+	do {
+		__set_current_state(TASK_INTERRUPTIBLE);
+
+		spin_lock_irq(&hpet_lock);
+		data = devp->hd_irqdata;
+		devp->hd_irqdata = 0;
+		spin_unlock_irq(&hpet_lock);
+
+		if (data)
+			break;
+		else if (file->f_flags & O_NONBLOCK) {
+			retval = -EAGAIN;
+			goto out;
+		} else if (signal_pending(current)) {
+			retval = -ERESTARTSYS;
+			goto out;
+		}
+
+		schedule();
+
+	} while (1);
+
+	retval = put_user(data, (unsigned long *)buf);
+	if (!retval)
+		retval = sizeof(unsigned long);
+      out:
+	current->state = TASK_RUNNING;
+	remove_wait_queue(&devp->hd_waitqueue, &wait);
+
+	return retval;
+}
+
+static unsigned int hpet_poll(struct file *file, poll_table * wait)
+{
+	unsigned long v;
+	struct hpet_dev *devp;
+
+	devp = file->private_data;
+
+	if (!devp->hd_ireqfreq)
+		return 0;
+
+	poll_wait(file, &devp->hd_waitqueue, wait);
+
+	spin_lock_irq(&hpet_lock);
+	v = devp->hd_irqdata;
+	spin_unlock_irq(&hpet_lock);
+
+	if (v != 0)
+		return POLLIN | POLLRDNORM;
+
+	return 0;
+}
+
+static int hpet_mmap(struct file *file, struct vm_area_struct *vma)
+{
+#ifdef	CONFIG_HPET_NOMMAP
+	return -ENOSYS;
+#else
+	struct hpet_dev *devp;
+	unsigned long addr;
+
+	if (((vma->vm_end - vma->vm_start) != PAGE_SIZE) || vma->vm_pgoff)
+		return -EINVAL;
+
+	if (vma->vm_flags & VM_WRITE)
+		return -EPERM;
+
+	devp = file->private_data;
+	addr = (unsigned long)devp->hd_hpet;
+
+	if (addr & (PAGE_SIZE - 1))
+		return -ENOSYS;
+
+	vma->vm_flags |= VM_IO;
+	vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
+	addr = __pa(addr);
+
+	if (remap_page_range
+	    (vma, vma->vm_start, addr, PAGE_SIZE, vma->vm_page_prot)) {
+		printk(KERN_ERR "remap_page_range failed in hpet.c\n");
+		return -EAGAIN;
+	}
+
+	return 0;
+#endif
+}
+
+static int hpet_fasync(int fd, struct file *file, int on)
+{
+	struct hpet_dev *devp;
+
+	devp = file->private_data;
+
+	if (fasync_helper(fd, file, on, &devp->hd_async_queue) >= 0)
+		return 0;
+	else
+		return -EIO;
+}
+
+static int hpet_release(struct inode *inode, struct file *file)
+{
+	struct hpet_dev *devp;
+	struct hpet_timer *timer;
+	int irq = 0;
+
+	devp = file->private_data;
+	timer = devp->hd_timer;
+
+	spin_lock_irq(&hpet_lock);
+
+	writeq((readq(&timer->hpet_config) & ~Tn_INT_ENB_CNF_MASK),
+	       &timer->hpet_config);
+
+	irq = devp->hd_irq;
+	devp->hd_irq = 0;
+
+	devp->hd_ireqfreq = 0;
+
+	if (devp->hd_flags & HPET_PERIODIC
+	    && readq(&timer->hpet_config) & Tn_TYPE_CNF_MASK) {
+		unsigned long v;
+
+		v = readq(&timer->hpet_config);
+		v ^= Tn_TYPE_CNF_MASK;
+		writeq(v, &timer->hpet_config);
+	}
+
+	devp->hd_flags &= ~(HPET_OPEN | HPET_IE | HPET_PERIODIC);
+	spin_unlock_irq(&hpet_lock);
+
+	if (irq)
+		free_irq(irq, devp);
+
+	if (file->f_flags & FASYNC)
+		hpet_fasync(-1, file, 0);
+
+	file->private_data = 0;
+	return 0;
+}
+
+static int hpet_ioctl_common(struct hpet_dev *, int, unsigned long, int);
+
+static int
+hpet_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
+	   unsigned long arg)
+{
+	struct hpet_dev *devp;
+
+	devp = file->private_data;
+	return hpet_ioctl_common(devp, cmd, arg, 0);
+}
+
+static int hpet_ioctl_ieon(struct hpet_dev *devp)
+{
+	struct hpet_timer *timer;
+	struct hpet *hpet;
+	struct hpets *hpetp;
+	int irq;
+	unsigned long g, v, t, m;
+	unsigned long flags, isr;
+
+	timer = devp->hd_timer;
+	hpet = devp->hd_hpet;
+	hpetp = devp->hd_hpets;
+
+	v = readq(&timer->hpet_config);
+	spin_lock_irq(&hpet_lock);
+
+	if (devp->hd_flags & HPET_IE) {
+		spin_unlock_irq(&hpet_lock);
+		return -EBUSY;
+	}
+
+	devp->hd_flags |= HPET_IE;
+	spin_unlock_irq(&hpet_lock);
+
+	t = readq(&timer->hpet_config);
+	irq = devp->hd_hdwirq;
+
+	if (irq) {
+		char name[7];
+
+		sprintf(name, "hpet%d", (int)(devp - hpetp->hp_dev));
+
+		if (request_irq
+		    (irq, hpet_interrupt, SA_INTERRUPT, name, (void *)devp)) {
+			printk(KERN_ERR "hpet: IRQ %d is not free\n", irq);
+			irq = 0;
+		}
+	}
+
+	if (irq == 0) {
+		spin_lock_irq(&hpet_lock);
+		devp->hd_flags ^= HPET_IE;
+		spin_unlock_irq(&hpet_lock);
+		return -EIO;
+	}
+
+	devp->hd_irq = irq;
+	t = devp->hd_ireqfreq;
+	v = readq(&timer->hpet_config);
+	g = v | Tn_INT_ENB_CNF_MASK;
+
+	if (devp->hd_flags & HPET_PERIODIC) {
+		write_counter(t, &timer->hpet_compare);
+		g |= Tn_TYPE_CNF_MASK;
+		v |= Tn_TYPE_CNF_MASK;
+		writeq(v, &timer->hpet_config);
+		v |= Tn_VAL_SET_CNF_MASK;
+		writeq(v, &timer->hpet_config);
+		local_irq_save(flags);
+		m = read_counter(&hpet->hpet_mc);
+		write_counter(t + m + hpetp->hp_delta, &timer->hpet_compare);
+	} else {
+		local_irq_save(flags);
+		m = read_counter(&hpet->hpet_mc);
+		write_counter(t + m + hpetp->hp_delta, &timer->hpet_compare);
+	}
+
+	isr = (1 << (devp - hpets->hp_dev));
+	writeq(isr, &hpet->hpet_isr);
+	writeq(g, &timer->hpet_config);
+	local_irq_restore(flags);
+
+	return 0;
+}
+
+static inline unsigned long hpet_time_div(unsigned long dis)
+{
+	unsigned long long m = 1000000000000000ULL;
+
+	do_div(m, dis);
+
+	return (unsigned long)m;
+}
+
+static int
+hpet_ioctl_common(struct hpet_dev *devp, int cmd, unsigned long arg, int kernel)
+{
+	struct hpet_timer *timer;
+	struct hpet *hpet;
+	struct hpets *hpetp;
+	int err;
+	unsigned long v;
+
+	switch (cmd) {
+	case HPET_IE_OFF:
+	case HPET_INFO:
+	case HPET_EPI:
+	case HPET_DPI:
+	case HPET_IRQFREQ:
+		timer = devp->hd_timer;
+		hpet = devp->hd_hpet;
+		hpetp = devp->hd_hpets;
+		break;
+	case HPET_IE_ON:
+		return hpet_ioctl_ieon(devp);
+	default:
+		return -EINVAL;
+	}
+
+	err = 0;
+
+	switch (cmd) {
+	case HPET_IE_OFF:
+		if ((devp->hd_flags & HPET_IE) == 0)
+			break;
+		v = readq(&timer->hpet_config);
+		v &= ~Tn_INT_ENB_CNF_MASK;
+		writeq(v, &timer->hpet_config);
+		if (devp->hd_irq) {
+			free_irq(devp->hd_irq, devp);
+			devp->hd_irq = 0;
+		}
+		devp->hd_flags ^= HPET_IE;
+		break;
+	case HPET_INFO:
+		{
+			struct hpet_info info;
+
+			info.hi_ireqfreq = hpet_time_div(hpetp->hp_period *
+							 devp->hd_ireqfreq);
+			info.hi_flags =
+			    readq(&timer->hpet_config) & Tn_PER_INT_CAP_MASK;
+			info.hi_hpet = devp->hd_hpets->hp_which;
+			info.hi_timer = devp - devp->hd_hpets->hp_dev;
+			if (copy_to_user((void *)arg, &info, sizeof(info)))
+				err = -EFAULT;
+			break;
+		}
+	case HPET_EPI:
+		v = readq(&timer->hpet_config);
+		if ((v & Tn_PER_INT_CAP_MASK) == 0) {
+			err = -ENXIO;
+			break;
+		}
+		devp->hd_flags |= HPET_PERIODIC;
+		break;
+	case HPET_DPI:
+		v = readq(&timer->hpet_config);
+		if ((v & Tn_PER_INT_CAP_MASK) == 0) {
+			err = -ENXIO;
+			break;
+		}
+		if (devp->hd_flags & HPET_PERIODIC &&
+		    readq(&timer->hpet_config) & Tn_TYPE_CNF_MASK) {
+			v = readq(&timer->hpet_config);
+			v ^= Tn_TYPE_CNF_MASK;
+			writeq(v, &timer->hpet_config);
+		}
+		devp->hd_flags &= ~HPET_PERIODIC;
+		break;
+	case HPET_IRQFREQ:
+		if (!kernel && (arg > hpet_max_freq) &&
+		    !capable(CAP_SYS_RESOURCE)) {
+			err = -EACCES;
+			break;
+		}
+
+		if (arg & (arg - 1)) {
+			err = -EINVAL;
+			break;
+		}
+
+		devp->hd_ireqfreq = hpet_time_div(hpetp->hp_period * arg);
+	}
+
+	return err;
+}
+
+static struct file_operations hpet_fops = {
+	.owner = THIS_MODULE,
+	.llseek = no_llseek,
+	.read = hpet_read,
+	.poll = hpet_poll,
+	.ioctl = hpet_ioctl,
+	.open = hpet_open,
+	.release = hpet_release,
+	.fasync = hpet_fasync,
+	.mmap = hpet_mmap,
+};
+
+EXPORT_SYMBOL(hpet_alloc);
+EXPORT_SYMBOL(hpet_register);
+EXPORT_SYMBOL(hpet_unregister);
+EXPORT_SYMBOL(hpet_control);
+
+int hpet_register(struct hpet_task *tp, int periodic)
+{
+	unsigned int i;
+	u64 mask;
+	struct hpet_timer *timer;
+	struct hpet_dev *devp;
+	struct hpets *hpetp;
+
+	switch (periodic) {
+	case 1:
+		mask = Tn_PER_INT_CAP_MASK;
+		break;
+	case 0:
+		mask = 0;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	spin_lock_irq(&hpet_task_lock);
+	spin_lock(&hpet_lock);
+
+	for (devp = 0, hpetp = hpets; hpetp && !devp; hpetp = hpetp->hp_next)
+		for (timer = hpetp->hp_hpet->hpet_timers, i = 0;
+		     i < hpetp->hp_ntimer; i++, timer++) {
+			if ((readq(&timer->hpet_config) & Tn_PER_INT_CAP_MASK)
+			    != mask)
+				continue;
+
+			devp = &hpetp->hp_dev[i];
+
+			if (devp->hd_flags & HPET_OPEN || devp->hd_task) {
+				devp = 0;
+				continue;
+			}
+
+			tp->ht_opaque = devp;
+			devp->hd_task = tp;
+			break;
+		}
+
+	spin_unlock(&hpet_lock);
+	spin_unlock_irq(&hpet_task_lock);
+
+	if (tp->ht_opaque)
+		return 0;
+	else
+		return -EBUSY;
+}
+
+static inline int hpet_tpcheck(struct hpet_task *tp)
+{
+	struct hpet_dev *devp;
+	struct hpets *hpetp;
+
+	devp = tp->ht_opaque;
+
+	if (!devp)
+		return -ENXIO;
+
+	for (hpetp = hpets; hpetp; hpetp = hpetp->hp_next)
+		if (devp >= hpetp->hp_dev
+		    && devp < (hpetp->hp_dev + hpetp->hp_ntimer)
+		    && devp->hd_hpet == hpetp->hp_hpet)
+			return 0;
+
+	return -ENXIO;
+}
+
+int hpet_unregister(struct hpet_task *tp)
+{
+	struct hpet_dev *devp;
+	struct hpet_timer *timer;
+	int err;
+
+	if ((err = hpet_tpcheck(tp)))
+		return err;
+
+	spin_lock_irq(&hpet_task_lock);
+	spin_lock(&hpet_lock);
+
+	devp = tp->ht_opaque;
+	if (devp->hd_task != tp) {
+		spin_unlock(&hpet_lock);
+		spin_unlock_irq(&hpet_task_lock);
+		return -ENXIO;
+	}
+
+	timer = devp->hd_timer;
+	writeq((readq(&timer->hpet_config) & ~Tn_INT_ENB_CNF_MASK),
+	       &timer->hpet_config);
+	devp->hd_flags &= ~(HPET_IE | HPET_PERIODIC);
+	devp->hd_task = 0;
+	spin_unlock(&hpet_lock);
+	spin_unlock_irq(&hpet_task_lock);
+
+	return 0;
+}
+
+int hpet_control(struct hpet_task *tp, unsigned int cmd, unsigned long arg)
+{
+	struct hpet_dev *devp;
+	int err;
+
+	if ((err = hpet_tpcheck(tp)))
+		return err;
+
+	spin_lock_irq(&hpet_lock);
+	devp = tp->ht_opaque;
+	if (devp->hd_task != tp) {
+		spin_unlock_irq(&hpet_lock);
+		return -ENXIO;
+	}
+	spin_unlock_irq(&hpet_lock);
+	return hpet_ioctl_common(devp, cmd, arg, 1);
+}
+
+#ifdef	CONFIG_TIME_INTERPOLATION
+
+static unsigned long hpet_offset, last_wall_hpet;
+static long hpet_nsecs_per_cycle, hpet_cycles_per_sec;
+
+static unsigned long hpet_getoffset(void)
+{
+	return hpet_offset + (read_counter(&hpets->hp_hpet->hpet_mc) -
+			      last_wall_hpet) * hpet_nsecs_per_cycle;
+}
+
+static void hpet_update(long delta)
+{
+	unsigned long mc;
+	unsigned long offset;
+
+	mc = read_counter(&hpets->hp_hpet->hpet_mc);
+	offset = hpet_offset + (mc - last_wall_hpet) * hpet_nsecs_per_cycle;
+
+	if (delta < 0 || (unsigned long)delta < offset)
+		hpet_offset = offset - delta;
+	else
+		hpet_offset = 0;
+	last_wall_hpet = mc;
+}
+
+static void hpet_reset(void)
+{
+	hpet_offset = 0;
+	last_wall_hpet = read_counter(&hpets->hp_hpet->hpet_mc);
+}
+
+static struct time_interpolator hpet_interpolator = {
+	.get_offset = hpet_getoffset,
+	.update = hpet_update,
+	.reset = hpet_reset
+};
+
+#endif
+
+static ctl_table hpet_table[] = {
+	{
+	 .ctl_name = 1,
+	 .procname = "max-user-freq",
+	 .data = &hpet_max_freq,
+	 .maxlen = sizeof(int),
+	 .mode = 0644,
+	 .proc_handler = &proc_dointvec,
+	 },
+	{.ctl_name = 0}
+};
+
+static ctl_table hpet_root[] = {
+	{
+	 .ctl_name = 1,
+	 .procname = "hpet",
+	 .maxlen = 0,
+	 .mode = 0555,
+	 .child = hpet_table,
+	 },
+	{.ctl_name = 0}
+};
+
+static ctl_table dev_root[] = {
+	{
+	 .ctl_name = CTL_DEV,
+	 .procname = "dev",
+	 .maxlen = 0,
+	 .mode = 0555,
+	 .child = hpet_root,
+	 },
+	{.ctl_name = 0}
+};
+
+static struct ctl_table_header *sysctl_header;
+
+static void *hpet_start(struct seq_file *s, loff_t * pos)
+{
+	struct hpets *hpetp;
+	loff_t n;
+
+	for (n = *pos, hpetp = hpets; hpetp; hpetp = hpetp->hp_next)
+		if (!n--)
+			return hpetp;
+
+	return 0;
+}
+
+static void *hpet_next(struct seq_file *s, void *v, loff_t * pos)
+{
+	struct hpets *hpetp;
+
+	hpetp = v;
+	++*pos;
+	return hpetp->hp_next;
+}
+
+static void hpet_stop(struct seq_file *s, void *v)
+{
+	return;
+}
+
+static int hpet_show(struct seq_file *s, void *v)
+{
+	struct hpets *hpetp;
+	struct hpet *hpet;
+	u64 cap, vendor, period;
+
+	hpetp = v;
+	hpet = hpetp->hp_hpet;
+
+	cap = readq(&hpet->hpet_cap);
+	period = (cap & HPET_COUNTER_CLK_PERIOD_MASK) >>
+	    HPET_COUNTER_CLK_PERIOD_SHIFT;
+	vendor = (cap & HPET_VENDOR_ID_MASK) >> HPET_VENDOR_ID_SHIFT;
+
+	seq_printf(s,
+		   "HPET%d period = %d 10**-15  vendor = 0x%x number timer = %d\n",
+		   hpetp->hp_which, (u32) period, (u32) vendor,
+		   hpetp->hp_ntimer);
+
+	return 0;
+}
+
+static struct seq_operations hpet_seq_ops = {
+	.start = hpet_start,
+	.next = hpet_next,
+	.stop = hpet_stop,
+	.show = hpet_show
+};
+
+static int hpet_proc_open(struct inode *inode, struct file *file)
+{
+	return seq_open(file, &hpet_seq_ops);
+}
+
+static struct file_operations hpet_proc_fops = {
+	.open = hpet_proc_open,
+	.read = seq_read,
+	.llseek = seq_lseek,
+	.release = seq_release
+};
+
+/*
+ * Adjustment for when arming the timer with
+ * initial conditions.  That is, main counter
+ * ticks expired before interrupts are enabled.
+ */
+#define	TICK_CALIBRATE	(1000UL)
+
+static unsigned long __init hpet_calibrate(struct hpets *hpetp)
+{
+	struct hpet_timer *timer;
+	unsigned long t, m, count, i, flags, start;
+	struct hpet_dev *devp;
+	int j;
+	struct hpet *hpet;
+
+	for (timer = 0, j = 0, devp = hpetp->hp_dev; j < hpetp->hp_ntimer;
+	     j++, devp++)
+		if ((devp->hd_flags & HPET_OPEN) == 0) {
+			timer = devp->hd_timer;
+			break;
+		}
+
+	if (!timer)
+		return 0;
+
+	hpet = hpets->hp_hpet;
+	t = read_counter(&timer->hpet_compare);
+
+	i = 0;
+	count = hpet_time_div(hpetp->hp_period * TICK_CALIBRATE);
+
+	local_irq_save(flags);
+
+	start = read_counter(&hpet->hpet_mc);
+
+	do {
+		m = read_counter(&hpet->hpet_mc);
+		write_counter(t + m + hpetp->hp_delta, &timer->hpet_compare);
+	} while (i++, (m - start) < count);
+
+	local_irq_restore(flags);
+
+	return (m - start) / i;
+}
+
+int __init hpet_alloc(struct hpet_data *hdp)
+{
+	u64 cap, mcfg;
+	struct hpet_dev *devp;
+	u32 i, ntimer;
+	struct hpets *hpetp;
+	size_t siz;
+	struct hpet *hpet;
+	static struct hpets *last __initdata = (struct hpets *)0;
+
+	/*
+	 * hpet_alloc can be called by platform dependent code.
+	 * if platform dependent code has allocated the hpet
+	 * ACPI also reports hpet, then we catch it here.
+	 */
+	for (hpetp = hpets; hpetp; hpetp = hpetp->hp_next)
+		if (hpetp->hp_hpet == (struct hpet *)(hdp->hd_address))
+			return 0;
+
+	siz = sizeof(struct hpets) + ((hdp->hd_nirqs - 1) *
+				      sizeof(struct hpet_dev));
+
+	hpetp = kmalloc(siz, GFP_KERNEL);
+
+	if (!hpetp)
+		return -ENOMEM;
+
+	memset(hpetp, 0, siz);
+
+	hpetp->hp_which = hpet_nhpet++;
+	hpetp->hp_hpet = (struct hpet *)hdp->hd_address;
+
+	hpetp->hp_ntimer = hdp->hd_nirqs;
+
+	for (i = 0; i < hdp->hd_nirqs; i++)
+		hpetp->hp_dev[i].hd_hdwirq = hdp->hd_irq[i];
+
+	hpet = hpetp->hp_hpet;
+
+	cap = readq(&hpet->hpet_cap);
+
+	ntimer = ((cap & HPET_NUM_TIM_CAP_MASK) >> HPET_NUM_TIM_CAP_SHIFT) + 1;
+
+	if (hpetp->hp_ntimer != ntimer) {
+		printk(KERN_WARNING "hpet: number irqs doesn't agree"
+		       " with number of timers\n");
+		kfree(hpetp);
+		return -ENODEV;
+	}
+
+	if (last)
+		last->hp_next = hpetp;
+	else
+		hpets = hpetp;
+
+	last = hpetp;
+
+	hpetp->hp_period = (cap & HPET_COUNTER_CLK_PERIOD_MASK) >>
+	    HPET_COUNTER_CLK_PERIOD_SHIFT;
+
+	mcfg = readq(&hpet->hpet_config);
+	if ((mcfg & HPET_ENABLE_CNF_MASK) == 0) {
+		write_counter(0L, &hpet->hpet_mc);
+		mcfg |= HPET_ENABLE_CNF_MASK;
+		writeq(mcfg, &hpet->hpet_config);
+	}
+
+	for (i = 0, devp = hpetp->hp_dev; i < hpetp->hp_ntimer;
+	     i++, hpet_ntimer++, devp++) {
+		unsigned long v;
+		struct hpet_timer *timer;
+
+		timer = &hpet->hpet_timers[devp - hpetp->hp_dev];
+		v = readq(&timer->hpet_config);
+
+		devp->hd_hpets = hpetp;
+		devp->hd_hpet = hpet;
+		devp->hd_timer = timer;
+
+		/*
+		 * If the timer was reserved by platform code,
+		 * then make timer unavailable for opens.
+		 */
+		if (hdp->hd_state & (1 << i)) {
+			devp->hd_flags = HPET_OPEN;
+			continue;
+		}
+
+		init_waitqueue_head(&devp->hd_waitqueue);
+	}
+
+	hpetp->hp_delta = hpet_calibrate(hpetp);
+
+	return 0;
+}
+
+static acpi_status __init hpet_resources(struct acpi_resource *res, void *data)
+{
+	struct hpet_data *hdp;
+	acpi_status status;
+	struct acpi_resource_address64 addr;
+	struct hpets *hpetp;
+
+	hdp = data;
+
+	status = acpi_resource_to_address64(res, &addr);
+
+	if (ACPI_SUCCESS(status)) {
+		unsigned long size;
+
+		size = addr.max_address_range - addr.min_address_range + 1;
+		hdp->hd_address =
+		    (unsigned long)ioremap(addr.min_address_range, size);
+
+		for (hpetp = hpets; hpetp; hpetp = hpetp->hp_next)
+			if (hpetp->hp_hpet == (struct hpet *)(hdp->hd_address))
+				return -EBUSY;
+	} else if (res->id == ACPI_RSTYPE_EXT_IRQ) {
+		struct acpi_resource_ext_irq *irqp;
+		int i;
+
+		irqp = &res->data.extended_irq;
+
+		if (irqp->number_of_interrupts > 0) {
+			hdp->hd_nirqs = irqp->number_of_interrupts;
+
+			for (i = 0; i < hdp->hd_nirqs; i++)
+#ifdef	CONFIG_IA64
+				hdp->hd_irq[i] =
+				    acpi_register_irq(irqp->interrupts[i],
+						      irqp->active_high_low,
+						      irqp->edge_level);
+#else
+				hdp->hd_irq[i] = irqp->interrupts[i];
+#endif
+		}
+	}
+
+	return AE_OK;
+}
+
+static int __init hpet_acpi_add(struct acpi_device *device)
+{
+	acpi_status result;
+	struct hpet_data data;
+
+	memset(&data, 0, sizeof(data));
+
+	result =
+	    acpi_walk_resources(device->handle, METHOD_NAME__CRS,
+				hpet_resources, &data);
+
+	if (ACPI_FAILURE(result))
+		return -ENODEV;
+
+	if (!data.hd_address || !data.hd_nirqs) {
+		printk("%s: no address or irqs in _CRS\n", __FUNCTION__);
+		return -ENODEV;
+	}
+
+	return hpet_alloc(&data);
+}
+
+static int __init hpet_acpi_remove(struct acpi_device *device, int type)
+{
+	return 0;
+}
+
+static struct acpi_driver hpet_acpi_driver __initdata = {
+	.name = "hpet",
+	.class = "",
+	.ids = "PNP0103",
+	.ops = {
+		.add = hpet_acpi_add,
+		.remove = hpet_acpi_remove,
+		},
+};
+
+static struct miscdevice hpet_misc = { HPET_MINOR, "hpet", &hpet_fops };
+
+static int __init hpet_init(void)
+{
+	struct proc_dir_entry *entry;
+
+	(void)acpi_bus_register_driver(&hpet_acpi_driver);
+
+	if (hpets) {
+		if (misc_register(&hpet_misc))
+			return -ENODEV;
+
+		entry = create_proc_entry("driver/hpet", 0, 0);
+
+		if (entry)
+			entry->proc_fops = &hpet_proc_fops;
+
+		sysctl_header = register_sysctl_table(dev_root, 0);
+
+#ifdef	CONFIG_TIME_INTERPOLATION
+		{
+			struct hpet *hpet;
+
+			hpet = hpets->hp_hpet;
+			hpet_cycles_per_sec = hpet_time_div(hpets->hp_period);
+			hpet_interpolator.frequency = hpet_cycles_per_sec;
+			hpet_interpolator.drift = hpet_cycles_per_sec *
+			    HPET_DRIFT / 1000000;
+			hpet_nsecs_per_cycle = 1000000000 / hpet_cycles_per_sec;
+			register_time_interpolator(&hpet_interpolator);
+		}
+#endif
+		return 0;
+	} else
+		return -ENODEV;
+}
+
+static void __exit hpet_exit(void)
+{
+	acpi_bus_unregister_driver(&hpet_acpi_driver);
+
+	if (hpets) {
+		unregister_sysctl_table(sysctl_header);
+		remove_proc_entry("driver/hpet", NULL);
+	}
+
+	return;
+}
+
+module_init(hpet_init);
+module_exit(hpet_exit);
+MODULE_AUTHOR("Bob Picco <Robert.Picco@hp.com>");
+MODULE_LICENSE("GPL");
--- diff/drivers/input/serio/serio_raw.c	1970-01-01 01:00:00.000000000 +0100
+++ source/drivers/input/serio/serio_raw.c	2004-06-11 19:22:01.000000000 +0100
@@ -0,0 +1,388 @@
+/*
+ * Raw serio device providing access to a raw byte stream from underlying
+ * serio port. Closely emulates behavior of pre-2.6 /dev/psaux device
+ *
+ * Copyright (c) 2004 Dmitry Torokhov
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published by
+ * the Free Software Foundation.
+ */
+
+#include <linux/slab.h>
+#include <linux/poll.h>
+#include <linux/module.h>
+#include <linux/serio.h>
+#include <linux/init.h>
+#include <linux/major.h>
+#include <linux/device.h>
+#include <linux/devfs_fs_kernel.h>
+#include <linux/miscdevice.h>
+#include <linux/wait.h>
+
+MODULE_AUTHOR("Dmitry Torokhov <dtor@mail.ru>");
+MODULE_DESCRIPTION("Raw serio driver");
+MODULE_LICENSE("GPL");
+
+#define SERIO_RAW_QUEUE_LEN	64
+struct serio_raw {
+	unsigned char queue[SERIO_RAW_QUEUE_LEN];
+	unsigned int tail, head;
+	spinlock_t lock;
+
+	char name[16];
+	unsigned int refcnt;
+	struct serio *serio;
+	struct miscdevice dev;
+	wait_queue_head_t wait;
+	struct list_head list;
+	struct list_head node;
+};
+
+struct serio_raw_list {
+	struct fasync_struct *fasync;
+	struct serio_raw *serio_raw;
+	struct list_head node;
+};
+
+static DECLARE_MUTEX(serio_raw_sem);
+static LIST_HEAD(serio_raw_list);
+static unsigned int serio_raw_no;
+
+/*********************************************************************
+ *             Interface with userspace (file operations)            *
+ *********************************************************************/
+
+static int serio_raw_fasync(int fd, struct file *file, int on)
+{
+	struct serio_raw_list *list = file->private_data;
+	int retval;
+
+	retval = fasync_helper(fd, file, on, &list->fasync);
+	return retval < 0 ? retval : 0;
+}
+
+static struct serio_raw *serio_raw_locate(int minor)
+{
+	struct serio_raw *serio_raw;
+
+	list_for_each_entry(serio_raw, &serio_raw_list, node) {
+		if (serio_raw->dev.minor == minor)
+			return serio_raw;
+	}
+
+	return NULL;
+}
+
+static int serio_raw_open(struct inode *inode, struct file *file)
+{
+	struct serio_raw *serio_raw;
+	struct serio_raw_list *list;
+	int retval = 0;
+
+	retval = down_interruptible(&serio_raw_sem);
+	if (retval)
+		return retval;
+
+	if (!(serio_raw = serio_raw_locate(iminor(inode)))) {
+		retval = -ENODEV;
+		goto out;
+	}
+
+	if (!serio_raw->serio) {
+		retval = -ENODEV;
+		goto out;
+	}
+
+	if (!(list = kmalloc(sizeof(struct serio_raw_list), GFP_KERNEL))) {
+		retval = -ENOMEM;
+		goto out;
+	}
+
+	memset(list, 0, sizeof(struct serio_raw_list));
+	list->serio_raw = serio_raw;
+	file->private_data = list;
+
+	serio_raw->refcnt++;
+	list_add_tail(&list->node, &serio_raw->list);
+
+out:
+	up(&serio_raw_sem);
+	return retval;
+}
+
+static int serio_raw_cleanup(struct serio_raw *serio_raw)
+{
+	if (--serio_raw->refcnt == 0) {
+		misc_deregister(&serio_raw->dev);
+		list_del_init(&serio_raw->node);
+		kfree(serio_raw);
+
+		return 1;
+	}
+
+	return 0;
+}
+
+static int serio_raw_release(struct inode *inode, struct file *file)
+{
+	struct serio_raw_list *list = file->private_data;
+	struct serio_raw *serio_raw = list->serio_raw;
+
+	down(&serio_raw_sem);
+
+	serio_raw_fasync(-1, file, 0);
+	serio_raw_cleanup(serio_raw);
+
+	up(&serio_raw_sem);
+	return 0;
+}
+
+static int serio_raw_fetch_byte(struct serio_raw *serio_raw, char *c)
+{
+	unsigned long flags;
+	int empty;
+
+	spin_lock_irqsave(&serio_raw->lock, flags);
+
+	empty = serio_raw->head == serio_raw->tail;
+	if (!empty) {
+		*c = serio_raw->queue[serio_raw->tail];
+		serio_raw->tail = (serio_raw->tail + 1) % SERIO_RAW_QUEUE_LEN;
+	}
+
+	spin_unlock_irqrestore(&serio_raw->lock, flags);
+
+	return !empty;
+}
+
+static ssize_t serio_raw_read(struct file *file, char *buffer, size_t count, loff_t *ppos)
+{
+	struct serio_raw_list *list = file->private_data;
+	struct serio_raw *serio_raw = list->serio_raw;
+	char c;
+	ssize_t retval = 0;
+
+	if (!serio_raw->serio)
+		return -ENODEV;
+
+	if (serio_raw->head == serio_raw->tail && (file->f_flags & O_NONBLOCK))
+		return -EAGAIN;
+
+	retval = wait_event_interruptible(list->serio_raw->wait,
+					  serio_raw->head != serio_raw->tail || !serio_raw->serio);
+	if (retval)
+		return retval;
+
+	if (!serio_raw->serio)
+		return -ENODEV;
+
+	while (retval < count && serio_raw_fetch_byte(serio_raw, &c)) {
+		if (put_user(c, buffer++))
+			return -EFAULT;
+		retval++;
+	}
+
+	return retval;
+}
+
+static ssize_t serio_raw_write(struct file *file, const char *buffer, size_t count, loff_t *ppos)
+{
+	struct serio_raw_list *list = file->private_data;
+	ssize_t written = 0;
+	int retval;
+	unsigned char c;
+
+	retval = down_interruptible(&serio_raw_sem);
+	if (retval)
+		return retval;
+
+	if (!list->serio_raw->serio) {
+		retval = -ENODEV;
+		goto out;
+	}
+
+	if (count > 32)
+		count = 32;
+
+	while (count--) {
+		if (get_user(c, buffer++)) {
+			retval = -EFAULT;
+			goto out;
+		}
+		if (serio_write(list->serio_raw->serio, c)) {
+			retval = -EIO;
+			goto out;
+		}
+		written++;
+	};
+
+out:
+	up(&serio_raw_sem);
+	return written;
+}
+
+static unsigned int serio_raw_poll(struct file *file, poll_table *wait)
+{
+	struct serio_raw_list *list = file->private_data;
+
+	poll_wait(file, &list->serio_raw->wait, wait);
+
+	if (list->serio_raw->head != list->serio_raw->tail)
+		return POLLIN | POLLRDNORM;
+
+	return 0;
+}
+
+struct file_operations serio_raw_fops = {
+	.owner =	THIS_MODULE,
+	.open =		serio_raw_open,
+	.release =	serio_raw_release,
+	.read =		serio_raw_read,
+	.write =	serio_raw_write,
+	.poll =		serio_raw_poll,
+	.fasync =	serio_raw_fasync,
+};
+
+
+/*********************************************************************
+ *                   Interface with serio port   	             *
+ *********************************************************************/
+
+static irqreturn_t serio_raw_interrupt(struct serio *serio, unsigned char data,
+					unsigned int dfl, struct pt_regs *regs)
+{
+	struct serio_raw *serio_raw = serio->private;
+	struct serio_raw_list *list;
+	unsigned int head = serio_raw->head;
+	unsigned long flags;
+
+	spin_lock_irqsave(&serio_raw->lock, flags);
+
+	serio_raw->queue[head] = data;
+	head = (head + 1) % SERIO_RAW_QUEUE_LEN;
+	if (likely(head != serio_raw->tail)) {
+		serio_raw->head = head;
+		list_for_each_entry(list, &serio_raw->list, node)
+			kill_fasync(&list->fasync, SIGIO, POLL_IN);
+		wake_up_interruptible(&serio_raw->wait);
+	}
+
+	spin_unlock_irqrestore(&serio_raw->lock, flags);
+
+	return IRQ_HANDLED;
+}
+
+static void serio_raw_connect(struct serio *serio, struct serio_dev *dev)
+{
+	struct serio_raw *serio_raw;
+	int err;
+
+	if ((serio->type & SERIO_TYPE) != SERIO_8042_RAW)
+		return;
+
+	if (!(serio_raw = kmalloc(sizeof(struct serio_raw), GFP_KERNEL))) {
+		printk(KERN_ERR "serio_raw.c: can't allocate memory for a device\n");
+		return;
+	}
+
+	down(&serio_raw_sem);
+
+	memset(serio_raw, 0, sizeof(struct serio_raw));
+	snprintf(serio_raw->name, sizeof(serio_raw->name), "serio_raw%d", serio_raw_no++);
+	serio_raw->refcnt = 1;
+	serio_raw->serio = serio;
+	INIT_LIST_HEAD(&serio_raw->list);
+        init_waitqueue_head(&serio_raw->wait);
+
+	serio->private = serio_raw;
+	if (serio_open(serio, dev))
+		goto out_free;
+
+	list_add_tail(&serio_raw->node, &serio_raw_list);
+
+	serio_raw->dev.minor = PSMOUSE_MINOR;
+	serio_raw->dev.name = serio_raw->name;
+	serio_raw->dev.fops = &serio_raw_fops;
+
+	err = misc_register(&serio_raw->dev);
+	if (err) {
+		serio_raw->dev.minor = MISC_DYNAMIC_MINOR;
+		err = misc_register(&serio_raw->dev);
+	}
+
+	if (err) {
+		printk(KERN_INFO "serio_raw: failed to register raw access device for %s\n",
+			serio->phys);
+		goto out_close;
+	}
+
+	printk(KERN_INFO "serio_raw: raw access enabled on %s (%s, minor %d)\n",
+		serio->phys, serio_raw->name, serio_raw->dev.minor);
+	goto out;
+
+out_close:
+	serio_close(serio);
+	list_del_init(&serio_raw->node);
+out_free:
+	serio->private = NULL;
+	kfree(serio_raw);
+out:
+	up(&serio_raw_sem);
+}
+
+static int serio_raw_reconnect(struct serio *serio)
+{
+	struct serio_raw *serio_raw = serio->private;
+	struct serio_dev *dev = serio->dev;
+
+	if (!dev || !serio_raw) {
+		printk(KERN_DEBUG "serio_raw: reconnect request, but serio is disconnected, ignoring...\n");
+		return -1;
+	}
+
+	/*
+	 * Nothing needs to be done here, we just need this method to
+	 * keep the same device.
+	 */
+	return 0;
+}
+
+static void serio_raw_disconnect(struct serio *serio)
+{
+	struct serio_raw *serio_raw;
+
+	down(&serio_raw_sem);
+
+	serio_raw = serio->private;
+
+	serio_close(serio);
+	serio->private = NULL;
+
+	serio_raw->serio = NULL;
+	if (!serio_raw_cleanup(serio_raw))
+		wake_up_interruptible(&serio_raw->wait);
+
+	up(&serio_raw_sem);
+}
+
+static struct serio_dev serio_raw_dev = {
+	.interrupt =	serio_raw_interrupt,
+	.connect =	serio_raw_connect,
+	.reconnect =	serio_raw_reconnect,
+	.disconnect =	serio_raw_disconnect,
+};
+
+int __init serio_raw_init(void)
+{
+	serio_register_device(&serio_raw_dev);
+	return 0;
+}
+
+void __exit serio_raw_exit(void)
+{
+	serio_unregister_device(&serio_raw_dev);
+}
+
+module_init(serio_raw_init);
+module_exit(serio_raw_exit);
--- diff/drivers/md/dm-exception-store.c	1970-01-01 01:00:00.000000000 +0100
+++ source/drivers/md/dm-exception-store.c	2004-06-11 19:22:02.000000000 +0100
@@ -0,0 +1,648 @@
+/*
+ * dm-snapshot.c
+ *
+ * Copyright (C) 2001-2002 Sistina Software (UK) Limited.
+ *
+ * This file is released under the GPL.
+ */
+
+#include "dm.h"
+#include "dm-snap.h"
+#include "dm-io.h"
+#include "kcopyd.h"
+
+#include <linux/mm.h>
+#include <linux/pagemap.h>
+#include <linux/vmalloc.h>
+#include <linux/slab.h>
+
+/*-----------------------------------------------------------------
+ * Persistent snapshots, by persistent we mean that the snapshot
+ * will survive a reboot.
+ *---------------------------------------------------------------*/
+
+/*
+ * We need to store a record of which parts of the origin have
+ * been copied to the snapshot device.  The snapshot code
+ * requires that we copy exception chunks to chunk aligned areas
+ * of the COW store.  It makes sense therefore, to store the
+ * metadata in chunk size blocks.
+ *
+ * There is no backward or forward compatibility implemented,
+ * snapshots with different disk versions than the kernel will
+ * not be usable.  It is expected that "lvcreate" will blank out
+ * the start of a fresh COW device before calling the snapshot
+ * constructor.
+ *
+ * The first chunk of the COW device just contains the header.
+ * After this there is a chunk filled with exception metadata,
+ * followed by as many exception chunks as can fit in the
+ * metadata areas.
+ *
+ * All on disk structures are in little-endian format.  The end
+ * of the exceptions info is indicated by an exception with a
+ * new_chunk of 0, which is invalid since it would point to the
+ * header chunk.
+ */
+
+/*
+ * Magic for persistent snapshots: "SnAp" - Feeble isn't it.
+ */
+#define SNAP_MAGIC 0x70416e53
+
+/*
+ * The on-disk version of the metadata.
+ */
+#define SNAPSHOT_DISK_VERSION 1
+
+struct disk_header {
+	uint32_t magic;
+
+	/*
+	 * Is this snapshot valid.  There is no way of recovering
+	 * an invalid snapshot.
+	 */
+	uint32_t valid;
+
+	/*
+	 * Simple, incrementing version. no backward
+	 * compatibility.
+	 */
+	uint32_t version;
+
+	/* In sectors */
+	uint32_t chunk_size;
+};
+
+struct disk_exception {
+	uint64_t old_chunk;
+	uint64_t new_chunk;
+};
+
+struct commit_callback {
+	void (*callback)(void *, int success);
+	void *context;
+};
+
+/*
+ * The top level structure for a persistent exception store.
+ */
+struct pstore {
+	struct dm_snapshot *snap;	/* up pointer to my snapshot */
+	int version;
+	int valid;
+	uint32_t chunk_size;
+	uint32_t exceptions_per_area;
+
+	/*
+	 * Now that we have an asynchronous kcopyd there is no
+	 * need for large chunk sizes, so it wont hurt to have a
+	 * whole chunks worth of metadata in memory at once.
+	 */
+	void *area;
+
+	/*
+	 * Used to keep track of which metadata area the data in
+	 * 'chunk' refers to.
+	 */
+	uint32_t current_area;
+
+	/*
+	 * The next free chunk for an exception.
+	 */
+	uint32_t next_free;
+
+	/*
+	 * The index of next free exception in the current
+	 * metadata area.
+	 */
+	uint32_t current_committed;
+
+	atomic_t pending_count;
+	uint32_t callback_count;
+	struct commit_callback *callbacks;
+};
+
+static inline unsigned int sectors_to_pages(unsigned int sectors)
+{
+	return sectors / (PAGE_SIZE >> 9);
+}
+
+static int alloc_area(struct pstore *ps)
+{
+	int r = -ENOMEM;
+	size_t len;
+
+	len = ps->chunk_size << SECTOR_SHIFT;
+
+	/*
+	 * Allocate the chunk_size block of memory that will hold
+	 * a single metadata area.
+	 */
+	ps->area = vmalloc(len);
+	if (!ps->area)
+		return r;
+
+	return 0;
+}
+
+static void free_area(struct pstore *ps)
+{
+	vfree(ps->area);
+}
+
+/*
+ * Read or write a chunk aligned and sized block of data from a device.
+ */
+static int chunk_io(struct pstore *ps, uint32_t chunk, int rw)
+{
+	struct io_region where;
+	unsigned long bits;
+
+	where.bdev = ps->snap->cow->bdev;
+	where.sector = ps->chunk_size * chunk;
+	where.count = ps->chunk_size;
+
+	return dm_io_sync_vm(1, &where, rw, ps->area, &bits);
+}
+
+/*
+ * Read or write a metadata area.  Remembering to skip the first
+ * chunk which holds the header.
+ */
+static int area_io(struct pstore *ps, uint32_t area, int rw)
+{
+	int r;
+	uint32_t chunk;
+
+	/* convert a metadata area index to a chunk index */
+	chunk = 1 + ((ps->exceptions_per_area + 1) * area);
+
+	r = chunk_io(ps, chunk, rw);
+	if (r)
+		return r;
+
+	ps->current_area = area;
+	return 0;
+}
+
+static int zero_area(struct pstore *ps, uint32_t area)
+{
+	memset(ps->area, 0, ps->chunk_size << SECTOR_SHIFT);
+	return area_io(ps, area, WRITE);
+}
+
+static int read_header(struct pstore *ps, int *new_snapshot)
+{
+	int r;
+	struct disk_header *dh;
+
+	r = chunk_io(ps, 0, READ);
+	if (r)
+		return r;
+
+	dh = (struct disk_header *) ps->area;
+
+	if (le32_to_cpu(dh->magic) == 0) {
+		*new_snapshot = 1;
+
+	} else if (le32_to_cpu(dh->magic) == SNAP_MAGIC) {
+		*new_snapshot = 0;
+		ps->valid = le32_to_cpu(dh->valid);
+		ps->version = le32_to_cpu(dh->version);
+		ps->chunk_size = le32_to_cpu(dh->chunk_size);
+
+	} else {
+		DMWARN("Invalid/corrupt snapshot");
+		r = -ENXIO;
+	}
+
+	return r;
+}
+
+static int write_header(struct pstore *ps)
+{
+	struct disk_header *dh;
+
+	memset(ps->area, 0, ps->chunk_size << SECTOR_SHIFT);
+
+	dh = (struct disk_header *) ps->area;
+	dh->magic = cpu_to_le32(SNAP_MAGIC);
+	dh->valid = cpu_to_le32(ps->valid);
+	dh->version = cpu_to_le32(ps->version);
+	dh->chunk_size = cpu_to_le32(ps->chunk_size);
+
+	return chunk_io(ps, 0, WRITE);
+}
+
+/*
+ * Access functions for the disk exceptions, these do the endian conversions.
+ */
+static struct disk_exception *get_exception(struct pstore *ps, uint32_t index)
+{
+	if (index >= ps->exceptions_per_area)
+		return NULL;
+
+	return ((struct disk_exception *) ps->area) + index;
+}
+
+static int read_exception(struct pstore *ps,
+			  uint32_t index, struct disk_exception *result)
+{
+	struct disk_exception *e;
+
+	e = get_exception(ps, index);
+	if (!e)
+		return -EINVAL;
+
+	/* copy it */
+	result->old_chunk = le64_to_cpu(e->old_chunk);
+	result->new_chunk = le64_to_cpu(e->new_chunk);
+
+	return 0;
+}
+
+static int write_exception(struct pstore *ps,
+			   uint32_t index, struct disk_exception *de)
+{
+	struct disk_exception *e;
+
+	e = get_exception(ps, index);
+	if (!e)
+		return -EINVAL;
+
+	/* copy it */
+	e->old_chunk = cpu_to_le64(de->old_chunk);
+	e->new_chunk = cpu_to_le64(de->new_chunk);
+
+	return 0;
+}
+
+/*
+ * Registers the exceptions that are present in the current area.
+ * 'full' is filled in to indicate if the area has been
+ * filled.
+ */
+static int insert_exceptions(struct pstore *ps, int *full)
+{
+	int r;
+	unsigned int i;
+	struct disk_exception de;
+
+	/* presume the area is full */
+	*full = 1;
+
+	for (i = 0; i < ps->exceptions_per_area; i++) {
+		r = read_exception(ps, i, &de);
+
+		if (r)
+			return r;
+
+		/*
+		 * If the new_chunk is pointing at the start of
+		 * the COW device, where the first metadata area
+		 * is we know that we've hit the end of the
+		 * exceptions.  Therefore the area is not full.
+		 */
+		if (de.new_chunk == 0LL) {
+			ps->current_committed = i;
+			*full = 0;
+			break;
+		}
+
+		/*
+		 * Keep track of the start of the free chunks.
+		 */
+		if (ps->next_free <= de.new_chunk)
+			ps->next_free = de.new_chunk + 1;
+
+		/*
+		 * Otherwise we add the exception to the snapshot.
+		 */
+		r = dm_add_exception(ps->snap, de.old_chunk, de.new_chunk);
+		if (r)
+			return r;
+	}
+
+	return 0;
+}
+
+static int read_exceptions(struct pstore *ps)
+{
+	uint32_t area;
+	int r, full = 1;
+
+	/*
+	 * Keeping reading chunks and inserting exceptions until
+	 * we find a partially full area.
+	 */
+	for (area = 0; full; area++) {
+		r = area_io(ps, area, READ);
+		if (r)
+			return r;
+
+		r = insert_exceptions(ps, &full);
+		if (r)
+			return r;
+	}
+
+	return 0;
+}
+
+static inline struct pstore *get_info(struct exception_store *store)
+{
+	return (struct pstore *) store->context;
+}
+
+static void persistent_fraction_full(struct exception_store *store,
+				     sector_t *numerator, sector_t *denominator)
+{
+	*numerator = get_info(store)->next_free * store->snap->chunk_size;
+	*denominator = get_dev_size(store->snap->cow->bdev);
+}
+
+static void persistent_destroy(struct exception_store *store)
+{
+	struct pstore *ps = get_info(store);
+
+	dm_io_put(sectors_to_pages(ps->chunk_size));
+	vfree(ps->callbacks);
+	free_area(ps);
+	kfree(ps);
+}
+
+static int persistent_read_metadata(struct exception_store *store)
+{
+	int r, new_snapshot;
+	struct pstore *ps = get_info(store);
+
+	/*
+	 * Read the snapshot header.
+	 */
+	r = read_header(ps, &new_snapshot);
+	if (r)
+		return r;
+
+	/*
+	 * Do we need to setup a new snapshot ?
+	 */
+	if (new_snapshot) {
+		r = write_header(ps);
+		if (r) {
+			DMWARN("write_header failed");
+			return r;
+		}
+
+		r = zero_area(ps, 0);
+		if (r) {
+			DMWARN("zero_area(0) failed");
+			return r;
+		}
+
+	} else {
+		/*
+		 * Sanity checks.
+		 */
+		if (!ps->valid) {
+			DMWARN("snapshot is marked invalid");
+			return -EINVAL;
+		}
+
+		if (ps->version != SNAPSHOT_DISK_VERSION) {
+			DMWARN("unable to handle snapshot disk version %d",
+			       ps->version);
+			return -EINVAL;
+		}
+
+		/*
+		 * Read the metadata.
+		 */
+		r = read_exceptions(ps);
+		if (r)
+			return r;
+	}
+
+	return 0;
+}
+
+static int persistent_prepare(struct exception_store *store,
+			      struct exception *e)
+{
+	struct pstore *ps = get_info(store);
+	uint32_t stride;
+	sector_t size = get_dev_size(store->snap->cow->bdev);
+
+	/* Is there enough room ? */
+	if (size < ((ps->next_free + 1) * store->snap->chunk_size))
+		return -ENOSPC;
+
+	e->new_chunk = ps->next_free;
+
+	/*
+	 * Move onto the next free pending, making sure to take
+	 * into account the location of the metadata chunks.
+	 */
+	stride = (ps->exceptions_per_area + 1);
+	if ((++ps->next_free % stride) == 1)
+		ps->next_free++;
+
+	atomic_inc(&ps->pending_count);
+	return 0;
+}
+
+static void persistent_commit(struct exception_store *store,
+			      struct exception *e,
+			      void (*callback) (void *, int success),
+			      void *callback_context)
+{
+	int r;
+	unsigned int i;
+	struct pstore *ps = get_info(store);
+	struct disk_exception de;
+	struct commit_callback *cb;
+
+	de.old_chunk = e->old_chunk;
+	de.new_chunk = e->new_chunk;
+	write_exception(ps, ps->current_committed++, &de);
+
+	/*
+	 * Add the callback to the back of the array.  This code
+	 * is the only place where the callback array is
+	 * manipulated, and we know that it will never be called
+	 * multiple times concurrently.
+	 */
+	cb = ps->callbacks + ps->callback_count++;
+	cb->callback = callback;
+	cb->context = callback_context;
+
+	/*
+	 * If there are no more exceptions in flight, or we have
+	 * filled this metadata area we commit the exceptions to
+	 * disk.
+	 */
+	if (atomic_dec_and_test(&ps->pending_count) ||
+	    (ps->current_committed == ps->exceptions_per_area)) {
+		r = area_io(ps, ps->current_area, WRITE);
+		if (r)
+			ps->valid = 0;
+
+		for (i = 0; i < ps->callback_count; i++) {
+			cb = ps->callbacks + i;
+			cb->callback(cb->context, r == 0 ? 1 : 0);
+		}
+
+		ps->callback_count = 0;
+	}
+
+	/*
+	 * Have we completely filled the current area ?
+	 */
+	if (ps->current_committed == ps->exceptions_per_area) {
+		ps->current_committed = 0;
+		r = zero_area(ps, ps->current_area + 1);
+		if (r)
+			ps->valid = 0;
+	}
+}
+
+static void persistent_drop(struct exception_store *store)
+{
+	struct pstore *ps = get_info(store);
+
+	ps->valid = 0;
+	if (write_header(ps))
+		DMWARN("write header failed");
+}
+
+int dm_create_persistent(struct exception_store *store, uint32_t chunk_size)
+{
+	int r;
+	struct pstore *ps;
+
+	r = dm_io_get(sectors_to_pages(chunk_size));
+	if (r)
+		return r;
+
+	/* allocate the pstore */
+	ps = kmalloc(sizeof(*ps), GFP_KERNEL);
+	if (!ps) {
+		r = -ENOMEM;
+		goto bad;
+	}
+
+	ps->snap = store->snap;
+	ps->valid = 1;
+	ps->version = SNAPSHOT_DISK_VERSION;
+	ps->chunk_size = chunk_size;
+	ps->exceptions_per_area = (chunk_size << SECTOR_SHIFT) /
+	    sizeof(struct disk_exception);
+	ps->next_free = 2;	/* skipping the header and first area */
+	ps->current_committed = 0;
+
+	r = alloc_area(ps);
+	if (r)
+		goto bad;
+
+	/*
+	 * Allocate space for all the callbacks.
+	 */
+	ps->callback_count = 0;
+	atomic_set(&ps->pending_count, 0);
+	ps->callbacks = dm_vcalloc(ps->exceptions_per_area,
+				   sizeof(*ps->callbacks));
+
+	if (!ps->callbacks) {
+		r = -ENOMEM;
+		goto bad;
+	}
+
+	store->destroy = persistent_destroy;
+	store->read_metadata = persistent_read_metadata;
+	store->prepare_exception = persistent_prepare;
+	store->commit_exception = persistent_commit;
+	store->drop_snapshot = persistent_drop;
+	store->fraction_full = persistent_fraction_full;
+	store->context = ps;
+
+	return 0;
+
+      bad:
+	dm_io_put(sectors_to_pages(chunk_size));
+	if (ps) {
+		if (ps->callbacks)
+			vfree(ps->callbacks);
+
+		kfree(ps);
+	}
+	return r;
+}
+
+/*-----------------------------------------------------------------
+ * Implementation of the store for non-persistent snapshots.
+ *---------------------------------------------------------------*/
+struct transient_c {
+	sector_t next_free;
+};
+
+static void transient_destroy(struct exception_store *store)
+{
+	kfree(store->context);
+}
+
+static int transient_read_metadata(struct exception_store *store)
+{
+	return 0;
+}
+
+static int transient_prepare(struct exception_store *store, struct exception *e)
+{
+	struct transient_c *tc = (struct transient_c *) store->context;
+	sector_t size = get_dev_size(store->snap->cow->bdev);
+
+	if (size < (tc->next_free + store->snap->chunk_size))
+		return -1;
+
+	e->new_chunk = sector_to_chunk(store->snap, tc->next_free);
+	tc->next_free += store->snap->chunk_size;
+
+	return 0;
+}
+
+static void transient_commit(struct exception_store *store,
+		      struct exception *e,
+		      void (*callback) (void *, int success),
+		      void *callback_context)
+{
+	/* Just succeed */
+	callback(callback_context, 1);
+}
+
+static void transient_fraction_full(struct exception_store *store,
+				    sector_t *numerator, sector_t *denominator)
+{
+	*numerator = ((struct transient_c *) store->context)->next_free;
+	*denominator = get_dev_size(store->snap->cow->bdev);
+}
+
+int dm_create_transient(struct exception_store *store,
+			struct dm_snapshot *s, int blocksize)
+{
+	struct transient_c *tc;
+
+	memset(store, 0, sizeof(*store));
+	store->destroy = transient_destroy;
+	store->read_metadata = transient_read_metadata;
+	store->prepare_exception = transient_prepare;
+	store->commit_exception = transient_commit;
+	store->fraction_full = transient_fraction_full;
+	store->snap = s;
+
+	tc = kmalloc(sizeof(struct transient_c), GFP_KERNEL);
+	if (!tc)
+		return -ENOMEM;
+
+	tc->next_free = 0;
+	store->context = tc;
+
+	return 0;
+}
--- diff/drivers/md/dm-io.c	1970-01-01 01:00:00.000000000 +0100
+++ source/drivers/md/dm-io.c	2004-06-11 19:22:02.000000000 +0100
@@ -0,0 +1,637 @@
+/*
+ * Copyright (C) 2003 Sistina Software
+ *
+ * This file is released under the GPL.
+ */
+
+#include "dm-io.h"
+
+#include <linux/bio.h>
+#include <linux/mempool.h>
+#include <linux/module.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+
+#define BIO_POOL_SIZE 256
+
+
+/*-----------------------------------------------------------------
+ * Bio set, move this to bio.c
+ *---------------------------------------------------------------*/
+#define BV_NAME_SIZE 16
+struct biovec_pool {
+	int nr_vecs;
+	char name[BV_NAME_SIZE];
+	kmem_cache_t *slab;
+	mempool_t *pool;
+	atomic_t allocated;	/* FIXME: debug */
+};
+
+#define BIOVEC_NR_POOLS 6
+struct bio_set {
+	char name[BV_NAME_SIZE];
+	kmem_cache_t *bio_slab;
+	mempool_t *bio_pool;
+	struct biovec_pool pools[BIOVEC_NR_POOLS];
+};
+
+static void bio_set_exit(struct bio_set *bs)
+{
+	unsigned i;
+	struct biovec_pool *bp;
+
+	if (bs->bio_pool)
+		mempool_destroy(bs->bio_pool);
+
+	if (bs->bio_slab)
+		kmem_cache_destroy(bs->bio_slab);
+
+	for (i = 0; i < BIOVEC_NR_POOLS; i++) {
+		bp = bs->pools + i;
+		if (bp->pool)
+			mempool_destroy(bp->pool);
+
+		if (bp->slab)
+			kmem_cache_destroy(bp->slab);
+	}
+}
+
+static void mk_name(char *str, size_t len, const char *prefix, unsigned count)
+{
+	snprintf(str, len, "%s-%u", prefix, count);
+}
+
+static int bio_set_init(struct bio_set *bs, const char *slab_prefix,
+			 unsigned pool_entries, unsigned scale)
+{
+	/* FIXME: this must match bvec_index(), why not go the
+	 * whole hog and have a pool per power of 2 ? */
+	static unsigned _vec_lengths[BIOVEC_NR_POOLS] = {
+		1, 4, 16, 64, 128, BIO_MAX_PAGES
+	};
+
+
+	unsigned i, size;
+	struct biovec_pool *bp;
+
+	/* zero the bs so we can tear down properly on error */
+	memset(bs, 0, sizeof(*bs));
+
+	/*
+	 * Set up the bio pool.
+	 */
+	snprintf(bs->name, sizeof(bs->name), "%s-bio", slab_prefix);
+
+	bs->bio_slab = kmem_cache_create(bs->name, sizeof(struct bio), 0,
+					 SLAB_HWCACHE_ALIGN, NULL, NULL);
+	if (!bs->bio_slab) {
+		DMWARN("can't init bio slab");
+		goto bad;
+	}
+
+	bs->bio_pool = mempool_create(pool_entries, mempool_alloc_slab,
+				      mempool_free_slab, bs->bio_slab);
+	if (!bs->bio_pool) {
+		DMWARN("can't init bio pool");
+		goto bad;
+	}
+
+	/*
+	 * Set up the biovec pools.
+	 */
+	for (i = 0; i < BIOVEC_NR_POOLS; i++) {
+		bp = bs->pools + i;
+		bp->nr_vecs = _vec_lengths[i];
+		atomic_set(&bp->allocated, 1); /* FIXME: debug */
+
+
+		size = bp->nr_vecs * sizeof(struct bio_vec);
+
+		mk_name(bp->name, sizeof(bp->name), slab_prefix, i);
+		bp->slab = kmem_cache_create(bp->name, size, 0,
+					     SLAB_HWCACHE_ALIGN, NULL, NULL);
+		if (!bp->slab) {
+			DMWARN("can't init biovec slab cache");
+			goto bad;
+		}
+
+		if (i >= scale)
+			pool_entries >>= 1;
+
+		bp->pool = mempool_create(pool_entries, mempool_alloc_slab,
+					  mempool_free_slab, bp->slab);
+		if (!bp->pool) {
+			DMWARN("can't init biovec mempool");
+			goto bad;
+		}
+	}
+
+	return 0;
+
+ bad:
+	bio_set_exit(bs);
+	return -ENOMEM;
+}
+
+/* FIXME: blech */
+static inline unsigned bvec_index(unsigned nr)
+{
+	switch (nr) {
+	case 1:		return 0;
+	case 2 ... 4: 	return 1;
+	case 5 ... 16:	return 2;
+	case 17 ... 64:	return 3;
+	case 65 ... 128:return 4;
+	case 129 ... BIO_MAX_PAGES: return 5;
+	}
+
+	BUG();
+	return 0;
+}
+
+static inline void bs_bio_init(struct bio *bio)
+{
+	bio->bi_next = NULL;
+	bio->bi_flags = 1 << BIO_UPTODATE;
+	bio->bi_rw = 0;
+	bio->bi_vcnt = 0;
+	bio->bi_idx = 0;
+	bio->bi_phys_segments = 0;
+	bio->bi_hw_segments = 0;
+	bio->bi_size = 0;
+	bio->bi_max_vecs = 0;
+	bio->bi_end_io = NULL;
+	atomic_set(&bio->bi_cnt, 1);
+	bio->bi_private = NULL;
+}
+
+static unsigned _bio_count = 0;
+struct bio *bio_set_alloc(struct bio_set *bs, int gfp_mask, int nr_iovecs)
+{
+	struct biovec_pool *bp;
+	struct bio_vec *bv = NULL;
+	unsigned long idx;
+	struct bio *bio;
+
+	bio = mempool_alloc(bs->bio_pool, gfp_mask);
+	if (unlikely(!bio))
+		return NULL;
+
+	bio_init(bio);
+
+	if (likely(nr_iovecs)) {
+		idx = bvec_index(nr_iovecs);
+		bp = bs->pools + idx;
+		bv = mempool_alloc(bp->pool, gfp_mask);
+		if (!bv) {
+			mempool_free(bio, bs->bio_pool);
+			return NULL;
+		}
+
+		memset(bv, 0, bp->nr_vecs * sizeof(*bv));
+		bio->bi_flags |= idx << BIO_POOL_OFFSET;
+		bio->bi_max_vecs = bp->nr_vecs;
+		atomic_inc(&bp->allocated);
+	}
+
+	bio->bi_io_vec = bv;
+	return bio;
+}
+
+static void bio_set_free(struct bio_set *bs, struct bio *bio)
+{
+	struct biovec_pool *bp = bs->pools + BIO_POOL_IDX(bio);
+
+	if (atomic_dec_and_test(&bp->allocated))
+		BUG();
+
+	mempool_free(bio->bi_io_vec, bp->pool);
+	mempool_free(bio, bs->bio_pool);
+}
+
+/*-----------------------------------------------------------------
+ * dm-io proper
+ *---------------------------------------------------------------*/
+static struct bio_set _bios;
+
+/* FIXME: can we shrink this ? */
+struct io {
+	unsigned long error;
+	atomic_t count;
+	struct task_struct *sleeper;
+	io_notify_fn callback;
+	void *context;
+};
+
+/*
+ * io contexts are only dynamically allocated for asynchronous
+ * io.  Since async io is likely to be the majority of io we'll
+ * have the same number of io contexts as buffer heads ! (FIXME:
+ * must reduce this).
+ */
+static unsigned _num_ios;
+static mempool_t *_io_pool;
+
+static void *alloc_io(int gfp_mask, void *pool_data)
+{
+	return kmalloc(sizeof(struct io), gfp_mask);
+}
+
+static void free_io(void *element, void *pool_data)
+{
+	kfree(element);
+}
+
+static unsigned int pages_to_ios(unsigned int pages)
+{
+	return 4 * pages;	/* too many ? */
+}
+
+static int resize_pool(unsigned int new_ios)
+{
+	int r = 0;
+
+	if (_io_pool) {
+		if (new_ios == 0) {
+			/* free off the pool */
+			mempool_destroy(_io_pool);
+			_io_pool = NULL;
+			bio_set_exit(&_bios);
+
+		} else {
+			/* resize the pool */
+			r = mempool_resize(_io_pool, new_ios, GFP_KERNEL);
+		}
+
+	} else {
+		/* create new pool */
+		_io_pool = mempool_create(new_ios, alloc_io, free_io, NULL);
+		if (!_io_pool)
+			r = -ENOMEM;
+
+		r = bio_set_init(&_bios, "dm-io", 512, 1);
+		if (r) {
+			mempool_destroy(_io_pool);
+			_io_pool = NULL;
+		}
+	}
+
+	if (!r)
+		_num_ios = new_ios;
+
+	return r;
+}
+
+int dm_io_get(unsigned int num_pages)
+{
+	return resize_pool(_num_ios + pages_to_ios(num_pages));
+}
+
+void dm_io_put(unsigned int num_pages)
+{
+	resize_pool(_num_ios - pages_to_ios(num_pages));
+}
+
+/*-----------------------------------------------------------------
+ * We need to keep track of which region a bio is doing io for.
+ * In order to save a memory allocation we store this the last
+ * bvec which we know is unused (blech).
+ *---------------------------------------------------------------*/
+static inline void bio_set_region(struct bio *bio, unsigned region)
+{
+	bio->bi_io_vec[bio->bi_max_vecs - 1].bv_len = region;
+}
+
+static inline unsigned bio_get_region(struct bio *bio)
+{
+	return bio->bi_io_vec[bio->bi_max_vecs - 1].bv_len;
+}
+
+/*-----------------------------------------------------------------
+ * We need an io object to keep track of the number of bios that
+ * have been dispatched for a particular io.
+ *---------------------------------------------------------------*/
+static void dec_count(struct io *io, unsigned int region, int error)
+{
+	if (error)
+		set_bit(region, &io->error);
+
+	if (atomic_dec_and_test(&io->count)) {
+		if (io->sleeper)
+			wake_up_process(io->sleeper);
+
+		else {
+			int r = io->error;
+			io_notify_fn fn = io->callback;
+			void *context = io->context;
+
+			mempool_free(io, _io_pool);
+			fn(r, context);
+		}
+	}
+}
+
+/* FIXME Move this to bio.h? */
+static void zero_fill_bio(struct bio *bio)
+{
+	unsigned long flags;
+	struct bio_vec *bv;
+	int i;
+
+	bio_for_each_segment(bv, bio, i) {
+		char *data = bvec_kmap_irq(bv, &flags);
+		memset(data, 0, bv->bv_len);
+		flush_dcache_page(bv->bv_page);
+		bvec_kunmap_irq(data, &flags);
+	}
+}
+
+static int endio(struct bio *bio, unsigned int done, int error)
+{
+	struct io *io = (struct io *) bio->bi_private;
+
+	/* keep going until we've finished */
+	if (bio->bi_size)
+		return 1;
+
+	if (error && bio_data_dir(bio) == READ)
+		zero_fill_bio(bio);
+
+	dec_count(io, bio_get_region(bio), error);
+	bio_put(bio);
+
+	return 0;
+}
+
+static void bio_dtr(struct bio *bio)
+{
+	_bio_count--;
+	bio_set_free(&_bios, bio);
+}
+
+/*-----------------------------------------------------------------
+ * These little objects provide an abstraction for getting a new
+ * destination page for io.
+ *---------------------------------------------------------------*/
+struct dpages {
+	void (*get_page)(struct dpages *dp,
+			 struct page **p, unsigned long *len, unsigned *offset);
+	void (*next_page)(struct dpages *dp);
+
+	unsigned context_u;
+	void *context_ptr;
+};
+
+/*
+ * Functions for getting the pages from a list.
+ */
+static void list_get_page(struct dpages *dp,
+		  struct page **p, unsigned long *len, unsigned *offset)
+{
+	unsigned o = dp->context_u;
+	struct page_list *pl = (struct page_list *) dp->context_ptr;
+
+	*p = pl->page;
+	*len = PAGE_SIZE - o;
+	*offset = o;
+}
+
+static void list_next_page(struct dpages *dp)
+{
+	struct page_list *pl = (struct page_list *) dp->context_ptr;
+	dp->context_ptr = pl->next;
+	dp->context_u = 0;
+}
+
+static void list_dp_init(struct dpages *dp, struct page_list *pl, unsigned offset)
+{
+	dp->get_page = list_get_page;
+	dp->next_page = list_next_page;
+	dp->context_u = offset;
+	dp->context_ptr = pl;
+}
+
+/*
+ * Functions for getting the pages from a bvec.
+ */
+static void bvec_get_page(struct dpages *dp,
+		  struct page **p, unsigned long *len, unsigned *offset)
+{
+	struct bio_vec *bvec = (struct bio_vec *) dp->context_ptr;
+	*p = bvec->bv_page;
+	*len = bvec->bv_len;
+	*offset = bvec->bv_offset;
+}
+
+static void bvec_next_page(struct dpages *dp)
+{
+	struct bio_vec *bvec = (struct bio_vec *) dp->context_ptr;
+	dp->context_ptr = bvec + 1;
+}
+
+static void bvec_dp_init(struct dpages *dp, struct bio_vec *bvec)
+{
+	dp->get_page = bvec_get_page;
+	dp->next_page = bvec_next_page;
+	dp->context_ptr = bvec;
+}
+
+static void vm_get_page(struct dpages *dp,
+		 struct page **p, unsigned long *len, unsigned *offset)
+{
+	*p = vmalloc_to_page(dp->context_ptr);
+	*offset = dp->context_u;
+	*len = PAGE_SIZE - dp->context_u;
+}
+
+static void vm_next_page(struct dpages *dp)
+{
+	dp->context_ptr += PAGE_SIZE - dp->context_u;
+	dp->context_u = 0;
+}
+
+static void vm_dp_init(struct dpages *dp, void *data)
+{
+	dp->get_page = vm_get_page;
+	dp->next_page = vm_next_page;
+	dp->context_u = ((unsigned long) data) & (PAGE_SIZE - 1);
+	dp->context_ptr = data;
+}
+
+/*-----------------------------------------------------------------
+ * IO routines that accept a list of pages.
+ *---------------------------------------------------------------*/
+static void do_region(int rw, unsigned int region, struct io_region *where,
+		      struct dpages *dp, struct io *io)
+{
+	struct bio *bio;
+	struct page *page;
+	unsigned long len;
+	unsigned offset;
+	unsigned num_bvecs;
+	sector_t remaining = where->count;
+
+	while (remaining) {
+		/*
+		 * Allocate a suitably sized bio, we add an extra
+		 * bvec for bio_get/set_region().
+		 */
+		num_bvecs = (remaining / (PAGE_SIZE >> 9)) + 2;
+		_bio_count++;
+		bio = bio_set_alloc(&_bios, GFP_NOIO, num_bvecs);
+		bio->bi_sector = where->sector + (where->count - remaining);
+		bio->bi_bdev = where->bdev;
+		bio->bi_end_io = endio;
+		bio->bi_private = io;
+		bio->bi_destructor = bio_dtr;
+		bio_set_region(bio, region);
+
+		/*
+		 * Try and add as many pages as possible.
+		 */
+		while (remaining) {
+			dp->get_page(dp, &page, &len, &offset);
+			len = min(len, to_bytes(remaining));
+			if (!bio_add_page(bio, page, len, offset))
+				break;
+
+			offset = 0;
+			remaining -= to_sector(len);
+			dp->next_page(dp);
+		}
+
+		atomic_inc(&io->count);
+		submit_bio(rw, bio);
+	}
+}
+
+static void dispatch_io(int rw, unsigned int num_regions,
+			struct io_region *where, struct dpages *dp,
+			struct io *io, int sync)
+{
+	int i;
+	struct dpages old_pages = *dp;
+
+	if (sync)
+		rw |= (1 << BIO_RW_SYNC);
+
+	/*
+	 * For multiple regions we need to be careful to rewind
+	 * the dp object for each call to do_region.
+	 */
+	for (i = 0; i < num_regions; i++) {
+		*dp = old_pages;
+		if (where[i].count)
+			do_region(rw, i, where + i, dp, io);
+	}
+
+	/*
+	 * Drop the extra refence that we were holding to avoid
+	 * the io being completed too early.
+	 */
+	dec_count(io, 0, 0);
+}
+
+static int sync_io(unsigned int num_regions, struct io_region *where,
+	    int rw, struct dpages *dp, unsigned long *error_bits)
+{
+	struct io io;
+
+	BUG_ON(num_regions > 1 && rw != WRITE);
+
+	io.error = 0;
+	atomic_set(&io.count, 1); /* see dispatch_io() */
+	io.sleeper = current;
+
+	dispatch_io(rw, num_regions, where, dp, &io, 1);
+
+	while (1) {
+		set_current_state(TASK_UNINTERRUPTIBLE);
+
+		if (!atomic_read(&io.count) || signal_pending(current))
+			break;
+
+		io_schedule();
+	}
+	set_current_state(TASK_RUNNING);
+
+	if (atomic_read(&io.count))
+		return -EINTR;
+
+	*error_bits = io.error;
+	return io.error ? -EIO : 0;
+}
+
+static int async_io(unsigned int num_regions, struct io_region *where, int rw,
+	     struct dpages *dp, io_notify_fn fn, void *context)
+{
+	struct io *io = mempool_alloc(_io_pool, GFP_NOIO);
+
+	io->error = 0;
+	atomic_set(&io->count, 1); /* see dispatch_io() */
+	io->sleeper = NULL;
+	io->callback = fn;
+	io->context = context;
+
+	dispatch_io(rw, num_regions, where, dp, io, 0);
+	return 0;
+}
+
+int dm_io_sync(unsigned int num_regions, struct io_region *where, int rw,
+	       struct page_list *pl, unsigned int offset,
+	       unsigned long *error_bits)
+{
+	struct dpages dp;
+	list_dp_init(&dp, pl, offset);
+	return sync_io(num_regions, where, rw, &dp, error_bits);
+}
+
+int dm_io_sync_bvec(unsigned int num_regions, struct io_region *where, int rw,
+		    struct bio_vec *bvec, unsigned long *error_bits)
+{
+	struct dpages dp;
+	bvec_dp_init(&dp, bvec);
+	return sync_io(num_regions, where, rw, &dp, error_bits);
+}
+
+int dm_io_sync_vm(unsigned int num_regions, struct io_region *where, int rw,
+		  void *data, unsigned long *error_bits)
+{
+	struct dpages dp;
+	vm_dp_init(&dp, data);
+	return sync_io(num_regions, where, rw, &dp, error_bits);
+}
+
+int dm_io_async(unsigned int num_regions, struct io_region *where, int rw,
+		struct page_list *pl, unsigned int offset,
+		io_notify_fn fn, void *context)
+{
+	struct dpages dp;
+	list_dp_init(&dp, pl, offset);
+	return async_io(num_regions, where, rw, &dp, fn, context);
+}
+
+int dm_io_async_bvec(unsigned int num_regions, struct io_region *where, int rw,
+		     struct bio_vec *bvec, io_notify_fn fn, void *context)
+{
+	struct dpages dp;
+	bvec_dp_init(&dp, bvec);
+	return async_io(num_regions, where, rw, &dp, fn, context);
+}
+
+int dm_io_async_vm(unsigned int num_regions, struct io_region *where, int rw,
+		   void *data, io_notify_fn fn, void *context)
+{
+	struct dpages dp;
+	vm_dp_init(&dp, data);
+	return async_io(num_regions, where, rw, &dp, fn, context);
+}
+
+EXPORT_SYMBOL(dm_io_get);
+EXPORT_SYMBOL(dm_io_put);
+EXPORT_SYMBOL(dm_io_sync);
+EXPORT_SYMBOL(dm_io_async);
+EXPORT_SYMBOL(dm_io_sync_bvec);
+EXPORT_SYMBOL(dm_io_async_bvec);
+EXPORT_SYMBOL(dm_io_sync_vm);
+EXPORT_SYMBOL(dm_io_async_vm);
--- diff/drivers/md/dm-io.h	1970-01-01 01:00:00.000000000 +0100
+++ source/drivers/md/dm-io.h	2004-06-11 19:22:02.000000000 +0100
@@ -0,0 +1,77 @@
+/*
+ * Copyright (C) 2003 Sistina Software
+ *
+ * This file is released under the GPL.
+ */
+
+#ifndef _DM_IO_H
+#define _DM_IO_H
+
+#include "dm.h"
+
+/* FIXME make this configurable */
+#define DM_MAX_IO_REGIONS 8
+
+struct io_region {
+	struct block_device *bdev;
+	sector_t sector;
+	sector_t count;
+};
+
+struct page_list {
+	struct page_list *next;
+	struct page *page;
+};
+
+
+/*
+ * 'error' is a bitset, with each bit indicating whether an error
+ * occurred doing io to the corresponding region.
+ */
+typedef void (*io_notify_fn)(unsigned long error, void *context);
+
+
+/*
+ * Before anyone uses the IO interface they should call
+ * dm_io_get(), specifying roughly how many pages they are
+ * expecting to perform io on concurrently.
+ *
+ * This function may block.
+ */
+int dm_io_get(unsigned int num_pages);
+void dm_io_put(unsigned int num_pages);
+
+/*
+ * Synchronous IO.
+ *
+ * Please ensure that the rw flag in the next two functions is
+ * either READ or WRITE, ie. we don't take READA.  Any
+ * regions with a zero count field will be ignored.
+ */
+int dm_io_sync(unsigned int num_regions, struct io_region *where, int rw,
+	       struct page_list *pl, unsigned int offset,
+	       unsigned long *error_bits);
+
+int dm_io_sync_bvec(unsigned int num_regions, struct io_region *where, int rw,
+		    struct bio_vec *bvec, unsigned long *error_bits);
+
+int dm_io_sync_vm(unsigned int num_regions, struct io_region *where, int rw,
+		  void *data, unsigned long *error_bits);
+
+/*
+ * Aynchronous IO.
+ *
+ * The 'where' array may be safely allocated on the stack since
+ * the function takes a copy.
+ */
+int dm_io_async(unsigned int num_regions, struct io_region *where, int rw,
+		struct page_list *pl, unsigned int offset,
+		io_notify_fn fn, void *context);
+
+int dm_io_async_bvec(unsigned int num_regions, struct io_region *where, int rw,
+		     struct bio_vec *bvec, io_notify_fn fn, void *context);
+
+int dm_io_async_vm(unsigned int num_regions, struct io_region *where, int rw,
+		   void *data, io_notify_fn fn, void *context);
+
+#endif
--- diff/drivers/md/dm-log.c	1970-01-01 01:00:00.000000000 +0100
+++ source/drivers/md/dm-log.c	2004-06-11 19:22:02.000000000 +0100
@@ -0,0 +1,629 @@
+/*
+ * Copyright (C) 2003 Sistina Software
+ *
+ * This file is released under the LGPL.
+ */
+
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/vmalloc.h>
+
+#include "dm-log.h"
+#include "dm-io.h"
+
+static LIST_HEAD(_log_types);
+static spinlock_t _lock = SPIN_LOCK_UNLOCKED;
+
+int dm_register_dirty_log_type(struct dirty_log_type *type)
+{
+	if (!try_module_get(type->module))
+		return -EINVAL;
+
+	spin_lock(&_lock);
+	type->use_count = 0;
+	list_add(&type->list, &_log_types);
+	spin_unlock(&_lock);
+
+	return 0;
+}
+
+int dm_unregister_dirty_log_type(struct dirty_log_type *type)
+{
+	spin_lock(&_lock);
+
+	if (type->use_count)
+		DMWARN("Attempt to unregister a log type that is still in use");
+	else {
+		list_del(&type->list);
+		module_put(type->module);
+	}
+
+	spin_unlock(&_lock);
+
+	return 0;
+}
+
+static struct dirty_log_type *get_type(const char *type_name)
+{
+	struct dirty_log_type *type;
+
+	spin_lock(&_lock);
+	list_for_each_entry (type, &_log_types, list)
+		if (!strcmp(type_name, type->name)) {
+			type->use_count++;
+			spin_unlock(&_lock);
+			return type;
+		}
+
+	spin_unlock(&_lock);
+	return NULL;
+}
+
+static void put_type(struct dirty_log_type *type)
+{
+	spin_lock(&_lock);
+	type->use_count--;
+	spin_unlock(&_lock);
+}
+
+struct dirty_log *dm_create_dirty_log(const char *type_name, struct dm_target *ti,
+				      unsigned int argc, char **argv)
+{
+	struct dirty_log_type *type;
+	struct dirty_log *log;
+
+	log = kmalloc(sizeof(*log), GFP_KERNEL);
+	if (!log)
+		return NULL;
+
+	type = get_type(type_name);
+	if (!type) {
+		kfree(log);
+		return NULL;
+	}
+
+	log->type = type;
+	if (type->ctr(log, ti, argc, argv)) {
+		kfree(log);
+		put_type(type);
+		return NULL;
+	}
+
+	return log;
+}
+
+void dm_destroy_dirty_log(struct dirty_log *log)
+{
+	log->type->dtr(log);
+	put_type(log->type);
+	kfree(log);
+}
+
+/*-----------------------------------------------------------------
+ * Persistent and core logs share a lot of their implementation.
+ * FIXME: need a reload method to be called from a resume
+ *---------------------------------------------------------------*/
+/*
+ * Magic for persistent mirrors: "MiRr"
+ */
+#define MIRROR_MAGIC 0x4D695272
+
+/*
+ * The on-disk version of the metadata.
+ */
+#define MIRROR_DISK_VERSION 1
+#define LOG_OFFSET 2
+
+struct log_header {
+	uint32_t magic;
+
+	/*
+	 * Simple, incrementing version. no backward
+	 * compatibility.
+	 */
+	uint32_t version;
+	sector_t nr_regions;
+};
+
+struct log_c {
+	struct dm_target *ti;
+	int touched;
+	sector_t region_size;
+	unsigned int region_count;
+	region_t sync_count;
+
+	unsigned bitset_uint32_count;
+	uint32_t *clean_bits;
+	uint32_t *sync_bits;
+	uint32_t *recovering_bits;	/* FIXME: this seems excessive */
+
+	int sync_search;
+
+	/*
+	 * Disk log fields
+	 */
+	struct dm_dev *log_dev;
+	struct log_header header;
+
+	struct io_region header_location;
+	struct log_header *disk_header;
+
+	struct io_region bits_location;
+	uint32_t *disk_bits;
+};
+
+/*
+ * The touched member needs to be updated every time we access
+ * one of the bitsets.
+ */
+static  inline int log_test_bit(uint32_t *bs, unsigned bit)
+{
+	return test_bit(bit, (unsigned long *) bs) ? 1 : 0;
+}
+
+static inline void log_set_bit(struct log_c *l,
+			       uint32_t *bs, unsigned bit)
+{
+	set_bit(bit, (unsigned long *) bs);
+	l->touched = 1;
+}
+
+static inline void log_clear_bit(struct log_c *l,
+				 uint32_t *bs, unsigned bit)
+{
+	clear_bit(bit, (unsigned long *) bs);
+	l->touched = 1;
+}
+
+/*----------------------------------------------------------------
+ * Header IO
+ *--------------------------------------------------------------*/
+static void header_to_disk(struct log_header *core, struct log_header *disk)
+{
+	disk->magic = cpu_to_le32(core->magic);
+	disk->version = cpu_to_le32(core->version);
+	disk->nr_regions = cpu_to_le64(core->nr_regions);
+}
+
+static void header_from_disk(struct log_header *core, struct log_header *disk)
+{
+	core->magic = le32_to_cpu(disk->magic);
+	core->version = le32_to_cpu(disk->version);
+	core->nr_regions = le64_to_cpu(disk->nr_regions);
+}
+
+static int read_header(struct log_c *log)
+{
+	int r;
+	unsigned long ebits;
+
+	r = dm_io_sync_vm(1, &log->header_location, READ,
+			  log->disk_header, &ebits);
+	if (r)
+		return r;
+
+	header_from_disk(&log->header, log->disk_header);
+
+	if (log->header.magic != MIRROR_MAGIC) {
+		log->header.magic = MIRROR_MAGIC;
+		log->header.version = MIRROR_DISK_VERSION;
+		log->header.nr_regions = 0;
+	}
+
+	if (log->header.version != MIRROR_DISK_VERSION) {
+		DMWARN("incompatible disk log version");
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static inline int write_header(struct log_c *log)
+{
+	unsigned long ebits;
+
+	header_to_disk(&log->header, log->disk_header);
+	return dm_io_sync_vm(1, &log->header_location, WRITE,
+			     log->disk_header, &ebits);
+}
+
+/*----------------------------------------------------------------
+ * Bits IO
+ *--------------------------------------------------------------*/
+static inline void bits_to_core(uint32_t *core, uint32_t *disk, unsigned count)
+{
+	unsigned i;
+
+	for (i = 0; i < count; i++)
+		core[i] = le32_to_cpu(disk[i]);
+}
+
+static inline void bits_to_disk(uint32_t *core, uint32_t *disk, unsigned count)
+{
+	unsigned i;
+
+	/* copy across the clean/dirty bitset */
+	for (i = 0; i < count; i++)
+		disk[i] = cpu_to_le32(core[i]);
+}
+
+static int read_bits(struct log_c *log)
+{
+	int r;
+	unsigned long ebits;
+
+	r = dm_io_sync_vm(1, &log->bits_location, READ,
+			  log->disk_bits, &ebits);
+	if (r)
+		return r;
+
+	bits_to_core(log->clean_bits, log->disk_bits,
+		     log->bitset_uint32_count);
+	return 0;
+}
+
+static int write_bits(struct log_c *log)
+{
+	unsigned long ebits;
+	bits_to_disk(log->clean_bits, log->disk_bits,
+		     log->bitset_uint32_count);
+	return dm_io_sync_vm(1, &log->bits_location, WRITE,
+			     log->disk_bits, &ebits);
+}
+
+/*----------------------------------------------------------------
+ * constructor/destructor
+ *--------------------------------------------------------------*/
+#define BYTE_SHIFT 3
+static int core_ctr(struct dirty_log *log, struct dm_target *ti,
+		    unsigned int argc, char **argv)
+{
+	struct log_c *lc;
+	sector_t region_size;
+	unsigned int region_count;
+	size_t bitset_size;
+
+	if (argc != 1) {
+		DMWARN("wrong number of arguments to log_c");
+		return -EINVAL;
+	}
+
+	if (sscanf(argv[0], SECTOR_FORMAT, &region_size) != 1) {
+		DMWARN("invalid region size string");
+		return -EINVAL;
+	}
+
+	region_count = dm_div_up(ti->len, region_size);
+
+	lc = kmalloc(sizeof(*lc), GFP_KERNEL);
+	if (!lc) {
+		DMWARN("couldn't allocate core log");
+		return -ENOMEM;
+	}
+
+	lc->ti = ti;
+	lc->touched = 0;
+	lc->region_size = region_size;
+	lc->region_count = region_count;
+
+	/*
+	 * Work out how many words we need to hold the bitset.
+	 */
+	bitset_size = dm_round_up(region_count,
+				  sizeof(*lc->clean_bits) << BYTE_SHIFT);
+	bitset_size >>= BYTE_SHIFT;
+
+	lc->bitset_uint32_count = bitset_size / 4;
+	lc->clean_bits = vmalloc(bitset_size);
+	if (!lc->clean_bits) {
+		DMWARN("couldn't allocate clean bitset");
+		kfree(lc);
+		return -ENOMEM;
+	}
+	memset(lc->clean_bits, -1, bitset_size);
+
+	lc->sync_bits = vmalloc(bitset_size);
+	if (!lc->sync_bits) {
+		DMWARN("couldn't allocate sync bitset");
+		vfree(lc->clean_bits);
+		kfree(lc);
+		return -ENOMEM;
+	}
+	memset(lc->sync_bits, 0, bitset_size);
+        lc->sync_count = 0;
+
+	lc->recovering_bits = vmalloc(bitset_size);
+	if (!lc->recovering_bits) {
+		DMWARN("couldn't allocate sync bitset");
+		vfree(lc->sync_bits);
+		vfree(lc->clean_bits);
+		kfree(lc);
+		return -ENOMEM;
+	}
+	memset(lc->recovering_bits, 0, bitset_size);
+	lc->sync_search = 0;
+	log->context = lc;
+	return 0;
+}
+
+static void core_dtr(struct dirty_log *log)
+{
+	struct log_c *lc = (struct log_c *) log->context;
+	vfree(lc->clean_bits);
+	vfree(lc->sync_bits);
+	vfree(lc->recovering_bits);
+	kfree(lc);
+}
+
+static int disk_ctr(struct dirty_log *log, struct dm_target *ti,
+		    unsigned int argc, char **argv)
+{
+	int r;
+	size_t size;
+	struct log_c *lc;
+	struct dm_dev *dev;
+
+	if (argc != 2) {
+		DMWARN("wrong number of arguments to log_d");
+		return -EINVAL;
+	}
+
+	r = dm_get_device(ti, argv[0], 0, 0 /* FIXME */,
+			  FMODE_READ | FMODE_WRITE, &dev);
+	if (r)
+		return r;
+
+	r = core_ctr(log, ti, argc - 1, argv + 1);
+	if (r) {
+		dm_put_device(ti, dev);
+		return r;
+	}
+
+	lc = (struct log_c *) log->context;
+	lc->log_dev = dev;
+
+	/* setup the disk header fields */
+	lc->header_location.bdev = lc->log_dev->bdev;
+	lc->header_location.sector = 0;
+	lc->header_location.count = 1;
+
+	/*
+	 * We can't read less than this amount, even though we'll
+	 * not be using most of this space.
+	 */
+	lc->disk_header = vmalloc(1 << SECTOR_SHIFT);
+	if (!lc->disk_header)
+		goto bad;
+
+	/* setup the disk bitset fields */
+	lc->bits_location.bdev = lc->log_dev->bdev;
+	lc->bits_location.sector = LOG_OFFSET;
+
+	size = dm_round_up(lc->bitset_uint32_count * sizeof(uint32_t),
+			   1 << SECTOR_SHIFT);
+	lc->bits_location.count = size >> SECTOR_SHIFT;
+	lc->disk_bits = vmalloc(size);
+	if (!lc->disk_bits) {
+		vfree(lc->disk_header);
+		goto bad;
+	}
+	return 0;
+
+ bad:
+	dm_put_device(ti, lc->log_dev);
+	core_dtr(log);
+	return -ENOMEM;
+}
+
+static void disk_dtr(struct dirty_log *log)
+{
+	struct log_c *lc = (struct log_c *) log->context;
+	dm_put_device(lc->ti, lc->log_dev);
+	vfree(lc->disk_header);
+	vfree(lc->disk_bits);
+	core_dtr(log);
+}
+
+static int count_bits32(uint32_t *addr, unsigned size)
+{
+	int count = 0, i;
+
+	for (i = 0; i < size; i++) {
+		count += hweight32(*(addr+i));
+	}
+	return count;
+}
+
+static int disk_resume(struct dirty_log *log)
+{
+	int r;
+	unsigned i;
+	struct log_c *lc = (struct log_c *) log->context;
+	size_t size = lc->bitset_uint32_count * sizeof(uint32_t);
+
+	/* read the disk header */
+	r = read_header(lc);
+	if (r)
+		return r;
+
+	/* read the bits */
+	r = read_bits(lc);
+	if (r)
+		return r;
+
+	/* zero any new bits if the mirror has grown */
+	for (i = lc->header.nr_regions; i < lc->region_count; i++)
+		/* FIXME: amazingly inefficient */
+		log_clear_bit(lc, lc->clean_bits, i);
+
+	/* copy clean across to sync */
+	memcpy(lc->sync_bits, lc->clean_bits, size);
+	lc->sync_count = count_bits32(lc->clean_bits, lc->bitset_uint32_count);
+
+	/* write the bits */
+	r = write_bits(lc);
+	if (r)
+		return r;
+
+	/* set the correct number of regions in the header */
+	lc->header.nr_regions = lc->region_count;
+
+	/* write the new header */
+	return write_header(lc);
+}
+
+static sector_t core_get_region_size(struct dirty_log *log)
+{
+	struct log_c *lc = (struct log_c *) log->context;
+	return lc->region_size;
+}
+
+static int core_is_clean(struct dirty_log *log, region_t region)
+{
+	struct log_c *lc = (struct log_c *) log->context;
+	return log_test_bit(lc->clean_bits, region);
+}
+
+static int core_in_sync(struct dirty_log *log, region_t region, int block)
+{
+	struct log_c *lc = (struct log_c *) log->context;
+	return log_test_bit(lc->sync_bits, region);
+}
+
+static int core_flush(struct dirty_log *log)
+{
+	/* no op */
+	return 0;
+}
+
+static int disk_flush(struct dirty_log *log)
+{
+	int r;
+	struct log_c *lc = (struct log_c *) log->context;
+
+	/* only write if the log has changed */
+	if (!lc->touched)
+		return 0;
+
+	r = write_bits(lc);
+	if (!r)
+		lc->touched = 0;
+
+	return r;
+}
+
+static void core_mark_region(struct dirty_log *log, region_t region)
+{
+	struct log_c *lc = (struct log_c *) log->context;
+	log_clear_bit(lc, lc->clean_bits, region);
+}
+
+static void core_clear_region(struct dirty_log *log, region_t region)
+{
+	struct log_c *lc = (struct log_c *) log->context;
+	log_set_bit(lc, lc->clean_bits, region);
+}
+
+static int core_get_resync_work(struct dirty_log *log, region_t *region)
+{
+	struct log_c *lc = (struct log_c *) log->context;
+
+	if (lc->sync_search >= lc->region_count)
+		return 0;
+
+	do {
+		*region = find_next_zero_bit((unsigned long *) lc->sync_bits,
+					     lc->region_count,
+					     lc->sync_search);
+		lc->sync_search = *region + 1;
+
+		if (*region == lc->region_count)
+			return 0;
+
+	} while (log_test_bit(lc->recovering_bits, *region));
+
+	log_set_bit(lc, lc->recovering_bits, *region);
+	return 1;
+}
+
+static void core_complete_resync_work(struct dirty_log *log, region_t region,
+				      int success)
+{
+	struct log_c *lc = (struct log_c *) log->context;
+
+	log_clear_bit(lc, lc->recovering_bits, region);
+	if (success) {
+		log_set_bit(lc, lc->sync_bits, region);
+                lc->sync_count++;
+        }
+}
+
+static region_t core_get_sync_count(struct dirty_log *log)
+{
+        struct log_c *lc = (struct log_c *) log->context;
+
+        return lc->sync_count;
+}
+
+static struct dirty_log_type _core_type = {
+	.name = "core",
+	.module = THIS_MODULE,
+	.ctr = core_ctr,
+	.dtr = core_dtr,
+	.get_region_size = core_get_region_size,
+	.is_clean = core_is_clean,
+	.in_sync = core_in_sync,
+	.flush = core_flush,
+	.mark_region = core_mark_region,
+	.clear_region = core_clear_region,
+	.get_resync_work = core_get_resync_work,
+	.complete_resync_work = core_complete_resync_work,
+        .get_sync_count = core_get_sync_count
+};
+
+static struct dirty_log_type _disk_type = {
+	.name = "disk",
+	.module = THIS_MODULE,
+	.ctr = disk_ctr,
+	.dtr = disk_dtr,
+	.suspend = disk_flush,
+	.resume = disk_resume,
+	.get_region_size = core_get_region_size,
+	.is_clean = core_is_clean,
+	.in_sync = core_in_sync,
+	.flush = disk_flush,
+	.mark_region = core_mark_region,
+	.clear_region = core_clear_region,
+	.get_resync_work = core_get_resync_work,
+	.complete_resync_work = core_complete_resync_work,
+        .get_sync_count = core_get_sync_count
+};
+
+int __init dm_dirty_log_init(void)
+{
+	int r;
+
+	r = dm_register_dirty_log_type(&_core_type);
+	if (r)
+		DMWARN("couldn't register core log");
+
+	r = dm_register_dirty_log_type(&_disk_type);
+	if (r) {
+		DMWARN("couldn't register disk type");
+		dm_unregister_dirty_log_type(&_core_type);
+	}
+
+	return r;
+}
+
+void dm_dirty_log_exit(void)
+{
+	dm_unregister_dirty_log_type(&_disk_type);
+	dm_unregister_dirty_log_type(&_core_type);
+}
+
+EXPORT_SYMBOL(dm_register_dirty_log_type);
+EXPORT_SYMBOL(dm_unregister_dirty_log_type);
+EXPORT_SYMBOL(dm_create_dirty_log);
+EXPORT_SYMBOL(dm_destroy_dirty_log);
--- diff/drivers/md/dm-log.h	1970-01-01 01:00:00.000000000 +0100
+++ source/drivers/md/dm-log.h	2004-06-11 19:22:02.000000000 +0100
@@ -0,0 +1,124 @@
+/*
+ * Copyright (C) 2003 Sistina Software
+ *
+ * This file is released under the LGPL.
+ */
+
+#ifndef DM_DIRTY_LOG
+#define DM_DIRTY_LOG
+
+#include "dm.h"
+
+typedef sector_t region_t;
+
+struct dirty_log_type;
+
+struct dirty_log {
+	struct dirty_log_type *type;
+	void *context;
+};
+
+struct dirty_log_type {
+	struct list_head list;
+	const char *name;
+	struct module *module;
+	unsigned int use_count;
+
+	int (*ctr)(struct dirty_log *log, struct dm_target *ti,
+		   unsigned int argc, char **argv);
+	void (*dtr)(struct dirty_log *log);
+
+	/*
+	 * There are times when we don't want the log to touch
+	 * the disk.
+	 */
+	int (*suspend)(struct dirty_log *log);
+	int (*resume)(struct dirty_log *log);
+
+	/*
+	 * Retrieves the smallest size of region that the log can
+	 * deal with.
+	 */
+	sector_t (*get_region_size)(struct dirty_log *log);
+
+        /*
+	 * A predicate to say whether a region is clean or not.
+	 * May block.
+	 */
+	int (*is_clean)(struct dirty_log *log, region_t region);
+
+	/*
+	 *  Returns: 0, 1, -EWOULDBLOCK, < 0
+	 *
+	 * A predicate function to check the area given by
+	 * [sector, sector + len) is in sync.
+	 *
+	 * If -EWOULDBLOCK is returned the state of the region is
+	 * unknown, typically this will result in a read being
+	 * passed to a daemon to deal with, since a daemon is
+	 * allowed to block.
+	 */
+	int (*in_sync)(struct dirty_log *log, region_t region, int can_block);
+
+	/*
+	 * Flush the current log state (eg, to disk).  This
+	 * function may block.
+	 */
+	int (*flush)(struct dirty_log *log);
+
+	/*
+	 * Mark an area as clean or dirty.  These functions may
+	 * block, though for performance reasons blocking should
+	 * be extremely rare (eg, allocating another chunk of
+	 * memory for some reason).
+	 */
+	void (*mark_region)(struct dirty_log *log, region_t region);
+	void (*clear_region)(struct dirty_log *log, region_t region);
+
+	/*
+	 * Returns: <0 (error), 0 (no region), 1 (region)
+	 *
+	 * The mirrord will need perform recovery on regions of
+	 * the mirror that are in the NOSYNC state.  This
+	 * function asks the log to tell the caller about the
+	 * next region that this machine should recover.
+	 *
+	 * Do not confuse this function with 'in_sync()', one
+	 * tells you if an area is synchronised, the other
+	 * assigns recovery work.
+	*/
+	int (*get_resync_work)(struct dirty_log *log, region_t *region);
+
+	/*
+	 * This notifies the log that the resync of an area has
+	 * been completed.  The log should then mark this region
+	 * as CLEAN.
+	 */
+	void (*complete_resync_work)(struct dirty_log *log,
+				     region_t region, int success);
+
+        /*
+	 * Returns the number of regions that are in sync.
+         */
+        region_t (*get_sync_count)(struct dirty_log *log);
+};
+
+int dm_register_dirty_log_type(struct dirty_log_type *type);
+int dm_unregister_dirty_log_type(struct dirty_log_type *type);
+
+
+/*
+ * Make sure you use these two functions, rather than calling
+ * type->constructor/destructor() directly.
+ */
+struct dirty_log *dm_create_dirty_log(const char *type_name, struct dm_target *ti,
+				      unsigned int argc, char **argv);
+void dm_destroy_dirty_log(struct dirty_log *log);
+
+/*
+ * init/exit functions.
+ */
+int dm_dirty_log_init(void);
+void dm_dirty_log_exit(void);
+
+#endif
--- diff/drivers/md/dm-raid1.c	1970-01-01 01:00:00.000000000 +0100
+++ source/drivers/md/dm-raid1.c	2004-06-11 19:22:02.000000000 +0100
@@ -0,0 +1,1283 @@
+/*
+ * Copyright (C) 2003 Sistina Software Limited.
+ *
+ * This file is released under the GPL.
+ */
+
+#include "dm.h"
+#include "dm-bio-list.h"
+#include "dm-io.h"
+#include "dm-log.h"
+#include "kcopyd.h"
+
+#include <linux/ctype.h>
+#include <linux/init.h>
+#include <linux/mempool.h>
+#include <linux/module.h>
+#include <linux/pagemap.h>
+#include <linux/slab.h>
+#include <linux/time.h>
+#include <linux/vmalloc.h>
+#include <linux/workqueue.h>
+
+static struct workqueue_struct *_kmirrord_wq;
+static struct work_struct _kmirrord_work;
+
+static inline void wake(void)
+{
+	queue_work(_kmirrord_wq, &_kmirrord_work);
+}
+
+/*-----------------------------------------------------------------
+ * Region hash
+ *
+ * The mirror splits itself up into discrete regions.  Each
+ * region can be in one of three states: clean, dirty,
+ * nosync.  There is no need to put clean regions in the hash.
+ *
+ * In addition to being present in the hash table a region _may_
+ * be present on one of three lists.
+ *
+ *   clean_regions: Regions on this list have no io pending to
+ *   them, they are in sync, we are no longer interested in them,
+ *   they are dull.  rh_update_states() will remove them from the
+ *   hash table.
+ *
+ *   quiesced_regions: These regions have been spun down, ready
+ *   for recovery.  rh_recovery_start() will remove regions from
+ *   this list and hand them to kmirrord, which will schedule the
+ *   recovery io with kcopyd.
+ *
+ *   recovered_regions: Regions that kcopyd has successfully
+ *   recovered.  rh_update_states() will now schedule any delayed
+ *   io, up the recovery_count, and remove the region from the
+ *   hash.
+ *
+ * There are 2 locks:
+ *   A rw spin lock 'hash_lock' protects just the hash table,
+ *   this is never held in write mode from interrupt context,
+ *   which I believe means that we only have to disable irqs when
+ *   doing a write lock.
+ *
+ *   An ordinary spin lock 'region_lock' that protects the three
+ *   lists in the region_hash, with the 'state', 'list' and
+ *   'bhs_delayed' fields of the regions.  This is used from irq
+ *   context, so all other uses will have to suspend local irqs.
+ *---------------------------------------------------------------*/
+struct mirror_set;
+struct region_hash {
+	struct mirror_set *ms;
+	sector_t region_size;
+	unsigned region_shift;
+
+	/* holds persistent region state */
+	struct dirty_log *log;
+
+	/* hash table */
+	rwlock_t hash_lock;
+	mempool_t *region_pool;
+	unsigned int mask;
+	unsigned int nr_buckets;
+	struct list_head *buckets;
+
+	spinlock_t region_lock;
+	struct semaphore recovery_count;
+	struct list_head clean_regions;
+	struct list_head quiesced_regions;
+	struct list_head recovered_regions;
+};
+
+enum {
+	RH_CLEAN,
+	RH_DIRTY,
+	RH_NOSYNC,
+	RH_RECOVERING
+};
+
+struct region {
+	struct region_hash *rh;	/* FIXME: can we get rid of this ? */
+	region_t key;
+	int state;
+
+	struct list_head hash_list;
+	struct list_head list;
+
+	atomic_t pending;
+	struct bio *delayed_bios;
+};
+
+/*
+ * Conversion fns
+ */
+static inline region_t bio_to_region(struct region_hash *rh, struct bio *bio)
+{
+	return bio->bi_sector >> rh->region_shift;
+}
+
+static inline sector_t region_to_sector(struct region_hash *rh, region_t region)
+{
+	return region << rh->region_shift;
+}
+
+/* FIXME move this */
+static void queue_bio(struct mirror_set *ms, struct bio *bio, int rw);
+
+static void *region_alloc(int gfp_mask, void *pool_data)
+{
+	return kmalloc(sizeof(struct region), gfp_mask);
+}
+
+static void region_free(void *element, void *pool_data)
+{
+	kfree(element);
+}
+
+#define MIN_REGIONS 64
+#define MAX_RECOVERY 1
+static int rh_init(struct region_hash *rh, struct mirror_set *ms,
+		   struct dirty_log *log, sector_t region_size,
+		   region_t nr_regions)
+{
+	unsigned int nr_buckets, max_buckets;
+	size_t i;
+
+	/*
+	 * Calculate a suitable number of buckets for our hash
+	 * table.
+	 */
+	max_buckets = nr_regions >> 6;
+	for (nr_buckets = 128u; nr_buckets < max_buckets; nr_buckets <<= 1)
+		;
+	nr_buckets >>= 1;
+
+	rh->ms = ms;
+	rh->log = log;
+	rh->region_size = region_size;
+	rh->region_shift = ffs(region_size) - 1;
+	rwlock_init(&rh->hash_lock);
+	rh->mask = nr_buckets - 1;
+	rh->nr_buckets = nr_buckets;
+
+	rh->buckets = vmalloc(nr_buckets * sizeof(*rh->buckets));
+	if (!rh->buckets) {
+		DMERR("unable to allocate region hash memory");
+		return -ENOMEM;
+	}
+
+	for (i = 0; i < nr_buckets; i++)
+		INIT_LIST_HEAD(rh->buckets + i);
+
+	spin_lock_init(&rh->region_lock);
+	sema_init(&rh->recovery_count, 0);
+	INIT_LIST_HEAD(&rh->clean_regions);
+	INIT_LIST_HEAD(&rh->quiesced_regions);
+	INIT_LIST_HEAD(&rh->recovered_regions);
+
+	rh->region_pool = mempool_create(MIN_REGIONS, region_alloc,
+					 region_free, NULL);
+	if (!rh->region_pool) {
+		vfree(rh->buckets);
+		rh->buckets = NULL;
+		return -ENOMEM;
+	}
+
+	return 0;
+}
+
+static void rh_exit(struct region_hash *rh)
+{
+	unsigned int h;
+	struct region *reg;
+	struct list_head *tmp, *tmp2;
+
+	BUG_ON(!list_empty(&rh->quiesced_regions));
+	for (h = 0; h < rh->nr_buckets; h++) {
+		list_for_each_safe (tmp, tmp2, rh->buckets + h) {
+			reg = list_entry(tmp, struct region, hash_list);
+			BUG_ON(atomic_read(&reg->pending));
+			mempool_free(reg, rh->region_pool);
+		}
+	}
+
+	if (rh->log)
+		dm_destroy_dirty_log(rh->log);
+	if (rh->region_pool)
+		mempool_destroy(rh->region_pool);
+	vfree(rh->buckets);
+}
+
+#define RH_HASH_MULT 2654435387U
+
+static inline unsigned int rh_hash(struct region_hash *rh, region_t region)
+{
+	return (unsigned int) ((region * RH_HASH_MULT) >> 12) & rh->mask;
+}
+
+static struct region *__rh_lookup(struct region_hash *rh, region_t region)
+{
+	struct region *reg;
+
+	list_for_each_entry (reg, rh->buckets + rh_hash(rh, region), hash_list)
+		if (reg->key == region)
+			return reg;
+
+	return NULL;
+}
+
+static void __rh_insert(struct region_hash *rh, struct region *reg)
+{
+	unsigned int h = rh_hash(rh, reg->key);
+	list_add(&reg->hash_list, rh->buckets + h);
+}
+
+static struct region *__rh_alloc(struct region_hash *rh, region_t region)
+{
+	struct region *reg, *nreg;
+
+	read_unlock(&rh->hash_lock);
+	nreg = mempool_alloc(rh->region_pool, GFP_NOIO);
+	nreg->state = rh->log->type->in_sync(rh->log, region, 1) ?
+		RH_CLEAN : RH_NOSYNC;
+	nreg->rh = rh;
+	nreg->key = region;
+
+	INIT_LIST_HEAD(&nreg->list);
+
+	atomic_set(&nreg->pending, 0);
+	nreg->delayed_bios = NULL;
+	write_lock_irq(&rh->hash_lock);
+
+	reg = __rh_lookup(rh, region);
+	if (reg)
+		/* we lost the race */
+		mempool_free(nreg, rh->region_pool);
+
+	else {
+		__rh_insert(rh, nreg);
+		if (nreg->state == RH_CLEAN) {
+			spin_lock_irq(&rh->region_lock);
+			list_add(&nreg->list, &rh->clean_regions);
+			spin_unlock_irq(&rh->region_lock);
+		}
+		reg = nreg;
+	}
+	write_unlock_irq(&rh->hash_lock);
+	read_lock(&rh->hash_lock);
+
+	return reg;
+}
+
+static inline struct region *__rh_find(struct region_hash *rh, region_t region)
+{
+	struct region *reg;
+
+	reg = __rh_lookup(rh, region);
+	if (!reg)
+		reg = __rh_alloc(rh, region);
+
+	return reg;
+}
+
+static int rh_state(struct region_hash *rh, region_t region, int may_block)
+{
+	int r;
+	struct region *reg;
+
+	read_lock(&rh->hash_lock);
+	reg = __rh_lookup(rh, region);
+	read_unlock(&rh->hash_lock);
+
+	if (reg)
+		return reg->state;
+
+	/*
+	 * The region wasn't in the hash, so we fall back to the
+	 * dirty log.
+	 */
+	r = rh->log->type->in_sync(rh->log, region, may_block);
+
+	/*
+	 * Any error from the dirty log (eg. -EWOULDBLOCK) gets
+	 * taken as a RH_NOSYNC
+	 */
+	return r == 1 ? RH_CLEAN : RH_NOSYNC;
+}
+
+static inline int rh_in_sync(struct region_hash *rh,
+			     region_t region, int may_block)
+{
+	int state = rh_state(rh, region, may_block);
+	return state == RH_CLEAN || state == RH_DIRTY;
+}
+
+static void dispatch_bios(struct mirror_set *ms, struct bio *bio)
+{
+	struct bio *nbio;
+
+	while (bio) {
+		nbio = bio->bi_next;
+		queue_bio(ms, bio, WRITE);
+		bio = nbio;
+	}
+}
+
+static void rh_update_states(struct region_hash *rh)
+{
+	struct region *reg, *next;
+
+	LIST_HEAD(clean);
+	LIST_HEAD(recovered);
+
+	/*
+	 * Quickly grab the lists.
+	 */
+	write_lock_irq(&rh->hash_lock);
+	spin_lock(&rh->region_lock);
+	if (!list_empty(&rh->clean_regions)) {
+		list_splice(&rh->clean_regions, &clean);
+		INIT_LIST_HEAD(&rh->clean_regions);
+
+		list_for_each_entry (reg, &clean, list) {
+			rh->log->type->clear_region(rh->log, reg->key);
+			list_del(&reg->hash_list);
+		}
+	}
+
+	if (!list_empty(&rh->recovered_regions)) {
+		list_splice(&rh->recovered_regions, &recovered);
+		INIT_LIST_HEAD(&rh->recovered_regions);
+
+		list_for_each_entry (reg, &recovered, list)
+			list_del(&reg->hash_list);
+	}
+	spin_unlock(&rh->region_lock);
+	write_unlock_irq(&rh->hash_lock);
+
+	/*
+	 * All the regions on the recovered and clean lists have
+	 * now been pulled out of the system, so no need to do
+	 * any more locking.
+	 */
+	list_for_each_entry_safe (reg, next, &recovered, list) {
+		rh->log->type->clear_region(rh->log, reg->key);
+		rh->log->type->complete_resync_work(rh->log, reg->key, 1);
+		dispatch_bios(rh->ms, reg->delayed_bios);
+		up(&rh->recovery_count);
+		mempool_free(reg, rh->region_pool);
+	}
+
+	if (!list_empty(&recovered))
+		rh->log->type->flush(rh->log);
+
+	list_for_each_entry_safe (reg, next, &clean, list)
+		mempool_free(reg, rh->region_pool);
+}
+
+static void rh_inc(struct region_hash *rh, region_t region)
+{
+	struct region *reg;
+
+	read_lock(&rh->hash_lock);
+	reg = __rh_find(rh, region);
+	if (reg->state == RH_CLEAN) {
+		rh->log->type->mark_region(rh->log, reg->key);
+
+		spin_lock_irq(&rh->region_lock);
+		reg->state = RH_DIRTY;
+		list_del_init(&reg->list);	/* take off the clean list */
+		spin_unlock_irq(&rh->region_lock);
+	}
+
+	atomic_inc(&reg->pending);
+	read_unlock(&rh->hash_lock);
+}
+
+static void rh_inc_pending(struct region_hash *rh, struct bio_list *bios)
+{
+	struct bio *bio;
+
+	for (bio = bios->head; bio; bio = bio->bi_next)
+		rh_inc(rh, bio_to_region(rh, bio));
+}
+
+static void rh_dec(struct region_hash *rh, region_t region)
+{
+	unsigned long flags;
+	struct region *reg;
+	int should_wake = 0;
+
+	read_lock(&rh->hash_lock);
+	reg = __rh_lookup(rh, region);
+	read_unlock(&rh->hash_lock);
+
+	if (atomic_dec_and_test(&reg->pending)) {
+		spin_lock_irqsave(&rh->region_lock, flags);
+		if (reg->state == RH_RECOVERING) {
+			list_add_tail(&reg->list, &rh->quiesced_regions);
+		} else {
+			reg->state = RH_CLEAN;
+			list_add(&reg->list, &rh->clean_regions);
+		}
+		spin_unlock_irqrestore(&rh->region_lock, flags);
+		should_wake = 1;
+	}
+
+	if (should_wake)
+		wake();
+}
+
+/*
+ * Starts quiescing a region in preparation for recovery.
+ */
+static int __rh_recovery_prepare(struct region_hash *rh)
+{
+	int r;
+	struct region *reg;
+	region_t region;
+
+	/*
+	 * Ask the dirty log what's next.
+	 */
+	r = rh->log->type->get_resync_work(rh->log, &region);
+	if (r <= 0)
+		return r;
+
+	/*
+	 * Get this region, and start it quiescing by setting the
+	 * recovering flag.
+	 */
+	read_lock(&rh->hash_lock);
+	reg = __rh_find(rh, region);
+	read_unlock(&rh->hash_lock);
+
+	spin_lock_irq(&rh->region_lock);
+	reg->state = RH_RECOVERING;
+
+	/* Already quiesced ? */
+	if (atomic_read(&reg->pending))
+		list_del_init(&reg->list);
+
+	else {
+		list_del_init(&reg->list);
+		list_add(&reg->list, &rh->quiesced_regions);
+	}
+	spin_unlock_irq(&rh->region_lock);
+
+	return 1;
+}
+
+static void rh_recovery_prepare(struct region_hash *rh)
+{
+	while (!down_trylock(&rh->recovery_count))
+		if (__rh_recovery_prepare(rh) <= 0) {
+			up(&rh->recovery_count);
+			break;
+		}
+}
+
+/*
+ * Returns any quiesced regions.
+ */
+static struct region *rh_recovery_start(struct region_hash *rh)
+{
+	struct region *reg = NULL;
+
+	spin_lock_irq(&rh->region_lock);
+	if (!list_empty(&rh->quiesced_regions)) {
+		reg = list_entry(rh->quiesced_regions.next,
+				 struct region, list);
+		list_del_init(&reg->list);	/* remove from the quiesced list */
+	}
+	spin_unlock_irq(&rh->region_lock);
+
+	return reg;
+}
+
+/* FIXME: success ignored for now */
+static void rh_recovery_end(struct region *reg, int success)
+{
+	struct region_hash *rh = reg->rh;
+
+	spin_lock_irq(&rh->region_lock);
+	list_add(&reg->list, &reg->rh->recovered_regions);
+	spin_unlock_irq(&rh->region_lock);
+
+	wake();
+}
+
+static void rh_flush(struct region_hash *rh)
+{
+	rh->log->type->flush(rh->log);
+}
+
+static void rh_delay(struct region_hash *rh, struct bio *bio)
+{
+	struct region *reg;
+
+	read_lock(&rh->hash_lock);
+	reg = __rh_find(rh, bio_to_region(rh, bio));
+	bio->bi_next = reg->delayed_bios;
+	reg->delayed_bios = bio;
+	read_unlock(&rh->hash_lock);
+}
+
+static void rh_stop_recovery(struct region_hash *rh)
+{
+	int i;
+
+	/* wait for any recovering regions */
+	for (i = 0; i < MAX_RECOVERY; i++)
+		down(&rh->recovery_count);
+}
+
+static void rh_start_recovery(struct region_hash *rh)
+{
+	int i;
+
+	for (i = 0; i < MAX_RECOVERY; i++)
+		up(&rh->recovery_count);
+
+	wake();
+}
+
+/*-----------------------------------------------------------------
+ * Mirror set structures.
+ *---------------------------------------------------------------*/
+struct mirror {
+	atomic_t error_count;
+	struct dm_dev *dev;
+	sector_t offset;
+};
+
+struct mirror_set {
+	struct dm_target *ti;
+	struct list_head list;
+	struct region_hash rh;
+	struct kcopyd_client *kcopyd_client;
+
+	spinlock_t lock;	/* protects the next two lists */
+	struct bio_list reads;
+	struct bio_list writes;
+
+	/* recovery */
+	region_t nr_regions;
+	int in_sync;
+
+	unsigned int nr_mirrors;
+	struct mirror mirror[0];
+};
+
+/*
+ * Every mirror should look like this one.
+ */
+#define DEFAULT_MIRROR 0
+
+/*
+ * This is yucky.  We squirrel the mirror_set struct away inside
+ * bi_next for write buffers.  This is safe since the bh
+ * doesn't get submitted to the lower levels of block layer.
+ */
+static struct mirror_set *bio_get_ms(struct bio *bio)
+{
+	return (struct mirror_set *) bio->bi_next;
+}
+
+static void bio_set_ms(struct bio *bio, struct mirror_set *ms)
+{
+	bio->bi_next = (struct bio *) ms;
+}
+
+/*-----------------------------------------------------------------
+ * Recovery.
+ *
+ * When a mirror is first activated we may find that some regions
+ * are in the no-sync state.  We have to recover these by
+ * recopying from the default mirror to all the others.
+ *---------------------------------------------------------------*/
+static void recovery_complete(int read_err, unsigned int write_err,
+			      void *context)
+{
+	struct region *reg = (struct region *) context;
+
+	/* FIXME: better error handling */
+	rh_recovery_end(reg, read_err || write_err);
+}
+
+static int recover(struct mirror_set *ms, struct region *reg)
+{
+	int r;
+	unsigned int i;
+	struct io_region from, to[ms->nr_mirrors - 1], *dest;
+	struct mirror *m;
+	unsigned long flags = 0;
+
+	/* fill in the source */
+	m = ms->mirror + DEFAULT_MIRROR;
+	from.bdev = m->dev->bdev;
+	from.sector = m->offset + region_to_sector(reg->rh, reg->key);
+	if (reg->key == (ms->nr_regions - 1)) {
+		/*
+		 * The final region may be smaller than
+		 * region_size.
+		 */
+		from.count = ms->ti->len & (reg->rh->region_size - 1);
+		if (!from.count)
+			from.count = reg->rh->region_size;
+	} else
+		from.count = reg->rh->region_size;
+
+	/* fill in the destinations */
+	for (i = 0, dest = to; i < ms->nr_mirrors; i++) {
+		if (i == DEFAULT_MIRROR)
+			continue;
+
+		m = ms->mirror + i;
+		dest->bdev = m->dev->bdev;
+		dest->sector = m->offset + region_to_sector(reg->rh, reg->key);
+		dest->count = from.count;
+		dest++;
+	}
+
+	/* hand to kcopyd */
+	set_bit(KCOPYD_IGNORE_ERROR, &flags);
+	r = kcopyd_copy(ms->kcopyd_client, &from, ms->nr_mirrors - 1, to, flags,
+			recovery_complete, reg);
+
+	return r;
+}
+
+static void do_recovery(struct mirror_set *ms)
+{
+	int r;
+	struct region *reg;
+	struct dirty_log *log = ms->rh.log;
+
+	/*
+	 * Start quiescing some regions.
+	 */
+	rh_recovery_prepare(&ms->rh);
+
+	/*
+	 * Copy any already quiesced regions.
+	 */
+	while ((reg = rh_recovery_start(&ms->rh))) {
+		r = recover(ms, reg);
+		if (r)
+			rh_recovery_end(reg, 0);
+	}
+
+	/*
+	 * Update the in sync flag.
+	 */
+	if (!ms->in_sync &&
+	    (log->type->get_sync_count(log) == ms->nr_regions)) {
+		/* the sync is complete */
+		dm_table_event(ms->ti->table);
+		ms->in_sync = 1;
+	}
+}
+
+/*-----------------------------------------------------------------
+ * Reads
+ *---------------------------------------------------------------*/
+static struct mirror *choose_mirror(struct mirror_set *ms, sector_t sector)
+{
+	/* FIXME: add read balancing */
+	return ms->mirror + DEFAULT_MIRROR;
+}
+
+/*
+ * remap a buffer to a particular mirror.
+ */
+static void map_bio(struct mirror_set *ms, struct mirror *m, struct bio *bio)
+{
+	bio->bi_bdev = m->dev->bdev;
+	bio->bi_sector = m->offset + (bio->bi_sector - ms->ti->begin);
+}
+
+static void do_reads(struct mirror_set *ms, struct bio_list *reads)
+{
+	region_t region;
+	struct bio *bio;
+	struct mirror *m;
+
+	while ((bio = bio_list_pop(reads))) {
+		region = bio_to_region(&ms->rh, bio);
+
+		/*
+		 * We can only read balance if the region is in sync.
+		 */
+		if (rh_in_sync(&ms->rh, region, 0))
+			m = choose_mirror(ms, bio->bi_sector);
+		else
+			m = ms->mirror + DEFAULT_MIRROR;
+
+		map_bio(ms, m, bio);
+		generic_make_request(bio);
+	}
+}
+
+/*-----------------------------------------------------------------
+ * Writes.
+ *
+ * We do different things with the write io depending on the
+ * state of the region that it's in:
+ *
+ * SYNC: 	increment pending, use kcopyd to write to *all* mirrors
+ * RECOVERING:	delay the io until recovery completes
+ * NOSYNC:	increment pending, just write to the default mirror
+ *---------------------------------------------------------------*/
+static void write_callback(unsigned long error, void *context)
+{
+	unsigned int i;
+	int uptodate = 1;
+	struct bio *bio = (struct bio *) context;
+	struct mirror_set *ms;
+
+	ms = bio_get_ms(bio);
+	bio_set_ms(bio, NULL);
+
+	/*
+	 * NOTE: We don't decrement the pending count here,
+	 * instead it is done by the targets endio function.
+	 * This way we handle both writes to SYNC and NOSYNC
+	 * regions with the same code.
+	 */
+
+	if (error) {
+		/*
+		 * only error the io if all mirrors failed.
+		 * FIXME: bogus
+		 */
+		uptodate = 0;
+		for (i = 0; i < ms->nr_mirrors; i++)
+			if (!test_bit(i, &error)) {
+				uptodate = 1;
+				break;
+			}
+	}
+	bio_endio(bio, bio->bi_size, 0);
+}
+
+static void do_write(struct mirror_set *ms, struct bio *bio)
+{
+	unsigned int i;
+	struct io_region io[ms->nr_mirrors];
+	struct mirror *m;
+
+	for (i = 0; i < ms->nr_mirrors; i++) {
+		m = ms->mirror + i;
+
+		io[i].bdev = m->dev->bdev;
+		io[i].sector = m->offset + (bio->bi_sector - ms->ti->begin);
+		io[i].count = bio->bi_size >> 9;
+	}
+
+	bio_set_ms(bio, ms);
+	dm_io_async_bvec(ms->nr_mirrors, io, WRITE,
+			 bio->bi_io_vec + bio->bi_idx,
+			 write_callback, bio);
+}
+
+static void do_writes(struct mirror_set *ms, struct bio_list *writes)
+{
+	int state;
+	struct bio *bio;
+	struct bio_list sync, nosync, recover, *this_list = NULL;
+
+	if (!writes->head)
+		return;
+
+	/*
+	 * Classify each write.
+	 */
+	bio_list_init(&sync);
+	bio_list_init(&nosync);
+	bio_list_init(&recover);
+
+	while ((bio = bio_list_pop(writes))) {
+		state = rh_state(&ms->rh, bio_to_region(&ms->rh, bio), 1);
+		switch (state) {
+		case RH_CLEAN:
+		case RH_DIRTY:
+			this_list = &sync;
+			break;
+
+		case RH_NOSYNC:
+			this_list = &nosync;
+			break;
+
+		case RH_RECOVERING:
+			this_list = &recover;
+			break;
+		}
+
+		bio_list_add(this_list, bio);
+	}
+
+	/*
+	 * Increment the pending counts for any regions that will
+	 * be written to (writes to recover regions are going to
+	 * be delayed).
+	 */
+	rh_inc_pending(&ms->rh, &sync);
+	rh_inc_pending(&ms->rh, &nosync);
+	rh_flush(&ms->rh);
+
+	/*
+	 * Dispatch io.
+	 */
+	while ((bio = bio_list_pop(&sync)))
+		do_write(ms, bio);
+
+	while ((bio = bio_list_pop(&recover)))
+		rh_delay(&ms->rh, bio);
+
+	while ((bio = bio_list_pop(&nosync))) {
+		map_bio(ms, ms->mirror + DEFAULT_MIRROR, bio);
+		generic_make_request(bio);
+	}
+}
+
+/*-----------------------------------------------------------------
+ * kmirrord
+ *---------------------------------------------------------------*/
+static LIST_HEAD(_mirror_sets);
+static DECLARE_RWSEM(_mirror_sets_lock);
+
+static void do_mirror(struct mirror_set *ms)
+{
+	struct bio_list reads, writes;
+
+	spin_lock(&ms->lock);
+	memcpy(&reads, &ms->reads, sizeof(reads));
+	bio_list_init(&ms->reads);
+	memcpy(&writes, &ms->writes, sizeof(writes));
+	bio_list_init(&ms->writes);
+	spin_unlock(&ms->lock);
+
+	rh_update_states(&ms->rh);
+	do_recovery(ms);
+	do_reads(ms, &reads);
+	do_writes(ms, &writes);
+}
+
+static void do_work(void *ignored)
+{
+	struct mirror_set *ms;
+
+	down_read(&_mirror_sets_lock);
+	list_for_each_entry (ms, &_mirror_sets, list)
+		do_mirror(ms);
+	up_read(&_mirror_sets_lock);
+}
+
+/*-----------------------------------------------------------------
+ * Target functions
+ *---------------------------------------------------------------*/
+static struct mirror_set *alloc_context(unsigned int nr_mirrors,
+					sector_t region_size,
+					struct dm_target *ti,
+					struct dirty_log *dl)
+{
+	size_t len;
+	struct mirror_set *ms = NULL;
+
+	if (array_too_big(sizeof(*ms), sizeof(ms->mirror[0]), nr_mirrors))
+		return NULL;
+
+	len = sizeof(*ms) + (sizeof(ms->mirror[0]) * nr_mirrors);
+
+	ms = kmalloc(len, GFP_KERNEL);
+	if (!ms) {
+		ti->error = "dm-mirror: Cannot allocate mirror context";
+		return NULL;
+	}
+
+	memset(ms, 0, len);
+	spin_lock_init(&ms->lock);
+
+	ms->ti = ti;
+	ms->nr_mirrors = nr_mirrors;
+	ms->nr_regions = dm_div_up(ti->len, region_size);
+	ms->in_sync = 0;
+
+	if (rh_init(&ms->rh, ms, dl, region_size, ms->nr_regions)) {
+		ti->error = "dm-mirror: Error creating dirty region hash";
+		kfree(ms);
+		return NULL;
+	}
+
+	return ms;
+}
+
+static void free_context(struct mirror_set *ms, struct dm_target *ti,
+			 unsigned int m)
+{
+	while (m--)
+		dm_put_device(ti, ms->mirror[m].dev);
+
+	rh_exit(&ms->rh);
+	kfree(ms);
+}
+
+static inline int _check_region_size(struct dm_target *ti, sector_t size)
+{
+	return !(size % (PAGE_SIZE >> 9) || (size & (size - 1)) ||
+		 size > ti->len);
+}
+
+static int get_mirror(struct mirror_set *ms, struct dm_target *ti,
+		      unsigned int mirror, char **argv)
+{
+	sector_t offset;
+
+	if (sscanf(argv[1], SECTOR_FORMAT, &offset) != 1) {
+		ti->error = "dm-mirror: Invalid offset";
+		return -EINVAL;
+	}
+
+	if (dm_get_device(ti, argv[0], offset, ti->len,
+			  dm_table_get_mode(ti->table),
+			  &ms->mirror[mirror].dev)) {
+		ti->error = "dm-mirror: Device lookup failure";
+		return -ENXIO;
+	}
+
+	ms->mirror[mirror].offset = offset;
+
+	return 0;
+}
+
+static int add_mirror_set(struct mirror_set *ms)
+{
+	down_write(&_mirror_sets_lock);
+	list_add_tail(&ms->list, &_mirror_sets);
+	up_write(&_mirror_sets_lock);
+	wake();
+
+	return 0;
+}
+
+static void del_mirror_set(struct mirror_set *ms)
+{
+	down_write(&_mirror_sets_lock);
+	list_del(&ms->list);
+	up_write(&_mirror_sets_lock);
+}
+
+/*
+ * Create dirty log: log_type #log_params <log_params>
+ */
+static struct dirty_log *create_dirty_log(struct dm_target *ti,
+					  unsigned int argc, char **argv,
+					  unsigned int *args_used)
+{
+	unsigned int param_count;
+	struct dirty_log *dl;
+
+	if (argc < 2) {
+		ti->error = "dm-mirror: Insufficient mirror log arguments";
+		return NULL;
+	}
+
+	if (sscanf(argv[1], "%u", &param_count) != 1) {
+		ti->error = "dm-mirror: Invalid mirror log argument count";
+		return NULL;
+	}
+
+	*args_used = 2 + param_count;
+
+	if (argc < *args_used) {
+		ti->error = "dm-mirror: Insufficient mirror log arguments";
+		return NULL;
+	}
+
+	dl = dm_create_dirty_log(argv[0], ti, param_count, argv + 2);
+	if (!dl) {
+		ti->error = "dm-mirror: Error creating mirror dirty log";
+		return NULL;
+	}
+
+	if (!_check_region_size(ti, dl->type->get_region_size(dl))) {
+		ti->error = "dm-mirror: Invalid region size";
+		dm_destroy_dirty_log(dl);
+		return NULL;
+	}
+
+	return dl;
+}
+
+/*
+ * Construct a mirror mapping:
+ *
+ * log_type #log_params <log_params>
+ * #mirrors [mirror_path offset]{2,}
+ *
+ * For now, #log_params = 1, log_type = "core"
+ *
+ */
+#define DM_IO_PAGES 64
+static int mirror_ctr(struct dm_target *ti, unsigned int argc, char **argv)
+{
+	int r;
+	unsigned int nr_mirrors, m, args_used;
+	struct mirror_set *ms;
+	struct dirty_log *dl;
+
+	dl = create_dirty_log(ti, argc, argv, &args_used);
+	if (!dl)
+		return -EINVAL;
+
+	argv += args_used;
+	argc -= args_used;
+
+	if (!argc || sscanf(argv[0], "%u", &nr_mirrors) != 1 ||
+	    nr_mirrors < 2) {
+		ti->error = "dm-mirror: Invalid number of mirrors";
+		dm_destroy_dirty_log(dl);
+		return -EINVAL;
+	}
+
+	argv++, argc--;
+
+	if (argc != nr_mirrors * 2) {
+		ti->error = "dm-mirror: Wrong number of mirror arguments";
+		dm_destroy_dirty_log(dl);
+		return -EINVAL;
+	}
+
+	ms = alloc_context(nr_mirrors, dl->type->get_region_size(dl), ti, dl);
+	if (!ms) {
+		dm_destroy_dirty_log(dl);
+		return -ENOMEM;
+	}
+
+	/* Get the mirror parameter sets */
+	for (m = 0; m < nr_mirrors; m++) {
+		r = get_mirror(ms, ti, m, argv);
+		if (r) {
+			free_context(ms, ti, m);
+			return r;
+		}
+		argv += 2;
+		argc -= 2;
+	}
+
+	ti->private = ms;
+
+	r = kcopyd_client_create(DM_IO_PAGES, &ms->kcopyd_client);
+	if (r) {
+		free_context(ms, ti, ms->nr_mirrors);
+		return r;
+	}
+
+	add_mirror_set(ms);
+	return 0;
+}
+
+static void mirror_dtr(struct dm_target *ti)
+{
+	struct mirror_set *ms = (struct mirror_set *) ti->private;
+
+	del_mirror_set(ms);
+	kcopyd_client_destroy(ms->kcopyd_client);
+	free_context(ms, ti, ms->nr_mirrors);
+}
+
+static void queue_bio(struct mirror_set *ms, struct bio *bio, int rw)
+{
+	int should_wake = 0;
+	struct bio_list *bl;
+
+	bl = (rw == WRITE) ? &ms->writes : &ms->reads;
+	spin_lock(&ms->lock);
+	should_wake = !(bl->head);
+	bio_list_add(bl, bio);
+	spin_unlock(&ms->lock);
+
+	if (should_wake)
+		wake();
+}
+
+/*
+ * Mirror mapping function
+ */
+static int mirror_map(struct dm_target *ti, struct bio *bio,
+		      union map_info *map_context)
+{
+	int r, rw = bio_rw(bio);
+	struct mirror *m;
+	struct mirror_set *ms = ti->private;
+
+	map_context->ll = bio->bi_sector >> ms->rh.region_shift;
+
+	if (rw == WRITE) {
+		queue_bio(ms, bio, rw);
+		return 0;
+	}
+
+	r = ms->rh.log->type->in_sync(ms->rh.log,
+				      bio_to_region(&ms->rh, bio), 0);
+	if (r < 0 && r != -EWOULDBLOCK)
+		return r;
+
+	if (r == -EWOULDBLOCK)	/* FIXME: ugly */
+		r = 0;
+
+	/*
+	 * We don't want to fast track a recovery just for a read
+	 * ahead.  So we just let it silently fail.
+	 * FIXME: get rid of this.
+	 */
+	if (!r && rw == READA)
+		return -EIO;
+
+	if (!r) {
+		/* Pass this io over to the daemon */
+		queue_bio(ms, bio, rw);
+		return 0;
+	}
+
+	m = choose_mirror(ms, bio->bi_sector);
+	if (!m)
+		return -EIO;
+
+	map_bio(ms, m, bio);
+	return 1;
+}
+
+static int mirror_end_io(struct dm_target *ti, struct bio *bio,
+			 int error, union map_info *map_context)
+{
+	int rw = bio_rw(bio);
+	struct mirror_set *ms = (struct mirror_set *) ti->private;
+	region_t region = map_context->ll;
+
+	/*
+	 * We need to dec pending if this was a write.
+	 */
+	if (rw == WRITE)
+		rh_dec(&ms->rh, region);
+
+	return 0;
+}
+
+static void mirror_suspend(struct dm_target *ti)
+{
+	struct mirror_set *ms = (struct mirror_set *) ti->private;
+	struct dirty_log *log = ms->rh.log;
+	rh_stop_recovery(&ms->rh);
+	if (log->type->suspend && log->type->suspend(log))
+		/* FIXME: need better error handling */
+		DMWARN("log suspend failed");
+}
+
+static void mirror_resume(struct dm_target *ti)
+{
+	struct mirror_set *ms = (struct mirror_set *) ti->private;
+	struct dirty_log *log = ms->rh.log;
+	if (log->type->resume && log->type->resume(log))
+		/* FIXME: need better error handling */
+		DMWARN("log resume failed");
+	rh_start_recovery(&ms->rh);
+}
+
+static int mirror_status(struct dm_target *ti, status_type_t type,
+			 char *result, unsigned int maxlen)
+{
+	char buffer[32];
+	unsigned int m, sz = 0;
+	struct mirror_set *ms = (struct mirror_set *) ti->private;
+
+#define EMIT(x...) sz += ((sz >= maxlen) ? \
+			  0 : scnprintf(result + sz, maxlen - sz, x))
+
+	switch (type) {
+	case STATUSTYPE_INFO:
+		EMIT("%d ", ms->nr_mirrors);
+
+		for (m = 0; m < ms->nr_mirrors; m++) {
+			format_dev_t(buffer, ms->mirror[m].dev->bdev->bd_dev);
+			EMIT("%s ", buffer);
+		}
+
+		EMIT(SECTOR_FORMAT "/" SECTOR_FORMAT,
+		     ms->rh.log->type->get_sync_count(ms->rh.log),
+		     ms->nr_regions);
+		break;
+
+	case STATUSTYPE_TABLE:
+		EMIT("%s 1 " SECTOR_FORMAT " %d ",
+		     ms->rh.log->type->name, ms->rh.region_size,
+		     ms->nr_mirrors);
+
+		for (m = 0; m < ms->nr_mirrors; m++) {
+			format_dev_t(buffer, ms->mirror[m].dev->bdev->bd_dev);
+			EMIT("%s " SECTOR_FORMAT " ",
+			     buffer, ms->mirror[m].offset);
+		}
+	}
+
+	return 0;
+}
+
+static struct target_type mirror_target = {
+	.name	 = "mirror",
+	.version = {1, 0, 1},
+	.module	 = THIS_MODULE,
+	.ctr	 = mirror_ctr,
+	.dtr	 = mirror_dtr,
+	.map	 = mirror_map,
+	.end_io	 = mirror_end_io,
+	.suspend = mirror_suspend,
+	.resume	 = mirror_resume,
+	.status	 = mirror_status,
+};
+
+static int __init dm_mirror_init(void)
+{
+	int r;
+
+	r = dm_dirty_log_init();
+	if (r)
+		return r;
+
+	_kmirrord_wq = create_workqueue("kmirrord");
+	if (!_kmirrord_wq) {
+		DMERR("couldn't start kmirrord");
+		dm_dirty_log_exit();
+		return r;
+	}
+	INIT_WORK(&_kmirrord_work, do_work, NULL);
+
+	r = dm_register_target(&mirror_target);
+	if (r < 0) {
+		DMERR("%s: Failed to register mirror target",
+		      mirror_target.name);
+		dm_dirty_log_exit();
+		destroy_workqueue(_kmirrord_wq);
+	}
+
+	return r;
+}
+
+static void __exit dm_mirror_exit(void)
+{
+	int r;
+
+	r = dm_unregister_target(&mirror_target);
+	if (r < 0)
+		DMERR("%s: unregister failed %d", mirror_target.name, r);
+
+	destroy_workqueue(_kmirrord_wq);
+	dm_dirty_log_exit();
+}
+
+/* Module hooks */
+module_init(dm_mirror_init);
+module_exit(dm_mirror_exit);
+
+MODULE_DESCRIPTION(DM_NAME " mirror target");
+MODULE_AUTHOR("Joe Thornber");
+MODULE_LICENSE("GPL");
--- diff/drivers/md/dm-snap.c	1970-01-01 01:00:00.000000000 +0100
+++ source/drivers/md/dm-snap.c	2004-06-11 19:22:02.000000000 +0100
@@ -0,0 +1,1213 @@
+/*
+ * dm-snapshot.c
+ *
+ * Copyright (C) 2001-2002 Sistina Software (UK) Limited.
+ *
+ * This file is released under the GPL.
+ */
+
+#include <linux/blkdev.h>
+#include <linux/config.h>
+#include <linux/ctype.h>
+#include <linux/device-mapper.h>
+#include <linux/fs.h>
+#include <linux/init.h>
+#include <linux/kdev_t.h>
+#include <linux/list.h>
+#include <linux/mempool.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/vmalloc.h>
+
+#include "dm-snap.h"
+#include "dm-bio-list.h"
+#include "kcopyd.h"
+
+/*
+ * The percentage increment we will wake up users at
+ */
+#define WAKE_UP_PERCENT 5
+
+/*
+ * kcopyd priority of snapshot operations
+ */
+#define SNAPSHOT_COPY_PRIORITY 2
+
+/*
+ * Each snapshot reserves this many pages for io
+ */
+#define SNAPSHOT_PAGES 256
+
+struct pending_exception {
+	struct exception e;
+
+	/*
+	 * Origin buffers waiting for this to complete are held
+	 * in a bio list
+	 */
+	struct bio_list origin_bios;
+	struct bio_list snapshot_bios;
+
+	/*
+	 * Other pending_exceptions that are processing this
+	 * chunk.  When this list is empty, we know we can
+	 * complete the origins.
+	 */
+	struct list_head siblings;
+
+	/* Pointer back to snapshot context */
+	struct dm_snapshot *snap;
+
+	/*
+	 * 1 indicates the exception has already been sent to
+	 * kcopyd.
+	 */
+	int started;
+};
+
+/*
+ * Hash table mapping origin volumes to lists of snapshots and
+ * a lock to protect it
+ */
+static kmem_cache_t *exception_cache;
+static kmem_cache_t *pending_cache;
+static mempool_t *pending_pool;
+
+/*
+ * One of these per registered origin, held in the snapshot_origins hash
+ */
+struct origin {
+	/* The origin device */
+	struct block_device *bdev;
+
+	struct list_head hash_list;
+
+	/* List of snapshots for this origin */
+	struct list_head snapshots;
+};
+
+/*
+ * Size of the hash table for origin volumes. If we make this
+ * the size of the minors list then it should be nearly perfect
+ */
+#define ORIGIN_HASH_SIZE 256
+#define ORIGIN_MASK      0xFF
+static struct list_head *_origins;
+static struct rw_semaphore _origins_lock;
+
+static int init_origin_hash(void)
+{
+	int i;
+
+	_origins = kmalloc(ORIGIN_HASH_SIZE * sizeof(struct list_head),
+			   GFP_KERNEL);
+	if (!_origins) {
+		DMERR("Device mapper: Snapshot: unable to allocate memory");
+		return -ENOMEM;
+	}
+
+	for (i = 0; i < ORIGIN_HASH_SIZE; i++)
+		INIT_LIST_HEAD(_origins + i);
+	init_rwsem(&_origins_lock);
+
+	return 0;
+}
+
+static void exit_origin_hash(void)
+{
+	kfree(_origins);
+}
+
+static inline unsigned int origin_hash(struct block_device *bdev)
+{
+	return bdev->bd_dev & ORIGIN_MASK;
+}
+
+static struct origin *__lookup_origin(struct block_device *origin)
+{
+	struct list_head *ol;
+	struct origin *o;
+
+	ol = &_origins[origin_hash(origin)];
+	list_for_each_entry (o, ol, hash_list)
+		if (bdev_equal(o->bdev, origin))
+			return o;
+
+	return NULL;
+}
+
+static void __insert_origin(struct origin *o)
+{
+	struct list_head *sl = &_origins[origin_hash(o->bdev)];
+	list_add_tail(&o->hash_list, sl);
+}
+
+/*
+ * Make a note of the snapshot and its origin so we can look it
+ * up when the origin has a write on it.
+ */
+static int register_snapshot(struct dm_snapshot *snap)
+{
+	struct origin *o;
+	struct block_device *bdev = snap->origin->bdev;
+
+	down_write(&_origins_lock);
+	o = __lookup_origin(bdev);
+
+	if (!o) {
+		/* New origin */
+		o = kmalloc(sizeof(*o), GFP_KERNEL);
+		if (!o) {
+			up_write(&_origins_lock);
+			return -ENOMEM;
+		}
+
+		/* Initialise the struct */
+		INIT_LIST_HEAD(&o->snapshots);
+		o->bdev = bdev;
+
+		__insert_origin(o);
+	}
+
+	list_add_tail(&snap->list, &o->snapshots);
+
+	up_write(&_origins_lock);
+	return 0;
+}
+
+static void unregister_snapshot(struct dm_snapshot *s)
+{
+	struct origin *o;
+
+	down_write(&_origins_lock);
+	o = __lookup_origin(s->origin->bdev);
+
+	list_del(&s->list);
+	if (list_empty(&o->snapshots)) {
+		list_del(&o->hash_list);
+		kfree(o);
+	}
+
+	up_write(&_origins_lock);
+}
+
+/*
+ * Implementation of the exception hash tables.
+ */
+static int init_exception_table(struct exception_table *et, uint32_t size)
+{
+	unsigned int i;
+
+	et->hash_mask = size - 1;
+	et->table = dm_vcalloc(size, sizeof(struct list_head));
+	if (!et->table)
+		return -ENOMEM;
+
+	for (i = 0; i < size; i++)
+		INIT_LIST_HEAD(et->table + i);
+
+	return 0;
+}
+
+static void exit_exception_table(struct exception_table *et, kmem_cache_t *mem)
+{
+	struct list_head *slot;
+	struct exception *ex, *next;
+	int i, size;
+
+	size = et->hash_mask + 1;
+	for (i = 0; i < size; i++) {
+		slot = et->table + i;
+
+		list_for_each_entry_safe (ex, next, slot, hash_list)
+			kmem_cache_free(mem, ex);
+	}
+
+	vfree(et->table);
+}
+
+static inline uint32_t exception_hash(struct exception_table *et, chunk_t chunk)
+{
+	return chunk & et->hash_mask;
+}
+
+static void insert_exception(struct exception_table *eh, struct exception *e)
+{
+	struct list_head *l = &eh->table[exception_hash(eh, e->old_chunk)];
+	list_add(&e->hash_list, l);
+}
+
+static inline void remove_exception(struct exception *e)
+{
+	list_del(&e->hash_list);
+}
+
+/*
+ * Return the exception data for a sector, or NULL if not
+ * remapped.
+ */
+static struct exception *lookup_exception(struct exception_table *et,
+					  chunk_t chunk)
+{
+	struct list_head *slot;
+	struct exception *e;
+
+	slot = &et->table[exception_hash(et, chunk)];
+	list_for_each_entry (e, slot, hash_list)
+		if (e->old_chunk == chunk)
+			return e;
+
+	return NULL;
+}
+
+static inline struct exception *alloc_exception(void)
+{
+	struct exception *e;
+
+	e = kmem_cache_alloc(exception_cache, GFP_NOIO);
+	if (!e)
+		e = kmem_cache_alloc(exception_cache, GFP_ATOMIC);
+
+	return e;
+}
+
+static inline void free_exception(struct exception *e)
+{
+	kmem_cache_free(exception_cache, e);
+}
+
+static inline struct pending_exception *alloc_pending_exception(void)
+{
+	return mempool_alloc(pending_pool, GFP_NOIO);
+}
+
+static inline void free_pending_exception(struct pending_exception *pe)
+{
+	mempool_free(pe, pending_pool);
+}
+
+int dm_add_exception(struct dm_snapshot *s, chunk_t old, chunk_t new)
+{
+	struct exception *e;
+
+	e = alloc_exception();
+	if (!e)
+		return -ENOMEM;
+
+	e->old_chunk = old;
+	e->new_chunk = new;
+	insert_exception(&s->complete, e);
+	return 0;
+}
+
+/*
+ * Hard coded magic.
+ */
+static int calc_max_buckets(void)
+{
+	/* use a fixed size of 2MB */
+	unsigned long mem = 2 * 1024 * 1024;
+	mem /= sizeof(struct list_head);
+
+	return mem;
+}
+
+/*
+ * Rounds a number down to a power of 2.
+ */
+static inline uint32_t round_down(uint32_t n)
+{
+	while (n & (n - 1))
+		n &= (n - 1);
+	return n;
+}
+
+/*
+ * Allocate room for a suitable hash table.
+ */
+static int init_hash_tables(struct dm_snapshot *s)
+{
+	sector_t hash_size, cow_dev_size, origin_dev_size, max_buckets;
+
+	/*
+	 * Calculate based on the size of the original volume or
+	 * the COW volume...
+	 */
+	cow_dev_size = get_dev_size(s->cow->bdev);
+	origin_dev_size = get_dev_size(s->origin->bdev);
+	max_buckets = calc_max_buckets();
+
+	hash_size = min(origin_dev_size, cow_dev_size) >> s->chunk_shift;
+	hash_size = min(hash_size, max_buckets);
+
+	/* Round it down to a power of 2 */
+	hash_size = round_down(hash_size);
+	if (init_exception_table(&s->complete, hash_size))
+		return -ENOMEM;
+
+	/*
+	 * Allocate hash table for in-flight exceptions
+	 * Make this smaller than the real hash table
+	 */
+	hash_size >>= 3;
+	if (hash_size < 64)
+		hash_size = 64;
+
+	if (init_exception_table(&s->pending, hash_size)) {
+		exit_exception_table(&s->complete, exception_cache);
+		return -ENOMEM;
+	}
+
+	return 0;
+}
+
+/*
+ * Round a number up to the nearest 'size' boundary.  size must
+ * be a power of 2.
+ */
+static inline ulong round_up(ulong n, ulong size)
+{
+	size--;
+	return (n + size) & ~size;
+}
+
+/*
+ * Construct a snapshot mapping: <origin_dev> <COW-dev> <p/n> <chunk-size>
+ */
+static int snapshot_ctr(struct dm_target *ti, unsigned int argc, char **argv)
+{
+	struct dm_snapshot *s;
+	unsigned long chunk_size;
+	int r = -EINVAL;
+	char persistent;
+	char *origin_path;
+	char *cow_path;
+	char *value;
+	int blocksize;
+
+	if (argc < 4) {
+		ti->error = "dm-snapshot: requires exactly 4 arguments";
+		r = -EINVAL;
+		goto bad1;
+	}
+
+	origin_path = argv[0];
+	cow_path = argv[1];
+	persistent = toupper(*argv[2]);
+
+	if (persistent != 'P' && persistent != 'N') {
+		ti->error = "Persistent flag is not P or N";
+		r = -EINVAL;
+		goto bad1;
+	}
+
+	chunk_size = simple_strtoul(argv[3], &value, 10);
+	if (chunk_size == 0 || value == NULL) {
+		ti->error = "Invalid chunk size";
+		r = -EINVAL;
+		goto bad1;
+	}
+
+	s = kmalloc(sizeof(*s), GFP_KERNEL);
+	if (s == NULL) {
+		ti->error = "Cannot allocate snapshot context private "
+		    "structure";
+		r = -ENOMEM;
+		goto bad1;
+	}
+
+	r = dm_get_device(ti, origin_path, 0, ti->len, FMODE_READ, &s->origin);
+	if (r) {
+		ti->error = "Cannot get origin device";
+		goto bad2;
+	}
+
+	r = dm_get_device(ti, cow_path, 0, 0,
+			  FMODE_READ | FMODE_WRITE, &s->cow);
+	if (r) {
+		dm_put_device(ti, s->origin);
+		ti->error = "Cannot get COW device";
+		goto bad2;
+	}
+
+	/*
+	 * Chunk size must be multiple of page size.  Silently
+	 * round up if it's not.
+	 */
+	chunk_size = round_up(chunk_size, PAGE_SIZE >> 9);
+
+	/* Validate the chunk size against the device block size */
+	blocksize = s->cow->bdev->bd_disk->queue->hardsect_size;
+	if (chunk_size % (blocksize >> 9)) {
+		ti->error = "Chunk size is not a multiple of device blocksize";
+		r = -EINVAL;
+		goto bad3;
+	}
+
+	/* Check chunk_size is a power of 2 */
+	if (chunk_size & (chunk_size - 1)) {
+		ti->error = "Chunk size is not a power of 2";
+		r = -EINVAL;
+		goto bad3;
+	}
+
+	s->chunk_size = chunk_size;
+	s->chunk_mask = chunk_size - 1;
+	s->type = persistent;
+	s->chunk_shift = ffs(chunk_size) - 1;
+
+	s->valid = 1;
+	s->have_metadata = 0;
+	s->last_percent = 0;
+	init_rwsem(&s->lock);
+	s->table = ti->table;
+
+	/* Allocate hash table for COW data */
+	if (init_hash_tables(s)) {
+		ti->error = "Unable to allocate hash table space";
+		r = -ENOMEM;
+		goto bad3;
+	}
+
+	/*
+	 * Check the persistent flag - done here because we need the iobuf
+	 * to check the LV header
+	 */
+	s->store.snap = s;
+
+	if (persistent == 'P')
+		r = dm_create_persistent(&s->store, chunk_size);
+	else
+		r = dm_create_transient(&s->store, s, blocksize);
+
+	if (r) {
+		ti->error = "Couldn't create exception store";
+		r = -EINVAL;
+		goto bad4;
+	}
+
+	r = kcopyd_client_create(SNAPSHOT_PAGES, &s->kcopyd_client);
+	if (r) {
+		ti->error = "Could not create kcopyd client";
+		goto bad5;
+	}
+
+	/* Add snapshot to the list of snapshots for this origin */
+	if (register_snapshot(s)) {
+		r = -EINVAL;
+		ti->error = "Cannot register snapshot origin";
+		goto bad6;
+	}
+
+	ti->private = s;
+	ti->split_io = chunk_size;
+
+	return 0;
+
+ bad6:
+	kcopyd_client_destroy(s->kcopyd_client);
+
+ bad5:
+	s->store.destroy(&s->store);
+
+ bad4:
+	exit_exception_table(&s->pending, pending_cache);
+	exit_exception_table(&s->complete, exception_cache);
+
+ bad3:
+	dm_put_device(ti, s->cow);
+	dm_put_device(ti, s->origin);
+
+ bad2:
+	kfree(s);
+
+ bad1:
+	return r;
+}
+
+static void snapshot_dtr(struct dm_target *ti)
+{
+	struct dm_snapshot *s = (struct dm_snapshot *) ti->private;
+
+	unregister_snapshot(s);
+
+	exit_exception_table(&s->pending, pending_cache);
+	exit_exception_table(&s->complete, exception_cache);
+
+	/* Deallocate memory used */
+	s->store.destroy(&s->store);
+
+	dm_put_device(ti, s->origin);
+	dm_put_device(ti, s->cow);
+	kcopyd_client_destroy(s->kcopyd_client);
+	kfree(s);
+}
+
+/*
+ * Flush a list of buffers.
+ */
+static void flush_bios(struct bio *bio)
+{
+	struct bio *n;
+
+	while (bio) {
+		n = bio->bi_next;
+		bio->bi_next = NULL;
+		generic_make_request(bio);
+		bio = n;
+	}
+}
+
+/*
+ * Error a list of buffers.
+ */
+static void error_bios(struct bio *bio)
+{
+	struct bio *n;
+
+	while (bio) {
+		n = bio->bi_next;
+		bio->bi_next = NULL;
+		bio_io_error(bio, bio->bi_size);
+		bio = n;
+	}
+}
+
+static struct bio *__flush_bios(struct pending_exception *pe)
+{
+	struct pending_exception *sibling;
+
+	if (list_empty(&pe->siblings))
+		return bio_list_get(&pe->origin_bios);
+
+	sibling = list_entry(pe->siblings.next,
+			     struct pending_exception, siblings);
+
+	list_del(&pe->siblings);
+
+	/* This is fine as long as kcopyd is single-threaded. If kcopyd
+	 * becomes multi-threaded, we'll need some locking here.
+	 */
+	bio_list_merge(&sibling->origin_bios, &pe->origin_bios);
+
+	return NULL;
+}
+
+static void pending_complete(struct pending_exception *pe, int success)
+{
+	struct exception *e;
+	struct dm_snapshot *s = pe->snap;
+	struct bio *flush = NULL;
+
+	if (success) {
+		e = alloc_exception();
+		if (!e) {
+			DMWARN("Unable to allocate exception.");
+			down_write(&s->lock);
+			s->store.drop_snapshot(&s->store);
+			s->valid = 0;
+			flush = __flush_bios(pe);
+			up_write(&s->lock);
+
+			error_bios(bio_list_get(&pe->snapshot_bios));
+			goto out;
+		}
+		memcpy(e, &pe->e, sizeof(*e));
+
+		/*
+		 * Add a proper exception, and remove the
+		 * in-flight exception from the list.
+		 */
+		down_write(&s->lock);
+		insert_exception(&s->complete, e);
+		remove_exception(&pe->e);
+		flush = __flush_bios(pe);
+
+		/* Submit any pending write bios */
+		up_write(&s->lock);
+
+		flush_bios(bio_list_get(&pe->snapshot_bios));
+	} else {
+		/* Read/write error - snapshot is unusable */
+		down_write(&s->lock);
+		if (s->valid)
+			DMERR("Error reading/writing snapshot");
+		s->store.drop_snapshot(&s->store);
+		s->valid = 0;
+		remove_exception(&pe->e);
+		flush = __flush_bios(pe);
+		up_write(&s->lock);
+
+		error_bios(bio_list_get(&pe->snapshot_bios));
+
+		dm_table_event(s->table);
+	}
+
+ out:
+	free_pending_exception(pe);
+
+	if (flush)
+		flush_bios(flush);
+}
+
+static void commit_callback(void *context, int success)
+{
+	struct pending_exception *pe = (struct pending_exception *) context;
+	pending_complete(pe, success);
+}
+
+/*
+ * Called when the copy I/O has finished.  kcopyd actually runs
+ * this code so don't block.
+ */
+static void copy_callback(int read_err, unsigned int write_err, void *context)
+{
+	struct pending_exception *pe = (struct pending_exception *) context;
+	struct dm_snapshot *s = pe->snap;
+
+	if (read_err || write_err)
+		pending_complete(pe, 0);
+
+	else
+		/* Update the metadata if we are persistent */
+		s->store.commit_exception(&s->store, &pe->e, commit_callback,
+					  pe);
+}
+
+/*
+ * Dispatches the copy operation to kcopyd.
+ */
+static inline void start_copy(struct pending_exception *pe)
+{
+	struct dm_snapshot *s = pe->snap;
+	struct io_region src, dest;
+	struct block_device *bdev = s->origin->bdev;
+	sector_t dev_size;
+
+	dev_size = get_dev_size(bdev);
+
+	src.bdev = bdev;
+	src.sector = chunk_to_sector(s, pe->e.old_chunk);
+	src.count = min(s->chunk_size, dev_size - src.sector);
+
+	dest.bdev = s->cow->bdev;
+	dest.sector = chunk_to_sector(s, pe->e.new_chunk);
+	dest.count = src.count;
+
+	/* Hand over to kcopyd */
+	kcopyd_copy(s->kcopyd_client,
+		    &src, 1, &dest, 0, copy_callback, pe);
+}
+
+/*
+ * Looks to see if this snapshot already has a pending exception
+ * for this chunk, otherwise it allocates a new one and inserts
+ * it into the pending table.
+ *
+ * NOTE: a write lock must be held on snap->lock before calling
+ * this.
+ */
+static struct pending_exception *
+__find_pending_exception(struct dm_snapshot *s, struct bio *bio)
+{
+	struct exception *e;
+	struct pending_exception *pe;
+	chunk_t chunk = sector_to_chunk(s, bio->bi_sector);
+
+	/*
+	 * Is there a pending exception for this already ?
+	 */
+	e = lookup_exception(&s->pending, chunk);
+	if (e) {
+		/* cast the exception to a pending exception */
+		pe = container_of(e, struct pending_exception, e);
+
+	} else {
+		/*
+		 * Create a new pending exception, we don't want
+		 * to hold the lock while we do this.
+		 */
+		up_write(&s->lock);
+		pe = alloc_pending_exception();
+		down_write(&s->lock);
+
+		e = lookup_exception(&s->pending, chunk);
+		if (e) {
+			free_pending_exception(pe);
+			pe = container_of(e, struct pending_exception, e);
+		} else {
+			pe->e.old_chunk = chunk;
+			bio_list_init(&pe->origin_bios);
+			bio_list_init(&pe->snapshot_bios);
+			INIT_LIST_HEAD(&pe->siblings);
+			pe->snap = s;
+			pe->started = 0;
+
+			if (s->store.prepare_exception(&s->store, &pe->e)) {
+				free_pending_exception(pe);
+				s->valid = 0;
+				return NULL;
+			}
+
+			insert_exception(&s->pending, &pe->e);
+		}
+	}
+
+	return pe;
+}
+
+static inline void remap_exception(struct dm_snapshot *s, struct exception *e,
+				   struct bio *bio)
+{
+	bio->bi_bdev = s->cow->bdev;
+	bio->bi_sector = chunk_to_sector(s, e->new_chunk) +
+		(bio->bi_sector & s->chunk_mask);
+}
+
+static int snapshot_map(struct dm_target *ti, struct bio *bio,
+			union map_info *map_context)
+{
+	struct exception *e;
+	struct dm_snapshot *s = (struct dm_snapshot *) ti->private;
+	int r = 1;
+	chunk_t chunk;
+	struct pending_exception *pe;
+
+	chunk = sector_to_chunk(s, bio->bi_sector);
+
+	/* Full snapshots are not usable */
+	if (!s->valid)
+		return -1;
+
+	/*
+	 * Write to snapshot - higher level takes care of RW/RO
+	 * flags so we should only get this if we are
+	 * writeable.
+	 */
+	if (bio_rw(bio) == WRITE) {
+
+		/* FIXME: should only take write lock if we need
+		 * to copy an exception */
+		down_write(&s->lock);
+
+		/* If the block is already remapped - use that, else remap it */
+		e = lookup_exception(&s->complete, chunk);
+		if (e) {
+			remap_exception(s, e, bio);
+			up_write(&s->lock);
+
+		} else {
+			pe = __find_pending_exception(s, bio);
+
+			if (!pe) {
+				if (s->store.drop_snapshot)
+					s->store.drop_snapshot(&s->store);
+				s->valid = 0;
+				r = -EIO;
+				up_write(&s->lock);
+			} else {
+				remap_exception(s, &pe->e, bio);
+				bio_list_add(&pe->snapshot_bios, bio);
+
+				if (!pe->started) {
+					/* this is protected by snap->lock */
+					pe->started = 1;
+					up_write(&s->lock);
+					start_copy(pe);
+				} else
+					up_write(&s->lock);
+				r = 0;
+			}
+		}
+
+	} else {
+		/*
+		 * FIXME: this read path scares me because we
+		 * always use the origin when we have a pending
+		 * exception.  However I can't think of a
+		 * situation where this is wrong - ejt.
+		 */
+
+		/* Do reads */
+		down_read(&s->lock);
+
+		/* See if it it has been remapped */
+		e = lookup_exception(&s->complete, chunk);
+		if (e)
+			remap_exception(s, e, bio);
+		else
+			bio->bi_bdev = s->origin->bdev;
+
+		up_read(&s->lock);
+	}
+
+	return r;
+}
+
+static void snapshot_resume(struct dm_target *ti)
+{
+	struct dm_snapshot *s = (struct dm_snapshot *) ti->private;
+
+	if (s->have_metadata)
+		return;
+
+	if (s->store.read_metadata(&s->store)) {
+		down_write(&s->lock);
+		s->valid = 0;
+		up_write(&s->lock);
+	}
+
+	s->have_metadata = 1;
+}
+
+static int snapshot_status(struct dm_target *ti, status_type_t type,
+			   char *result, unsigned int maxlen)
+{
+	struct dm_snapshot *snap = (struct dm_snapshot *) ti->private;
+	char cow[32];
+	char org[32];
+
+	switch (type) {
+	case STATUSTYPE_INFO:
+		if (!snap->valid)
+			snprintf(result, maxlen, "Invalid");
+		else {
+			if (snap->store.fraction_full) {
+				sector_t numerator, denominator;
+				snap->store.fraction_full(&snap->store,
+							  &numerator,
+							  &denominator);
+				snprintf(result, maxlen,
+					 SECTOR_FORMAT "/" SECTOR_FORMAT,
+					 numerator, denominator);
+			}
+			else
+				snprintf(result, maxlen, "Unknown");
+		}
+		break;
+
+	case STATUSTYPE_TABLE:
+		/*
+		 * kdevname returns a static pointer so we need
+		 * to make private copies if the output is to
+		 * make sense.
+		 */
+		format_dev_t(cow, snap->cow->bdev->bd_dev);
+		format_dev_t(org, snap->origin->bdev->bd_dev);
+		snprintf(result, maxlen, "%s %s %c " SECTOR_FORMAT, org, cow,
+			 snap->type, snap->chunk_size);
+		break;
+	}
+
+	return 0;
+}
+
+/*-----------------------------------------------------------------
+ * Origin methods
+ *---------------------------------------------------------------*/
+static void list_merge(struct list_head *l1, struct list_head *l2)
+{
+	struct list_head *l1_n, *l2_p;
+
+	l1_n = l1->next;
+	l2_p = l2->prev;
+
+	l1->next = l2;
+	l2->prev = l1;
+
+	l2_p->next = l1_n;
+	l1_n->prev = l2_p;
+}
+
+static int __origin_write(struct list_head *snapshots, struct bio *bio)
+{
+	int r = 1, first = 1;
+	struct dm_snapshot *snap;
+	struct exception *e;
+	struct pending_exception *pe, *last = NULL;
+	chunk_t chunk;
+
+	/* Do all the snapshots on this origin */
+	list_for_each_entry (snap, snapshots, list) {
+
+		/* Only deal with valid snapshots */
+		if (!snap->valid)
+			continue;
+
+		down_write(&snap->lock);
+
+		/*
+		 * Remember, different snapshots can have
+		 * different chunk sizes.
+		 */
+		chunk = sector_to_chunk(snap, bio->bi_sector);
+
+		/*
+		 * Check exception table to see if block
+		 * is already remapped in this snapshot
+		 * and trigger an exception if not.
+		 */
+		e = lookup_exception(&snap->complete, chunk);
+		if (!e) {
+			pe = __find_pending_exception(snap, bio);
+			if (!pe) {
+				snap->store.drop_snapshot(&snap->store);
+				snap->valid = 0;
+
+			} else {
+				if (last)
+					list_merge(&pe->siblings,
+						   &last->siblings);
+
+				last = pe;
+				r = 0;
+			}
+		}
+
+		up_write(&snap->lock);
+	}
+
+	/*
+	 * Now that we have a complete pe list we can start the copying.
+	 */
+	if (last) {
+		pe = last;
+		do {
+			down_write(&pe->snap->lock);
+			if (first)
+				bio_list_add(&pe->origin_bios, bio);
+			if (!pe->started) {
+				pe->started = 1;
+				up_write(&pe->snap->lock);
+				start_copy(pe);
+			} else
+				up_write(&pe->snap->lock);
+			first = 0;
+			pe = list_entry(pe->siblings.next,
+					struct pending_exception, siblings);
+
+		} while (pe != last);
+	}
+
+	return r;
+}
+
+/*
+ * Called on a write from the origin driver.
+ */
+static int do_origin(struct dm_dev *origin, struct bio *bio)
+{
+	struct origin *o;
+	int r = 1;
+
+	down_read(&_origins_lock);
+	o = __lookup_origin(origin->bdev);
+	if (o)
+		r = __origin_write(&o->snapshots, bio);
+	up_read(&_origins_lock);
+
+	return r;
+}
+
+/*
+ * Origin: maps a linear range of a device, with hooks for snapshotting.
+ */
+
+/*
+ * Construct an origin mapping: <dev_path>
+ * The context for an origin is merely a 'struct dm_dev *'
+ * pointing to the real device.
+ */
+static int origin_ctr(struct dm_target *ti, unsigned int argc, char **argv)
+{
+	int r;
+	struct dm_dev *dev;
+
+	if (argc != 1) {
+		ti->error = "dm-origin: incorrect number of arguments";
+		return -EINVAL;
+	}
+
+	r = dm_get_device(ti, argv[0], 0, ti->len,
+			  dm_table_get_mode(ti->table), &dev);
+	if (r) {
+		ti->error = "Cannot get target device";
+		return r;
+	}
+
+	ti->private = dev;
+	return 0;
+}
+
+static void origin_dtr(struct dm_target *ti)
+{
+	struct dm_dev *dev = (struct dm_dev *) ti->private;
+	dm_put_device(ti, dev);
+}
+
+static int origin_map(struct dm_target *ti, struct bio *bio,
+		      union map_info *map_context)
+{
+	struct dm_dev *dev = (struct dm_dev *) ti->private;
+	bio->bi_bdev = dev->bdev;
+
+	/* Only tell snapshots if this is a write */
+	return (bio_rw(bio) == WRITE) ? do_origin(dev, bio) : 1;
+}
+
+#define min_not_zero(l, r) (l == 0) ? r : ((r == 0) ? l : min(l, r))
+
+/*
+ * Set the target "split_io" field to the minimum of all the snapshots'
+ * chunk sizes.
+ */
+static void origin_resume(struct dm_target *ti)
+{
+	struct dm_dev *dev = (struct dm_dev *) ti->private;
+	struct dm_snapshot *snap;
+	struct origin *o;
+	chunk_t chunk_size = 0;
+
+	down_read(&_origins_lock);
+	o = __lookup_origin(dev->bdev);
+	if (o)
+		list_for_each_entry (snap, &o->snapshots, list)
+			chunk_size = min_not_zero(chunk_size, snap->chunk_size);
+	up_read(&_origins_lock);
+
+	ti->split_io = chunk_size;
+}
+
+static int origin_status(struct dm_target *ti, status_type_t type, char *result,
+			 unsigned int maxlen)
+{
+	struct dm_dev *dev = (struct dm_dev *) ti->private;
+	char buffer[32];
+
+	switch (type) {
+	case STATUSTYPE_INFO:
+		result[0] = '\0';
+		break;
+
+	case STATUSTYPE_TABLE:
+		format_dev_t(buffer, dev->bdev->bd_dev);
+		snprintf(result, maxlen, "%s", buffer);
+		break;
+	}
+
+	return 0;
+}
+
+static struct target_type origin_target = {
+	.name    = "snapshot-origin",
+	.version = {1, 0, 1},
+	.module  = THIS_MODULE,
+	.ctr     = origin_ctr,
+	.dtr     = origin_dtr,
+	.map     = origin_map,
+	.resume  = origin_resume,
+	.status  = origin_status,
+};
+
+static struct target_type snapshot_target = {
+	.name    = "snapshot",
+	.version = {1, 0, 1},
+	.module  = THIS_MODULE,
+	.ctr     = snapshot_ctr,
+	.dtr     = snapshot_dtr,
+	.map     = snapshot_map,
+	.resume  = snapshot_resume,
+	.status  = snapshot_status,
+};
+
+static int __init dm_snapshot_init(void)
+{
+	int r;
+
+	r = dm_register_target(&snapshot_target);
+	if (r) {
+		DMERR("snapshot target register failed %d", r);
+		return r;
+	}
+
+	r = dm_register_target(&origin_target);
+	if (r < 0) {
+		DMERR("Device mapper: Origin: register failed %d\n", r);
+		goto bad1;
+	}
+
+	r = init_origin_hash();
+	if (r) {
+		DMERR("init_origin_hash failed.");
+		goto bad2;
+	}
+
+	exception_cache = kmem_cache_create("dm-snapshot-ex",
+					    sizeof(struct exception),
+					    __alignof__(struct exception),
+					    0, NULL, NULL);
+	if (!exception_cache) {
+		DMERR("Couldn't create exception cache.");
+		r = -ENOMEM;
+		goto bad3;
+	}
+
+	pending_cache =
+	    kmem_cache_create("dm-snapshot-in",
+			      sizeof(struct pending_exception),
+			      __alignof__(struct pending_exception),
+			      0, NULL, NULL);
+	if (!pending_cache) {
+		DMERR("Couldn't create pending cache.");
+		r = -ENOMEM;
+		goto bad4;
+	}
+
+	pending_pool = mempool_create(128, mempool_alloc_slab,
+				      mempool_free_slab, pending_cache);
+	if (!pending_pool) {
+		DMERR("Couldn't create pending pool.");
+		r = -ENOMEM;
+		goto bad5;
+	}
+
+	return 0;
+
+      bad5:
+	kmem_cache_destroy(pending_cache);
+      bad4:
+	kmem_cache_destroy(exception_cache);
+      bad3:
+	exit_origin_hash();
+      bad2:
+	dm_unregister_target(&origin_target);
+      bad1:
+	dm_unregister_target(&snapshot_target);
+	return r;
+}
+
+static void __exit dm_snapshot_exit(void)
+{
+	int r;
+
+	r = dm_unregister_target(&snapshot_target);
+	if (r)
+		DMERR("snapshot unregister failed %d", r);
+
+	r = dm_unregister_target(&origin_target);
+	if (r)
+		DMERR("origin unregister failed %d", r);
+
+	exit_origin_hash();
+	mempool_destroy(pending_pool);
+	kmem_cache_destroy(pending_cache);
+	kmem_cache_destroy(exception_cache);
+}
+
+/* Module hooks */
+module_init(dm_snapshot_init);
+module_exit(dm_snapshot_exit);
+
+MODULE_DESCRIPTION(DM_NAME " snapshot target");
+MODULE_AUTHOR("Joe Thornber");
+MODULE_LICENSE("GPL");
--- diff/drivers/md/dm-snap.h	1970-01-01 01:00:00.000000000 +0100
+++ source/drivers/md/dm-snap.h	2004-06-11 19:22:02.000000000 +0100
@@ -0,0 +1,161 @@
+/*
+ * dm-snapshot.c
+ *
+ * Copyright (C) 2001-2002 Sistina Software (UK) Limited.
+ *
+ * This file is released under the GPL.
+ */
+
+#ifndef DM_SNAPSHOT_H
+#define DM_SNAPSHOT_H
+
+#include "dm.h"
+#include <linux/blkdev.h>
+
+struct exception_table {
+	uint32_t hash_mask;
+	struct list_head *table;
+};
+
+/*
+ * The snapshot code deals with largish chunks of the disk at a
+ * time. Typically 64k - 256k.
+ */
+/* FIXME: can we get away with limiting these to a uint32_t ? */
+typedef sector_t chunk_t;
+
+/*
+ * An exception is used where an old chunk of data has been
+ * replaced by a new one.
+ */
+struct exception {
+	struct list_head hash_list;
+
+	chunk_t old_chunk;
+	chunk_t new_chunk;
+};
+
+/*
+ * Abstraction to handle the meta/layout of exception stores (the
+ * COW device).
+ */
+struct exception_store {
+
+	/*
+	 * Destroys this object when you've finished with it.
+	 */
+	void (*destroy) (struct exception_store *store);
+
+	/*
+	 * The target shouldn't read the COW device until this is
+	 * called.
+	 */
+	int (*read_metadata) (struct exception_store *store);
+
+	/*
+	 * Find somewhere to store the next exception.
+	 */
+	int (*prepare_exception) (struct exception_store *store,
+				  struct exception *e);
+
+	/*
+	 * Update the metadata with this exception.
+	 */
+	void (*commit_exception) (struct exception_store *store,
+				  struct exception *e,
+				  void (*callback) (void *, int success),
+				  void *callback_context);
+
+	/*
+	 * The snapshot is invalid, note this in the metadata.
+	 */
+	void (*drop_snapshot) (struct exception_store *store);
+
+	/*
+	 * Return how full the snapshot is.
+	 */
+	void (*fraction_full) (struct exception_store *store,
+			       sector_t *numerator,
+			       sector_t *denominator);
+
+	struct dm_snapshot *snap;
+	void *context;
+};
+
+struct dm_snapshot {
+	struct rw_semaphore lock;
+	struct dm_table *table;
+
+	struct dm_dev *origin;
+	struct dm_dev *cow;
+
+	/* List of snapshots per Origin */
+	struct list_head list;
+
+	/* Size of data blocks saved - must be a power of 2 */
+	chunk_t chunk_size;
+	chunk_t chunk_mask;
+	chunk_t chunk_shift;
+
+	/* You can't use a snapshot if this is 0 (e.g. if full) */
+	int valid;
+	int have_metadata;
+
+	/* Used for display of table */
+	char type;
+
+	/* The last percentage we notified */
+	int last_percent;
+
+	struct exception_table pending;
+	struct exception_table complete;
+
+	/* The on disk metadata handler */
+	struct exception_store store;
+
+	struct kcopyd_client *kcopyd_client;
+};
+
+/*
+ * Used by the exception stores to load exceptions hen
+ * initialising.
+ */
+int dm_add_exception(struct dm_snapshot *s, chunk_t old, chunk_t new);
+
+/*
+ * Constructor and destructor for the default persistent
+ * store.
+ */
+int dm_create_persistent(struct exception_store *store, uint32_t chunk_size);
+
+int dm_create_transient(struct exception_store *store,
+			struct dm_snapshot *s, int blocksize);
+
+/*
+ * Return the number of sectors in the device.
+ */
+static inline sector_t get_dev_size(struct block_device *bdev)
+{
+	return bdev->bd_inode->i_size >> SECTOR_SHIFT;
+}
+
+static inline chunk_t sector_to_chunk(struct dm_snapshot *s, sector_t sector)
+{
+	return (sector & ~s->chunk_mask) >> s->chunk_shift;
+}
+
+static inline sector_t chunk_to_sector(struct dm_snapshot *s, chunk_t chunk)
+{
+	return chunk << s->chunk_shift;
+}
+
+static inline int bdev_equal(struct block_device *lhs, struct block_device *rhs)
+{
+	/*
+	 * There is only ever one instance of a particular block
+	 * device so we can compare pointers safely.
+	 */
+	return lhs == rhs;
+}
+
+#endif
--- diff/drivers/md/dm-zero.c	1970-01-01 01:00:00.000000000 +0100
+++ source/drivers/md/dm-zero.c	2004-06-11 19:22:02.000000000 +0100
@@ -0,0 +1,97 @@
+/*
+ * Copyright (C) 2003 Christophe Saout <christophe@saout.de>
+ *
+ * This file is released under the GPL.
+ */
+
+#include "dm.h"
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/bio.h>
+
+/*
+ * Construct a dummy mapping that only returns zeros
+ */
+static int zero_ctr(struct dm_target *ti, unsigned int argc, char **argv)
+{
+	if (argc != 0) {
+		ti->error = "dm-zero: No arguments required";
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+/*
+ * Fills the bio pages with zeros
+ */
+static void zero_fill_bio(struct bio *bio)
+{
+	unsigned long flags;
+	struct bio_vec *bv;
+	int i;
+
+	bio_for_each_segment(bv, bio, i) {
+		char *data = bvec_kmap_irq(bv, &flags);
+		memset(data, 0, bv->bv_len);
+		flush_dcache_page(bv->bv_page);
+		bvec_kunmap_irq(data, &flags);
+	}
+}
+
+/*
+ * Return zeros only on reads
+ */
+static int zero_map(struct dm_target *ti, struct bio *bio,
+		      union map_info *map_context)
+{
+	switch(bio_rw(bio)) {
+	case READ:
+		zero_fill_bio(bio);
+		break;
+	case READA:
+		/* readahead of null bytes only wastes buffer cache */
+		return -EIO;
+	case WRITE:
+		/* writes get silently dropped */
+		break;
+	}
+
+	bio_endio(bio, bio->bi_size, 0);
+
+	/* accepted bio, don't make new request */
+	return 0;
+}
+
+static struct target_type zero_target = {
+	.name   = "zero",
+	.module = THIS_MODULE,
+	.ctr    = zero_ctr,
+	.map    = zero_map,
+};
+
+int __init dm_zero_init(void)
+{
+	int r = dm_register_target(&zero_target);
+
+	if (r < 0)
+		DMERR("zero: register failed %d", r);
+
+	return r;
+}
+
+void __exit dm_zero_exit(void)
+{
+	int r = dm_unregister_target(&zero_target);
+
+	if (r < 0)
+		DMERR("zero: unregister failed %d", r);
+}
+
+module_init(dm_zero_init)
+module_exit(dm_zero_exit)
+
+MODULE_AUTHOR("Christophe Saout <christophe@saout.de>");
+MODULE_DESCRIPTION(DM_NAME " dummy target returning zeros");
+MODULE_LICENSE("GPL");
--- diff/drivers/md/kcopyd.c	1970-01-01 01:00:00.000000000 +0100
+++ source/drivers/md/kcopyd.c	2004-06-11 19:22:02.000000000 +0100
@@ -0,0 +1,671 @@
+/*
+ * Copyright (C) 2002 Sistina Software (UK) Limited.
+ *
+ * This file is released under the GPL.
+ *
+ * Kcopyd provides a simple interface for copying an area of one
+ * block-device to one or more other block-devices, with an asynchronous
+ * completion notification.
+ */
+
+#include <asm/atomic.h>
+
+#include <linux/blkdev.h>
+#include <linux/config.h>
+#include <linux/fs.h>
+#include <linux/init.h>
+#include <linux/list.h>
+#include <linux/mempool.h>
+#include <linux/module.h>
+#include <linux/pagemap.h>
+#include <linux/slab.h>
+#include <linux/vmalloc.h>
+#include <linux/workqueue.h>
+
+#include "kcopyd.h"
+
+/* FIXME: this is only needed for the DMERR macros */
+#include "dm.h"
+
+static struct workqueue_struct *_kcopyd_wq;
+static struct work_struct _kcopyd_work;
+
+static inline void wake(void)
+{
+	queue_work(_kcopyd_wq, &_kcopyd_work);
+}
+
+/*-----------------------------------------------------------------
+ * Each kcopyd client has its own little pool of preallocated
+ * pages for kcopyd io.
+ *---------------------------------------------------------------*/
+struct kcopyd_client {
+	struct list_head list;
+
+	spinlock_t lock;
+	struct page_list *pages;
+	unsigned int nr_pages;
+	unsigned int nr_free_pages;
+};
+
+static struct page_list *alloc_pl(void)
+{
+	struct page_list *pl;
+
+	pl = kmalloc(sizeof(*pl), GFP_KERNEL);
+	if (!pl)
+		return NULL;
+
+	pl->page = alloc_page(GFP_KERNEL);
+	if (!pl->page) {
+		kfree(pl);
+		return NULL;
+	}
+
+	SetPageLocked(pl->page);
+	return pl;
+}
+
+static void free_pl(struct page_list *pl)
+{
+	ClearPageLocked(pl->page);
+	__free_page(pl->page);
+	kfree(pl);
+}
+
+static int kcopyd_get_pages(struct kcopyd_client *kc,
+			    unsigned int nr, struct page_list **pages)
+{
+	struct page_list *pl;
+
+	spin_lock(&kc->lock);
+	if (kc->nr_free_pages < nr) {
+		spin_unlock(&kc->lock);
+		return -ENOMEM;
+	}
+
+	kc->nr_free_pages -= nr;
+	for (*pages = pl = kc->pages; --nr; pl = pl->next)
+		;
+
+	kc->pages = pl->next;
+	pl->next = 0;
+
+	spin_unlock(&kc->lock);
+
+	return 0;
+}
+
+static void kcopyd_put_pages(struct kcopyd_client *kc, struct page_list *pl)
+{
+	struct page_list *cursor;
+
+	spin_lock(&kc->lock);
+	for (cursor = pl; cursor->next; cursor = cursor->next)
+		kc->nr_free_pages++;
+
+	kc->nr_free_pages++;
+	cursor->next = kc->pages;
+	kc->pages = pl;
+	spin_unlock(&kc->lock);
+}
+
+/*
+ * These three functions resize the page pool.
+ */
+static void drop_pages(struct page_list *pl)
+{
+	struct page_list *next;
+
+	while (pl) {
+		next = pl->next;
+		free_pl(pl);
+		pl = next;
+	}
+}
+
+static int client_alloc_pages(struct kcopyd_client *kc, unsigned int nr)
+{
+	unsigned int i;
+	struct page_list *pl = NULL, *next;
+
+	for (i = 0; i < nr; i++) {
+		next = alloc_pl();
+		if (!next) {
+			if (pl)
+				drop_pages(pl);
+			return -ENOMEM;
+		}
+		next->next = pl;
+		pl = next;
+	}
+
+	kcopyd_put_pages(kc, pl);
+	kc->nr_pages += nr;
+	return 0;
+}
+
+static void client_free_pages(struct kcopyd_client *kc)
+{
+	BUG_ON(kc->nr_free_pages != kc->nr_pages);
+	drop_pages(kc->pages);
+	kc->pages = NULL;
+	kc->nr_free_pages = kc->nr_pages = 0;
+}
+
+/*-----------------------------------------------------------------
+ * kcopyd_jobs need to be allocated by the *clients* of kcopyd,
+ * for this reason we use a mempool to prevent the client from
+ * ever having to do io (which could cause a deadlock).
+ *---------------------------------------------------------------*/
+struct kcopyd_job {
+	struct kcopyd_client *kc;
+	struct list_head list;
+	unsigned long flags;
+
+	/*
+	 * Error state of the job.
+	 */
+	int read_err;
+	unsigned int write_err;
+
+	/*
+	 * Either READ or WRITE
+	 */
+	int rw;
+	struct io_region source;
+
+	/*
+	 * The destinations for the transfer.
+	 */
+	unsigned int num_dests;
+	struct io_region dests[KCOPYD_MAX_REGIONS];
+
+	sector_t offset;
+	unsigned int nr_pages;
+	struct page_list *pages;
+
+	/*
+	 * Set this to ensure you are notified when the job has
+	 * completed.  'context' is for callback to use.
+	 */
+	kcopyd_notify_fn fn;
+	void *context;
+
+	/*
+	 * These fields are only used if the job has been split
+	 * into more manageable parts.
+	 */
+	struct semaphore lock;
+	atomic_t sub_jobs;
+	sector_t progress;
+};
+
+/* FIXME: this should scale with the number of pages */
+#define MIN_JOBS 512
+
+static kmem_cache_t *_job_cache;
+static mempool_t *_job_pool;
+
+/*
+ * We maintain three lists of jobs:
+ *
+ * i)   jobs waiting for pages
+ * ii)  jobs that have pages, and are waiting for the io to be issued.
+ * iii) jobs that have completed.
+ *
+ * All three of these are protected by job_lock.
+ */
+static spinlock_t _job_lock = SPIN_LOCK_UNLOCKED;
+
+static LIST_HEAD(_complete_jobs);
+static LIST_HEAD(_io_jobs);
+static LIST_HEAD(_pages_jobs);
+
+static int __init jobs_init(void)
+{
+	INIT_LIST_HEAD(&_complete_jobs);
+	INIT_LIST_HEAD(&_io_jobs);
+	INIT_LIST_HEAD(&_pages_jobs);
+
+	_job_cache = kmem_cache_create("kcopyd-jobs",
+				       sizeof(struct kcopyd_job),
+				       __alignof__(struct kcopyd_job),
+				       0, NULL, NULL);
+	if (!_job_cache)
+		return -ENOMEM;
+
+	_job_pool = mempool_create(MIN_JOBS, mempool_alloc_slab,
+				   mempool_free_slab, _job_cache);
+	if (!_job_pool) {
+		kmem_cache_destroy(_job_cache);
+		return -ENOMEM;
+	}
+
+	return 0;
+}
+
+static void jobs_exit(void)
+{
+	BUG_ON(!list_empty(&_complete_jobs));
+	BUG_ON(!list_empty(&_io_jobs));
+	BUG_ON(!list_empty(&_pages_jobs));
+
+	mempool_destroy(_job_pool);
+	kmem_cache_destroy(_job_cache);
+}
+
+/*
+ * Functions to push and pop a job onto the head of a given job
+ * list.
+ */
+static inline struct kcopyd_job *pop(struct list_head *jobs)
+{
+	struct kcopyd_job *job = NULL;
+	unsigned long flags;
+
+	spin_lock_irqsave(&_job_lock, flags);
+
+	if (!list_empty(jobs)) {
+		job = list_entry(jobs->next, struct kcopyd_job, list);
+		list_del(&job->list);
+	}
+	spin_unlock_irqrestore(&_job_lock, flags);
+
+	return job;
+}
+
+static inline void push(struct list_head *jobs, struct kcopyd_job *job)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&_job_lock, flags);
+	list_add_tail(&job->list, jobs);
+	spin_unlock_irqrestore(&_job_lock, flags);
+}
+
+/*
+ * These three functions process 1 item from the corresponding
+ * job list.
+ *
+ * They return:
+ * < 0: error
+ *   0: success
+ * > 0: can't process yet.
+ */
+static int run_complete_job(struct kcopyd_job *job)
+{
+	void *context = job->context;
+	int read_err = job->read_err;
+	unsigned int write_err = job->write_err;
+	kcopyd_notify_fn fn = job->fn;
+
+	kcopyd_put_pages(job->kc, job->pages);
+	mempool_free(job, _job_pool);
+	fn(read_err, write_err, context);
+	return 0;
+}
+
+static void complete_io(unsigned long error, void *context)
+{
+	struct kcopyd_job *job = (struct kcopyd_job *) context;
+
+	if (error) {
+		if (job->rw == WRITE)
+			job->write_err &= error;
+		else
+			job->read_err = 1;
+
+		if (!test_bit(KCOPYD_IGNORE_ERROR, &job->flags)) {
+			push(&_complete_jobs, job);
+			wake();
+			return;
+		}
+	}
+
+	if (job->rw == WRITE)
+		push(&_complete_jobs, job);
+
+	else {
+		job->rw = WRITE;
+		push(&_io_jobs, job);
+	}
+
+	wake();
+}
+
+/*
+ * Request io on as many buffer heads as we can currently get for
+ * a particular job.
+ */
+static int run_io_job(struct kcopyd_job *job)
+{
+	int r;
+
+	if (job->rw == READ)
+		r = dm_io_async(1, &job->source, job->rw,
+				job->pages,
+				job->offset, complete_io, job);
+
+	else
+		r = dm_io_async(job->num_dests, job->dests, job->rw,
+				job->pages,
+				job->offset, complete_io, job);
+
+	return r;
+}
+
+static int run_pages_job(struct kcopyd_job *job)
+{
+	int r;
+
+	job->nr_pages = dm_div_up(job->dests[0].count + job->offset,
+				  PAGE_SIZE >> 9);
+	r = kcopyd_get_pages(job->kc, job->nr_pages, &job->pages);
+	if (!r) {
+		/* this job is ready for io */
+		push(&_io_jobs, job);
+		return 0;
+	}
+
+	if (r == -ENOMEM)
+		/* can't complete now */
+		return 1;
+
+	return r;
+}
+
+/*
+ * Run through a list for as long as possible.  Returns the count
+ * of successful jobs.
+ */
+static int process_jobs(struct list_head *jobs, int (*fn) (struct kcopyd_job *))
+{
+	struct kcopyd_job *job;
+	int r, count = 0;
+
+	while ((job = pop(jobs))) {
+
+		r = fn(job);
+
+		if (r < 0) {
+			/* error this rogue job */
+			if (job->rw == WRITE)
+				job->write_err = (unsigned int) -1;
+			else
+				job->read_err = 1;
+			push(&_complete_jobs, job);
+			break;
+		}
+
+		if (r > 0) {
+			/*
+			 * We couldn't service this job ATM, so
+			 * push this job back onto the list.
+			 */
+			push(jobs, job);
+			break;
+		}
+
+		count++;
+	}
+
+	return count;
+}
+
+/*
+ * kcopyd does this every time it's woken up.
+ */
+static void do_work(void *ignored)
+{
+	/*
+	 * The order that these are called is *very* important.
+	 * complete jobs can free some pages for pages jobs.
+	 * Pages jobs when successful will jump onto the io jobs
+	 * list.  io jobs call wake when they complete and it all
+	 * starts again.
+	 */
+	process_jobs(&_complete_jobs, run_complete_job);
+	process_jobs(&_pages_jobs, run_pages_job);
+	process_jobs(&_io_jobs, run_io_job);
+}
+
+/*
+ * If we are copying a small region we just dispatch a single job
+ * to do the copy, otherwise the io has to be split up into many
+ * jobs.
+ */
+static void dispatch_job(struct kcopyd_job *job)
+{
+	push(&_pages_jobs, job);
+	wake();
+}
+
+#define SUB_JOB_SIZE 128
+static void segment_complete(int read_err,
+			     unsigned int write_err, void *context)
+{
+	/* FIXME: tidy this function */
+	sector_t progress = 0;
+	sector_t count = 0;
+	struct kcopyd_job *job = (struct kcopyd_job *) context;
+
+	down(&job->lock);
+
+	/* update the error */
+	if (read_err)
+		job->read_err = 1;
+
+	if (write_err)
+		job->write_err &= write_err;
+
+	/*
+	 * Only dispatch more work if there hasn't been an error.
+	 */
+	if ((!job->read_err && !job->write_err) ||
+	    test_bit(KCOPYD_IGNORE_ERROR, &job->flags)) {
+		/* get the next chunk of work */
+		progress = job->progress;
+		count = job->source.count - progress;
+		if (count) {
+			if (count > SUB_JOB_SIZE)
+				count = SUB_JOB_SIZE;
+
+			job->progress += count;
+		}
+	}
+	up(&job->lock);
+
+	if (count) {
+		int i;
+		struct kcopyd_job *sub_job = mempool_alloc(_job_pool, GFP_NOIO);
+
+		memcpy(sub_job, job, sizeof(*job));
+		sub_job->source.sector += progress;
+		sub_job->source.count = count;
+
+		for (i = 0; i < job->num_dests; i++) {
+			sub_job->dests[i].sector += progress;
+			sub_job->dests[i].count = count;
+		}
+
+		sub_job->fn = segment_complete;
+		sub_job->context = job;
+		dispatch_job(sub_job);
+
+	} else if (atomic_dec_and_test(&job->sub_jobs)) {
+
+		/*
+		 * To avoid a race we must keep the job around
+		 * until after the notify function has completed.
+		 * Otherwise the client may try and stop the job
+		 * after we've completed.
+		 */
+		job->fn(read_err, write_err, job->context);
+		mempool_free(job, _job_pool);
+	}
+}
+
+/*
+ * Create some little jobs that will do the move between
+ * them.
+ */
+#define SPLIT_COUNT 8
+static void split_job(struct kcopyd_job *job)
+{
+	int i;
+
+	atomic_set(&job->sub_jobs, SPLIT_COUNT);
+	for (i = 0; i < SPLIT_COUNT; i++)
+		segment_complete(0, 0u, job);
+}
+
+int kcopyd_copy(struct kcopyd_client *kc, struct io_region *from,
+		unsigned int num_dests, struct io_region *dests,
+		unsigned int flags, kcopyd_notify_fn fn, void *context)
+{
+	struct kcopyd_job *job;
+
+	/*
+	 * Allocate a new job.
+	 */
+	job = mempool_alloc(_job_pool, GFP_NOIO);
+
+	/*
+	 * set up for the read.
+	 */
+	job->kc = kc;
+	job->flags = flags;
+	job->read_err = 0;
+	job->write_err = 0;
+	job->rw = READ;
+
+	memcpy(&job->source, from, sizeof(*from));
+
+	job->num_dests = num_dests;
+	memcpy(&job->dests, dests, sizeof(*dests) * num_dests);
+
+	job->offset = 0;
+	job->nr_pages = 0;
+	job->pages = NULL;
+
+	job->fn = fn;
+	job->context = context;
+
+	if (job->source.count < SUB_JOB_SIZE)
+		dispatch_job(job);
+
+	else {
+		init_MUTEX(&job->lock);
+		job->progress = 0;
+		split_job(job);
+	}
+
+	return 0;
+}
+
+/*
+ * Cancels a kcopyd job, eg. someone might be deactivating a
+ * mirror.
+ */
+int kcopyd_cancel(struct kcopyd_job *job, int block)
+{
+	/* FIXME: finish */
+	return -1;
+}
+
+/*-----------------------------------------------------------------
+ * Unit setup
+ *---------------------------------------------------------------*/
+static DECLARE_MUTEX(_client_lock);
+static LIST_HEAD(_clients);
+
+static int client_add(struct kcopyd_client *kc)
+{
+	down(&_client_lock);
+	list_add(&kc->list, &_clients);
+	up(&_client_lock);
+	return 0;
+}
+
+static void client_del(struct kcopyd_client *kc)
+{
+	down(&_client_lock);
+	list_del(&kc->list);
+	up(&_client_lock);
+}
+
+int kcopyd_client_create(unsigned int nr_pages, struct kcopyd_client **result)
+{
+	int r = 0;
+	struct kcopyd_client *kc;
+
+	kc = kmalloc(sizeof(*kc), GFP_KERNEL);
+	if (!kc)
+		return -ENOMEM;
+
+	kc->lock = SPIN_LOCK_UNLOCKED;
+	kc->pages = NULL;
+	kc->nr_pages = kc->nr_free_pages = 0;
+	r = client_alloc_pages(kc, nr_pages);
+	if (r) {
+		kfree(kc);
+		return r;
+	}
+
+	r = dm_io_get(nr_pages);
+	if (r) {
+		client_free_pages(kc);
+		kfree(kc);
+		return r;
+	}
+
+	r = client_add(kc);
+	if (r) {
+		dm_io_put(nr_pages);
+		client_free_pages(kc);
+		kfree(kc);
+		return r;
+	}
+
+	*result = kc;
+	return 0;
+}
+
+void kcopyd_client_destroy(struct kcopyd_client *kc)
+{
+	dm_io_put(kc->nr_pages);
+	client_free_pages(kc);
+	client_del(kc);
+	kfree(kc);
+}
+
+
+int __init kcopyd_init(void)
+{
+	int r;
+
+	r = jobs_init();
+	if (r)
+		return r;
+
+	_kcopyd_wq = create_singlethread_workqueue("kcopyd");
+	if (!_kcopyd_wq) {
+		jobs_exit();
+		return -ENOMEM;
+	}
+
+	INIT_WORK(&_kcopyd_work, do_work, NULL);
+	return 0;
+}
+
+void kcopyd_exit(void)
+{
+	jobs_exit();
+	destroy_workqueue(_kcopyd_wq);
+}
+
+EXPORT_SYMBOL(kcopyd_client_create);
+EXPORT_SYMBOL(kcopyd_client_destroy);
+EXPORT_SYMBOL(kcopyd_copy);
+EXPORT_SYMBOL(kcopyd_cancel);
--- diff/drivers/md/kcopyd.h	1970-01-01 01:00:00.000000000 +0100
+++ source/drivers/md/kcopyd.h	2004-06-11 19:22:02.000000000 +0100
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2001 Sistina Software
+ *
+ * This file is released under the GPL.
+ *
+ * Kcopyd provides a simple interface for copying an area of one
+ * block-device to one or more other block-devices, with an asynchronous
+ * completion notification.
+ */
+
+#ifndef DM_KCOPYD_H
+#define DM_KCOPYD_H
+
+#include "dm-io.h"
+
+int kcopyd_init(void);
+void kcopyd_exit(void);
+
+/* FIXME: make this configurable */
+#define KCOPYD_MAX_REGIONS 8
+
+#define KCOPYD_IGNORE_ERROR 1
+
+/*
+ * To use kcopyd you must first create a kcopyd client object.
+ */
+struct kcopyd_client;
+int kcopyd_client_create(unsigned int num_pages, struct kcopyd_client **result);
+void kcopyd_client_destroy(struct kcopyd_client *kc);
+
+/*
+ * Submit a copy job to kcopyd.  This is built on top of the
+ * previous three fns.
+ *
+ * read_err is a boolean,
+ * write_err is a bitset, with 1 bit for each destination region
+ */
+typedef void (*kcopyd_notify_fn)(int read_err,
+				 unsigned int write_err, void *context);
+
+int kcopyd_copy(struct kcopyd_client *kc, struct io_region *from,
+		unsigned int num_dests, struct io_region *dests,
+		unsigned int flags, kcopyd_notify_fn fn, void *context);
+
+#endif
--- diff/drivers/mtd/maps/wr_sbc82xx_flash.c	1970-01-01 01:00:00.000000000 +0100
+++ source/drivers/mtd/maps/wr_sbc82xx_flash.c	2004-06-11 19:22:02.000000000 +0100
@@ -0,0 +1,167 @@
+/*
+ * $Id: wr_sbc82xx_flash.c,v 1.1 2004/06/07 10:21:32 dwmw2 Exp $
+ *
+ * Map for flash chips on Wind River PowerQUICC II SBC82xx board.
+ *
+ * Copyright (C) 2004 Red Hat, Inc.
+ *
+ * Author: David Woodhouse <dwmw2@infradead.org>
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <asm/io.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/map.h>
+#include <linux/config.h>
+#include <linux/mtd/partitions.h>
+
+#include <asm/immap_8260.h>
+
+static struct mtd_info *sbcmtd[3];
+static struct mtd_partition *sbcmtd_parts[3];
+
+struct map_info sbc82xx_flash_map[3] = {
+	{.name = "Boot flash"},
+	{.name = "Alternate boot flash"},
+	{.name = "User flash"}
+};
+
+static struct mtd_partition smallflash_parts[] = {
+	{
+		.name =		"space",
+		.size =		0x100000,
+		.offset =	0,
+	}, {
+		.name =		"bootloader",
+		.size =		MTDPART_SIZ_FULL,
+		.offset =	MTDPART_OFS_APPEND,
+	}
+};
+
+static struct mtd_partition bigflash_parts[] = {
+	{
+		.name =		"bootloader",
+		.size =		0x80000,
+		.offset =	0,
+	}, {
+		.name =		"file system",
+		.size =		MTDPART_SIZ_FULL,
+		.offset =	MTDPART_OFS_APPEND,
+	}
+};
+
+static const char *part_probes[] __initdata = {"cmdlinepart", "RedBoot", NULL};
+
+int __init init_sbc82xx_flash(void)
+{
+	volatile  memctl8260_t *mc = &immr->im_memctl;
+	int bigflash;
+	int i;
+
+	/* First, register the boot flash, whichever we're booting from */
+	if ((mc->memc_br0 & 0x00001800) == 0x00001800) {
+		bigflash = 0;
+	} else if ((mc->memc_br0 & 0x00001800) == 0x00000800) {
+		bigflash = 1;
+	} else {
+		printk(KERN_WARNING "Bus Controller register BR0 is %08x. Cannot determine flash configuration\n", mc->memc_br0);
+		return 1;
+	}
+
+	/* Set parameters for the big flash chip (CS6 or CS0) */
+	sbc82xx_flash_map[bigflash].buswidth = 4;
+	sbc82xx_flash_map[bigflash].size = 0x4000000;
+
+	/* Set parameters for the small flash chip (CS0 or CS6) */
+	sbc82xx_flash_map[!bigflash].buswidth = 1;
+	sbc82xx_flash_map[!bigflash].size = 0x200000;
+
+	/* Set parameters for the user flash chip (CS1) */
+	sbc82xx_flash_map[2].buswidth = 4;
+	sbc82xx_flash_map[2].size = 0x4000000;
+
+	sbc82xx_flash_map[0].phys = mc->memc_br0 & 0xffff8000;
+	sbc82xx_flash_map[1].phys = mc->memc_br6 & 0xffff8000;
+	sbc82xx_flash_map[2].phys = mc->memc_br1 & 0xffff8000;
+
+	for (i=0; i<3; i++) {
+		int8_t flashcs[3] = { 0, 6, 1 };
+		int nr_parts;
+
+		printk(KERN_NOTICE "PowerQUICC II %s (%ld MiB on CS%d",
+		       sbc82xx_flash_map[i].name, sbc82xx_flash_map[i].size >> 20, flashcs[i]);
+		if (!sbc82xx_flash_map[i].phys) {
+			/* We know it can't be at zero. */
+			printk("): disabled by bootloader.\n");
+			continue;
+		}
+		printk(" at %08lx)\n",  sbc82xx_flash_map[i].phys);
+
+		sbc82xx_flash_map[i].virt = (unsigned long)ioremap(sbc82xx_flash_map[i].phys, sbc82xx_flash_map[i].size);
+
+		if (!sbc82xx_flash_map[i].virt) {
+			printk("Failed to ioremap\n");
+			continue;
+		}
+
+		simple_map_init(&sbc82xx_flash_map[i]);
+
+		sbcmtd[i] = do_map_probe("cfi_probe", &sbc82xx_flash_map[i]);
+
+		if (!sbcmtd[i])
+			continue;
+
+		sbcmtd[i]->owner = THIS_MODULE;
+
+		nr_parts = parse_mtd_partitions(sbcmtd[i], part_probes,
+						&sbcmtd_parts[i], 0);
+		if (nr_parts > 0) {
+			add_mtd_partitions (sbcmtd[i], sbcmtd_parts[i], nr_parts);
+			continue;
+		}
+
+		/* No partitioning detected. Use default */
+		if (i == 2) {
+			add_mtd_device(sbcmtd[i]);
+		} else if (i == bigflash) {
+			add_mtd_partitions (sbcmtd[i], bigflash_parts, ARRAY_SIZE(bigflash_parts));
+		} else {
+			add_mtd_partitions (sbcmtd[i], smallflash_parts, ARRAY_SIZE(smallflash_parts));
+		}
+	}
+	return 0;
+}
+
+static void __exit cleanup_sbc82xx_flash(void)
+{
+	int i;
+
+	for (i=0; i<3; i++) {
+		if (!sbcmtd[i])
+			continue;
+
+		if (i<2 || sbcmtd_parts[i])
+			del_mtd_partitions(sbcmtd[i]);
+		else
+			del_mtd_device(sbcmtd[i]);
+			
+		kfree(sbcmtd_parts[i]);
+		map_destroy(sbcmtd[i]);
+		
+		iounmap((void *)sbc82xx_flash_map[i].virt);
+		sbc82xx_flash_map[i].virt = 0;
+	}
+}
+
+module_init(init_sbc82xx_flash);
+module_exit(cleanup_sbc82xx_flash);
+
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("David Woodhouse <dwmw2@infradead.org>");
+MODULE_DESCRIPTION("Flash map driver for WindRiver PowerQUICC II");
--- diff/drivers/net/kgdb_eth.c	1970-01-01 01:00:00.000000000 +0100
+++ source/drivers/net/kgdb_eth.c	2004-06-11 19:22:02.000000000 +0100
@@ -0,0 +1,132 @@
+/*
+ * Network interface GDB stub
+ *
+ * Written by San Mehat (nettwerk@biodome.org)
+ * Based upon 'gdbserial' by David Grothe (dave@gcom.com)
+ * and Scott Foehner (sfoehner@engr.sgi.com)
+ *
+ * Twiddled for 2.6 by Robert Walsh <rjwalsh@durables.org>
+ * and wangdi <wangdi@clusterfs.com>.
+ *
+ * Refactored for netpoll API by Matt Mackall <mpm@selenic.com>
+ *
+ */
+
+#include <linux/sched.h>
+#include <linux/interrupt.h>
+#include <linux/config.h>
+#include <linux/string.h>
+#include <linux/netpoll.h>
+
+#include <asm/system.h>
+#include <asm/kgdb.h>
+#include <asm/io.h>
+#include <asm/bitops.h>
+#include <asm/system.h>
+#include <asm/irq.h>
+#include <asm/atomic.h>
+
+#define IN_BUF_SIZE 512 /* power of 2, please */
+#define OUT_BUF_SIZE 256
+
+static char in_buf[IN_BUF_SIZE], out_buf[OUT_BUF_SIZE];
+static int in_head, in_tail, out_count;
+static atomic_t in_count;
+int kgdboe = 0; /* Default to tty mode */
+
+extern void set_debug_traps(void);
+extern void breakpoint(void);
+static void rx_hook(struct netpoll *np, int port, char *msg, int len);
+
+static struct netpoll np = {
+	.name = "kgdboe",
+	.dev_name = "eth0",
+	.rx_hook = rx_hook,
+	.local_port = 6443,
+	.remote_port = 6442,
+	.remote_mac = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff},
+};
+static int configured;
+
+int eth_getDebugChar(void)
+{
+	int chr;
+
+	while (atomic_read(&in_count) == 0)
+		netpoll_poll(&np);
+
+	chr = in_buf[in_tail++];
+	in_tail &= (IN_BUF_SIZE - 1);
+	atomic_dec(&in_count);
+	return chr;
+}
+
+void eth_flushDebugChar(void)
+{
+	if(out_count && np.dev) {
+		netpoll_send_udp(&np, out_buf, out_count);
+		out_count = 0;
+	}
+}
+
+void eth_putDebugChar(int chr)
+{
+	out_buf[out_count++] = chr;
+	if(out_count == OUT_BUF_SIZE)
+		eth_flushDebugChar();
+}
+
+static void rx_hook(struct netpoll *np, int port, char *msg, int len)
+{
+	int i;
+
+	np->remote_port = port;
+
+	/* Is this gdb trying to attach? */
+	if (!netpoll_trap() && len == 8 && !strncmp(msg, "$Hc-1#09", 8))
+		kgdb_schedule_breakpoint();
+
+	for (i = 0; i < len; i++) {
+		if (msg[i] == 3)
+			kgdb_schedule_breakpoint();
+
+		if (atomic_read(&in_count) >= IN_BUF_SIZE) {
+			/* buffer overflow, clear it */
+			in_head = in_tail = 0;
+			atomic_set(&in_count, 0);
+			break;
+		}
+		in_buf[in_head++] = msg[i];
+		in_head &= (IN_BUF_SIZE - 1);
+		atomic_inc(&in_count);
+	}
+}
+
+static int option_setup(char *opt)
+{
+	configured = !netpoll_parse_options(&np, opt);
+	return 0;
+}
+__setup("kgdboe=", option_setup);
+
+static int init_kgdboe(void)
+{
+#ifdef CONFIG_SMP
+	if (num_online_cpus() > CONFIG_NO_KGDB_CPUS) {
+		printk("kgdb: too manu cpus. Cannot enable debugger with more than %d cpus\n", CONFIG_NO_KGDB_CPUS);
+		return -1;
+	}
+#endif
+
+	set_debug_traps();
+
+	if(!configured || netpoll_setup(&np))
+		return 1;
+
+	kgdboe = 1;
+	printk(KERN_INFO "kgdb: debugging over ethernet enabled\n");
+
+	return 0;
+}
+
+module_init(init_kgdboe);
--- diff/drivers/net/via-velocity.c	1970-01-01 01:00:00.000000000 +0100
+++ source/drivers/net/via-velocity.c	2004-06-11 19:22:03.000000000 +0100
@@ -0,0 +1,3273 @@
+/*
+ * This code is derived from the VIA reference driver (copyright message
+ * below) provided to Red Hat by VIA Networking Technologies, Inc. for
+ * addition to the Linux kernel.
+ *
+ * The code has been merged into one source file, cleaned up to follow
+ * Linux coding style,  ported to the Linux 2.6 kernel tree and cleaned
+ * for 64bit hardware platforms.
+ *
+ * TODO
+ *	Big-endian support
+ *	rx_copybreak/alignment
+ *	Scatter gather
+ *	More testing
+ *
+ * The changes are (c) Copyright 2004, Red Hat Inc. <alan@redhat.com>
+ * Additional fixes and clean up: Francois Romieu
+ *
+ * This source has not been verified for use in safety critical systems.
+ *
+ * Please direct queries about the revamped driver to the linux-kernel
+ * list not VIA.
+ *
+ * Original code:
+ *
+ * Copyright (c) 1996, 2003 VIA Networking Technologies, Inc.
+ * All rights reserved.
+ *
+ * This software may be redistributed and/or modified under
+ * the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or
+ * 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.
+ *
+ * Author: Chuang Liang-Shing, AJ Jiang
+ *
+ * Date: Jan 24, 2003
+ *
+ * MODULE_LICENSE("GPL");
+ *
+ */
+
+
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/config.h>
+#include <linux/init.h>
+#include <linux/mm.h>
+#include <linux/errno.h>
+#include <linux/ioport.h>
+#include <linux/pci.h>
+#include <linux/kernel.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+#include <linux/delay.h>
+#include <linux/timer.h>
+#include <linux/slab.h>
+#include <linux/interrupt.h>
+#include <linux/version.h>
+#include <linux/string.h>
+#include <linux/wait.h>
+#include <asm/io.h>
+#include <linux/if.h>
+#include <linux/config.h>
+#include <asm/uaccess.h>
+#include <linux/proc_fs.h>
+#include <linux/inetdevice.h>
+#include <linux/reboot.h>
+#include <linux/ethtool.h>
+#include <linux/mii.h>
+#include <linux/in.h>
+#include <linux/if_arp.h>
+#include <linux/ip.h>
+#include <linux/tcp.h>
+#include <linux/udp.h>
+
+#include "via-velocity.h"
+
+
+static int velocity_nics = 0;
+static int msglevel = MSG_LEVEL_INFO;
+
+
+static int velocity_mii_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd);
+static struct ethtool_ops velocity_ethtool_ops;
+
+/*
+    Define module options
+*/
+
+MODULE_AUTHOR("VIA Networking Technologies, Inc.");
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("VIA Networking Velocity Family Gigabit Ethernet Adapter Driver");
+
+#define VELOCITY_PARAM(N,D) \
+        static const int N[MAX_UNITS]=OPTION_DEFAULT;\
+        MODULE_PARM(N, "1-" __MODULE_STRING(MAX_UNITS) "i");\
+        MODULE_PARM_DESC(N, D);
+
+#define RX_DESC_MIN     64
+#define RX_DESC_MAX     255
+#define RX_DESC_DEF     64
+VELOCITY_PARAM(RxDescriptors, "Number of receive descriptors");
+
+#define TX_DESC_MIN     16
+#define TX_DESC_MAX     256
+#define TX_DESC_DEF     64
+VELOCITY_PARAM(TxDescriptors, "Number of transmit descriptors");
+
+#define VLAN_ID_MIN     0
+#define VLAN_ID_MAX     4095
+#define VLAN_ID_DEF     0
+/* VID_setting[] is used for setting the VID of NIC.
+   0: default VID.
+   1-4094: other VIDs.
+*/
+VELOCITY_PARAM(VID_setting, "802.1Q VLAN ID");
+
+#define RX_THRESH_MIN   0
+#define RX_THRESH_MAX   3
+#define RX_THRESH_DEF   0
+/* rx_thresh[] is used for controlling the receive fifo threshold.
+   0: indicate the rxfifo threshold is 128 bytes.
+   1: indicate the rxfifo threshold is 512 bytes.
+   2: indicate the rxfifo threshold is 1024 bytes.
+   3: indicate the rxfifo threshold is store & forward.
+*/
+VELOCITY_PARAM(rx_thresh, "Receive fifo threshold");
+
+#define DMA_LENGTH_MIN  0
+#define DMA_LENGTH_MAX  7
+#define DMA_LENGTH_DEF  0
+
+/* DMA_length[] is used for controlling the DMA length
+   0: 8 DWORDs
+   1: 16 DWORDs
+   2: 32 DWORDs
+   3: 64 DWORDs
+   4: 128 DWORDs
+   5: 256 DWORDs
+   6: SF(flush till emply)
+   7: SF(flush till emply)
+*/
+VELOCITY_PARAM(DMA_length, "DMA length");
+
+#define TAGGING_DEF     0
+/* enable_tagging[] is used for enabling 802.1Q VID tagging.
+   0: disable VID seeting(default).
+   1: enable VID setting.
+*/
+VELOCITY_PARAM(enable_tagging, "Enable 802.1Q tagging");
+
+#define IP_ALIG_DEF     0
+/* IP_byte_align[] is used for IP header DWORD byte aligned
+   0: indicate the IP header won't be DWORD byte aligned.(Default) .
+   1: indicate the IP header will be DWORD byte aligned.
+      In some enviroment, the IP header should be DWORD byte aligned,
+      or the packet will be droped when we receive it. (eg: IPVS)
+*/
+VELOCITY_PARAM(IP_byte_align, "Enable IP header dword aligned");
+
+#define TX_CSUM_DEF     1
+/* txcsum_offload[] is used for setting the checksum offload ability of NIC.
+   (We only support RX checksum offload now)
+   0: disable csum_offload[checksum offload
+   1: enable checksum offload. (Default)
+*/
+VELOCITY_PARAM(txcsum_offload, "Enable transmit packet checksum offload");
+
+#define FLOW_CNTL_DEF   1
+#define FLOW_CNTL_MIN   1
+#define FLOW_CNTL_MAX   5
+
+/* flow_control[] is used for setting the flow control ability of NIC.
+   1: hardware deafult - AUTO (default). Use Hardware default value in ANAR.
+   2: enable TX flow control.
+   3: enable RX flow control.
+   4: enable RX/TX flow control.
+   5: disable
+*/
+VELOCITY_PARAM(flow_control, "Enable flow control ability");
+
+#define MED_LNK_DEF 0
+#define MED_LNK_MIN 0
+#define MED_LNK_MAX 4
+/* speed_duplex[] is used for setting the speed and duplex mode of NIC.
+   0: indicate autonegotiation for both speed and duplex mode
+   1: indicate 100Mbps half duplex mode
+   2: indicate 100Mbps full duplex mode
+   3: indicate 10Mbps half duplex mode
+   4: indicate 10Mbps full duplex mode
+
+   Note:
+        if EEPROM have been set to the force mode, this option is ignored
+            by driver.
+*/
+VELOCITY_PARAM(speed_duplex, "Setting the speed and duplex mode");
+
+#define VAL_PKT_LEN_DEF     0
+/* ValPktLen[] is used for setting the checksum offload ability of NIC.
+   0: Receive frame with invalid layer 2 length (Default)
+   1: Drop frame with invalid layer 2 length
+*/
+VELOCITY_PARAM(ValPktLen, "Receiving or Drop invalid 802.3 frame");
+
+#define WOL_OPT_DEF     0
+#define WOL_OPT_MIN     0
+#define WOL_OPT_MAX     7
+/* wol_opts[] is used for controlling wake on lan behavior.
+   0: Wake up if recevied a magic packet. (Default)
+   1: Wake up if link status is on/off.
+   2: Wake up if recevied an arp packet.
+   4: Wake up if recevied any unicast packet.
+   Those value can be sumed up to support more than one option.
+*/
+VELOCITY_PARAM(wol_opts, "Wake On Lan options");
+
+#define INT_WORKS_DEF   20
+#define INT_WORKS_MIN   10
+#define INT_WORKS_MAX   64
+
+VELOCITY_PARAM(int_works, "Number of packets per interrupt services");
+
+static int velocity_found1(struct pci_dev *pdev, const struct pci_device_id *ent);
+static void velocity_init_info(struct pci_dev *pdev, struct velocity_info *vptr, struct velocity_info_tbl *info);
+static int velocity_get_pci_info(struct velocity_info *, struct pci_dev *pdev);
+static void velocity_print_info(struct velocity_info *vptr);
+static int velocity_open(struct net_device *dev);
+static int velocity_change_mtu(struct net_device *dev, int mtu);
+static int velocity_xmit(struct sk_buff *skb, struct net_device *dev);
+static int velocity_intr(int irq, void *dev_instance, struct pt_regs *regs);
+static void velocity_set_multi(struct net_device *dev);
+static struct net_device_stats *velocity_get_stats(struct net_device *dev);
+static int velocity_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
+static int velocity_close(struct net_device *dev);
+static int velocity_rx_srv(struct velocity_info *vptr, int status);
+static int velocity_receive_frame(struct velocity_info *, int idx);
+static int velocity_alloc_rx_buf(struct velocity_info *, int idx);
+static void velocity_init_registers(struct velocity_info *vptr, enum velocity_init_type type);
+static void velocity_free_rd_ring(struct velocity_info *vptr);
+static void velocity_free_tx_buf(struct velocity_info *vptr, struct velocity_td_info *);
+static int velocity_soft_reset(struct velocity_info *vptr);
+static void mii_init(struct velocity_info *vptr, u32 mii_status);
+static u32 velocity_get_opt_media_mode(struct velocity_info *vptr);
+static void velocity_print_link_status(struct velocity_info *vptr);
+static void safe_disable_mii_autopoll(struct mac_regs * regs);
+static void velocity_shutdown(struct velocity_info *vptr);
+static void enable_flow_control_ability(struct velocity_info *vptr);
+static void enable_mii_autopoll(struct mac_regs * regs);
+static int velocity_mii_read(struct mac_regs *, u8 byIdx, u16 * pdata);
+static int velocity_mii_write(struct mac_regs *, u8 byMiiAddr, u16 data);
+static int velocity_set_wol(struct velocity_info *vptr);
+static void velocity_save_context(struct velocity_info *vptr, struct velocity_context *context);
+static void velocity_restore_context(struct velocity_info *vptr, struct velocity_context *context);
+static u32 mii_check_media_mode(struct mac_regs * regs);
+static u32 check_connection_type(struct mac_regs * regs);
+static void velocity_init_cam_filter(struct velocity_info *vptr);
+static int velocity_set_media_mode(struct velocity_info *vptr, u32 mii_status);
+
+#ifdef CONFIG_PM
+static int velocity_suspend(struct pci_dev *pdev, u32 state);
+static int velocity_resume(struct pci_dev *pdev);
+
+static int velocity_netdev_event(struct notifier_block *nb, unsigned long notification, void *ptr);
+
+static struct notifier_block velocity_inetaddr_notifier = {
+      .notifier_call	= velocity_netdev_event,
+};
+static int velocity_notifier_registered;
+
+#endif				/* CONFIG_PM */
+
+/*
+ *	Internal board variants. At the moment we have only one
+ */
+
+static struct velocity_info_tbl chip_info_table[] = {
+	{CHIP_TYPE_VT6110, "VIA Networking Velocity Family Gigabit Ethernet Adapter", 256, 1, 0x00FFFFFFUL},
+	{0, NULL}
+};
+
+/*
+ *	Describe the PCI device identifiers that we support in this
+ *	device driver. Used for hotplug autoloading.
+ */
+
+static struct pci_device_id velocity_id_table[] __devinitdata = {
+	{0x1106, 0x3119, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (unsigned long) &chip_info_table[0]},
+	{0,}
+};
+
+MODULE_DEVICE_TABLE(pci, velocity_id_table);
+
+/**
+ *	get_chip_name	- 	identifier to name
+ *	@id: chip identifier
+ *
+ *	Given a chip identifier return a suitable description. Returns
+ *	a pointer a static string valid while the driver is loaded.
+ */
+
+static char __devinit *get_chip_name(enum chip_type chip_id)
+{
+	int i;
+	for (i = 0; chip_info_table[i].name != NULL; i++)
+		if (chip_info_table[i].chip_id == chip_id)
+			break;
+	return chip_info_table[i].name;
+}
+
+/**
+ *	velocity_remove1	-	device unplug
+ *	@pdev: PCI device being removed
+ *
+ *	Device unload callback. Called on an unplug or on module
+ *	unload for each active device that is present. Disconnects
+ *	the device from the network layer and frees all the resources
+ */
+
+static void __devexit velocity_remove1(struct pci_dev *pdev)
+{
+	struct net_device *dev = pci_get_drvdata(pdev);
+	struct velocity_info *vptr = dev->priv;
+
+	unregister_netdev(dev);
+	iounmap(vptr->mac_regs);
+	pci_release_regions(pdev);
+	pci_disable_device(pdev);
+	pci_set_drvdata(pdev, NULL);
+	free_netdev(dev);
+}
+
+/**
+ *	velocity_set_int_opt	-	parser for integer options
+ *	@opt: pointer to option value
+ *	@val: value the user requested (or -1 for default)
+ *	@min: lowest value allowed
+ *	@max: highest value allowed
+ *	@def: default value
+ *	@name: property name
+ *	@dev: device name
+ *
+ *	Set an integer property in the module options. This function does
+ *	all the verification and checking as well as reporting so that
+ *	we don't duplicate code for each option.
+ */
+
+static void __devinit velocity_set_int_opt(int *opt, int val, int min, int max, int def, char *name, char *devname)
+{
+	if (val == -1)
+		*opt = def;
+	else if (val < min || val > max) {
+		VELOCITY_PRT(MSG_LEVEL_INFO, KERN_NOTICE "%s: the value of parameter %s is invalid, the valid range is (%d-%d)\n",
+					devname, name, min, max);
+		*opt = def;
+	} else {
+		VELOCITY_PRT(MSG_LEVEL_INFO, KERN_INFO "%s: set value of parameter %s to %d\n",
+					devname, name, val);
+		*opt = val;
+	}
+}
+
+/**
+ *	velocity_set_bool_opt	-	parser for boolean options
+ *	@opt: pointer to option value
+ *	@val: value the user requested (or -1 for default)
+ *	@def: default value (yes/no)
+ *	@flag: numeric value to set for true.
+ *	@name: property name
+ *	@dev: device name
+ *
+ *	Set a boolean property in the module options. This function does
+ *	all the verification and checking as well as reporting so that
+ *	we don't duplicate code for each option.
+ */
+
+static void __devinit velocity_set_bool_opt(u32 * opt, int val, int def, u32 flag, char *name, char *devname)
+{
+	(*opt) &= (~flag);
+	if (val == -1)
+		*opt |= (def ? flag : 0);
+	else if (val < 0 || val > 1) {
+		printk(KERN_NOTICE "%s: the value of parameter %s is invalid, the valid range is (0-1)\n",
+			devname, name);
+		*opt |= (def ? flag : 0);
+	} else {
+		printk(KERN_INFO "%s: set parameter %s to %s\n",
+			devname, name, val ? "TRUE" : "FALSE");
+		*opt |= (val ? flag : 0);
+	}
+}
+
+/**
+ *	velocity_get_options	-	set options on device
+ *	@opts: option structure for the device
+ *	@index: index of option to use in module options array
+ *	@devname: device name
+ *
+ *	Turn the module and command options into a single structure
+ *	for the current device
+ */
+
+static void __devinit velocity_get_options(struct velocity_opt *opts, int index, char *devname)
+{
+
+	velocity_set_int_opt(&opts->rx_thresh, rx_thresh[index], RX_THRESH_MIN, RX_THRESH_MAX, RX_THRESH_DEF, "rx_thresh", devname);
+	velocity_set_int_opt(&opts->DMA_length, DMA_length[index], DMA_LENGTH_MIN, DMA_LENGTH_MAX, DMA_LENGTH_DEF, "DMA_length", devname);
+	velocity_set_int_opt(&opts->numrx, RxDescriptors[index], RX_DESC_MIN, RX_DESC_MAX, RX_DESC_DEF, "RxDescriptors", devname);
+	velocity_set_int_opt(&opts->numtx, TxDescriptors[index], TX_DESC_MIN, TX_DESC_MAX, TX_DESC_DEF, "TxDescriptors", devname);
+	velocity_set_int_opt(&opts->vid, VID_setting[index], VLAN_ID_MIN, VLAN_ID_MAX, VLAN_ID_DEF, "VID_setting", devname);
+	velocity_set_bool_opt(&opts->flags, enable_tagging[index], TAGGING_DEF, VELOCITY_FLAGS_TAGGING, "enable_tagging", devname);
+	velocity_set_bool_opt(&opts->flags, txcsum_offload[index], TX_CSUM_DEF, VELOCITY_FLAGS_TX_CSUM, "txcsum_offload", devname);
+	velocity_set_int_opt(&opts->flow_cntl, flow_control[index], FLOW_CNTL_MIN, FLOW_CNTL_MAX, FLOW_CNTL_DEF, "flow_control", devname);
+	velocity_set_bool_opt(&opts->flags, IP_byte_align[index], IP_ALIG_DEF, VELOCITY_FLAGS_IP_ALIGN, "IP_byte_align", devname);
+	velocity_set_bool_opt(&opts->flags, ValPktLen[index], VAL_PKT_LEN_DEF, VELOCITY_FLAGS_VAL_PKT_LEN, "ValPktLen", devname);
+	velocity_set_int_opt((int *) &opts->spd_dpx, speed_duplex[index], MED_LNK_MIN, MED_LNK_MAX, MED_LNK_DEF, "Media link mode", devname);
+	velocity_set_int_opt((int *) &opts->wol_opts, wol_opts[index], WOL_OPT_MIN, WOL_OPT_MAX, WOL_OPT_DEF, "Wake On Lan options", devname);
+	velocity_set_int_opt((int *) &opts->int_works, int_works[index], INT_WORKS_MIN, INT_WORKS_MAX, INT_WORKS_DEF, "Interrupt service works", devname);
+	opts->numrx = (opts->numrx & ~3);
+}
+
+/**
+ *	velocity_init_cam_filter	-	initialise CAM
+ *	@vptr: velocity to program
+ *
+ *	Initialize the content addressable memory used for filters. Load
+ *	appropriately according to the presence of VLAN
+ */
+
+static void velocity_init_cam_filter(struct velocity_info *vptr)
+{
+	struct mac_regs * regs = vptr->mac_regs;
+
+	/* T urn on MCFG_PQEN, turn off MCFG_RTGOPT */
+	WORD_REG_BITS_SET(MCFG_PQEN, MCFG_RTGOPT, &regs->MCFG);
+	WORD_REG_BITS_ON(MCFG_VIDFR, &regs->MCFG);
+
+	/* Disable all CAMs */
+	memset(vptr->vCAMmask, 0, sizeof(u8) * 8);
+	memset(vptr->mCAMmask, 0, sizeof(u8) * 8);
+	mac_set_cam_mask(regs, vptr->vCAMmask, VELOCITY_VLAN_ID_CAM);
+	mac_set_cam_mask(regs, vptr->mCAMmask, VELOCITY_MULTICAST_CAM);
+
+	/* Enable first VCAM */
+	if (vptr->flags & VELOCITY_FLAGS_TAGGING) {
+		/* If Tagging option is enabled and VLAN ID is not zero, then
+		   turn on MCFG_RTGOPT also */
+		if (vptr->options.vid != 0)
+			WORD_REG_BITS_ON(MCFG_RTGOPT, &regs->MCFG);
+
+		mac_set_cam(regs, 0, (u8 *) & (vptr->options.vid), VELOCITY_VLAN_ID_CAM);
+		vptr->vCAMmask[0] |= 1;
+		mac_set_cam_mask(regs, vptr->vCAMmask, VELOCITY_VLAN_ID_CAM);
+	} else {
+		u16 temp = 0;
+		mac_set_cam(regs, 0, (u8 *) &temp, VELOCITY_VLAN_ID_CAM);
+		temp = 1;
+		mac_set_cam_mask(regs, (u8 *) &temp, VELOCITY_VLAN_ID_CAM);
+	}
+}
+
+/**
+ *	velocity_rx_reset	-	handle a receive reset
+ *	@vptr: velocity we are resetting
+ *
+ *	Reset the ownership and status for the receive ring side.
+ *	Hand all the receive queue to the NIC.
+ */
+
+static void velocity_rx_reset(struct velocity_info *vptr)
+{
+
+	struct mac_regs * regs = vptr->mac_regs;
+	int i;
+
+	vptr->rd_used = vptr->rd_curr = 0;
+
+	/*
+	 *	Init state, all RD entries belong to the NIC
+	 */
+	for (i = 0; i < vptr->options.numrx; ++i)
+		vptr->rd_ring[i].rdesc0.owner = cpu_to_le32(OWNED_BY_NIC);
+
+	writew(vptr->options.numrx, &regs->RBRDU);
+	writel(vptr->rd_pool_dma, &regs->RDBaseLo);
+	writew(0, &regs->RDIdx);
+	writew(vptr->options.numrx - 1, &regs->RDCSize);
+}
+
+/**
+ *	velocity_init_registers	-	initialise MAC registers
+ *	@vptr: velocity to init
+ *	@type: type of initialisation (hot or cold)
+ *
+ *	Initialise the MAC on a reset or on first set up on the
+ *	hardware.
+ */
+
+static void velocity_init_registers(struct velocity_info *vptr,
+				    enum velocity_init_type type)
+{
+	struct mac_regs * regs = vptr->mac_regs;
+	int i, mii_status;
+
+	mac_wol_reset(regs);
+
+	switch (type) {
+	case VELOCITY_INIT_RESET:
+	case VELOCITY_INIT_WOL:
+
+		netif_stop_queue(vptr->dev);
+
+		/*
+		 *	Reset RX to prevent RX pointer not on the 4X location
+		 */
+		velocity_rx_reset(vptr);
+		mac_rx_queue_run(regs);
+		mac_rx_queue_wake(regs);
+
+		mii_status = velocity_get_opt_media_mode(vptr);
+		if (velocity_set_media_mode(vptr, mii_status) != VELOCITY_LINK_CHANGE) {
+			velocity_print_link_status(vptr);
+			if (!(vptr->mii_status & VELOCITY_LINK_FAIL))
+				netif_wake_queue(vptr->dev);
+		}
+
+		enable_flow_control_ability(vptr);
+
+		mac_clear_isr(regs);
+		writel(CR0_STOP, &regs->CR0Clr);
+		writel((CR0_DPOLL | CR0_TXON | CR0_RXON | CR0_STRT),
+							&regs->CR0Set);
+
+		break;
+
+	case VELOCITY_INIT_COLD:
+	default:
+		/*
+		 *	Do reset
+		 */
+		velocity_soft_reset(vptr);
+		mdelay(5);
+
+		mac_eeprom_reload(regs);
+		for (i = 0; i < 6; i++) {
+			writeb(vptr->dev->dev_addr[i], &(regs->PAR[i]));
+		}
+		/*
+		 *	clear Pre_ACPI bit.
+		 */
+		BYTE_REG_BITS_OFF(CFGA_PACPI, &(regs->CFGA));
+		mac_set_rx_thresh(regs, vptr->options.rx_thresh);
+		mac_set_dma_length(regs, vptr->options.DMA_length);
+
+		writeb(WOLCFG_SAM | WOLCFG_SAB, &regs->WOLCFGSet);
+		/*
+		 *	Bback off algorithm use original IEEE standard
+		 */
+		BYTE_REG_BITS_SET(CFGB_OFSET, (CFGB_CRANDOM | CFGB_CAP | CFGB_MBA | CFGB_BAKOPT), &regs->CFGB);
+
+		/*
+		 *	Set packet filter: Receive directed and broadcast address
+		 */
+		velocity_set_multi(vptr->dev);
+
+		/*
+		 *	Enable MII auto-polling
+		 */
+		enable_mii_autopoll(regs);
+
+		vptr->int_mask = INT_MASK_DEF;
+
+		writel(cpu_to_le32(vptr->rd_pool_dma), &regs->RDBaseLo);
+		writew(vptr->options.numrx - 1, &regs->RDCSize);
+		mac_rx_queue_run(regs);
+		mac_rx_queue_wake(regs);
+
+		writew(vptr->options.numtx - 1, &regs->TDCSize);
+
+		for (i = 0; i < vptr->num_txq; i++) {
+			writel(cpu_to_le32(vptr->td_pool_dma[i]), &(regs->TDBaseLo[i]));
+			mac_tx_queue_run(regs, i);
+		}
+
+		velocity_init_cam_filter(vptr);
+
+		init_flow_control_register(vptr);
+
+		writel(CR0_STOP, &regs->CR0Clr);
+		writel((CR0_DPOLL | CR0_TXON | CR0_RXON | CR0_STRT), &regs->CR0Set);
+
+		mii_status = velocity_get_opt_media_mode(vptr);
+		netif_stop_queue(vptr->dev);
+		mac_clear_isr(regs);
+
+		mii_init(vptr, mii_status);
+
+		if (velocity_set_media_mode(vptr, mii_status) != VELOCITY_LINK_CHANGE) {
+			velocity_print_link_status(vptr);
+			if (!(vptr->mii_status & VELOCITY_LINK_FAIL))
+				netif_wake_queue(vptr->dev);
+		}
+
+		enable_flow_control_ability(vptr);
+		mac_hw_mibs_init(regs);
+		mac_write_int_mask(vptr->int_mask, regs);
+		mac_clear_isr(regs);
+
+	}
+}
+
+/**
+ *	velocity_soft_reset	-	soft reset
+ *	@vptr: velocity to reset
+ *
+ *	Kick off a soft reset of the velocity adapter and then poll
+ *	until the reset sequence has completed before returning.
+ */
+
+static int velocity_soft_reset(struct velocity_info *vptr)
+{
+	struct mac_regs * regs = vptr->mac_regs;
+	int i = 0;
+
+	writel(CR0_SFRST, &regs->CR0Set);
+
+	for (i = 0; i < W_MAX_TIMEOUT; i++) {
+		udelay(5);
+		if (!DWORD_REG_BITS_IS_ON(CR0_SFRST, &regs->CR0Set))
+			break;
+	}
+
+	if (i == W_MAX_TIMEOUT) {
+		writel(CR0_FORSRST, &regs->CR0Set);
+		/* FIXME: PCI POSTING */
+		/* delay 2ms */
+		mdelay(2);
+	}
+	return 0;
+}
+
+/**
+ *	velocity_found1		-	set up discovered velocity card
+ *	@pdev: PCI device
+ *	@ent: PCI device table entry that matched
+ *
+ *	Configure a discovered adapter from scratch. Return a negative
+ *	errno error code on failure paths.
+ */
+
+static int __devinit velocity_found1(struct pci_dev *pdev, const struct pci_device_id *ent)
+{
+	static int first = 1;
+	struct net_device *dev;
+	int i;
+	struct velocity_info_tbl *info = (struct velocity_info_tbl *) ent->driver_data;
+	struct velocity_info *vptr;
+	struct mac_regs * regs;
+	int ret = -ENOMEM;
+
+	if (velocity_nics++ >= MAX_UNITS) {
+		printk(KERN_NOTICE VELOCITY_NAME ": already found %d NICs.\n",
+				velocity_nics);
+		return -ENODEV;
+	}
+
+	dev = alloc_etherdev(sizeof(struct velocity_info));
+
+	if (dev == NULL) {
+		printk(KERN_ERR VELOCITY_NAME ": allocate net device failed.\n");
+		goto out;
+	}
+
+	/* Chain it all together */
+
+	SET_MODULE_OWNER(dev);
+	SET_NETDEV_DEV(dev, &pdev->dev);
+	vptr = dev->priv;
+
+
+	if (first) {
+		printk(KERN_INFO "%s Ver. %s\n",
+			VELOCITY_FULL_DRV_NAM, VELOCITY_VERSION);
+		printk(KERN_INFO "Copyright (c) 2002, 2003 VIA Networking Technologies, Inc.\n");
+		printk(KERN_INFO "Copyright (c) 2004 Red Hat Inc.\n");
+		first = 0;
+	}
+
+	velocity_init_info(pdev, vptr, info);
+
+	vptr->dev = dev;
+
+	dev->priv = vptr;
+	dev->irq = pdev->irq;
+
+	ret = pci_enable_device(pdev);
+	if (ret < 0)
+		goto err_free_dev;
+
+	ret = velocity_get_pci_info(vptr, pdev);
+	if (ret < 0) {
+		printk(KERN_ERR VELOCITY_NAME ": Failed to find PCI device.\n");
+		goto err_disable;
+	}
+
+	ret = pci_request_regions(pdev, VELOCITY_NAME);
+	if (ret < 0) {
+		printk(KERN_ERR VELOCITY_NAME ": Failed to find PCI device.\n");
+		goto err_disable;
+	}
+
+	regs = ioremap(vptr->memaddr, vptr->io_size);
+	if (regs == NULL) {
+		ret = -EIO;
+		goto err_release_res;
+	}
+
+	vptr->mac_regs = regs;
+
+	mac_wol_reset(regs);
+
+	dev->base_addr = vptr->ioaddr;
+
+	for (i = 0; i < 6; i++)
+		dev->dev_addr[i] = readb(&regs->PAR[i]);
+
+
+	velocity_get_options(&vptr->options, velocity_nics - 1, dev->name);
+
+	/*
+	 *	Mask out the options cannot be set to the chip
+	 */
+
+	vptr->options.flags &= info->flags;
+
+	/*
+	 *	Enable the chip specified capbilities
+	 */
+
+	vptr->flags = vptr->options.flags | (info->flags & 0xFF000000UL);
+
+	vptr->wol_opts = vptr->options.wol_opts;
+	vptr->flags |= VELOCITY_FLAGS_WOL_ENABLED;
+
+	vptr->phy_id = MII_GET_PHY_ID(vptr->mac_regs);
+
+	dev->irq = pdev->irq;
+	dev->open = velocity_open;
+	dev->hard_start_xmit = velocity_xmit;
+	dev->stop = velocity_close;
+	dev->get_stats = velocity_get_stats;
+	dev->set_multicast_list = velocity_set_multi;
+	dev->do_ioctl = velocity_ioctl;
+	dev->ethtool_ops = &velocity_ethtool_ops;
+	dev->change_mtu = velocity_change_mtu;
+#ifdef  VELOCITY_ZERO_COPY_SUPPORT
+	dev->features |= NETIF_F_SG;
+#endif
+
+	if (vptr->flags & VELOCITY_FLAGS_TX_CSUM) {
+		dev->features |= NETIF_F_HW_CSUM;
+	}
+
+	ret = register_netdev(dev);
+	if (ret < 0)
+		goto err_iounmap;
+
+	velocity_print_info(vptr);
+	pci_set_drvdata(pdev, dev);
+
+	/* and leave the chip powered down */
+
+	pci_set_power_state(pdev, 3);
+out:
+#ifdef CONFIG_PM
+	if (ret == 0 && !velocity_notifier_registered) {
+		velocity_notifier_registered = 1;
+		register_inetaddr_notifier(&velocity_inetaddr_notifier);
+	}
+#endif
+	return ret;
+
+err_iounmap:
+	iounmap(regs);
+err_release_res:
+	pci_release_regions(pdev);
+err_disable:
+	pci_disable_device(pdev);
+err_free_dev:
+	free_netdev(dev);
+	goto out;
+}
+
+/**
+ *	velocity_print_info	-	per driver data
+ *	@vptr: velocity
+ *
+ *	Print per driver data as the kernel driver finds Velocity
+ *	hardware
+ */
+
+static void __devinit velocity_print_info(struct velocity_info *vptr)
+{
+	struct net_device *dev = vptr->dev;
+
+	printk(KERN_INFO "%s: %s\n", dev->name, get_chip_name(vptr->chip_id));
+	printk(KERN_INFO "%s: Ethernet Address: %2.2X:%2.2X:%2.2X:%2.2X:%2.2X:%2.2X\n",
+		dev->name,
+		dev->dev_addr[0], dev->dev_addr[1], dev->dev_addr[2],
+		dev->dev_addr[3], dev->dev_addr[4], dev->dev_addr[5]);
+}
+
+/**
+ *	velocity_init_info	-	init private data
+ *	@pdev: PCI device
+ *	@vptr: Velocity info
+ *	@info: Board type
+ *
+ *	Set up the initial velocity_info struct for the device that has been
+ *	discovered.
+ */
+
+static void __devinit velocity_init_info(struct pci_dev *pdev, struct velocity_info *vptr, struct velocity_info_tbl *info)
+{
+	memset(vptr, 0, sizeof(struct velocity_info));
+
+	vptr->pdev = pdev;
+	vptr->chip_id = info->chip_id;
+	vptr->io_size = info->io_size;
+	vptr->num_txq = info->txqueue;
+	vptr->multicast_limit = MCAM_SIZE;
+
+	spin_lock_init(&vptr->lock);
+	spin_lock_init(&vptr->xmit_lock);
+}
+
+/**
+ *	velocity_get_pci_info	-	retrieve PCI info for device
+ *	@vptr: velocity device
+ *	@pdev: PCI device it matches
+ *
+ *	Retrieve the PCI configuration space data that interests us from
+ *	the kernel PCI layer
+ */
+
+static int __devinit velocity_get_pci_info(struct velocity_info *vptr, struct pci_dev *pdev)
+{
+
+	if(pci_read_config_byte(pdev, PCI_REVISION_ID, &vptr->rev_id) < 0)
+		return -EIO;
+
+	pci_set_master(pdev);
+
+	vptr->ioaddr = pci_resource_start(pdev, 0);
+	vptr->memaddr = pci_resource_start(pdev, 1);
+
+	if(!(pci_resource_flags(pdev, 0) & IORESOURCE_IO))
+	{
+		printk(KERN_ERR "%s: region #0 is not an I/O resource, aborting.\n",
+				pci_name(pdev));
+		return -EINVAL;
+	}
+
+	if((pci_resource_flags(pdev, 1) & IORESOURCE_IO))
+	{
+		printk(KERN_ERR "%s: region #1 is an I/O resource, aborting.\n",
+				pci_name(pdev));
+		return -EINVAL;
+	}
+
+	if(pci_resource_len(pdev, 1) < 256)
+	{
+		printk(KERN_ERR "%s: region #1 is too small.\n",
+				pci_name(pdev));
+		return -EINVAL;
+	}
+	vptr->pdev = pdev;
+
+	return 0;
+}
+
+/**
+ *	velocity_init_rings	-	set up DMA rings
+ *	@vptr: Velocity to set up
+ *
+ *	Allocate PCI mapped DMA rings for the receive and transmit layer
+ *	to use.
+ */
+
+static int velocity_init_rings(struct velocity_info *vptr)
+{
+	int i;
+	unsigned int psize;
+	unsigned int tsize;
+	dma_addr_t pool_dma;
+	u8 *pool;
+
+	/*
+	 *	Allocate all RD/TD rings a single pool
+	 */
+
+	psize = vptr->options.numrx * sizeof(struct rx_desc) +
+		vptr->options.numtx * sizeof(struct tx_desc) * vptr->num_txq;
+
+	/*
+	 * pci_alloc_consistent() fulfills the requirement for 64 bytes
+	 * alignment
+	 */
+	pool = pci_alloc_consistent(vptr->pdev, psize, &pool_dma);
+
+	if (pool == NULL) {
+		printk(KERN_ERR "%s : DMA memory allocation failed.\n",
+					vptr->dev->name);
+		return -ENOMEM;
+	}
+
+	memset(pool, 0, psize);
+
+	vptr->rd_ring = (struct rx_desc *) pool;
+
+	vptr->rd_pool_dma = pool_dma;
+
+	tsize = vptr->options.numtx * PKT_BUF_SZ * vptr->num_txq;
+	vptr->tx_bufs = pci_alloc_consistent(vptr->pdev, tsize,
+						&vptr->tx_bufs_dma);
+
+	if (vptr->tx_bufs == NULL) {
+		printk(KERN_ERR "%s: DMA memory allocation failed.\n",
+					vptr->dev->name);
+		pci_free_consistent(vptr->pdev, psize, pool, pool_dma);
+		return -ENOMEM;
+	}
+
+	memset(vptr->tx_bufs, 0, vptr->options.numtx * PKT_BUF_SZ * vptr->num_txq);
+
+	i = vptr->options.numrx * sizeof(struct rx_desc);
+	pool += i;
+	pool_dma += i;
+	for (i = 0; i < vptr->num_txq; i++) {
+		int offset = vptr->options.numtx * sizeof(struct tx_desc);
+
+		vptr->td_pool_dma[i] = pool_dma;
+		vptr->td_rings[i] = (struct tx_desc *) pool;
+		pool += offset;
+		pool_dma += offset;
+	}
+	return 0;
+}
+
+/**
+ *	velocity_free_rings	-	free PCI ring pointers
+ *	@vptr: Velocity to free from
+ *
+ *	Clean up the PCI ring buffers allocated to this velocity.
+ */
+
+static void velocity_free_rings(struct velocity_info *vptr)
+{
+	int size;
+
+	size = vptr->options.numrx * sizeof(struct rx_desc) +
+	       vptr->options.numtx * sizeof(struct tx_desc) * vptr->num_txq;
+
+	pci_free_consistent(vptr->pdev, size, vptr->rd_ring, vptr->rd_pool_dma);
+
+	size = vptr->options.numtx * PKT_BUF_SZ * vptr->num_txq;
+
+	pci_free_consistent(vptr->pdev, size, vptr->tx_bufs, vptr->tx_bufs_dma);
+}
+
+/**
+ *	velocity_init_rd_ring	-	set up receive ring
+ *	@vptr: velocity to configure
+ *
+ *	Allocate and set up the receive buffers for each ring slot and
+ *	assign them to the network adapter.
+ */
+
+static int velocity_init_rd_ring(struct velocity_info *vptr)
+{
+	int i, ret = -ENOMEM;
+	struct rx_desc *rd;
+	struct velocity_rd_info *rd_info;
+	unsigned int rsize = sizeof(struct velocity_rd_info) *
+					vptr->options.numrx;
+
+	vptr->rd_info = kmalloc(rsize, GFP_KERNEL);
+	if(vptr->rd_info == NULL)
+		goto out;
+	memset(vptr->rd_info, 0, rsize);
+
+	/* Init the RD ring entries */
+	for (i = 0; i < vptr->options.numrx; i++) {
+		rd = &(vptr->rd_ring[i]);
+		rd_info = &(vptr->rd_info[i]);
+
+		ret = velocity_alloc_rx_buf(vptr, i);
+		if (ret < 0) {
+			VELOCITY_PRT(MSG_LEVEL_ERR, KERN_ERR
+				"%s: failed to allocate RX buffer.\n",
+				vptr->dev->name);
+			velocity_free_rd_ring(vptr);
+			goto out;
+		}
+		rd->rdesc0.owner = OWNED_BY_NIC;
+	}
+	vptr->rd_used = vptr->rd_curr = 0;
+out:
+	return ret;
+}
+
+/**
+ *	velocity_free_rd_ring	-	set up receive ring
+ *	@vptr: velocity to clean up
+ *
+ *	Free the receive buffers for each ring slot and any
+ *	attached socket buffers that need to go away.
+ */
+
+static void velocity_free_rd_ring(struct velocity_info *vptr)
+{
+	int i;
+
+	if (vptr->rd_info == NULL)
+		return;
+
+	for (i = 0; i < vptr->options.numrx; i++) {
+		struct velocity_rd_info *rd_info = &(vptr->rd_info[i]);
+
+		if (!rd_info->skb_dma)
+			continue;
+		pci_unmap_single(vptr->pdev, rd_info->skb_dma, vptr->rx_buf_sz,
+				 PCI_DMA_FROMDEVICE);
+		rd_info->skb_dma = (dma_addr_t) NULL;
+
+		dev_kfree_skb(rd_info->skb);
+		rd_info->skb = NULL;
+	}
+
+	kfree(vptr->rd_info);
+	vptr->rd_info = NULL;
+}
+
+/**
+ *	velocity_init_td_ring	-	set up transmit ring
+ *	@vptr:	velocity
+ *
+ *	Set up the transmit ring and chain the ring pointers together.
+ *	Returns zero on success or a negative posix errno code for
+ *	failure.
+ */
+
+static int velocity_init_td_ring(struct velocity_info *vptr)
+{
+	int i, j;
+	dma_addr_t curr;
+	struct tx_desc *td;
+	struct velocity_td_info *td_info;
+	unsigned int tsize = sizeof(struct velocity_td_info) *
+					vptr->options.numtx;
+
+	/* Init the TD ring entries */
+	for (j = 0; j < vptr->num_txq; j++) {
+		curr = vptr->td_pool_dma[j];
+
+		vptr->td_infos[j] = kmalloc(tsize, GFP_KERNEL);
+		if(vptr->td_infos[j] == NULL)
+		{
+			while(--j >= 0)
+				kfree(vptr->td_infos[j]);
+			return -ENOMEM;
+		}
+		memset(vptr->td_infos[j], 0, tsize);
+
+		for (i = 0; i < vptr->options.numtx; i++, curr += sizeof(struct tx_desc)) {
+			td = &(vptr->td_rings[j][i]);
+			td_info = &(vptr->td_infos[j][i]);
+			td_info->buf = vptr->tx_bufs + (i + j) * PKT_BUF_SZ;
+			td_info->buf_dma = vptr->tx_bufs_dma + (i + j) * PKT_BUF_SZ;
+		}
+		vptr->td_tail[j] = vptr->td_curr[j] = vptr->td_used[j] = 0;
+	}
+	return 0;
+}
+
+/*
+ *	FIXME: could we merge this with velocity_free_tx_buf ?
+ */
+
+static void velocity_free_td_ring_entry(struct velocity_info *vptr,
+							 int q, int n)
+{
+	struct velocity_td_info * td_info = &(vptr->td_infos[q][n]);
+	int i;
+
+	if (td_info == NULL)
+		return;
+
+	if (td_info->skb) {
+		for (i = 0; i < td_info->nskb_dma; i++)
+		{
+			if (td_info->skb_dma[i]) {
+				pci_unmap_single(vptr->pdev, td_info->skb_dma[i],
+					td_info->skb->len, PCI_DMA_TODEVICE);
+				td_info->skb_dma[i] = (dma_addr_t) NULL;
+			}
+		}
+		dev_kfree_skb(td_info->skb);
+		td_info->skb = NULL;
+	}
+}
+
+/**
+ *	velocity_free_td_ring	-	free td ring
+ *	@vptr: velocity
+ *
+ *	Free up the transmit ring for this particular velocity adapter.
+ *	We free the ring contents but not the ring itself.
+ */
+
+static void velocity_free_td_ring(struct velocity_info *vptr)
+{
+	int i, j;
+
+	for (j = 0; j < vptr->num_txq; j++) {
+		if (vptr->td_infos[j] == NULL)
+			continue;
+		for (i = 0; i < vptr->options.numtx; i++) {
+			velocity_free_td_ring_entry(vptr, j, i);
+
+		}
+		if (vptr->td_infos[j]) {
+			kfree(vptr->td_infos[j]);
+			vptr->td_infos[j] = NULL;
+		}
+	}
+}
+
+/**
+ *	velocity_rx_srv		-	service RX interrupt
+ *	@vptr: velocity
+ *	@status: adapter status (unused)
+ *
+ *	Walk the receive ring of the velocity adapter and remove
+ *	any received packets from the receive queue. Hand the ring
+ *	slots back to the adapter for reuse.
+ */
+
+static int velocity_rx_srv(struct velocity_info *vptr, int status)
+{
+	struct rx_desc *rd;
+	struct net_device_stats *stats = &vptr->stats;
+	struct mac_regs * regs = vptr->mac_regs;
+	int rd_curr = vptr->rd_curr;
+	int works = 0;
+
+	while (1) {
+
+		rd = &(vptr->rd_ring[rd_curr]);
+
+		if ((vptr->rd_info[rd_curr]).skb == NULL) {
+			if (velocity_alloc_rx_buf(vptr, rd_curr) < 0)
+				break;
+		}
+
+		if (works++ > 15)
+			break;
+
+		if (rd->rdesc0.owner == OWNED_BY_NIC)
+			break;
+
+		/*
+		 *	Don't drop CE or RL error frame although RXOK is off
+		 *	FIXME: need to handle copybreak
+		 */
+		if ((rd->rdesc0.RSR & RSR_RXOK) || (!(rd->rdesc0.RSR & RSR_RXOK) && (rd->rdesc0.RSR & (RSR_CE | RSR_RL)))) {
+			if (velocity_receive_frame(vptr, rd_curr) == 0) {
+				if (velocity_alloc_rx_buf(vptr, rd_curr) < 0) {
+					VELOCITY_PRT(MSG_LEVEL_ERR, KERN_ERR "%s: can not allocate rx buf\n", vptr->dev->name);
+					break;
+				}
+			} else {
+				stats->rx_dropped++;
+			}
+		} else {
+			if (rd->rdesc0.RSR & RSR_CRC)
+				stats->rx_crc_errors++;
+			if (rd->rdesc0.RSR & RSR_FAE)
+				stats->rx_frame_errors++;
+
+			stats->rx_dropped++;
+		}
+
+		rd->inten = 1;
+
+		if (++vptr->rd_used >= 4) {
+			int i, rd_prev = rd_curr;
+			for (i = 0; i < 4; i++) {
+				if (--rd_prev < 0)
+					rd_prev = vptr->options.numrx - 1;
+
+				rd = &(vptr->rd_ring[rd_prev]);
+				rd->rdesc0.owner = OWNED_BY_NIC;
+			}
+			writew(4, &(regs->RBRDU));
+			vptr->rd_used -= 4;
+		}
+
+		vptr->dev->last_rx = jiffies;
+
+		rd_curr++;
+		if (rd_curr >= vptr->options.numrx)
+			rd_curr = 0;
+	}
+	vptr->rd_curr = rd_curr;
+	VAR_USED(stats);
+	return works;
+}
+
+/**
+ *	velocity_rx_csum	-	checksum process
+ *	@rd: receive packet descriptor
+ *	@skb: network layer packet buffer
+ *
+ *	Process the status bits for the received packet and determine
+ *	if the checksum was computed and verified by the hardware
+ */
+
+static inline void velocity_rx_csum(struct rx_desc *rd, struct sk_buff *skb)
+{
+	skb->ip_summed = CHECKSUM_NONE;
+
+	if (rd->rdesc1.CSM & CSM_IPKT) {
+		if (rd->rdesc1.CSM & CSM_IPOK) {
+			if ((rd->rdesc1.CSM & CSM_TCPKT) ||
+					(rd->rdesc1.CSM & CSM_UDPKT)) {
+				if (!(rd->rdesc1.CSM & CSM_TUPOK)) {
+					return;
+				}
+			}
+			skb->ip_summed = CHECKSUM_UNNECESSARY;
+		}
+	}
+}
+
+/**
+ *	velocity_receive_frame	-	received packet processor
+ *	@vptr: velocity we are handling
+ *	@idx: ring index
+ *
+ *	A packet has arrived. We process the packet and if appropriate
+ *	pass the frame up the network stack
+ */
+
+static int velocity_receive_frame(struct velocity_info *vptr, int idx)
+{
+	struct net_device_stats *stats = &vptr->stats;
+	struct velocity_rd_info *rd_info = &(vptr->rd_info[idx]);
+	struct rx_desc *rd = &(vptr->rd_ring[idx]);
+	struct sk_buff *skb;
+
+	if (rd->rdesc0.RSR & (RSR_STP | RSR_EDP)) {
+		VELOCITY_PRT(MSG_LEVEL_VERBOSE, KERN_ERR " %s : the received frame span multple RDs.\n", vptr->dev->name);
+		stats->rx_length_errors++;
+		return -EINVAL;
+	}
+
+	if (rd->rdesc0.RSR & RSR_MAR)
+		vptr->stats.multicast++;
+
+	skb = rd_info->skb;
+	skb->dev = vptr->dev;
+
+	pci_unmap_single(vptr->pdev, rd_info->skb_dma, vptr->rx_buf_sz,
+							PCI_DMA_FROMDEVICE);
+	rd_info->skb_dma = (dma_addr_t) NULL;
+	rd_info->skb = NULL;
+
+	/* FIXME - memmove ? */
+	if (vptr->flags & VELOCITY_FLAGS_IP_ALIGN) {
+		int i;
+		for (i = rd->rdesc0.len + 4; i >= 0; i--)
+			*(skb->data + i + 2) = *(skb->data + i);
+		skb->data += 2;
+		skb->tail += 2;
+	}
+
+	skb_put(skb, (rd->rdesc0.len - 4));
+	skb->protocol = eth_type_trans(skb, skb->dev);
+
+	/*
+	 *	Drop frame not meeting IEEE 802.3
+	 */
+
+	if (vptr->flags & VELOCITY_FLAGS_VAL_PKT_LEN) {
+		if (rd->rdesc0.RSR & RSR_RL) {
+			stats->rx_length_errors++;
+			return -EINVAL;
+		}
+	}
+
+	velocity_rx_csum(rd, skb);
+
+	/*
+	 *	FIXME: need rx_copybreak handling
+	 */
+
+	stats->rx_bytes += skb->len;
+	netif_rx(skb);
+
+	return 0;
+}
+
+/**
+ *	velocity_alloc_rx_buf	-	allocate aligned receive buffer
+ *	@vptr: velocity
+ *	@idx: ring index
+ *
+ *	Allocate a new full sized buffer for the reception of a frame and
+ *	map it into PCI space for the hardware to use. The hardware
+ *	requires *64* byte alignment of the buffer which makes life
+ *	less fun than would be ideal.
+ */
+
+static int velocity_alloc_rx_buf(struct velocity_info *vptr, int idx)
+{
+	struct rx_desc *rd = &(vptr->rd_ring[idx]);
+	struct velocity_rd_info *rd_info = &(vptr->rd_info[idx]);
+
+	rd_info->skb = dev_alloc_skb(vptr->rx_buf_sz + 64);
+	if (rd_info->skb == NULL)
+		return -ENOMEM;
+
+	/*
+	 *	Do the gymnastics to get the buffer head for data at
+	 *	64byte alignment.
+	 */
+	skb_reserve(rd_info->skb, (unsigned long) rd_info->skb->tail & 63);
+	rd_info->skb->dev = vptr->dev;
+	rd_info->skb_dma = pci_map_single(vptr->pdev, rd_info->skb->tail, vptr->rx_buf_sz, PCI_DMA_FROMDEVICE);
+
+	/*
+	 *	Fill in the descriptor to match
+ 	 */
+
+	*((u32 *) & (rd->rdesc0)) = 0;
+	rd->len = cpu_to_le32(vptr->rx_buf_sz);
+	rd->inten = 1;
+	rd->pa_low = cpu_to_le32(rd_info->skb_dma);
+	rd->pa_high = 0;
+	return 0;
+}
+
+/**
+ *	tx_srv		-	transmit interrupt service
+ *	@vptr; Velocity
+ *	@status:
+ *
+ *	Scan the queues looking for transmitted packets that
+ *	we can complete and clean up. Update any statistics as
+ *	neccessary/
+ */
+
+static int velocity_tx_srv(struct velocity_info *vptr, u32 status)
+{
+	struct tx_desc *td;
+	int qnum;
+	int full = 0;
+	int idx;
+	int works = 0;
+	struct velocity_td_info *tdinfo;
+	struct net_device_stats *stats = &vptr->stats;
+
+	for (qnum = 0; qnum < vptr->num_txq; qnum++) {
+		for (idx = vptr->td_tail[qnum]; vptr->td_used[qnum] > 0;
+			idx = (idx + 1) % vptr->options.numtx) {
+
+			/*
+			 *	Get Tx Descriptor
+			 */
+			td = &(vptr->td_rings[qnum][idx]);
+			tdinfo = &(vptr->td_infos[qnum][idx]);
+
+			if (td->tdesc0.owner == OWNED_BY_NIC)
+				break;
+
+			if ((works++ > 15))
+				break;
+
+			if (td->tdesc0.TSR & TSR0_TERR) {
+				stats->tx_errors++;
+				stats->tx_dropped++;
+				if (td->tdesc0.TSR & TSR0_CDH)
+					stats->tx_heartbeat_errors++;
+				if (td->tdesc0.TSR & TSR0_CRS)
+					stats->tx_carrier_errors++;
+				if (td->tdesc0.TSR & TSR0_ABT)
+					stats->tx_aborted_errors++;
+				if (td->tdesc0.TSR & TSR0_OWC)
+					stats->tx_window_errors++;
+			} else {
+				stats->tx_packets++;
+				stats->tx_bytes += tdinfo->skb->len;
+			}
+			velocity_free_tx_buf(vptr, tdinfo);
+			vptr->td_used[qnum]--;
+		}
+		vptr->td_tail[qnum] = idx;
+
+		if (AVAIL_TD(vptr, qnum) < 1) {
+			full = 1;
+		}
+	}
+	/*
+	 *	Look to see if we should kick the transmit network
+	 *	layer for more work.
+	 */
+	if (netif_queue_stopped(vptr->dev) && (full == 0)
+	    && (!(vptr->mii_status & VELOCITY_LINK_FAIL))) {
+		netif_wake_queue(vptr->dev);
+	}
+	return works;
+}
+
+/**
+ *	velocity_print_link_status	-	link status reporting
+ *	@vptr: velocity to report on
+ *
+ *	Turn the link status of the velocity card into a kernel log
+ *	description of the new link state, detailing speed and duplex
+ *	status
+ */
+
+static void velocity_print_link_status(struct velocity_info *vptr)
+{
+
+	if (vptr->mii_status & VELOCITY_LINK_FAIL) {
+		VELOCITY_PRT(MSG_LEVEL_INFO, KERN_NOTICE "%s: failed to detect cable link\n", vptr->dev->name);
+	} else if (vptr->options.spd_dpx == SPD_DPX_AUTO) {
+		VELOCITY_PRT(MSG_LEVEL_INFO, KERN_NOTICE "%s: Link autonegation", vptr->dev->name);
+
+		if (vptr->mii_status & VELOCITY_SPEED_1000)
+			VELOCITY_PRT(MSG_LEVEL_INFO, " speed 1000M bps");
+		else if (vptr->mii_status & VELOCITY_SPEED_100)
+			VELOCITY_PRT(MSG_LEVEL_INFO, " speed 100M bps");
+		else
+			VELOCITY_PRT(MSG_LEVEL_INFO, " speed 10M bps");
+
+		if (vptr->mii_status & VELOCITY_DUPLEX_FULL)
+			VELOCITY_PRT(MSG_LEVEL_INFO, " full duplex\n");
+		else
+			VELOCITY_PRT(MSG_LEVEL_INFO, " half duplex\n");
+	} else {
+		VELOCITY_PRT(MSG_LEVEL_INFO, KERN_NOTICE "%s: Link forced", vptr->dev->name);
+		switch (vptr->options.spd_dpx) {
+		case SPD_DPX_100_HALF:
+			VELOCITY_PRT(MSG_LEVEL_INFO, " speed 100M bps half duplex\n");
+			break;
+		case SPD_DPX_100_FULL:
+			VELOCITY_PRT(MSG_LEVEL_INFO, " speed 100M bps full duplex\n");
+			break;
+		case SPD_DPX_10_HALF:
+			VELOCITY_PRT(MSG_LEVEL_INFO, " speed 10M bps half duplex\n");
+			break;
+		case SPD_DPX_10_FULL:
+			VELOCITY_PRT(MSG_LEVEL_INFO, " speed 10M bps full duplex\n");
+			break;
+		default:
+			break;
+		}
+	}
+}
+
+/**
+ *	velocity_error	-	handle error from controller
+ *	@vptr: velocity
+ *	@status: card status
+ *
+ *	Process an error report from the hardware and attempt to recover
+ *	the card itself. At the moment we cannot recover from some
+ *	theoretically impossible errors but this could be fixed using
+ *	the pci_device_failed logic to bounce the hardware
+ *
+ */
+
+static void velocity_error(struct velocity_info *vptr, int status)
+{
+
+	if (status & ISR_TXSTLI) {
+		struct mac_regs * regs = vptr->mac_regs;
+
+		printk(KERN_ERR "TD structure errror TDindex=%hx\n", readw(&regs->TDIdx[0]));
+		BYTE_REG_BITS_ON(TXESR_TDSTR, &regs->TXESR);
+		writew(TRDCSR_RUN, &regs->TDCSRClr);
+		netif_stop_queue(vptr->dev);
+
+		/* FIXME: port over the pci_device_failed code and use it
+		   here */
+	}
+
+	if (status & ISR_SRCI) {
+		struct mac_regs * regs = vptr->mac_regs;
+		int linked;
+
+		if (vptr->options.spd_dpx == SPD_DPX_AUTO) {
+			vptr->mii_status = check_connection_type(regs);
+
+			/*
+			 *	If it is a 3119, disable frame bursting in
+			 *	halfduplex mode and enable it in fullduplex
+			 *	 mode
+			 */
+			if (vptr->rev_id < REV_ID_VT3216_A0) {
+				if (vptr->mii_status | VELOCITY_DUPLEX_FULL)
+					BYTE_REG_BITS_ON(TCR_TB2BDIS, &regs->TCR);
+				else
+					BYTE_REG_BITS_OFF(TCR_TB2BDIS, &regs->TCR);
+			}
+			/*
+			 *	Only enable CD heart beat counter in 10HD mode
+			 */
+			if (!(vptr->mii_status & VELOCITY_DUPLEX_FULL) && (vptr->mii_status & VELOCITY_SPEED_10)) {
+				BYTE_REG_BITS_OFF(TESTCFG_HBDIS, &regs->TESTCFG);
+			} else {
+				BYTE_REG_BITS_ON(TESTCFG_HBDIS, &regs->TESTCFG);
+			}
+		}
+		/*
+		 *	Get link status from PHYSR0
+		 */
+		linked = readb(&regs->PHYSR0) & PHYSR0_LINKGD;
+
+		if (linked) {
+			vptr->mii_status &= ~VELOCITY_LINK_FAIL;
+		} else {
+			vptr->mii_status |= VELOCITY_LINK_FAIL;
+		}
+
+		velocity_print_link_status(vptr);
+		enable_flow_control_ability(vptr);
+
+		/*
+		 *	Re-enable auto-polling because SRCI will disable
+		 *	auto-polling
+		 */
+
+		enable_mii_autopoll(regs);
+
+		if (vptr->mii_status & VELOCITY_LINK_FAIL)
+			netif_stop_queue(vptr->dev);
+		else
+			netif_wake_queue(vptr->dev);
+
+	};
+	if (status & ISR_MIBFI)
+		velocity_update_hw_mibs(vptr);
+	if (status & ISR_LSTEI)
+		mac_rx_queue_wake(vptr->mac_regs);
+}
+
+/**
+ *	velocity_free_tx_buf	-	free transmit buffer
+ *	@vptr: velocity
+ *	@tdinfo: buffer
+ *
+ *	Release an transmit buffer. If the buffer was preallocated then
+ *	recycle it, if not then unmap the buffer.
+ */
+
+static void velocity_free_tx_buf(struct velocity_info *vptr, struct velocity_td_info *tdinfo)
+{
+	struct sk_buff *skb = tdinfo->skb;
+	int i;
+
+	/*
+	 *	Don't unmap the pre-allocated tx_bufs
+	 */
+	if (tdinfo->skb_dma && (tdinfo->skb_dma[0] != tdinfo->buf_dma)) {
+
+		for (i = 0; i < tdinfo->nskb_dma; i++) {
+#ifdef VELOCITY_ZERO_COPY_SUPPORT
+			pci_unmap_single(vptr->pdev, tdinfo->skb_dma[i], td->tdesc1.len, PCI_DMA_TODEVICE);
+#else
+			pci_unmap_single(vptr->pdev, tdinfo->skb_dma[i], skb->len, PCI_DMA_TODEVICE);
+#endif
+			tdinfo->skb_dma[i] = 0;
+		}
+	}
+	dev_kfree_skb_irq(skb);
+	tdinfo->skb = NULL;
+}
+
+/**
+ *	velocity_open		-	interface activation callback
+ *	@dev: network layer device to open
+ *
+ *	Called when the network layer brings the interface up. Returns
+ *	a negative posix error code on failure, or zero on success.
+ *
+ *	All the ring allocation and set up is done on open for this
+ *	adapter to minimise memory usage when inactive
+ */
+
+static int velocity_open(struct net_device *dev)
+{
+	struct velocity_info *vptr = dev->priv;
+	int ret;
+
+	vptr->rx_buf_sz = (dev->mtu <= 1504 ? PKT_BUF_SZ : dev->mtu + 32);
+
+	ret = velocity_init_rings(vptr);
+	if (ret < 0)
+		goto out;
+
+	ret = velocity_init_rd_ring(vptr);
+	if (ret < 0)
+		goto err_free_desc_rings;
+
+	ret = velocity_init_td_ring(vptr);
+	if (ret < 0)
+		goto err_free_rd_ring;
+
+	/* Ensure chip is running */
+	pci_set_power_state(vptr->pdev, 0);
+
+	velocity_init_registers(vptr, VELOCITY_INIT_COLD);
+
+	ret = request_irq(vptr->pdev->irq, &velocity_intr, SA_SHIRQ,
+			  dev->name, dev);
+	if (ret < 0) {
+		/* Power down the chip */
+		pci_set_power_state(vptr->pdev, 3);
+		goto err_free_td_ring;
+	}
+
+	mac_enable_int(vptr->mac_regs);
+	netif_start_queue(dev);
+	vptr->flags |= VELOCITY_FLAGS_OPENED;
+out:
+	return ret;
+
+err_free_td_ring:
+	velocity_free_td_ring(vptr);
+err_free_rd_ring:
+	velocity_free_rd_ring(vptr);
+err_free_desc_rings:
+	velocity_free_rings(vptr);
+	goto out;
+}
+
+/**
+ *	velocity_change_mtu	-	MTU change callback
+ *	@dev: network device
+ *	@new_mtu: desired MTU
+ *
+ *	Handle requests from the networking layer for MTU change on
+ *	this interface. It gets called on a change by the network layer.
+ *	Return zero for success or negative posix error code.
+ */
+
+static int velocity_change_mtu(struct net_device *dev, int new_mtu)
+{
+	struct velocity_info *vptr = dev->priv;
+	unsigned long flags;
+	int oldmtu = dev->mtu;
+	int ret = 0;
+
+	if ((new_mtu < VELOCITY_MIN_MTU) || new_mtu > (VELOCITY_MAX_MTU)) {
+		VELOCITY_PRT(MSG_LEVEL_ERR, KERN_NOTICE "%s: Invalid MTU.\n",
+				vptr->dev->name);
+		return -EINVAL;
+	}
+
+	if (new_mtu != oldmtu) {
+		spin_lock_irqsave(&vptr->lock, flags);
+
+		netif_stop_queue(dev);
+		velocity_shutdown(vptr);
+
+		velocity_free_td_ring(vptr);
+		velocity_free_rd_ring(vptr);
+
+		dev->mtu = new_mtu;
+		if (new_mtu > 8192)
+			vptr->rx_buf_sz = 9 * 1024;
+		else if (new_mtu > 4096)
+			vptr->rx_buf_sz = 8192;
+		else
+			vptr->rx_buf_sz = 4 * 1024;
+
+		ret = velocity_init_rd_ring(vptr);
+		if (ret < 0)
+			goto out_unlock;
+
+		ret = velocity_init_td_ring(vptr);
+		if (ret < 0)
+			goto out_unlock;
+
+		velocity_init_registers(vptr, VELOCITY_INIT_COLD);
+
+		mac_enable_int(vptr->mac_regs);
+		netif_start_queue(dev);
+out_unlock:
+		spin_unlock_irqrestore(&vptr->lock, flags);
+	}
+
+	return ret;
+}
+
+/**
+ *	velocity_shutdown	-	shut down the chip
+ *	@vptr: velocity to deactivate
+ *
+ *	Shuts down the internal operations of the velocity and
+ *	disables interrupts, autopolling, transmit and receive
+ */
+
+static void velocity_shutdown(struct velocity_info *vptr)
+{
+	struct mac_regs * regs = vptr->mac_regs;
+	mac_disable_int(regs);
+	writel(CR0_STOP, &regs->CR0Set);
+	writew(0xFFFF, &regs->TDCSRClr);
+	writeb(0xFF, &regs->RDCSRClr);
+	safe_disable_mii_autopoll(regs);
+	mac_clear_isr(regs);
+}
+
+/**
+ *	velocity_close		-	close adapter callback
+ *	@dev: network device
+ *
+ *	Callback from the network layer when the velocity is being
+ *	deactivated by the network layer
+ */
+
+static int velocity_close(struct net_device *dev)
+{
+	struct velocity_info *vptr = dev->priv;
+
+	netif_stop_queue(dev);
+	velocity_shutdown(vptr);
+
+	if (vptr->flags & VELOCITY_FLAGS_WOL_ENABLED)
+		velocity_get_ip(vptr);
+	if (dev->irq != 0)
+		free_irq(dev->irq, dev);
+
+	/* Power down the chip */
+	pci_set_power_state(vptr->pdev, 3);
+
+	/* Free the resources */
+	velocity_free_td_ring(vptr);
+	velocity_free_rd_ring(vptr);
+	velocity_free_rings(vptr);
+
+	vptr->flags &= (~VELOCITY_FLAGS_OPENED);
+	return 0;
+}
+
+/**
+ *	velocity_xmit		-	transmit packet callback
+ *	@skb: buffer to transmit
+ *	@dev: network device
+ *
+ *	Called by the networ layer to request a packet is queued to
+ *	the velocity. Returns zero on success.
+ */
+
+static int velocity_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+	struct velocity_info *vptr = dev->priv;
+	int qnum = 0;
+	struct tx_desc *td_ptr;
+	struct velocity_td_info *tdinfo;
+	unsigned long flags;
+	int index;
+
+	int pktlen = skb->len;
+
+	spin_lock_irqsave(&vptr->lock, flags);
+
+	index = vptr->td_curr[qnum];
+	td_ptr = &(vptr->td_rings[qnum][index]);
+	tdinfo = &(vptr->td_infos[qnum][index]);
+
+	td_ptr->tdesc1.TCPLS = TCPLS_NORMAL;
+	td_ptr->tdesc1.TCR = TCR0_TIC;
+	td_ptr->td_buf[0].queue = 0;
+
+	/*
+	 *	Pad short frames.
+	 */
+	if (pktlen < ETH_ZLEN) {
+		/* Cannot occur until ZC support */
+		if(skb_linearize(skb, GFP_ATOMIC))
+			return 0;
+		pktlen = ETH_ZLEN;
+		memcpy(tdinfo->buf, skb->data, skb->len);
+		memset(tdinfo->buf + skb->len, 0, ETH_ZLEN - skb->len);
+		tdinfo->skb = skb;
+		tdinfo->skb_dma[0] = tdinfo->buf_dma;
+		td_ptr->tdesc0.pktsize = pktlen;
+		td_ptr->td_buf[0].pa_low = cpu_to_le32(tdinfo->skb_dma[0]);
+		td_ptr->td_buf[0].pa_high = 0;
+		td_ptr->td_buf[0].bufsize = td_ptr->tdesc0.pktsize;
+		tdinfo->nskb_dma = 1;
+		td_ptr->tdesc1.CMDZ = 2;
+	} else
+#ifdef VELOCITY_ZERO_COPY_SUPPORT
+	if (skb_shinfo(skb)->nr_frags > 0) {
+		int nfrags = skb_shinfo(skb)->nr_frags;
+		tdinfo->skb = skb;
+		if (nfrags > 6) {
+			skb_linearize(skb, GFP_ATOMIC);
+			memcpy(tdinfo->buf, skb->data, skb->len);
+			tdinfo->skb_dma[0] = tdinfo->buf_dma;
+			td_ptr->tdesc0.pktsize =
+			td_ptr->td_buf[0].pa_low = cpu_to_le32(tdinfo->skb_dma[0]);
+			td_ptr->td_buf[0].pa_high = 0;
+			td_ptr->td_buf[0].bufsize = td_ptr->tdesc0.pktsize;
+			tdinfo->nskb_dma = 1;
+			td_ptr->tdesc1.CMDZ = 2;
+		} else {
+			int i = 0;
+			tdinfo->nskb_dma = 0;
+			tdinfo->skb_dma[i] = pci_map_single(vptr->pdev, skb->data, skb->len - skb->data_len, PCI_DMA_TODEVICE);
+
+			td_ptr->tdesc0.pktsize = pktlen;
+
+			/* FIXME: support 48bit DMA later */
+			td_ptr->td_buf[i].pa_low = cpu_to_le32(tdinfo->skb_dma);
+			td_ptr->td_buf[i].pa_high = 0;
+			td_ptr->td_buf[i].bufsize = skb->len->skb->data_len;
+
+			for (i = 0; i < nfrags; i++) {
+				skb_frag_t *frag = &skb_shinfo(skb)->frags[i];
+				void *addr = ((void *) page_address(frag->page + frag->page_offset));
+
+				tdinfo->skb_dma[i + 1] = pci_map_single(vptr->pdev, addr, frag->size, PCI_DMA_TODEVICE);
+
+				td_ptr->td_buf[i + 1].pa_low = cpu_to_le32(tdinfo->skb_dma[i + 1]);
+				td_ptr->td_buf[i + 1].pa_high = 0;
+				td_ptr->td_buf[i + 1].bufsize = frag->size;
+			}
+			tdinfo->nskb_dma = i - 1;
+			td_ptr->tdesc1.CMDZ = i;
+		}
+
+	} else
+#endif
+	{
+		/*
+		 *	Map the linear network buffer into PCI space and
+		 *	add it to the transmit ring.
+		 */
+		tdinfo->skb = skb;
+		tdinfo->skb_dma[0] = pci_map_single(vptr->pdev, skb->data, pktlen, PCI_DMA_TODEVICE);
+		td_ptr->tdesc0.pktsize = pktlen;
+		td_ptr->td_buf[0].pa_low = cpu_to_le32(tdinfo->skb_dma[0]);
+		td_ptr->td_buf[0].pa_high = 0;
+		td_ptr->td_buf[0].bufsize = td_ptr->tdesc0.pktsize;
+		tdinfo->nskb_dma = 1;
+		td_ptr->tdesc1.CMDZ = 2;
+	}
+
+	if (vptr->flags & VELOCITY_FLAGS_TAGGING) {
+		td_ptr->tdesc1.pqinf.VID = (vptr->options.vid & 0xfff);
+		td_ptr->tdesc1.pqinf.priority = 0;
+		td_ptr->tdesc1.pqinf.CFI = 0;
+		td_ptr->tdesc1.TCR |= TCR0_VETAG;
+	}
+
+	/*
+	 *	Handle hardware checksum
+	 */
+	if ((vptr->flags & VELOCITY_FLAGS_TX_CSUM)
+				 && (skb->ip_summed == CHECKSUM_HW)) {
+		struct iphdr *ip = skb->nh.iph;
+		if (ip->protocol == IPPROTO_TCP)
+			td_ptr->tdesc1.TCR |= TCR0_TCPCK;
+		else if (ip->protocol == IPPROTO_UDP)
+			td_ptr->tdesc1.TCR |= (TCR0_UDPCK);
+		td_ptr->tdesc1.TCR |= TCR0_IPCK;
+	}
+	{
+
+		int prev = index - 1;
+
+		if (prev < 0)
+			prev = vptr->options.numtx - 1;
+		td_ptr->tdesc0.owner = OWNED_BY_NIC;
+		vptr->td_used[qnum]++;
+		vptr->td_curr[qnum] = (index + 1) % vptr->options.numtx;
+
+		if (AVAIL_TD(vptr, qnum) < 1)
+			netif_stop_queue(dev);
+
+		td_ptr = &(vptr->td_rings[qnum][prev]);
+		td_ptr->td_buf[0].queue = 1;
+		mac_tx_queue_wake(vptr->mac_regs, qnum);
+	}
+	dev->trans_start = jiffies;
+	spin_unlock_irqrestore(&vptr->lock, flags);
+	return 0;
+}
+
+/**
+ *	velocity_intr		-	interrupt callback
+ *	@irq: interrupt number
+ *	@dev_instance: interrupting device
+ *	@pt_regs: CPU register state at interrupt
+ *
+ *	Called whenever an interrupt is generated by the velocity
+ *	adapter IRQ line. We may not be the source of the interrupt
+ *	and need to identify initially if we are, and if not exit as
+ *	efficiently as possible.
+ */
+
+static int velocity_intr(int irq, void *dev_instance, struct pt_regs *regs)
+{
+	struct net_device *dev = dev_instance;
+	struct velocity_info *vptr = dev->priv;
+	u32 isr_status;
+	int max_count = 0;
+
+
+	spin_lock(&vptr->lock);
+	isr_status = mac_read_isr(vptr->mac_regs);
+
+	/* Not us ? */
+	if (isr_status == 0) {
+		spin_unlock(&vptr->lock);
+		return IRQ_NONE;
+	}
+
+	mac_disable_int(vptr->mac_regs);
+
+	/*
+	 *	Keep processing the ISR until we have completed
+	 *	processing and the isr_status becomes zero
+	 */
+
+	while (isr_status != 0) {
+		mac_write_isr(vptr->mac_regs, isr_status);
+		if (isr_status & (~(ISR_PRXI | ISR_PPRXI | ISR_PTXI | ISR_PPTXI)))
+			velocity_error(vptr, isr_status);
+		if (isr_status & (ISR_PRXI | ISR_PPRXI))
+			max_count += velocity_rx_srv(vptr, isr_status);
+		if (isr_status & (ISR_PTXI | ISR_PPTXI))
+			max_count += velocity_tx_srv(vptr, isr_status);
+		isr_status = mac_read_isr(vptr->mac_regs);
+		if (max_count > vptr->options.int_works)
+		{
+			printk(KERN_WARNING "%s: excessive work at interrupt.\n",
+				dev->name);
+			max_count = 0;
+		}
+	}
+	spin_unlock(&vptr->lock);
+	mac_enable_int(vptr->mac_regs);
+	return IRQ_HANDLED;
+
+}
+
+
+/**
+ *	ether_crc	-	ethernet CRC function
+ *
+ *	Compute an ethernet CRC hash of the data block provided. This
+ *	is not performance optimised but is not needed in performance
+ *	critical code paths.
+ *
+ *	FIXME: could we use shared code here ?
+ */
+
+static inline u32 ether_crc(int length, unsigned char *data)
+{
+	static unsigned const ethernet_polynomial = 0x04c11db7U;
+
+	int crc = -1;
+
+	while (--length >= 0) {
+		unsigned char current_octet = *data++;
+		int bit;
+		for (bit = 0; bit < 8; bit++, current_octet >>= 1) {
+			crc = (crc << 1) ^ ((crc < 0) ^ (current_octet & 1) ? ethernet_polynomial : 0);
+		}
+	}
+	return crc;
+}
+
+/**
+ *	velocity_set_multi	-	filter list change callback
+ *	@dev: network device
+ *
+ *	Called by the network layer when the filter lists need to change
+ *	for a velocity adapter. Reload the CAMs with the new address
+ *	filter ruleset.
+ */
+
+static void velocity_set_multi(struct net_device *dev)
+{
+	struct velocity_info *vptr = dev->priv;
+	struct mac_regs * regs = vptr->mac_regs;
+	u8 rx_mode;
+	int i;
+	struct dev_mc_list *mclist;
+
+	if (dev->flags & IFF_PROMISC) {	/* Set promiscuous. */
+		/* Unconditionally log net taps. */
+		printk(KERN_NOTICE "%s: Promiscuous mode enabled.\n", dev->name);
+		writel(0xffffffff, &regs->MARCAM[0]);
+		writel(0xffffffff, &regs->MARCAM[4]);
+		rx_mode = (RCR_AM | RCR_AB | RCR_PROM);
+	} else if ((dev->mc_count > vptr->multicast_limit)
+		   || (dev->flags & IFF_ALLMULTI)) {
+		writel(0xffffffff, &regs->MARCAM[0]);
+		writel(0xffffffff, &regs->MARCAM[4]);
+		rx_mode = (RCR_AM | RCR_AB);
+	} else {
+		int offset = MCAM_SIZE - vptr->multicast_limit;
+		mac_get_cam_mask(regs, vptr->mCAMmask, VELOCITY_MULTICAST_CAM);
+
+		for (i = 0, mclist = dev->mc_list; mclist && i < dev->mc_count; i++, mclist = mclist->next) {
+			mac_set_cam(regs, i + offset, mclist->dmi_addr, VELOCITY_MULTICAST_CAM);
+			vptr->mCAMmask[(offset + i) / 8] |= 1 << ((offset + i) & 7);
+		}
+
+		mac_set_cam_mask(regs, vptr->mCAMmask, VELOCITY_MULTICAST_CAM);
+		rx_mode = (RCR_AM | RCR_AB);
+	}
+	if (dev->mtu > 1500)
+		rx_mode |= RCR_AL;
+
+	BYTE_REG_BITS_ON(rx_mode, &regs->RCR);
+
+}
+
+/**
+ *	velocity_get_status	-	statistics callback
+ *	@dev: network device
+ *
+ *	Callback from the network layer to allow driver statistics
+ *	to be resynchronized with hardware collected state. In the
+ *	case of the velocity we need to pull the MIB counters from
+ *	the hardware into the counters before letting the network
+ *	layer display them.
+ */
+
+static struct net_device_stats *velocity_get_stats(struct net_device *dev)
+{
+	struct velocity_info *vptr = dev->priv;
+
+	/* If the hardware is down, don't touch MII */
+	if(!netif_running(dev))
+		return &vptr->stats;
+
+	spin_lock_irq(&vptr->lock);
+	velocity_update_hw_mibs(vptr);
+	spin_unlock_irq(&vptr->lock);
+
+	vptr->stats.rx_packets = vptr->mib_counter[HW_MIB_ifRxAllPkts];
+	vptr->stats.rx_errors = vptr->mib_counter[HW_MIB_ifRxErrorPkts];
+	vptr->stats.rx_length_errors = vptr->mib_counter[HW_MIB_ifInRangeLengthErrors];
+
+//  unsigned long   rx_dropped;     /* no space in linux buffers    */
+	vptr->stats.collisions = vptr->mib_counter[HW_MIB_ifTxEtherCollisions];
+	/* detailed rx_errors: */
+//  unsigned long   rx_length_errors;
+//  unsigned long   rx_over_errors;     /* receiver ring buff overflow  */
+	vptr->stats.rx_crc_errors = vptr->mib_counter[HW_MIB_ifRxPktCRCE];
+//  unsigned long   rx_frame_errors;    /* recv'd frame alignment error */
+//  unsigned long   rx_fifo_errors;     /* recv'r fifo overrun      */
+//  unsigned long   rx_missed_errors;   /* receiver missed packet   */
+
+	/* detailed tx_errors */
+//  unsigned long   tx_fifo_errors;
+
+	return &vptr->stats;
+}
+
+
+/**
+ *	velocity_ioctl		-	ioctl entry point
+ *	@dev: network device
+ *	@rq: interface request ioctl
+ *	@cmd: command code
+ *
+ *	Called when the user issues an ioctl request to the network
+ *	device in question. The velocity interface supports MII.
+ */
+
+static int velocity_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
+{
+	struct velocity_info *vptr = dev->priv;
+	int ret;
+
+	/* If we are asked for information and the device is power
+	   saving then we need to bring the device back up to talk to it */
+
+	if(!netif_running(dev))
+		pci_set_power_state(vptr->pdev, 0);
+
+	switch (cmd) {
+	case SIOCGMIIPHY:	/* Get address of MII PHY in use. */
+	case SIOCGMIIREG:	/* Read MII PHY register. */
+	case SIOCSMIIREG:	/* Write to MII PHY register. */
+		ret = velocity_mii_ioctl(dev, rq, cmd);
+		break;
+
+	default:
+		ret = -EOPNOTSUPP;
+	}
+	if(!netif_running(dev))
+		pci_set_power_state(vptr->pdev, 3);
+
+
+	return ret;
+}
+
+/*
+ *	Definition for our device driver. The PCI layer interface
+ *	uses this to handle all our card discover and plugging
+ */
+
+static struct pci_driver velocity_driver = {
+      .name	= VELOCITY_NAME,
+      .id_table	= velocity_id_table,
+      .probe	= velocity_found1,
+      .remove	= __devexit_p(velocity_remove1),
+#ifdef CONFIG_PM
+      .suspend	= velocity_suspend,
+      .resume	= velocity_resume,
+#endif
+};
+
+/**
+ *	velocity_init_module	-	load time function
+ *
+ *	Called when the velocity module is loaded. The PCI driver
+ *	is registered with the PCI layer, and in turn will call
+ *	the probe functions for each velocity adapter installed
+ *	in the system.
+ */
+
+static int __init velocity_init_module(void)
+{
+	int ret;
+	ret = pci_module_init(&velocity_driver);
+
+	return ret;
+}
+
+/**
+ *	velocity_cleanup	-	module unload
+ *
+ *	When the velocity hardware is unloaded this function is called.
+ *	It will clean up the notifiers and the unregister the PCI
+ *	driver interface for this hardware. This in turn cleans up
+ *	all discovered interfaces before returning from the function
+ */
+
+static void __exit velocity_cleanup_module(void)
+{
+#ifdef CONFIG_PM
+	if (velocity_notifier_registered) {
+		unregister_inetaddr_notifier(&velocity_inetaddr_notifier);
+		velocity_notifier_registered = 0;
+	}
+#endif
+	pci_unregister_driver(&velocity_driver);
+}
+
+module_init(velocity_init_module);
+module_exit(velocity_cleanup_module);
+
+
+/*
+ * MII access , media link mode setting functions
+ */
+
+
+/**
+ *	mii_init	-	set up MII
+ *	@vptr: velocity adapter
+ *	@mii_status:  links tatus
+ *
+ *	Set up the PHY for the current link state.
+ */
+
+static void mii_init(struct velocity_info *vptr, u32 mii_status)
+{
+	u16 BMCR;
+
+	switch (PHYID_GET_PHY_ID(vptr->phy_id)) {
+	case PHYID_CICADA_CS8201:
+		/*
+		 *	Reset to hardware default
+		 */
+		MII_REG_BITS_OFF((ANAR_ASMDIR | ANAR_PAUSE), MII_REG_ANAR, vptr->mac_regs);
+		/*
+		 *	Turn on ECHODIS bit in NWay-forced full mode and turn it
+		 *	off it in NWay-forced half mode for NWay-forced v.s.
+		 *	legacy-forced issue.
+		 */
+		if (vptr->mii_status & VELOCITY_DUPLEX_FULL)
+			MII_REG_BITS_ON(TCSR_ECHODIS, MII_REG_TCSR, vptr->mac_regs);
+		else
+			MII_REG_BITS_OFF(TCSR_ECHODIS, MII_REG_TCSR, vptr->mac_regs);
+		/*
+		 *	Turn on Link/Activity LED enable bit for CIS8201
+		 */
+		MII_REG_BITS_ON(PLED_LALBE, MII_REG_PLED, vptr->mac_regs);
+		break;
+	case PHYID_VT3216_32BIT:
+	case PHYID_VT3216_64BIT:
+		/*
+		 *	Reset to hardware default
+		 */
+		MII_REG_BITS_ON((ANAR_ASMDIR | ANAR_PAUSE), MII_REG_ANAR, vptr->mac_regs);
+		/*
+		 *	Turn on ECHODIS bit in NWay-forced full mode and turn it
+		 *	off it in NWay-forced half mode for NWay-forced v.s.
+		 *	legacy-forced issue
+		 */
+		if (vptr->mii_status & VELOCITY_DUPLEX_FULL)
+			MII_REG_BITS_ON(TCSR_ECHODIS, MII_REG_TCSR, vptr->mac_regs);
+		else
+			MII_REG_BITS_OFF(TCSR_ECHODIS, MII_REG_TCSR, vptr->mac_regs);
+		break;
+
+	case PHYID_MARVELL_1000:
+	case PHYID_MARVELL_1000S:
+		/*
+		 *	Assert CRS on Transmit
+		 */
+		MII_REG_BITS_ON(PSCR_ACRSTX, MII_REG_PSCR, vptr->mac_regs);
+		/*
+		 *	Reset to hardware default
+		 */
+		MII_REG_BITS_ON((ANAR_ASMDIR | ANAR_PAUSE), MII_REG_ANAR, vptr->mac_regs);
+		break;
+	default:
+		;
+	}
+	velocity_mii_read(vptr->mac_regs, MII_REG_BMCR, &BMCR);
+	if (BMCR & BMCR_ISO) {
+		BMCR &= ~BMCR_ISO;
+		velocity_mii_write(vptr->mac_regs, MII_REG_BMCR, BMCR);
+	}
+}
+
+/**
+ *	safe_disable_mii_autopoll	-	autopoll off
+ *	@regs: velocity registers
+ *
+ *	Turn off the autopoll and wait for it to disable on the chip
+ */
+
+static void safe_disable_mii_autopoll(struct mac_regs * regs)
+{
+	u16 ww;
+
+	/*  turn off MAUTO */
+	writeb(0, &regs->MIICR);
+	for (ww = 0; ww < W_MAX_TIMEOUT; ww++) {
+		udelay(1);
+		if (BYTE_REG_BITS_IS_ON(MIISR_MIDLE, &regs->MIISR))
+			break;
+	}
+}
+
+/**
+ *	enable_mii_autopoll	-	turn on autopolling
+ *	@regs: velocity registers
+ *
+ *	Enable the MII link status autopoll feature on the Velocity
+ *	hardware. Wait for it to enable.
+ */
+
+static void enable_mii_autopoll(struct mac_regs * regs)
+{
+	int ii;
+
+	writeb(0, &(regs->MIICR));
+	writeb(MIIADR_SWMPL, &regs->MIIADR);
+
+	for (ii = 0; ii < W_MAX_TIMEOUT; ii++) {
+		udelay(1);
+		if (BYTE_REG_BITS_IS_ON(MIISR_MIDLE, &regs->MIISR))
+			break;
+	}
+
+	writeb(MIICR_MAUTO, &regs->MIICR);
+
+	for (ii = 0; ii < W_MAX_TIMEOUT; ii++) {
+		udelay(1);
+		if (!BYTE_REG_BITS_IS_ON(MIISR_MIDLE, &regs->MIISR))
+			break;
+	}
+
+}
+
+/**
+ *	velocity_mii_read	-	read MII data
+ *	@regs: velocity registers
+ *	@index: MII register index
+ *	@data: buffer for received data
+ *
+ *	Perform a single read of an MII 16bit register. Returns zero
+ *	on success or -ETIMEDOUT if the PHY did not respond.
+ */
+
+static int velocity_mii_read(struct mac_regs * regs, u8 index, u16 *data)
+{
+	u16 ww;
+
+	/*
+	 *	Disable MIICR_MAUTO, so that mii addr can be set normally
+	 */
+	safe_disable_mii_autopoll(regs);
+
+	writeb(index, &regs->MIIADR);
+
+	BYTE_REG_BITS_ON(MIICR_RCMD, &regs->MIICR);
+
+	for (ww = 0; ww < W_MAX_TIMEOUT; ww++) {
+		if (!(readb(&regs->MIICR) & MIICR_RCMD))
+			break;
+	}
+
+	*data = readw(&regs->MIIDATA);
+
+	enable_mii_autopoll(regs);
+	if (ww == W_MAX_TIMEOUT)
+		return -ETIMEDOUT;
+	return 0;
+}
+
+/**
+ *	velocity_mii_write	-	write MII data
+ *	@regs: velocity registers
+ *	@index: MII register index
+ *	@data: 16bit data for the MII register
+ *
+ *	Perform a single write to an MII 16bit register. Returns zero
+ *	on success or -ETIMEDOUT if the PHY did not respond.
+ */
+
+static int velocity_mii_write(struct mac_regs * regs, u8 mii_addr, u16 data)
+{
+	u16 ww;
+
+	/*
+	 *	Disable MIICR_MAUTO, so that mii addr can be set normally
+	 */
+	safe_disable_mii_autopoll(regs);
+
+	/* MII reg offset */
+	writeb(mii_addr, &regs->MIIADR);
+	/* set MII data */
+	writew(data, &regs->MIIDATA);
+
+	/* turn on MIICR_WCMD */
+	BYTE_REG_BITS_ON(MIICR_WCMD, &regs->MIICR);
+
+	/* W_MAX_TIMEOUT is the timeout period */
+	for (ww = 0; ww < W_MAX_TIMEOUT; ww++) {
+		udelay(5);
+		if (!(readb(&regs->MIICR) & MIICR_WCMD))
+			break;
+	}
+	enable_mii_autopoll(regs);
+
+	if (ww == W_MAX_TIMEOUT)
+		return -ETIMEDOUT;
+	return 0;
+}
+
+/**
+ *	velocity_get_opt_media_mode	-	get media selection
+ *	@vptr: velocity adapter
+ *
+ *	Get the media mode stored in EEPROM or module options and load
+ *	mii_status accordingly. The requested link state information
+ *	is also returned.
+ */
+
+static u32 velocity_get_opt_media_mode(struct velocity_info *vptr)
+{
+	u32 status = 0;
+
+	switch (vptr->options.spd_dpx) {
+	case SPD_DPX_AUTO:
+		status = VELOCITY_AUTONEG_ENABLE;
+		break;
+	case SPD_DPX_100_FULL:
+		status = VELOCITY_SPEED_100 | VELOCITY_DUPLEX_FULL;
+		break;
+	case SPD_DPX_10_FULL:
+		status = VELOCITY_SPEED_10 | VELOCITY_DUPLEX_FULL;
+		break;
+	case SPD_DPX_100_HALF:
+		status = VELOCITY_SPEED_100;
+		break;
+	case SPD_DPX_10_HALF:
+		status = VELOCITY_SPEED_10;
+		break;
+	}
+	vptr->mii_status = status;
+	return status;
+}
+
+/**
+ *	mii_set_auto_on		-	autonegotiate on
+ *	@vptr: velocity
+ *
+ *	Enable autonegotation on this interface
+ */
+
+static void mii_set_auto_on(struct velocity_info *vptr)
+{
+	if (MII_REG_BITS_IS_ON(BMCR_AUTO, MII_REG_BMCR, vptr->mac_regs))
+		MII_REG_BITS_ON(BMCR_REAUTO, MII_REG_BMCR, vptr->mac_regs);
+	else
+		MII_REG_BITS_ON(BMCR_AUTO, MII_REG_BMCR, vptr->mac_regs);
+}
+
+
+/*
+static void mii_set_auto_off(struct velocity_info * vptr)
+{
+    MII_REG_BITS_OFF(BMCR_AUTO, MII_REG_BMCR, vptr->mac_regs);
+}
+*/
+
+/**
+ *	set_mii_flow_control	-	flow control setup
+ *	@vptr: velocity interface
+ *
+ *	Set up the flow control on this interface according to
+ *	the supplied user/eeprom options.
+ */
+
+static void set_mii_flow_control(struct velocity_info *vptr)
+{
+	/*Enable or Disable PAUSE in ANAR */
+	switch (vptr->options.flow_cntl) {
+	case FLOW_CNTL_TX:
+		MII_REG_BITS_OFF(ANAR_PAUSE, MII_REG_ANAR, vptr->mac_regs);
+		MII_REG_BITS_ON(ANAR_ASMDIR, MII_REG_ANAR, vptr->mac_regs);
+		break;
+
+	case FLOW_CNTL_RX:
+		MII_REG_BITS_ON(ANAR_PAUSE, MII_REG_ANAR, vptr->mac_regs);
+		MII_REG_BITS_ON(ANAR_ASMDIR, MII_REG_ANAR, vptr->mac_regs);
+		break;
+
+	case FLOW_CNTL_TX_RX:
+		MII_REG_BITS_ON(ANAR_PAUSE, MII_REG_ANAR, vptr->mac_regs);
+		MII_REG_BITS_ON(ANAR_ASMDIR, MII_REG_ANAR, vptr->mac_regs);
+		break;
+
+	case FLOW_CNTL_DISABLE:
+		MII_REG_BITS_OFF(ANAR_PAUSE, MII_REG_ANAR, vptr->mac_regs);
+		MII_REG_BITS_OFF(ANAR_ASMDIR, MII_REG_ANAR, vptr->mac_regs);
+		break;
+	default:
+		break;
+	}
+}
+
+/**
+ *	velocity_set_media_mode		-	set media mode
+ *	@mii_status: old MII link state
+ *
+ *	Check the media link state and configure the flow control
+ *	PHY and also velocity hardware setup accordingly. In particular
+ *	we need to set up CD polling and frame bursting.
+ */
+
+static int velocity_set_media_mode(struct velocity_info *vptr, u32 mii_status)
+{
+	u32 curr_status;
+	struct mac_regs * regs = vptr->mac_regs;
+
+	vptr->mii_status = mii_check_media_mode(vptr->mac_regs);
+	curr_status = vptr->mii_status & (~VELOCITY_LINK_FAIL);
+
+	/* Set mii link status */
+	set_mii_flow_control(vptr);
+
+	/*
+	   Check if new status is consisent with current status
+	   if (((mii_status & curr_status) & VELOCITY_AUTONEG_ENABLE)
+	   || (mii_status==curr_status)) {
+	   vptr->mii_status=mii_check_media_mode(vptr->mac_regs);
+	   vptr->mii_status=check_connection_type(vptr->mac_regs);
+	   VELOCITY_PRT(MSG_LEVEL_INFO, "Velocity link no change\n");
+	   return 0;
+	   }
+	 */
+
+	if (PHYID_GET_PHY_ID(vptr->phy_id) == PHYID_CICADA_CS8201) {
+		MII_REG_BITS_ON(AUXCR_MDPPS, MII_REG_AUXCR, vptr->mac_regs);
+	}
+
+	/*
+	 *	If connection type is AUTO
+	 */
+	if (mii_status & VELOCITY_AUTONEG_ENABLE) {
+		VELOCITY_PRT(MSG_LEVEL_INFO, "Velocity is AUTO mode\n");
+		/* clear force MAC mode bit */
+		BYTE_REG_BITS_OFF(CHIPGCR_FCMODE, &regs->CHIPGCR);
+		/* set duplex mode of MAC according to duplex mode of MII */
+		MII_REG_BITS_ON(ANAR_TXFD | ANAR_TX | ANAR_10FD | ANAR_10, MII_REG_ANAR, vptr->mac_regs);
+		MII_REG_BITS_ON(G1000CR_1000FD | G1000CR_1000, MII_REG_G1000CR, vptr->mac_regs);
+		MII_REG_BITS_ON(BMCR_SPEED1G, MII_REG_BMCR, vptr->mac_regs);
+
+		/* enable AUTO-NEGO mode */
+		mii_set_auto_on(vptr);
+	} else {
+		u16 ANAR;
+		u8 CHIPGCR;
+
+		/*
+		 * 1. if it's 3119, disable frame bursting in halfduplex mode
+		 *    and enable it in fullduplex mode
+		 * 2. set correct MII/GMII and half/full duplex mode in CHIPGCR
+		 * 3. only enable CD heart beat counter in 10HD mode
+		 */
+
+		/* set force MAC mode bit */
+		BYTE_REG_BITS_ON(CHIPGCR_FCMODE, &regs->CHIPGCR);
+
+		CHIPGCR = readb(&regs->CHIPGCR);
+		CHIPGCR &= ~CHIPGCR_FCGMII;
+
+		if (mii_status & VELOCITY_DUPLEX_FULL) {
+			CHIPGCR |= CHIPGCR_FCFDX;
+			writeb(CHIPGCR, &regs->CHIPGCR);
+			VELOCITY_PRT(MSG_LEVEL_INFO, "set Velocity to forced full mode\n");
+			if (vptr->rev_id < REV_ID_VT3216_A0)
+				BYTE_REG_BITS_OFF(TCR_TB2BDIS, &regs->TCR);
+		} else {
+			CHIPGCR &= ~CHIPGCR_FCFDX;
+			VELOCITY_PRT(MSG_LEVEL_INFO, "set Velocity to forced half mode\n");
+			writeb(CHIPGCR, &regs->CHIPGCR);
+			if (vptr->rev_id < REV_ID_VT3216_A0)
+				BYTE_REG_BITS_ON(TCR_TB2BDIS, &regs->TCR);
+		}
+
+		MII_REG_BITS_OFF(G1000CR_1000FD | G1000CR_1000, MII_REG_G1000CR, vptr->mac_regs);
+
+		if (!(mii_status & VELOCITY_DUPLEX_FULL) && (mii_status & VELOCITY_SPEED_10)) {
+			BYTE_REG_BITS_OFF(TESTCFG_HBDIS, &regs->TESTCFG);
+		} else {
+			BYTE_REG_BITS_ON(TESTCFG_HBDIS, &regs->TESTCFG);
+		}
+		/* MII_REG_BITS_OFF(BMCR_SPEED1G, MII_REG_BMCR, vptr->mac_regs); */
+		velocity_mii_read(vptr->mac_regs, MII_REG_ANAR, &ANAR);
+		ANAR &= (~(ANAR_TXFD | ANAR_TX | ANAR_10FD | ANAR_10));
+		if (mii_status & VELOCITY_SPEED_100) {
+			if (mii_status & VELOCITY_DUPLEX_FULL)
+				ANAR |= ANAR_TXFD;
+			else
+				ANAR |= ANAR_TX;
+		} else {
+			if (mii_status & VELOCITY_DUPLEX_FULL)
+				ANAR |= ANAR_10FD;
+			else
+				ANAR |= ANAR_10;
+		}
+		velocity_mii_write(vptr->mac_regs, MII_REG_ANAR, ANAR);
+		/* enable AUTO-NEGO mode */
+		mii_set_auto_on(vptr);
+		/* MII_REG_BITS_ON(BMCR_AUTO, MII_REG_BMCR, vptr->mac_regs); */
+	}
+	/* vptr->mii_status=mii_check_media_mode(vptr->mac_regs); */
+	/* vptr->mii_status=check_connection_type(vptr->mac_regs); */
+	return VELOCITY_LINK_CHANGE;
+}
+
+/**
+ *	mii_check_media_mode	-	check media state
+ *	@regs: velocity registers
+ *
+ *	Check the current MII status and determine the link status
+ *	accordingly
+ */
+
+static u32 mii_check_media_mode(struct mac_regs * regs)
+{
+	u32 status = 0;
+	u16 ANAR;
+
+	if (!MII_REG_BITS_IS_ON(BMSR_LNK, MII_REG_BMSR, regs))
+		status |= VELOCITY_LINK_FAIL;
+
+	if (MII_REG_BITS_IS_ON(G1000CR_1000FD, MII_REG_G1000CR, regs))
+		status |= VELOCITY_SPEED_1000 | VELOCITY_DUPLEX_FULL;
+	else if (MII_REG_BITS_IS_ON(G1000CR_1000, MII_REG_G1000CR, regs))
+		status |= (VELOCITY_SPEED_1000);
+	else {
+		velocity_mii_read(regs, MII_REG_ANAR, &ANAR);
+		if (ANAR & ANAR_TXFD)
+			status |= (VELOCITY_SPEED_100 | VELOCITY_DUPLEX_FULL);
+		else if (ANAR & ANAR_TX)
+			status |= VELOCITY_SPEED_100;
+		else if (ANAR & ANAR_10FD)
+			status |= (VELOCITY_SPEED_10 | VELOCITY_DUPLEX_FULL);
+		else
+			status |= (VELOCITY_SPEED_10);
+	}
+
+	if (MII_REG_BITS_IS_ON(BMCR_AUTO, MII_REG_BMCR, regs)) {
+		velocity_mii_read(regs, MII_REG_ANAR, &ANAR);
+		if ((ANAR & (ANAR_TXFD | ANAR_TX | ANAR_10FD | ANAR_10))
+		    == (ANAR_TXFD | ANAR_TX | ANAR_10FD | ANAR_10)) {
+			if (MII_REG_BITS_IS_ON(G1000CR_1000 | G1000CR_1000FD, MII_REG_G1000CR, regs))
+				status |= VELOCITY_AUTONEG_ENABLE;
+		}
+	}
+
+	return status;
+}
+
+static u32 check_connection_type(struct mac_regs * regs)
+{
+	u32 status = 0;
+	u8 PHYSR0;
+	u16 ANAR;
+	PHYSR0 = readb(&regs->PHYSR0);
+
+	/*
+	   if (!(PHYSR0 & PHYSR0_LINKGD))
+	   status|=VELOCITY_LINK_FAIL;
+	 */
+
+	if (PHYSR0 & PHYSR0_FDPX)
+		status |= VELOCITY_DUPLEX_FULL;
+
+	if (PHYSR0 & PHYSR0_SPDG)
+		status |= VELOCITY_SPEED_1000;
+	if (PHYSR0 & PHYSR0_SPD10)
+		status |= VELOCITY_SPEED_10;
+	else
+		status |= VELOCITY_SPEED_100;
+
+	if (MII_REG_BITS_IS_ON(BMCR_AUTO, MII_REG_BMCR, regs)) {
+		velocity_mii_read(regs, MII_REG_ANAR, &ANAR);
+		if ((ANAR & (ANAR_TXFD | ANAR_TX | ANAR_10FD | ANAR_10))
+		    == (ANAR_TXFD | ANAR_TX | ANAR_10FD | ANAR_10)) {
+			if (MII_REG_BITS_IS_ON(G1000CR_1000 | G1000CR_1000FD, MII_REG_G1000CR, regs))
+				status |= VELOCITY_AUTONEG_ENABLE;
+		}
+	}
+
+	return status;
+}
+
+/**
+ *	enable_flow_control_ability	-	flow control
+ *	@vptr: veloity to configure
+ *
+ *	Set up flow control according to the flow control options
+ *	determined by the eeprom/configuration.
+ */
+
+static void enable_flow_control_ability(struct velocity_info *vptr)
+{
+
+	struct mac_regs * regs = vptr->mac_regs;
+
+	switch (vptr->options.flow_cntl) {
+
+	case FLOW_CNTL_DEFAULT:
+		if (BYTE_REG_BITS_IS_ON(PHYSR0_RXFLC, &regs->PHYSR0))
+			writel(CR0_FDXRFCEN, &regs->CR0Set);
+		else
+			writel(CR0_FDXRFCEN, &regs->CR0Clr);
+
+		if (BYTE_REG_BITS_IS_ON(PHYSR0_TXFLC, &regs->PHYSR0))
+			writel(CR0_FDXTFCEN, &regs->CR0Set);
+		else
+			writel(CR0_FDXTFCEN, &regs->CR0Clr);
+		break;
+
+	case FLOW_CNTL_TX:
+		writel(CR0_FDXTFCEN, &regs->CR0Set);
+		writel(CR0_FDXRFCEN, &regs->CR0Clr);
+		break;
+
+	case FLOW_CNTL_RX:
+		writel(CR0_FDXRFCEN, &regs->CR0Set);
+		writel(CR0_FDXTFCEN, &regs->CR0Clr);
+		break;
+
+	case FLOW_CNTL_TX_RX:
+		writel(CR0_FDXTFCEN, &regs->CR0Set);
+		writel(CR0_FDXRFCEN, &regs->CR0Set);
+		break;
+
+	case FLOW_CNTL_DISABLE:
+		writel(CR0_FDXRFCEN, &regs->CR0Clr);
+		writel(CR0_FDXTFCEN, &regs->CR0Clr);
+		break;
+
+	default:
+		break;
+	}
+
+}
+
+static int velocity_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
+{
+	struct velocity_info *vptr = dev->priv;
+	struct mac_regs * regs = vptr->mac_regs;
+	u32 status;
+	int state = vptr->pdev->current_state;
+
+	if(state != 0)
+		pci_set_power_state(vptr->pdev, 0);
+
+	status = check_connection_type(vptr->mac_regs);
+
+	cmd->supported = SUPPORTED_TP | SUPPORTED_Autoneg | SUPPORTED_10baseT_Half | SUPPORTED_10baseT_Full | SUPPORTED_100baseT_Half | SUPPORTED_100baseT_Full | SUPPORTED_1000baseT_Half | SUPPORTED_1000baseT_Full;
+	if (status & VELOCITY_SPEED_100)
+		cmd->speed = SPEED_100;
+	else
+		cmd->speed = SPEED_10;
+	cmd->autoneg = (status & VELOCITY_AUTONEG_ENABLE) ? AUTONEG_ENABLE : AUTONEG_DISABLE;
+	cmd->port = PORT_TP;
+	cmd->transceiver = XCVR_INTERNAL;
+	cmd->phy_address = readb(&regs->MIIADR) & 0x1F;
+
+	if (status & VELOCITY_DUPLEX_FULL)
+		cmd->duplex = DUPLEX_FULL;
+	else
+		cmd->duplex = DUPLEX_HALF;
+
+	if(state != 0)
+		pci_set_power_state(vptr->pdev, state);
+	return 0;
+}
+
+static int velocity_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
+{
+	struct velocity_info *vptr = dev->priv;
+	u32 curr_status;
+	u32 new_status = 0;
+	int ret = 0;
+	int state = vptr->pdev->current_state;
+
+	if(state != 0)
+		pci_set_power_state(vptr->pdev, 0);
+
+	curr_status = check_connection_type(vptr->mac_regs);
+	curr_status &= (~VELOCITY_LINK_FAIL);
+
+	new_status |= ((cmd->autoneg) ? VELOCITY_AUTONEG_ENABLE : 0);
+	new_status |= ((cmd->speed == SPEED_100) ? VELOCITY_SPEED_100 : 0);
+	new_status |= ((cmd->speed == SPEED_10) ? VELOCITY_SPEED_10 : 0);
+	new_status |= ((cmd->duplex == DUPLEX_FULL) ? VELOCITY_DUPLEX_FULL : 0);
+
+	if ((new_status & VELOCITY_AUTONEG_ENABLE) && (new_status != (curr_status | VELOCITY_AUTONEG_ENABLE)))
+		ret = -EINVAL;
+	else
+		velocity_set_media_mode(vptr, new_status);
+
+	if(state != 0)
+		pci_set_power_state(vptr->pdev, state);
+	return ret;
+}
+
+static u32 velocity_get_link(struct net_device *dev)
+{
+	struct velocity_info *vptr = dev->priv;
+	unsigned int ret;
+	int state = vptr->pdev->current_state;
+	struct mac_regs * regs = vptr->mac_regs;
+
+	if(state != 0)
+		pci_set_power_state(vptr->pdev, 0);
+
+	ret = BYTE_REG_BITS_IS_ON(PHYSR0_LINKGD, &regs->PHYSR0)  ? 0 : 1;
+
+	if(state != 0)
+		pci_set_power_state(vptr->pdev, state);
+	return ret;
+}
+
+static void velocity_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info)
+{
+	struct velocity_info *vptr = dev->priv;
+	strcpy(info->driver, VELOCITY_NAME);
+	strcpy(info->version, VELOCITY_VERSION);
+	strcpy(info->bus_info, vptr->pdev->slot_name);
+}
+
+static void velocity_ethtool_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
+{
+	struct velocity_info *vptr = dev->priv;
+	wol->supported = WAKE_PHY | WAKE_MAGIC | WAKE_UCAST | WAKE_ARP;
+	wol->wolopts |= WAKE_MAGIC;
+	/*
+	   if (vptr->wol_opts & VELOCITY_WOL_PHY)
+		   wol.wolopts|=WAKE_PHY;
+			 */
+	if (vptr->wol_opts & VELOCITY_WOL_UCAST)
+		wol->wolopts |= WAKE_UCAST;
+	if (vptr->wol_opts & VELOCITY_WOL_ARP)
+		wol->wolopts |= WAKE_ARP;
+	memcpy(&wol->sopass, vptr->wol_passwd, 6);
+}
+
+static int velocity_ethtool_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
+{
+	struct velocity_info *vptr = dev->priv;
+
+	if (!(wol->wolopts & (WAKE_PHY | WAKE_MAGIC | WAKE_UCAST | WAKE_ARP)))
+		return -EFAULT;
+	vptr->wol_opts = VELOCITY_WOL_MAGIC;
+
+	/*
+	   if (wol.wolopts & WAKE_PHY) {
+	   vptr->wol_opts|=VELOCITY_WOL_PHY;
+	   vptr->flags |=VELOCITY_FLAGS_WOL_ENABLED;
+	   }
+	 */
+
+	if (wol->wolopts & WAKE_MAGIC) {
+		vptr->wol_opts |= VELOCITY_WOL_MAGIC;
+		vptr->flags |= VELOCITY_FLAGS_WOL_ENABLED;
+	}
+	if (wol->wolopts & WAKE_UCAST) {
+		vptr->wol_opts |= VELOCITY_WOL_UCAST;
+		vptr->flags |= VELOCITY_FLAGS_WOL_ENABLED;
+	}
+	if (wol->wolopts & WAKE_ARP) {
+		vptr->wol_opts |= VELOCITY_WOL_ARP;
+		vptr->flags |= VELOCITY_FLAGS_WOL_ENABLED;
+	}
+	memcpy(vptr->wol_passwd, wol->sopass, 6);
+	return 0;
+}
+
+static u32 velocity_get_msglevel(struct net_device *dev)
+{
+	return msglevel;
+}
+
+static void velocity_set_msglevel(struct net_device *dev, u32 value)
+{
+	 msglevel = value;
+}
+
+static struct ethtool_ops velocity_ethtool_ops = {
+	.get_settings	=	velocity_get_settings,
+	.set_settings	=	velocity_set_settings,
+	.get_drvinfo	=	velocity_get_drvinfo,
+	.get_wol	=	velocity_ethtool_get_wol,
+	.set_wol	=	velocity_ethtool_set_wol,
+	.get_msglevel	=	velocity_get_msglevel,
+	.set_msglevel	=	velocity_set_msglevel,
+	.get_link	=	velocity_get_link
+};
+
+/**
+ *	velocity_mii_ioctl		-	MII ioctl handler
+ *	@dev: network device
+ *	@ifr: the ifreq block for the ioctl
+ *	@cmd: the command
+ *
+ *	Process MII requests made via ioctl from the network layer. These
+ *	are used by tools like kudzu to interrogate the link state of the
+ *	hardware
+ */
+
+static int velocity_mii_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
+{
+	struct velocity_info *vptr = dev->priv;
+	struct mac_regs * regs = vptr->mac_regs;
+	unsigned long flags;
+	struct mii_ioctl_data *miidata = (struct mii_ioctl_data *) &(ifr->ifr_data);
+	int err;
+
+	switch (cmd) {
+	case SIOCGMIIPHY:
+		miidata->phy_id = readb(&regs->MIIADR) & 0x1f;
+		break;
+	case SIOCGMIIREG:
+		if (!capable(CAP_NET_ADMIN))
+			return -EPERM;
+		if(velocity_mii_read(vptr->mac_regs, miidata->reg_num & 0x1f, &(miidata->val_out)) < 0)
+			return -ETIMEDOUT;
+		break;
+	case SIOCSMIIREG:
+		if (!capable(CAP_NET_ADMIN))
+			return -EPERM;
+		spin_lock_irqsave(&vptr->lock, flags);
+		err = velocity_mii_write(vptr->mac_regs, miidata->reg_num & 0x1f, miidata->val_in);
+		spin_unlock_irqrestore(&vptr->lock, flags);
+		check_connection_type(vptr->mac_regs);
+		if(err)
+			return err;
+		break;
+	default:
+		return -EOPNOTSUPP;
+	}
+	return 0;
+}
+
+#ifdef CONFIG_PM
+
+/**
+ *	velocity_save_context	-	save registers
+ *	@vptr: velocity
+ *	@context: buffer for stored context
+ *
+ *	Retrieve the current configuration from the velocity hardware
+ *	and stash it in the context structure, for use by the context
+ *	restore functions. This allows us to save things we need across
+ *	power down states
+ */
+
+static void velocity_save_context(struct velocity_info *vptr, struct velocity_context * context)
+{
+	struct mac_regs * regs = vptr->mac_regs;
+	u16 i;
+	u8 *ptr = (u8 *)regs;
+
+	for (i = MAC_REG_PAR; i < MAC_REG_CR0_CLR; i += 4)
+		*((u32 *) (context->mac_reg + i)) = readl(ptr + i);
+
+	for (i = MAC_REG_MAR; i < MAC_REG_TDCSR_CLR; i += 4)
+		*((u32 *) (context->mac_reg + i)) = readl(ptr + i);
+
+	for (i = MAC_REG_RDBASE_LO; i < MAC_REG_FIFO_TEST0; i += 4)
+		*((u32 *) (context->mac_reg + i)) = readl(ptr + i);
+
+}
+
+/**
+ *	velocity_restore_context	-	restore registers
+ *	@vptr: velocity
+ *	@context: buffer for stored context
+ *
+ *	Reload the register configuration from the velocity context
+ *	created by velocity_save_context.
+ */
+
+static void velocity_restore_context(struct velocity_info *vptr, struct velocity_context *context)
+{
+	struct mac_regs * regs = vptr->mac_regs;
+	int i;
+	u8 *ptr = (u8 *)regs;
+
+	for (i = MAC_REG_PAR; i < MAC_REG_CR0_SET; i += 4) {
+		writel(*((u32 *) (context->mac_reg + i)), ptr + i);
+	}
+
+	/* Just skip cr0 */
+	for (i = MAC_REG_CR1_SET; i < MAC_REG_CR0_CLR; i++) {
+		/* Clear */
+		writeb(~(*((u8 *) (context->mac_reg + i))), ptr + i + 4);
+		/* Set */
+		writeb(*((u8 *) (context->mac_reg + i)), ptr + i);
+	}
+
+	for (i = MAC_REG_MAR; i < MAC_REG_IMR; i += 4) {
+		writel(*((u32 *) (context->mac_reg + i)), ptr + i);
+	}
+
+	for (i = MAC_REG_RDBASE_LO; i < MAC_REG_FIFO_TEST0; i += 4) {
+		writel(*((u32 *) (context->mac_reg + i)), ptr + i);
+	}
+
+	for (i = MAC_REG_TDCSR_SET; i <= MAC_REG_RDCSR_SET; i++) {
+		writeb(*((u8 *) (context->mac_reg + i)), ptr + i);
+	}
+
+}
+
+static int velocity_suspend(struct pci_dev *pdev, u32 state)
+{
+	struct velocity_info *vptr = pci_get_drvdata(pdev);
+	unsigned long flags;
+
+	if(!netif_running(vptr->dev))
+		return 0;
+
+	netif_device_detach(vptr->dev);
+
+	spin_lock_irqsave(&vptr->lock, flags);
+	pci_save_state(pdev, vptr->pci_state);
+#ifdef ETHTOOL_GWOL
+	if (vptr->flags & VELOCITY_FLAGS_WOL_ENABLED) {
+		velocity_get_ip(vptr);
+		velocity_save_context(vptr, &vptr->context);
+		velocity_shutdown(vptr);
+		velocity_set_wol(vptr);
+		pci_enable_wake(pdev, 3, 1);
+		pci_set_power_state(pdev, 3);
+	} else {
+		velocity_save_context(vptr, &vptr->context);
+		velocity_shutdown(vptr);
+		pci_disable_device(pdev);
+		pci_set_power_state(pdev, state);
+	}
+#else
+	pci_set_power_state(pdev, state);
+#endif
+	spin_unlock_irqrestore(&vptr->lock, flags);
+	return 0;
+}
+
+static int velocity_resume(struct pci_dev *pdev)
+{
+	struct velocity_info *vptr = pci_get_drvdata(pdev);
+	unsigned long flags;
+	int i;
+
+	if(!netif_running(vptr->dev))
+		return 0;
+
+	pci_set_power_state(pdev, 0);
+	pci_enable_wake(pdev, 0, 0);
+	pci_restore_state(pdev, vptr->pci_state);
+
+	mac_wol_reset(vptr->mac_regs);
+
+	spin_lock_irqsave(&vptr->lock, flags);
+	velocity_restore_context(vptr, &vptr->context);
+	velocity_init_registers(vptr, VELOCITY_INIT_WOL);
+	mac_disable_int(vptr->mac_regs);
+
+	velocity_tx_srv(vptr, 0);
+
+	for (i = 0; i < vptr->num_txq; i++) {
+		if (vptr->td_used[i]) {
+			mac_tx_queue_wake(vptr->mac_regs, i);
+		}
+	}
+
+	mac_enable_int(vptr->mac_regs);
+	spin_unlock_irqrestore(&vptr->lock, flags);
+	netif_device_attach(vptr->dev);
+
+	return 0;
+}
+
+static int velocity_netdev_event(struct notifier_block *nb, unsigned long notification, void *ptr)
+{
+	struct in_ifaddr *ifa = (struct in_ifaddr *) ptr;
+	struct net_device *dev;
+	struct velocity_info *vptr;
+
+	if (ifa) {
+		dev = ifa->ifa_dev->dev;
+		vptr = dev->priv;
+		velocity_get_ip(vptr);
+	}
+	return NOTIFY_DONE;
+}
+#endif
+
+/*
+ * Purpose: Functions to set WOL.
+ */
+
+const static unsigned short crc16_tab[256] = {
+	0x0000, 0x1189, 0x2312, 0x329b, 0x4624, 0x57ad, 0x6536, 0x74bf,
+	0x8c48, 0x9dc1, 0xaf5a, 0xbed3, 0xca6c, 0xdbe5, 0xe97e, 0xf8f7,
+	0x1081, 0x0108, 0x3393, 0x221a, 0x56a5, 0x472c, 0x75b7, 0x643e,
+	0x9cc9, 0x8d40, 0xbfdb, 0xae52, 0xdaed, 0xcb64, 0xf9ff, 0xe876,
+	0x2102, 0x308b, 0x0210, 0x1399, 0x6726, 0x76af, 0x4434, 0x55bd,
+	0xad4a, 0xbcc3, 0x8e58, 0x9fd1, 0xeb6e, 0xfae7, 0xc87c, 0xd9f5,
+	0x3183, 0x200a, 0x1291, 0x0318, 0x77a7, 0x662e, 0x54b5, 0x453c,
+	0xbdcb, 0xac42, 0x9ed9, 0x8f50, 0xfbef, 0xea66, 0xd8fd, 0xc974,
+	0x4204, 0x538d, 0x6116, 0x709f, 0x0420, 0x15a9, 0x2732, 0x36bb,
+	0xce4c, 0xdfc5, 0xed5e, 0xfcd7, 0x8868, 0x99e1, 0xab7a, 0xbaf3,
+	0x5285, 0x430c, 0x7197, 0x601e, 0x14a1, 0x0528, 0x37b3, 0x263a,
+	0xdecd, 0xcf44, 0xfddf, 0xec56, 0x98e9, 0x8960, 0xbbfb, 0xaa72,
+	0x6306, 0x728f, 0x4014, 0x519d, 0x2522, 0x34ab, 0x0630, 0x17b9,
+	0xef4e, 0xfec7, 0xcc5c, 0xddd5, 0xa96a, 0xb8e3, 0x8a78, 0x9bf1,
+	0x7387, 0x620e, 0x5095, 0x411c, 0x35a3, 0x242a, 0x16b1, 0x0738,
+	0xffcf, 0xee46, 0xdcdd, 0xcd54, 0xb9eb, 0xa862, 0x9af9, 0x8b70,
+	0x8408, 0x9581, 0xa71a, 0xb693, 0xc22c, 0xd3a5, 0xe13e, 0xf0b7,
+	0x0840, 0x19c9, 0x2b52, 0x3adb, 0x4e64, 0x5fed, 0x6d76, 0x7cff,
+	0x9489, 0x8500, 0xb79b, 0xa612, 0xd2ad, 0xc324, 0xf1bf, 0xe036,
+	0x18c1, 0x0948, 0x3bd3, 0x2a5a, 0x5ee5, 0x4f6c, 0x7df7, 0x6c7e,
+	0xa50a, 0xb483, 0x8618, 0x9791, 0xe32e, 0xf2a7, 0xc03c, 0xd1b5,
+	0x2942, 0x38cb, 0x0a50, 0x1bd9, 0x6f66, 0x7eef, 0x4c74, 0x5dfd,
+	0xb58b, 0xa402, 0x9699, 0x8710, 0xf3af, 0xe226, 0xd0bd, 0xc134,
+	0x39c3, 0x284a, 0x1ad1, 0x0b58, 0x7fe7, 0x6e6e, 0x5cf5, 0x4d7c,
+	0xc60c, 0xd785, 0xe51e, 0xf497, 0x8028, 0x91a1, 0xa33a, 0xb2b3,
+	0x4a44, 0x5bcd, 0x6956, 0x78df, 0x0c60, 0x1de9, 0x2f72, 0x3efb,
+	0xd68d, 0xc704, 0xf59f, 0xe416, 0x90a9, 0x8120, 0xb3bb, 0xa232,
+	0x5ac5, 0x4b4c, 0x79d7, 0x685e, 0x1ce1, 0x0d68, 0x3ff3, 0x2e7a,
+	0xe70e, 0xf687, 0xc41c, 0xd595, 0xa12a, 0xb0a3, 0x8238, 0x93b1,
+	0x6b46, 0x7acf, 0x4854, 0x59dd, 0x2d62, 0x3ceb, 0x0e70, 0x1ff9,
+	0xf78f, 0xe606, 0xd49d, 0xc514, 0xb1ab, 0xa022, 0x92b9, 0x8330,
+	0x7bc7, 0x6a4e, 0x58d5, 0x495c, 0x3de3, 0x2c6a, 0x1ef1, 0x0f78
+};
+
+
+static u32 mask_pattern[2][4] = {
+	{0x00203000, 0x000003C0, 0x00000000, 0x0000000},	/* ARP		*/
+	{0xfffff000, 0xffffffff, 0xffffffff, 0x000ffff}		/* Magic Packet */
+};
+
+/**
+ *	ether_crc16	-	compute ethernet CRC
+ *	@len: buffer length
+ *	@cp: buffer
+ *	@crc16: initial CRC
+ *
+ *	Compute a CRC value for a block of data.
+ *	FIXME: can we use generic functions ?
+ */
+
+static u16 ether_crc16(int len, u8 * cp, u16 crc16)
+{
+	while (len--)
+		crc16 = (crc16 >> 8) ^ crc16_tab[(crc16 ^ *cp++) & 0xff];
+	return (crc16);
+}
+
+/**
+ *	bit_reverse		-	16bit reverse
+ *	@data: 16bit data t reverse
+ *
+ *	Reverse the order of a 16bit value and return the reversed bits
+ */
+
+static u16 bit_reverse(u16 data)
+{
+	u32 new = 0x00000000;
+	int ii;
+
+
+	for (ii = 0; ii < 16; ii++) {
+		new |= ((u32) (data & 1) << (31 - ii));
+		data >>= 1;
+	}
+
+	return (u16) (new >> 16);
+}
+
+/**
+ *	wol_calc_crc		-	WOL CRC
+ *	@pattern: data pattern
+ *	@mask_pattern: mask
+ *
+ *	Compute the wake on lan crc hashes for the packet header
+ *	we are interested in.
+ */
+
+u16 wol_calc_crc(int size, u8 * pattern, u8 *mask_pattern)
+{
+	u16 crc = 0xFFFF;
+	u8 mask;
+	int i, j;
+
+	for (i = 0; i < size; i++) {
+		mask = mask_pattern[i];
+
+		/* Skip this loop if the mask equals to zero */
+		if (mask == 0x00)
+			continue;
+
+		for (j = 0; j < 8; j++) {
+			if ((mask & 0x01) == 0) {
+				mask >>= 1;
+				continue;
+			}
+			mask >>= 1;
+			crc = ether_crc16(1, &(pattern[i * 8 + j]), crc);
+		}
+	}
+	/*	Finally, invert the result once to get the correct data */
+	crc = ~crc;
+	return bit_reverse(crc);
+}
+
+/**
+ *	velocity_set_wol	-	set up for wake on lan
+ *	@vptr: velocity to set WOL status on
+ *
+ *	Set a card up for wake on lan either by unicast or by
+ *	ARP packet.
+ *
+ *	FIXME: check static buffer is safe here
+ */
+
+static int velocity_set_wol(struct velocity_info *vptr)
+{
+	struct mac_regs * regs = vptr->mac_regs;
+	static u8 buf[256];
+	int i;
+
+	writew(0xFFFF, &regs->WOLCRClr);
+	writeb(WOLCFG_SAB | WOLCFG_SAM, &regs->WOLCFGSet);
+	writew(WOLCR_MAGIC_EN, &regs->WOLCRSet);
+
+	/*
+	   if (vptr->wol_opts & VELOCITY_WOL_PHY)
+	   writew((WOLCR_LINKON_EN|WOLCR_LINKOFF_EN), &regs->WOLCRSet);
+	 */
+
+	if (vptr->wol_opts & VELOCITY_WOL_UCAST) {
+		writew(WOLCR_UNICAST_EN, &regs->WOLCRSet);
+	}
+
+	if (vptr->wol_opts & VELOCITY_WOL_ARP) {
+		struct arp_packet *arp = (struct arp_packet *) buf;
+		u16 crc;
+		memset(buf, 0, sizeof(struct arp_packet) + 7);
+
+		for (i = 0; i < 4; i++)
+			writel(mask_pattern[0][i], &regs->ByteMask[0][i]);
+
+		arp->type = htons(ETH_P_ARP);
+		arp->ar_op = htons(1);
+
+		memcpy(arp->ar_tip, vptr->ip_addr, 4);
+
+		crc = wol_calc_crc((sizeof(struct arp_packet) + 7) / 8, buf, (u8 *) & mask_pattern[0][0]);
+
+		writew(crc, &regs->PatternCRC[0]);
+		writew(WOLCR_ARP_EN, &regs->WOLCRSet);
+	}
+
+	BYTE_REG_BITS_ON(PWCFG_WOLTYPE, &regs->PWCFGSet);
+	BYTE_REG_BITS_ON(PWCFG_LEGACY_WOLEN, &regs->PWCFGSet);
+
+	writew(0x0FFF, &regs->WOLSRClr);
+
+	if (vptr->mii_status & VELOCITY_AUTONEG_ENABLE) {
+		if (PHYID_GET_PHY_ID(vptr->phy_id) == PHYID_CICADA_CS8201)
+			MII_REG_BITS_ON(AUXCR_MDPPS, MII_REG_AUXCR, vptr->mac_regs);
+
+		MII_REG_BITS_OFF(G1000CR_1000FD | G1000CR_1000, MII_REG_G1000CR, vptr->mac_regs);
+	}
+
+	if (vptr->mii_status & VELOCITY_SPEED_1000)
+		MII_REG_BITS_ON(BMCR_REAUTO, MII_REG_BMCR, vptr->mac_regs);
+
+	BYTE_REG_BITS_ON(CHIPGCR_FCMODE, &regs->CHIPGCR);
+
+	{
+		u8 GCR;
+		GCR = readb(&regs->CHIPGCR);
+		GCR = (GCR & ~CHIPGCR_FCGMII) | CHIPGCR_FCFDX;
+		writeb(GCR, &regs->CHIPGCR);
+	}
+
+	BYTE_REG_BITS_OFF(ISR_PWEI, &regs->ISR);
+	/* Turn on SWPTAG just before entering power mode */
+	BYTE_REG_BITS_ON(STICKHW_SWPTAG, &regs->STICKHW);
+	/* Go to bed ..... */
+	BYTE_REG_BITS_ON((STICKHW_DS1 | STICKHW_DS0), &regs->STICKHW);
+
+	return 0;
+}
+
--- diff/drivers/net/via-velocity.h	1970-01-01 01:00:00.000000000 +0100
+++ source/drivers/net/via-velocity.h	2004-06-11 19:22:03.000000000 +0100
@@ -0,0 +1,1885 @@
+/*
+ * Copyright (c) 1996, 2003 VIA Networking Technologies, Inc.
+ * All rights reserved.
+ *
+ * This software may be redistributed and/or modified under
+ * the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or
+ * 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.
+ *
+ * File: via-velocity.h
+ *
+ * Purpose: Header file to define driver's private structures.
+ *
+ * Author: Chuang Liang-Shing, AJ Jiang
+ *
+ * Date: Jan 24, 2003
+ */
+
+
+#ifndef VELOCITY_H
+#define VELOCITY_H
+
+#define VELOCITY_TX_CSUM_SUPPORT
+
+#define VELOCITY_NAME          "via-velocity"
+#define VELOCITY_FULL_DRV_NAM  "VIA Networking Velocity Family Gigabit Ethernet Adapter Driver"
+#define VELOCITY_VERSION       "1.13"
+
+#define PKT_BUF_SZ          1540
+
+#define MAX_UNITS           8
+#define OPTION_DEFAULT      { [0 ... MAX_UNITS-1] = -1}
+
+#define REV_ID_VT6110       (0)
+#define DEVICE_ID           (0x3119)
+
+#define BYTE_REG_BITS_ON(x,p)       do { writeb(readb((p))|(x),(p));} while (0)
+#define WORD_REG_BITS_ON(x,p)       do { writew(readw((p))|(x),(p));} while (0)
+#define DWORD_REG_BITS_ON(x,p)      do { writel(readl((p))|(x),(p));} while (0)
+
+#define BYTE_REG_BITS_IS_ON(x,p)    (readb((p)) & (x))
+#define WORD_REG_BITS_IS_ON(x,p)    (readw((p)) & (x))
+#define DWORD_REG_BITS_IS_ON(x,p)   (readl((p)) & (x))
+
+#define BYTE_REG_BITS_OFF(x,p)      do { writeb(readb((p)) & (~(x)),(p));} while (0)
+#define WORD_REG_BITS_OFF(x,p)      do { writew(readw((p)) & (~(x)),(p));} while (0)
+#define DWORD_REG_BITS_OFF(x,p)     do { writel(readl((p)) & (~(x)),(p));} while (0)
+
+#define BYTE_REG_BITS_SET(x,m,p)    do { writeb( (readb((p)) & (~(m))) |(x),(p));} while (0)
+#define WORD_REG_BITS_SET(x,m,p)    do { writew( (readw((p)) & (~(m))) |(x),(p));} while (0)
+#define DWORD_REG_BITS_SET(x,m,p)   do { writel( (readl((p)) & (~(m)))|(x),(p));}  while (0)
+
+#define VAR_USED(p)     do {(p)=(p);} while (0)
+
+/*
+ * Purpose: Structures for MAX RX/TX descriptors.
+ */
+
+
+#define B_OWNED_BY_CHIP     1
+#define B_OWNED_BY_HOST     0
+
+/*
+ * Bits in the RSR0 register
+ */
+
+#define RSR_DETAG          0x0080
+#define RSR_SNTAG          0x0040
+#define RSR_RXER           0x0020
+#define RSR_RL             0x0010
+#define RSR_CE             0x0008
+#define RSR_FAE            0x0004
+#define RSR_CRC            0x0002
+#define RSR_VIDM           0x0001
+
+/*
+ * Bits in the RSR1 register
+ */
+
+#define RSR_RXOK           0x8000	// rx OK
+#define RSR_PFT            0x4000	// Perfect filtering address match
+#define RSR_MAR            0x2000	// MAC accept multicast address packet
+#define RSR_BAR            0x1000	// MAC accept broadcast address packet
+#define RSR_PHY            0x0800	// MAC accept physical address packet
+#define RSR_VTAG           0x0400	// 802.1p/1q tagging packet indicator
+#define RSR_STP            0x0200	// start of packet
+#define RSR_EDP            0x0100	// end of packet
+
+/*
+ * Bits in the RSR1 register
+ */
+
+#define RSR1_RXOK           0x80	// rx OK
+#define RSR1_PFT            0x40	// Perfect filtering address match
+#define RSR1_MAR            0x20	// MAC accept multicast address packet
+#define RSR1_BAR            0x10	// MAC accept broadcast address packet
+#define RSR1_PHY            0x08	// MAC accept physical address packet
+#define RSR1_VTAG           0x04	// 802.1p/1q tagging packet indicator
+#define RSR1_STP            0x02	// start of packet
+#define RSR1_EDP            0x01	// end of packet
+
+/*
+ * Bits in the CSM register
+ */
+
+#define CSM_IPOK            0x40	//IP Checkusm validatiaon ok
+#define CSM_TUPOK           0x20	//TCP/UDP Checkusm validatiaon ok
+#define CSM_FRAG            0x10	//Fragment IP datagram
+#define CSM_IPKT            0x04	//Received an IP packet
+#define CSM_TCPKT           0x02	//Received a TCP packet
+#define CSM_UDPKT           0x01	//Received a UDP packet
+
+/*
+ * Bits in the TSR0 register
+ */
+
+#define TSR0_ABT            0x0080	// Tx abort because of excessive collision
+#define TSR0_OWT            0x0040	// Jumbo frame Tx abort
+#define TSR0_OWC            0x0020	// Out of window collision
+#define TSR0_COLS           0x0010	// experience collision in this transmit event
+#define TSR0_NCR3           0x0008	// collision retry counter[3]
+#define TSR0_NCR2           0x0004	// collision retry counter[2]
+#define TSR0_NCR1           0x0002	// collision retry counter[1]
+#define TSR0_NCR0           0x0001	// collision retry counter[0]
+#define TSR0_TERR           0x8000	//
+#define TSR0_FDX            0x4000	// current transaction is serviced by full duplex mode
+#define TSR0_GMII           0x2000	// current transaction is serviced by GMII mode
+#define TSR0_LNKFL          0x1000	// packet serviced during link down
+#define TSR0_SHDN           0x0400	// shutdown case
+#define TSR0_CRS            0x0200	// carrier sense lost
+#define TSR0_CDH            0x0100	// AQE test fail (CD heartbeat)
+
+/*
+ * Bits in the TSR1 register
+ */
+
+#define TSR1_TERR           0x80	//
+#define TSR1_FDX            0x40	// current transaction is serviced by full duplex mode
+#define TSR1_GMII           0x20	// current transaction is serviced by GMII mode
+#define TSR1_LNKFL          0x10	// packet serviced during link down
+#define TSR1_SHDN           0x04	// shutdown case
+#define TSR1_CRS            0x02	// carrier sense lost
+#define TSR1_CDH            0x01	// AQE test fail (CD heartbeat)
+
+//
+// Bits in the TCR0 register
+//
+#define TCR0_TIC            0x80	// assert interrupt immediately while descriptor has been send complete
+#define TCR0_PIC            0x40	// priority interrupt request, INA# is issued over adaptive interrupt scheme
+#define TCR0_VETAG          0x20	// enable VLAN tag
+#define TCR0_IPCK           0x10	// request IP  checksum calculation.
+#define TCR0_UDPCK          0x08	// request UDP checksum calculation.
+#define TCR0_TCPCK          0x04	// request TCP checksum calculation.
+#define TCR0_JMBO           0x02	// indicate a jumbo packet in GMAC side
+#define TCR0_CRC            0x01	// disable CRC generation
+
+#define TCPLS_NORMAL        3
+#define TCPLS_START         2
+#define TCPLS_END           1
+#define TCPLS_MED           0
+
+
+// max transmit or receive buffer size
+#define CB_RX_BUF_SIZE     2048UL	// max buffer size
+					// NOTE: must be multiple of 4
+
+#define CB_MAX_RD_NUM       512	// MAX # of RD
+#define CB_MAX_TD_NUM       256	// MAX # of TD
+
+#define CB_INIT_RD_NUM_3119 128	// init # of RD, for setup VT3119
+#define CB_INIT_TD_NUM_3119 64	// init # of TD, for setup VT3119
+
+#define CB_INIT_RD_NUM      128	// init # of RD, for setup default
+#define CB_INIT_TD_NUM      64	// init # of TD, for setup default
+
+// for 3119
+#define CB_TD_RING_NUM      4	// # of TD rings.
+#define CB_MAX_SEG_PER_PKT  7	// max data seg per packet (Tx)
+
+
+/*
+ *	If collisions excess 15 times , tx will abort, and
+ *	if tx fifo underflow, tx will fail
+ *	we should try to resend it
+ */
+
+#define CB_MAX_TX_ABORT_RETRY   3
+
+/*
+ *	Receive descriptor
+ */
+
+struct rdesc0 {
+	u16 RSR;		/* Receive status */
+	u16 len:14;		/* Received packet length */
+	u16 reserved:1;
+	u16 owner:1;		/* Who owns this buffer ? */
+};
+
+struct rdesc1 {
+	u16 PQTAG;
+	u8 CSM;
+	u8 IPKT;
+};
+
+struct rx_desc {
+	struct rdesc0 rdesc0;
+	struct rdesc1 rdesc1;
+	u32 pa_low;		/* Low 32 bit PCI address */
+	u16 pa_high;		/* Next 16 bit PCI address (48 total) */
+	u16 len:15;		/* Frame size */
+	u16 inten:1;		/* Enable interrupt */
+} __attribute__ ((__packed__));
+
+/*
+ *	Transmit descriptor
+ */
+
+struct tdesc0 {
+	u16 TSR;		/* Transmit status register */
+	u16 pktsize:14;		/* Size of frame */
+	u16 reserved:1;
+	u16 owner:1;		/* Who owns the buffer */
+};
+
+struct pqinf {			/* Priority queue info */
+	u16 VID:12;
+	u16 CFI:1;
+	u16 priority:3;
+} __attribute__ ((__packed__));
+
+struct tdesc1 {
+	struct pqinf pqinf;
+	u8 TCR;
+	u8 TCPLS:2;
+	u8 reserved:2;
+	u8 CMDZ:4;
+} __attribute__ ((__packed__));
+
+struct td_buf {
+	u32 pa_low;
+	u16 pa_high;
+	u16 bufsize:14;
+	u16 reserved:1;
+	u16 queue:1;
+} __attribute__ ((__packed__));
+
+struct tx_desc {
+	struct tdesc0 tdesc0;
+	struct tdesc1 tdesc1;
+	struct td_buf td_buf[7];
+};
+
+struct velocity_rd_info {
+	struct sk_buff *skb;
+	dma_addr_t skb_dma;
+};
+
+/**
+ *	alloc_rd_info		-	allocate an rd info block
+ *
+ *	Alocate and initialize a receive info structure used for keeping
+ *	track of kernel side information related to each receive
+ *	descriptor we are using
+ */
+
+static inline struct velocity_rd_info *alloc_rd_info(void)
+{
+	struct velocity_rd_info *ptr;
+	if ((ptr = kmalloc(sizeof(struct velocity_rd_info), GFP_ATOMIC)) == NULL)
+		return NULL;
+	else {
+		memset(ptr, 0, sizeof(struct velocity_rd_info));
+		return ptr;
+	}
+}
+
+/*
+ *	Used to track transmit side buffers.
+ */
+
+struct velocity_td_info {
+	struct sk_buff *skb;
+	u8 *buf;
+	int nskb_dma;
+	dma_addr_t skb_dma[7];
+	dma_addr_t buf_dma;
+};
+
+enum {
+	OWNED_BY_HOST = 0,
+	OWNED_BY_NIC = 1
+} velocity_owner;
+
+
+/*
+ *	MAC registers and macros.
+ */
+
+
+#define MCAM_SIZE           64
+#define VCAM_SIZE           64
+#define TX_QUEUE_NO         4
+
+#define MAX_HW_MIB_COUNTER  32
+#define VELOCITY_MIN_MTU    (1514-14)
+#define VELOCITY_MAX_MTU    (9000)
+
+/*
+ *	Registers in the MAC
+ */
+
+#define MAC_REG_PAR         0x00	// physical address
+#define MAC_REG_RCR         0x06
+#define MAC_REG_TCR         0x07
+#define MAC_REG_CR0_SET     0x08
+#define MAC_REG_CR1_SET     0x09
+#define MAC_REG_CR2_SET     0x0A
+#define MAC_REG_CR3_SET     0x0B
+#define MAC_REG_CR0_CLR     0x0C
+#define MAC_REG_CR1_CLR     0x0D
+#define MAC_REG_CR2_CLR     0x0E
+#define MAC_REG_CR3_CLR     0x0F
+#define MAC_REG_MAR         0x10
+#define MAC_REG_CAM         0x10
+#define MAC_REG_DEC_BASE_HI 0x18
+#define MAC_REG_DBF_BASE_HI 0x1C
+#define MAC_REG_ISR_CTL     0x20
+#define MAC_REG_ISR_HOTMR   0x20
+#define MAC_REG_ISR_TSUPTHR 0x20
+#define MAC_REG_ISR_RSUPTHR 0x20
+#define MAC_REG_ISR_CTL1    0x21
+#define MAC_REG_TXE_SR      0x22
+#define MAC_REG_RXE_SR      0x23
+#define MAC_REG_ISR         0x24
+#define MAC_REG_ISR0        0x24
+#define MAC_REG_ISR1        0x25
+#define MAC_REG_ISR2        0x26
+#define MAC_REG_ISR3        0x27
+#define MAC_REG_IMR         0x28
+#define MAC_REG_IMR0        0x28
+#define MAC_REG_IMR1        0x29
+#define MAC_REG_IMR2        0x2A
+#define MAC_REG_IMR3        0x2B
+#define MAC_REG_TDCSR_SET   0x30
+#define MAC_REG_RDCSR_SET   0x32
+#define MAC_REG_TDCSR_CLR   0x34
+#define MAC_REG_RDCSR_CLR   0x36
+#define MAC_REG_RDBASE_LO   0x38
+#define MAC_REG_RDINDX      0x3C
+#define MAC_REG_TDBASE_LO   0x40
+#define MAC_REG_RDCSIZE     0x50
+#define MAC_REG_TDCSIZE     0x52
+#define MAC_REG_TDINDX      0x54
+#define MAC_REG_TDIDX0      0x54
+#define MAC_REG_TDIDX1      0x56
+#define MAC_REG_TDIDX2      0x58
+#define MAC_REG_TDIDX3      0x5A
+#define MAC_REG_PAUSE_TIMER 0x5C
+#define MAC_REG_RBRDU       0x5E
+#define MAC_REG_FIFO_TEST0  0x60
+#define MAC_REG_FIFO_TEST1  0x64
+#define MAC_REG_CAMADDR     0x68
+#define MAC_REG_CAMCR       0x69
+#define MAC_REG_GFTEST      0x6A
+#define MAC_REG_FTSTCMD     0x6B
+#define MAC_REG_MIICFG      0x6C
+#define MAC_REG_MIISR       0x6D
+#define MAC_REG_PHYSR0      0x6E
+#define MAC_REG_PHYSR1      0x6F
+#define MAC_REG_MIICR       0x70
+#define MAC_REG_MIIADR      0x71
+#define MAC_REG_MIIDATA     0x72
+#define MAC_REG_SOFT_TIMER0 0x74
+#define MAC_REG_SOFT_TIMER1 0x76
+#define MAC_REG_CFGA        0x78
+#define MAC_REG_CFGB        0x79
+#define MAC_REG_CFGC        0x7A
+#define MAC_REG_CFGD        0x7B
+#define MAC_REG_DCFG0       0x7C
+#define MAC_REG_DCFG1       0x7D
+#define MAC_REG_MCFG0       0x7E
+#define MAC_REG_MCFG1       0x7F
+
+#define MAC_REG_TBIST       0x80
+#define MAC_REG_RBIST       0x81
+#define MAC_REG_PMCC        0x82
+#define MAC_REG_STICKHW     0x83
+#define MAC_REG_MIBCR       0x84
+#define MAC_REG_EERSV       0x85
+#define MAC_REG_REVID       0x86
+#define MAC_REG_MIBREAD     0x88
+#define MAC_REG_BPMA        0x8C
+#define MAC_REG_EEWR_DATA   0x8C
+#define MAC_REG_BPMD_WR     0x8F
+#define MAC_REG_BPCMD       0x90
+#define MAC_REG_BPMD_RD     0x91
+#define MAC_REG_EECHKSUM    0x92
+#define MAC_REG_EECSR       0x93
+#define MAC_REG_EERD_DATA   0x94
+#define MAC_REG_EADDR       0x96
+#define MAC_REG_EMBCMD      0x97
+#define MAC_REG_JMPSR0      0x98
+#define MAC_REG_JMPSR1      0x99
+#define MAC_REG_JMPSR2      0x9A
+#define MAC_REG_JMPSR3      0x9B
+#define MAC_REG_CHIPGSR     0x9C
+#define MAC_REG_TESTCFG     0x9D
+#define MAC_REG_DEBUG       0x9E
+#define MAC_REG_CHIPGCR     0x9F
+#define MAC_REG_WOLCR0_SET  0xA0
+#define MAC_REG_WOLCR1_SET  0xA1
+#define MAC_REG_PWCFG_SET   0xA2
+#define MAC_REG_WOLCFG_SET  0xA3
+#define MAC_REG_WOLCR0_CLR  0xA4
+#define MAC_REG_WOLCR1_CLR  0xA5
+#define MAC_REG_PWCFG_CLR   0xA6
+#define MAC_REG_WOLCFG_CLR  0xA7
+#define MAC_REG_WOLSR0_SET  0xA8
+#define MAC_REG_WOLSR1_SET  0xA9
+#define MAC_REG_WOLSR0_CLR  0xAC
+#define MAC_REG_WOLSR1_CLR  0xAD
+#define MAC_REG_PATRN_CRC0  0xB0
+#define MAC_REG_PATRN_CRC1  0xB2
+#define MAC_REG_PATRN_CRC2  0xB4
+#define MAC_REG_PATRN_CRC3  0xB6
+#define MAC_REG_PATRN_CRC4  0xB8
+#define MAC_REG_PATRN_CRC5  0xBA
+#define MAC_REG_PATRN_CRC6  0xBC
+#define MAC_REG_PATRN_CRC7  0xBE
+#define MAC_REG_BYTEMSK0_0  0xC0
+#define MAC_REG_BYTEMSK0_1  0xC4
+#define MAC_REG_BYTEMSK0_2  0xC8
+#define MAC_REG_BYTEMSK0_3  0xCC
+#define MAC_REG_BYTEMSK1_0  0xD0
+#define MAC_REG_BYTEMSK1_1  0xD4
+#define MAC_REG_BYTEMSK1_2  0xD8
+#define MAC_REG_BYTEMSK1_3  0xDC
+#define MAC_REG_BYTEMSK2_0  0xE0
+#define MAC_REG_BYTEMSK2_1  0xE4
+#define MAC_REG_BYTEMSK2_2  0xE8
+#define MAC_REG_BYTEMSK2_3  0xEC
+#define MAC_REG_BYTEMSK3_0  0xF0
+#define MAC_REG_BYTEMSK3_1  0xF4
+#define MAC_REG_BYTEMSK3_2  0xF8
+#define MAC_REG_BYTEMSK3_3  0xFC
+
+/*
+ *	Bits in the RCR register
+ */
+
+#define RCR_AS              0x80
+#define RCR_AP              0x40
+#define RCR_AL              0x20
+#define RCR_PROM            0x10
+#define RCR_AB              0x08
+#define RCR_AM              0x04
+#define RCR_AR              0x02
+#define RCR_SEP             0x01
+
+/*
+ *	Bits in the TCR register
+ */
+
+#define TCR_TB2BDIS         0x80
+#define TCR_COLTMC1         0x08
+#define TCR_COLTMC0         0x04
+#define TCR_LB1             0x02	/* loopback[1] */
+#define TCR_LB0             0x01	/* loopback[0] */
+
+/*
+ *	Bits in the CR0 register
+ */
+
+#define CR0_TXON            0x00000008UL
+#define CR0_RXON            0x00000004UL
+#define CR0_STOP            0x00000002UL	/* stop MAC, default = 1 */
+#define CR0_STRT            0x00000001UL	/* start MAC */
+#define CR0_SFRST           0x00008000UL	/* software reset */
+#define CR0_TM1EN           0x00004000UL
+#define CR0_TM0EN           0x00002000UL
+#define CR0_DPOLL           0x00000800UL	/* disable rx/tx auto polling */
+#define CR0_DISAU           0x00000100UL
+#define CR0_XONEN           0x00800000UL
+#define CR0_FDXTFCEN        0x00400000UL	/* full-duplex TX flow control enable */
+#define CR0_FDXRFCEN        0x00200000UL	/* full-duplex RX flow control enable */
+#define CR0_HDXFCEN         0x00100000UL	/* half-duplex flow control enable */
+#define CR0_XHITH1          0x00080000UL	/* TX XON high threshold 1 */
+#define CR0_XHITH0          0x00040000UL	/* TX XON high threshold 0 */
+#define CR0_XLTH1           0x00020000UL	/* TX pause frame low threshold 1 */
+#define CR0_XLTH0           0x00010000UL	/* TX pause frame low threshold 0 */
+#define CR0_GSPRST          0x80000000UL
+#define CR0_FORSRST         0x40000000UL
+#define CR0_FPHYRST         0x20000000UL
+#define CR0_DIAG            0x10000000UL
+#define CR0_INTPCTL         0x04000000UL
+#define CR0_GINTMSK1        0x02000000UL
+#define CR0_GINTMSK0        0x01000000UL
+
+/*
+ *	Bits in the CR1 register
+ */
+
+#define CR1_SFRST           0x80	/* software reset */
+#define CR1_TM1EN           0x40
+#define CR1_TM0EN           0x20
+#define CR1_DPOLL           0x08	/* disable rx/tx auto polling */
+#define CR1_DISAU           0x01
+
+/*
+ *	Bits in the CR2 register
+ */
+
+#define CR2_XONEN           0x80
+#define CR2_FDXTFCEN        0x40	/* full-duplex TX flow control enable */
+#define CR2_FDXRFCEN        0x20	/* full-duplex RX flow control enable */
+#define CR2_HDXFCEN         0x10	/* half-duplex flow control enable */
+#define CR2_XHITH1          0x08	/* TX XON high threshold 1 */
+#define CR2_XHITH0          0x04	/* TX XON high threshold 0 */
+#define CR2_XLTH1           0x02	/* TX pause frame low threshold 1 */
+#define CR2_XLTH0           0x01	/* TX pause frame low threshold 0 */
+
+/*
+ *	Bits in the CR3 register
+ */
+
+#define CR3_GSPRST          0x80
+#define CR3_FORSRST         0x40
+#define CR3_FPHYRST         0x20
+#define CR3_DIAG            0x10
+#define CR3_INTPCTL         0x04
+#define CR3_GINTMSK1        0x02
+#define CR3_GINTMSK0        0x01
+
+#define ISRCTL_UDPINT       0x8000
+#define ISRCTL_TSUPDIS      0x4000
+#define ISRCTL_RSUPDIS      0x2000
+#define ISRCTL_PMSK1        0x1000
+#define ISRCTL_PMSK0        0x0800
+#define ISRCTL_INTPD        0x0400
+#define ISRCTL_HCRLD        0x0200
+#define ISRCTL_SCRLD        0x0100
+
+/*
+ *	Bits in the ISR_CTL1 register
+ */
+
+#define ISRCTL1_UDPINT      0x80
+#define ISRCTL1_TSUPDIS     0x40
+#define ISRCTL1_RSUPDIS     0x20
+#define ISRCTL1_PMSK1       0x10
+#define ISRCTL1_PMSK0       0x08
+#define ISRCTL1_INTPD       0x04
+#define ISRCTL1_HCRLD       0x02
+#define ISRCTL1_SCRLD       0x01
+
+/*
+ *	Bits in the TXE_SR register
+ */
+
+#define TXESR_TFDBS         0x08
+#define TXESR_TDWBS         0x04
+#define TXESR_TDRBS         0x02
+#define TXESR_TDSTR         0x01
+
+/*
+ *	Bits in the RXE_SR register
+ */
+
+#define RXESR_RFDBS         0x08
+#define RXESR_RDWBS         0x04
+#define RXESR_RDRBS         0x02
+#define RXESR_RDSTR         0x01
+
+/*
+ *	Bits in the ISR register
+ */
+
+#define ISR_ISR3            0x80000000UL
+#define ISR_ISR2            0x40000000UL
+#define ISR_ISR1            0x20000000UL
+#define ISR_ISR0            0x10000000UL
+#define ISR_TXSTLI          0x02000000UL
+#define ISR_RXSTLI          0x01000000UL
+#define ISR_HFLD            0x00800000UL
+#define ISR_UDPI            0x00400000UL
+#define ISR_MIBFI           0x00200000UL
+#define ISR_SHDNI           0x00100000UL
+#define ISR_PHYI            0x00080000UL
+#define ISR_PWEI            0x00040000UL
+#define ISR_TMR1I           0x00020000UL
+#define ISR_TMR0I           0x00010000UL
+#define ISR_SRCI            0x00008000UL
+#define ISR_LSTPEI          0x00004000UL
+#define ISR_LSTEI           0x00002000UL
+#define ISR_OVFI            0x00001000UL
+#define ISR_FLONI           0x00000800UL
+#define ISR_RACEI           0x00000400UL
+#define ISR_TXWB1I          0x00000200UL
+#define ISR_TXWB0I          0x00000100UL
+#define ISR_PTX3I           0x00000080UL
+#define ISR_PTX2I           0x00000040UL
+#define ISR_PTX1I           0x00000020UL
+#define ISR_PTX0I           0x00000010UL
+#define ISR_PTXI            0x00000008UL
+#define ISR_PRXI            0x00000004UL
+#define ISR_PPTXI           0x00000002UL
+#define ISR_PPRXI           0x00000001UL
+
+/*
+ *	Bits in the IMR register
+ */
+
+#define IMR_TXSTLM          0x02000000UL
+#define IMR_UDPIM           0x00400000UL
+#define IMR_MIBFIM          0x00200000UL
+#define IMR_SHDNIM          0x00100000UL
+#define IMR_PHYIM           0x00080000UL
+#define IMR_PWEIM           0x00040000UL
+#define IMR_TMR1IM          0x00020000UL
+#define IMR_TMR0IM          0x00010000UL
+
+#define IMR_SRCIM           0x00008000UL
+#define IMR_LSTPEIM         0x00004000UL
+#define IMR_LSTEIM          0x00002000UL
+#define IMR_OVFIM           0x00001000UL
+#define IMR_FLONIM          0x00000800UL
+#define IMR_RACEIM          0x00000400UL
+#define IMR_TXWB1IM         0x00000200UL
+#define IMR_TXWB0IM         0x00000100UL
+
+#define IMR_PTX3IM          0x00000080UL
+#define IMR_PTX2IM          0x00000040UL
+#define IMR_PTX1IM          0x00000020UL
+#define IMR_PTX0IM          0x00000010UL
+#define IMR_PTXIM           0x00000008UL
+#define IMR_PRXIM           0x00000004UL
+#define IMR_PPTXIM          0x00000002UL
+#define IMR_PPRXIM          0x00000001UL
+
+/* 0x0013FB0FUL  =  initial value of IMR */
+
+#define INT_MASK_DEF        (IMR_PPTXIM|IMR_PPRXIM|IMR_PTXIM|IMR_PRXIM|\
+                            IMR_PWEIM|IMR_TXWB0IM|IMR_TXWB1IM|IMR_FLONIM|\
+                            IMR_OVFIM|IMR_LSTEIM|IMR_LSTPEIM|IMR_SRCIM|IMR_MIBFIM|\
+                            IMR_SHDNIM|IMR_TMR1IM|IMR_TMR0IM|IMR_TXSTLM)
+
+/*
+ *	Bits in the TDCSR0/1, RDCSR0 register
+ */
+
+#define TRDCSR_DEAD         0x0008
+#define TRDCSR_WAK          0x0004
+#define TRDCSR_ACT          0x0002
+#define TRDCSR_RUN	    0x0001
+
+/*
+ *	Bits in the CAMADDR register
+ */
+
+#define CAMADDR_CAMEN       0x80
+#define CAMADDR_VCAMSL      0x40
+
+/*
+ *	Bits in the CAMCR register
+ */
+
+#define CAMCR_PS1           0x80
+#define CAMCR_PS0           0x40
+#define CAMCR_AITRPKT       0x20
+#define CAMCR_AITR16        0x10
+#define CAMCR_CAMRD         0x08
+#define CAMCR_CAMWR         0x04
+#define CAMCR_PS_CAM_MASK   0x40
+#define CAMCR_PS_CAM_DATA   0x80
+#define CAMCR_PS_MAR        0x00
+
+/*
+ *	Bits in the MIICFG register
+ */
+
+#define MIICFG_MPO1         0x80
+#define MIICFG_MPO0         0x40
+#define MIICFG_MFDC         0x20
+
+/*
+ *	Bits in the MIISR register
+ */
+
+#define MIISR_MIDLE         0x80
+
+/*
+ *	 Bits in the PHYSR0 register
+ */
+
+#define PHYSR0_PHYRST       0x80
+#define PHYSR0_LINKGD       0x40
+#define PHYSR0_FDPX         0x10
+#define PHYSR0_SPDG         0x08
+#define PHYSR0_SPD10        0x04
+#define PHYSR0_RXFLC        0x02
+#define PHYSR0_TXFLC        0x01
+
+/*
+ *	Bits in the PHYSR1 register
+ */
+
+#define PHYSR1_PHYTBI       0x01
+
+/*
+ *	Bits in the MIICR register
+ */
+
+#define MIICR_MAUTO         0x80
+#define MIICR_RCMD          0x40
+#define MIICR_WCMD          0x20
+#define MIICR_MDPM          0x10
+#define MIICR_MOUT          0x08
+#define MIICR_MDO           0x04
+#define MIICR_MDI           0x02
+#define MIICR_MDC           0x01
+
+/*
+ *	Bits in the MIIADR register
+ */
+
+#define MIIADR_SWMPL        0x80
+
+/*
+ *	Bits in the CFGA register
+ */
+
+#define CFGA_PMHCTG         0x08
+#define CFGA_GPIO1PD        0x04
+#define CFGA_ABSHDN         0x02
+#define CFGA_PACPI          0x01
+
+/*
+ *	Bits in the CFGB register
+ */
+
+#define CFGB_GTCKOPT        0x80
+#define CFGB_MIIOPT         0x40
+#define CFGB_CRSEOPT        0x20
+#define CFGB_OFSET          0x10
+#define CFGB_CRANDOM        0x08
+#define CFGB_CAP            0x04
+#define CFGB_MBA            0x02
+#define CFGB_BAKOPT         0x01
+
+/*
+ *	Bits in the CFGC register
+ */
+
+#define CFGC_EELOAD         0x80
+#define CFGC_BROPT          0x40
+#define CFGC_DLYEN          0x20
+#define CFGC_DTSEL          0x10
+#define CFGC_BTSEL          0x08
+#define CFGC_BPS2           0x04	/* bootrom select[2] */
+#define CFGC_BPS1           0x02	/* bootrom select[1] */
+#define CFGC_BPS0           0x01	/* bootrom select[0] */
+
+/*
+ * Bits in the CFGD register
+ */
+
+#define CFGD_IODIS          0x80
+#define CFGD_MSLVDACEN      0x40
+#define CFGD_CFGDACEN       0x20
+#define CFGD_PCI64EN        0x10
+#define CFGD_HTMRL4         0x08
+
+/*
+ *	Bits in the DCFG1 register
+ */
+
+#define DCFG_XMWI           0x8000
+#define DCFG_XMRM           0x4000
+#define DCFG_XMRL           0x2000
+#define DCFG_PERDIS         0x1000
+#define DCFG_MRWAIT         0x0400
+#define DCFG_MWWAIT         0x0200
+#define DCFG_LATMEN         0x0100
+
+/*
+ *	Bits in the MCFG0 register
+ */
+
+#define MCFG_RXARB          0x0080
+#define MCFG_RFT1           0x0020
+#define MCFG_RFT0           0x0010
+#define MCFG_LOWTHOPT       0x0008
+#define MCFG_PQEN           0x0004
+#define MCFG_RTGOPT         0x0002
+#define MCFG_VIDFR          0x0001
+
+/*
+ *	Bits in the MCFG1 register
+ */
+
+#define MCFG_TXARB          0x8000
+#define MCFG_TXQBK1         0x0800
+#define MCFG_TXQBK0         0x0400
+#define MCFG_TXQNOBK        0x0200
+#define MCFG_SNAPOPT        0x0100
+
+/*
+ *	Bits in the PMCC  register
+ */
+
+#define PMCC_DSI            0x80
+#define PMCC_D2_DIS         0x40
+#define PMCC_D1_DIS         0x20
+#define PMCC_D3C_EN         0x10
+#define PMCC_D3H_EN         0x08
+#define PMCC_D2_EN          0x04
+#define PMCC_D1_EN          0x02
+#define PMCC_D0_EN          0x01
+
+/*
+ *	Bits in STICKHW
+ */
+
+#define STICKHW_SWPTAG      0x10
+#define STICKHW_WOLSR       0x08
+#define STICKHW_WOLEN       0x04
+#define STICKHW_DS1         0x02	/* R/W by software/cfg cycle */
+#define STICKHW_DS0         0x01	/* suspend well DS write port */
+
+/*
+ *	Bits in the MIBCR register
+ */
+
+#define MIBCR_MIBISTOK      0x80
+#define MIBCR_MIBISTGO      0x40
+#define MIBCR_MIBINC        0x20
+#define MIBCR_MIBHI         0x10
+#define MIBCR_MIBFRZ        0x08
+#define MIBCR_MIBFLSH       0x04
+#define MIBCR_MPTRINI       0x02
+#define MIBCR_MIBCLR        0x01
+
+/*
+ *	Bits in the EERSV register
+ */
+
+#define EERSV_BOOT_RPL      ((u8) 0x01)	 /* Boot method selection for VT6110 */
+
+#define EERSV_BOOT_MASK     ((u8) 0x06)
+#define EERSV_BOOT_INT19    ((u8) 0x00)
+#define EERSV_BOOT_INT18    ((u8) 0x02)
+#define EERSV_BOOT_LOCAL    ((u8) 0x04)
+#define EERSV_BOOT_BEV      ((u8) 0x06)
+
+
+/*
+ *	Bits in BPCMD
+ */
+
+#define BPCMD_BPDNE         0x80
+#define BPCMD_EBPWR         0x02
+#define BPCMD_EBPRD         0x01
+
+/*
+ *	Bits in the EECSR register
+ */
+
+#define EECSR_EMBP          0x40	/* eeprom embeded programming */
+#define EECSR_RELOAD        0x20	/* eeprom content reload */
+#define EECSR_DPM           0x10	/* eeprom direct programming */
+#define EECSR_ECS           0x08	/* eeprom CS pin */
+#define EECSR_ECK           0x04	/* eeprom CK pin */
+#define EECSR_EDI           0x02	/* eeprom DI pin */
+#define EECSR_EDO           0x01	/* eeprom DO pin */
+
+/*
+ *	Bits in the EMBCMD register
+ */
+
+#define EMBCMD_EDONE        0x80
+#define EMBCMD_EWDIS        0x08
+#define EMBCMD_EWEN         0x04
+#define EMBCMD_EWR          0x02
+#define EMBCMD_ERD          0x01
+
+/*
+ *	Bits in TESTCFG register
+ */
+
+#define TESTCFG_HBDIS       0x80
+
+/*
+ *	Bits in CHIPGCR register
+ */
+
+#define CHIPGCR_FCGMII      0x80
+#define CHIPGCR_FCFDX       0x40
+#define CHIPGCR_FCRESV      0x20
+#define CHIPGCR_FCMODE      0x10
+#define CHIPGCR_LPSOPT      0x08
+#define CHIPGCR_TM1US       0x04
+#define CHIPGCR_TM0US       0x02
+#define CHIPGCR_PHYINTEN    0x01
+
+/*
+ *	Bits in WOLCR0
+ */
+
+#define WOLCR_MSWOLEN7      0x0080	/* enable pattern match filtering */
+#define WOLCR_MSWOLEN6      0x0040
+#define WOLCR_MSWOLEN5      0x0020
+#define WOLCR_MSWOLEN4      0x0010
+#define WOLCR_MSWOLEN3      0x0008
+#define WOLCR_MSWOLEN2      0x0004
+#define WOLCR_MSWOLEN1      0x0002
+#define WOLCR_MSWOLEN0      0x0001
+#define WOLCR_ARP_EN        0x0001
+
+/*
+ *	Bits in WOLCR1
+ */
+
+#define WOLCR_LINKOFF_EN      0x0800	/* link off detected enable */
+#define WOLCR_LINKON_EN       0x0400	/* link on detected enable */
+#define WOLCR_MAGIC_EN        0x0200	/* magic packet filter enable */
+#define WOLCR_UNICAST_EN      0x0100	/* unicast filter enable */
+
+
+/*
+ *	Bits in PWCFG
+ */
+
+#define PWCFG_PHYPWOPT          0x80	/* internal MII I/F timing */
+#define PWCFG_PCISTICK          0x40	/* PCI sticky R/W enable */
+#define PWCFG_WOLTYPE           0x20	/* pulse(1) or button (0) */
+#define PWCFG_LEGCY_WOL         0x10
+#define PWCFG_PMCSR_PME_SR      0x08
+#define PWCFG_PMCSR_PME_EN      0x04	/* control by PCISTICK */
+#define PWCFG_LEGACY_WOLSR      0x02	/* Legacy WOL_SR shadow */
+#define PWCFG_LEGACY_WOLEN      0x01	/* Legacy WOL_EN shadow */
+
+/*
+ *	Bits in WOLCFG
+ */
+
+#define WOLCFG_PMEOVR           0x80	/* for legacy use, force PMEEN always */
+#define WOLCFG_SAM              0x20	/* accept multicast case reset, default=0 */
+#define WOLCFG_SAB              0x10	/* accept broadcast case reset, default=0 */
+#define WOLCFG_SMIIACC          0x08	/* ?? */
+#define WOLCFG_SGENWH           0x02
+#define WOLCFG_PHYINTEN         0x01	/* 0:PHYINT trigger enable, 1:use internal MII
+					  to report status change */
+/*
+ *	Bits in WOLSR1
+ */
+
+#define WOLSR_LINKOFF_INT      0x0800
+#define WOLSR_LINKON_INT       0x0400
+#define WOLSR_MAGIC_INT        0x0200
+#define WOLSR_UNICAST_INT      0x0100
+
+/*
+ *	Ethernet address filter type
+ */
+
+#define PKT_TYPE_NONE               0x0000	/* Turn off receiver */
+#define PKT_TYPE_DIRECTED           0x0001	/* obselete, directed address is always accepted */
+#define PKT_TYPE_MULTICAST          0x0002
+#define PKT_TYPE_ALL_MULTICAST      0x0004
+#define PKT_TYPE_BROADCAST          0x0008
+#define PKT_TYPE_PROMISCUOUS        0x0020
+#define PKT_TYPE_LONG               0x2000	/* NOTE.... the definition of LONG is >2048 bytes in our chip */
+#define PKT_TYPE_RUNT               0x4000
+#define PKT_TYPE_ERROR              0x8000	/* Accept error packets, e.g. CRC error */
+
+/*
+ *	Loopback mode
+ */
+
+#define MAC_LB_NONE         0x00
+#define MAC_LB_INTERNAL     0x01
+#define MAC_LB_EXTERNAL     0x02
+
+/*
+ *	Enabled mask value of irq
+ */
+
+#if defined(_SIM)
+#define IMR_MASK_VALUE      0x0033FF0FUL	/* initial value of IMR
+						   set IMR0 to 0x0F according to spec */
+
+#else
+#define IMR_MASK_VALUE      0x0013FB0FUL	/* initial value of IMR
+						   ignore MIBFI,RACEI to
+						   reduce intr. frequency
+						   NOTE.... do not enable NoBuf int mask at driver driver
+						      when (1) NoBuf -> RxThreshold = SF
+							   (2) OK    -> RxThreshold = original value
+						 */
+#endif
+
+/*
+ *	Revision id
+ */
+
+#define REV_ID_VT3119_A0	0x00
+#define REV_ID_VT3119_A1	0x01
+#define REV_ID_VT3216_A0	0x10
+
+/*
+ *	Max time out delay time
+ */
+
+#define W_MAX_TIMEOUT       0x0FFFU
+
+
+/*
+ *	MAC registers as a structure. Cannot be directly accessed this
+ *	way but generates offsets for readl/writel() calls
+ */
+
+struct mac_regs {
+	volatile u8 PAR[6];		/* 0x00 */
+	volatile u8 RCR;
+	volatile u8 TCR;
+
+	volatile u32 CR0Set;		/* 0x08 */
+	volatile u32 CR0Clr;		/* 0x0C */
+
+	volatile u8 MARCAM[8];		/* 0x10 */
+
+	volatile u32 DecBaseHi;		/* 0x18 */
+	volatile u16 DbfBaseHi;		/* 0x1C */
+	volatile u16 reserved_1E;
+
+	volatile u16 ISRCTL;		/* 0x20 */
+	volatile u8 TXESR;
+	volatile u8 RXESR;
+
+	volatile u32 ISR;		/* 0x24 */
+	volatile u32 IMR;
+
+	volatile u32 TDStatusPort;	/* 0x2C */
+
+	volatile u16 TDCSRSet;		/* 0x30 */
+	volatile u8 RDCSRSet;
+	volatile u8 reserved_33;
+	volatile u16 TDCSRClr;
+	volatile u8 RDCSRClr;
+	volatile u8 reserved_37;
+
+	volatile u32 RDBaseLo;		/* 0x38 */
+	volatile u16 RDIdx;		/* 0x3C */
+	volatile u16 reserved_3E;
+
+	volatile u32 TDBaseLo[4];	/* 0x40 */
+
+	volatile u16 RDCSize;		/* 0x50 */
+	volatile u16 TDCSize;		/* 0x52 */
+	volatile u16 TDIdx[4];		/* 0x54 */
+	volatile u16 tx_pause_timer;	/* 0x5C */
+	volatile u16 RBRDU;		/* 0x5E */
+
+	volatile u32 FIFOTest0;		/* 0x60 */
+	volatile u32 FIFOTest1;		/* 0x64 */
+
+	volatile u8 CAMADDR;		/* 0x68 */
+	volatile u8 CAMCR;		/* 0x69 */
+	volatile u8 GFTEST;		/* 0x6A */
+	volatile u8 FTSTCMD;		/* 0x6B */
+
+	volatile u8 MIICFG;		/* 0x6C */
+	volatile u8 MIISR;
+	volatile u8 PHYSR0;
+	volatile u8 PHYSR1;
+	volatile u8 MIICR;
+	volatile u8 MIIADR;
+	volatile u16 MIIDATA;
+
+	volatile u16 SoftTimer0;	/* 0x74 */
+	volatile u16 SoftTimer1;
+
+	volatile u8 CFGA;		/* 0x78 */
+	volatile u8 CFGB;
+	volatile u8 CFGC;
+	volatile u8 CFGD;
+
+	volatile u16 DCFG;		/* 0x7C */
+	volatile u16 MCFG;
+
+	volatile u8 TBIST;		/* 0x80 */
+	volatile u8 RBIST;
+	volatile u8 PMCPORT;
+	volatile u8 STICKHW;
+
+	volatile u8 MIBCR;		/* 0x84 */
+	volatile u8 reserved_85;
+	volatile u8 rev_id;
+	volatile u8 PORSTS;
+
+	volatile u32 MIBData;		/* 0x88 */
+
+	volatile u16 EEWrData;
+
+	volatile u8 reserved_8E;
+	volatile u8 BPMDWr;
+	volatile u8 BPCMD;
+	volatile u8 BPMDRd;
+
+	volatile u8 EECHKSUM;		/* 0x92 */
+	volatile u8 EECSR;
+
+	volatile u16 EERdData;		/* 0x94 */
+	volatile u8 EADDR;
+	volatile u8 EMBCMD;
+
+
+	volatile u8 JMPSR0;		/* 0x98 */
+	volatile u8 JMPSR1;
+	volatile u8 JMPSR2;
+	volatile u8 JMPSR3;
+	volatile u8 CHIPGSR;		/* 0x9C */
+	volatile u8 TESTCFG;
+	volatile u8 DEBUG;
+	volatile u8 CHIPGCR;
+
+	volatile u16 WOLCRSet;		/* 0xA0 */
+	volatile u8 PWCFGSet;
+	volatile u8 WOLCFGSet;
+
+	volatile u16 WOLCRClr;		/* 0xA4 */
+	volatile u8 PWCFGCLR;
+	volatile u8 WOLCFGClr;
+
+	volatile u16 WOLSRSet;		/* 0xA8 */
+	volatile u16 reserved_AA;
+
+	volatile u16 WOLSRClr;		/* 0xAC */
+	volatile u16 reserved_AE;
+
+	volatile u16 PatternCRC[8];	/* 0xB0 */
+	volatile u32 ByteMask[4][4];	/* 0xC0 */
+} __attribute__ ((__packed__));
+
+
+enum hw_mib {
+	HW_MIB_ifRxAllPkts = 0,
+	HW_MIB_ifRxOkPkts,
+	HW_MIB_ifTxOkPkts,
+	HW_MIB_ifRxErrorPkts,
+	HW_MIB_ifRxRuntOkPkt,
+	HW_MIB_ifRxRuntErrPkt,
+	HW_MIB_ifRx64Pkts,
+	HW_MIB_ifTx64Pkts,
+	HW_MIB_ifRx65To127Pkts,
+	HW_MIB_ifTx65To127Pkts,
+	HW_MIB_ifRx128To255Pkts,
+	HW_MIB_ifTx128To255Pkts,
+	HW_MIB_ifRx256To511Pkts,
+	HW_MIB_ifTx256To511Pkts,
+	HW_MIB_ifRx512To1023Pkts,
+	HW_MIB_ifTx512To1023Pkts,
+	HW_MIB_ifRx1024To1518Pkts,
+	HW_MIB_ifTx1024To1518Pkts,
+	HW_MIB_ifTxEtherCollisions,
+	HW_MIB_ifRxPktCRCE,
+	HW_MIB_ifRxJumboPkts,
+	HW_MIB_ifTxJumboPkts,
+	HW_MIB_ifRxMacControlFrames,
+	HW_MIB_ifTxMacControlFrames,
+	HW_MIB_ifRxPktFAE,
+	HW_MIB_ifRxLongOkPkt,
+	HW_MIB_ifRxLongPktErrPkt,
+	HW_MIB_ifTXSQEErrors,
+	HW_MIB_ifRxNobuf,
+	HW_MIB_ifRxSymbolErrors,
+	HW_MIB_ifInRangeLengthErrors,
+	HW_MIB_ifLateCollisions,
+	HW_MIB_SIZE
+};
+
+enum chip_type {
+	CHIP_TYPE_VT6110 = 1,
+};
+
+struct velocity_info_tbl {
+	enum chip_type chip_id;
+	char *name;
+	int io_size;
+	int txqueue;
+	u32 flags;
+};
+
+#define mac_hw_mibs_init(regs) {\
+	BYTE_REG_BITS_ON(MIBCR_MIBFRZ,&((regs)->MIBCR));\
+	BYTE_REG_BITS_ON(MIBCR_MIBCLR,&((regs)->MIBCR));\
+	do {}\
+		while (BYTE_REG_BITS_IS_ON(MIBCR_MIBCLR,&((regs)->MIBCR)));\
+	BYTE_REG_BITS_OFF(MIBCR_MIBFRZ,&((regs)->MIBCR));\
+}
+
+#define mac_read_isr(regs)  		readl(&((regs)->ISR))
+#define mac_write_isr(regs, x)  	writel((x),&((regs)->ISR))
+#define mac_clear_isr(regs) 		writel(0xffffffffL,&((regs)->ISR))
+
+#define mac_write_int_mask(mask, regs) 	writel((mask),&((regs)->IMR));
+#define mac_disable_int(regs)       	writel(CR0_GINTMSK1,&((regs)->CR0Clr))
+#define mac_enable_int(regs)    	writel(CR0_GINTMSK1,&((regs)->CR0Set))
+
+#define mac_hw_mibs_read(regs, MIBs) {\
+	int i;\
+	BYTE_REG_BITS_ON(MIBCR_MPTRINI,&((regs)->MIBCR));\
+	for (i=0;i<HW_MIB_SIZE;i++) {\
+		(MIBs)[i]=readl(&((regs)->MIBData));\
+	}\
+}
+
+#define mac_set_dma_length(regs, n) {\
+	BYTE_REG_BITS_SET((n),0x07,&((regs)->DCFG));\
+}
+
+#define mac_set_rx_thresh(regs, n) {\
+	BYTE_REG_BITS_SET((n),(MCFG_RFT0|MCFG_RFT1),&((regs)->MCFG));\
+}
+
+#define mac_rx_queue_run(regs) {\
+	writeb(TRDCSR_RUN, &((regs)->RDCSRSet));\
+}
+
+#define mac_rx_queue_wake(regs) {\
+	writeb(TRDCSR_WAK, &((regs)->RDCSRSet));\
+}
+
+#define mac_tx_queue_run(regs, n) {\
+	writew(TRDCSR_RUN<<((n)*4),&((regs)->TDCSRSet));\
+}
+
+#define mac_tx_queue_wake(regs, n) {\
+	writew(TRDCSR_WAK<<(n*4),&((regs)->TDCSRSet));\
+}
+
+#define mac_eeprom_reload(regs) {\
+	int i=0;\
+	BYTE_REG_BITS_ON(EECSR_RELOAD,&((regs)->EECSR));\
+	do {\
+		udelay(10);\
+		if (i++>0x1000) {\
+			break;\
+		}\
+	}while (BYTE_REG_BITS_IS_ON(EECSR_RELOAD,&((regs)->EECSR)));\
+}
+
+enum velocity_cam_type {
+	VELOCITY_VLAN_ID_CAM = 0,
+	VELOCITY_MULTICAST_CAM
+};
+
+/**
+ *	mac_get_cam_mask	-	Read a CAM mask
+ *	@regs: register block for this velocity
+ *	@mask: buffer to store mask
+ *	@cam_type: CAM to fetch
+ *
+ *	Fetch the mask bits of the selected CAM and store them into the
+ *	provided mask buffer.
+ */
+
+static inline void mac_get_cam_mask(struct mac_regs * regs, u8 * mask, enum velocity_cam_type cam_type)
+{
+	int i;
+	/* Select CAM mask */
+	BYTE_REG_BITS_SET(CAMCR_PS_CAM_MASK, CAMCR_PS1 | CAMCR_PS0, &regs->CAMCR);
+
+	if (cam_type == VELOCITY_VLAN_ID_CAM)
+		writeb(CAMADDR_VCAMSL, &regs->CAMADDR);
+	else
+		writeb(0, &regs->CAMADDR);
+
+	/* read mask */
+	for (i = 0; i < 8; i++)
+		*mask++ = readb(&(regs->MARCAM[i]));
+
+	/* disable CAMEN */
+	writeb(0, &regs->CAMADDR);
+
+	/* Select mar */
+	BYTE_REG_BITS_SET(CAMCR_PS_MAR, CAMCR_PS1 | CAMCR_PS0, &regs->CAMCR);
+
+}
+
+/**
+ *	mac_set_cam_mask	-	Set a CAM mask
+ *	@regs: register block for this velocity
+ *	@mask: CAM mask to load
+ *	@cam_type: CAM to store
+ *
+ *	Store a new mask into a CAM
+ */
+
+static inline void mac_set_cam_mask(struct mac_regs * regs, u8 * mask, enum velocity_cam_type cam_type)
+{
+	int i;
+	/* Select CAM mask */
+	BYTE_REG_BITS_SET(CAMCR_PS_CAM_MASK, CAMCR_PS1 | CAMCR_PS0, &regs->CAMCR);
+
+	if (cam_type == VELOCITY_VLAN_ID_CAM)
+		writeb(CAMADDR_CAMEN | CAMADDR_VCAMSL, &regs->CAMADDR);
+	else
+		writeb(CAMADDR_CAMEN, &regs->CAMADDR);
+
+	for (i = 0; i < 8; i++) {
+		writeb(*mask++, &(regs->MARCAM[i]));
+	}
+	/* disable CAMEN */
+	writeb(0, &regs->CAMADDR);
+
+	/* Select CAM mask */
+	BYTE_REG_BITS_SET(CAMCR_PS_MAR, CAMCR_PS1 | CAMCR_PS0, &regs->CAMCR);
+}
+
+/**
+ *	mac_set_cam	-	set CAM data
+ *	@regs: register block of this velocity
+ *	@idx: Cam index
+ *	@addr: 2 or 6 bytes of CAM data
+ *	@cam_type: CAM to load
+ *
+ *	Load an address or vlan tag into a CAM
+ */
+
+static inline void mac_set_cam(struct mac_regs * regs, int idx, u8 *addr, enum velocity_cam_type cam_type)
+{
+	int i;
+
+	/* Select CAM mask */
+	BYTE_REG_BITS_SET(CAMCR_PS_CAM_DATA, CAMCR_PS1 | CAMCR_PS0, &regs->CAMCR);
+
+	idx &= (64 - 1);
+
+	if (cam_type == VELOCITY_VLAN_ID_CAM)
+		writeb(CAMADDR_CAMEN | CAMADDR_VCAMSL | idx, &regs->CAMADDR);
+	else
+		writeb(CAMADDR_CAMEN | idx, &regs->CAMADDR);
+
+	if (cam_type == VELOCITY_VLAN_ID_CAM)
+		writew(*((u16 *) addr), &regs->MARCAM[0]);
+	else {
+		for (i = 0; i < 6; i++) {
+			writeb(*addr++, &(regs->MARCAM[i]));
+		}
+	}
+	BYTE_REG_BITS_ON(CAMCR_CAMWR, &regs->CAMCR);
+
+	udelay(10);
+
+	writeb(0, &regs->CAMADDR);
+
+	/* Select CAM mask */
+	BYTE_REG_BITS_SET(CAMCR_PS_MAR, CAMCR_PS1 | CAMCR_PS0, &regs->CAMCR);
+}
+
+/**
+ *	mac_get_cam	-	fetch CAM data
+ *	@regs: register block of this velocity
+ *	@idx: Cam index
+ *	@addr: buffer to hold up to 6 bytes of CAM data
+ *	@cam_type: CAM to load
+ *
+ *	Load an address or vlan tag from a CAM into the buffer provided by
+ *	the caller. VLAN tags are 2 bytes the address cam entries are 6.
+ */
+
+static inline void mac_get_cam(struct mac_regs * regs, int idx, u8 *addr, enum velocity_cam_type cam_type)
+{
+	int i;
+
+	/* Select CAM mask */
+	BYTE_REG_BITS_SET(CAMCR_PS_CAM_DATA, CAMCR_PS1 | CAMCR_PS0, &regs->CAMCR);
+
+	idx &= (64 - 1);
+
+	if (cam_type == VELOCITY_VLAN_ID_CAM)
+		writeb(CAMADDR_CAMEN | CAMADDR_VCAMSL | idx, &regs->CAMADDR);
+	else
+		writeb(CAMADDR_CAMEN | idx, &regs->CAMADDR);
+
+	BYTE_REG_BITS_ON(CAMCR_CAMRD, &regs->CAMCR);
+
+	udelay(10);
+
+	if (cam_type == VELOCITY_VLAN_ID_CAM)
+		*((u16 *) addr) = readw(&(regs->MARCAM[0]));
+	else
+		for (i = 0; i < 6; i++, addr++)
+			*((u8 *) addr) = readb(&(regs->MARCAM[i]));
+
+	writeb(0, &regs->CAMADDR);
+
+	/* Select CAM mask */
+	BYTE_REG_BITS_SET(CAMCR_PS_MAR, CAMCR_PS1 | CAMCR_PS0, &regs->CAMCR);
+}
+
+/**
+ *	mac_wol_reset	-	reset WOL after exiting low power
+ *	@regs: register block of this velocity
+ *
+ *	Called after we drop out of wake on lan mode in order to
+ *	reset the Wake on lan features. This function doesn't restore
+ *	the rest of the logic from the result of sleep/wakeup
+ */
+
+inline static void mac_wol_reset(struct mac_regs * regs)
+{
+
+	/* Turn off SWPTAG right after leaving power mode */
+	BYTE_REG_BITS_OFF(STICKHW_SWPTAG, &regs->STICKHW);
+	/* clear sticky bits */
+	BYTE_REG_BITS_OFF((STICKHW_DS1 | STICKHW_DS0), &regs->STICKHW);
+
+	BYTE_REG_BITS_OFF(CHIPGCR_FCGMII, &regs->CHIPGCR);
+	BYTE_REG_BITS_OFF(CHIPGCR_FCMODE, &regs->CHIPGCR);
+	/* disable force PME-enable */
+	writeb(WOLCFG_PMEOVR, &regs->WOLCFGClr);
+	/* disable power-event config bit */
+	writew(0xFFFF, &regs->WOLCRClr);
+	/* clear power status */
+	writew(0xFFFF, &regs->WOLSRClr);
+}
+
+
+/*
+ * Header for WOL definitions. Used to compute hashes
+ */
+
+typedef u8 MCAM_ADDR[ETH_ALEN];
+
+struct arp_packet {
+	u8 dest_mac[ETH_ALEN];
+	u8 src_mac[ETH_ALEN];
+	u16 type;
+	u16 ar_hrd;
+	u16 ar_pro;
+	u8 ar_hln;
+	u8 ar_pln;
+	u16 ar_op;
+	u8 ar_sha[ETH_ALEN];
+	u8 ar_sip[4];
+	u8 ar_tha[ETH_ALEN];
+	u8 ar_tip[4];
+} __attribute__ ((__packed__));
+
+struct _magic_packet {
+	u8 dest_mac[6];
+	u8 src_mac[6];
+	u16 type;
+	u8 MAC[16][6];
+	u8 password[6];
+} __attribute__ ((__packed__));
+
+/*
+ *	Store for chip context when saving and restoring status. Not
+ *	all fields are saved/restored currently.
+ */
+
+struct velocity_context {
+	u8 mac_reg[256];
+	MCAM_ADDR cam_addr[MCAM_SIZE];
+	u16 vcam[VCAM_SIZE];
+	u32 cammask[2];
+	u32 patcrc[2];
+	u32 pattern[8];
+};
+
+
+/*
+ *	MII registers.
+ */
+
+
+/*
+ *	Registers in the MII (offset unit is WORD)
+ */
+
+#define MII_REG_BMCR        0x00	// physical address
+#define MII_REG_BMSR        0x01	//
+#define MII_REG_PHYID1      0x02	// OUI
+#define MII_REG_PHYID2      0x03	// OUI + Module ID + REV ID
+#define MII_REG_ANAR        0x04	//
+#define MII_REG_ANLPAR      0x05	//
+#define MII_REG_G1000CR     0x09	//
+#define MII_REG_G1000SR     0x0A	//
+#define MII_REG_MODCFG      0x10	//
+#define MII_REG_TCSR        0x16	//
+#define MII_REG_PLED        0x1B	//
+// NS, MYSON only
+#define MII_REG_PCR         0x17	//
+// ESI only
+#define MII_REG_PCSR        0x17	//
+#define MII_REG_AUXCR       0x1C	//
+
+// Marvell 88E1000/88E1000S
+#define MII_REG_PSCR        0x10	// PHY specific control register
+
+//
+// Bits in the BMCR register
+//
+#define BMCR_RESET          0x8000	//
+#define BMCR_LBK            0x4000	//
+#define BMCR_SPEED100       0x2000	//
+#define BMCR_AUTO           0x1000	//
+#define BMCR_PD             0x0800	//
+#define BMCR_ISO            0x0400	//
+#define BMCR_REAUTO         0x0200	//
+#define BMCR_FDX            0x0100	//
+#define BMCR_SPEED1G        0x0040	//
+//
+// Bits in the BMSR register
+//
+#define BMSR_AUTOCM         0x0020	//
+#define BMSR_LNK            0x0004	//
+
+//
+// Bits in the ANAR register
+//
+#define ANAR_ASMDIR         0x0800	// Asymmetric PAUSE support
+#define ANAR_PAUSE          0x0400	// Symmetric PAUSE Support
+#define ANAR_T4             0x0200	//
+#define ANAR_TXFD           0x0100	//
+#define ANAR_TX             0x0080	//
+#define ANAR_10FD           0x0040	//
+#define ANAR_10             0x0020	//
+//
+// Bits in the ANLPAR register
+//
+#define ANLPAR_ASMDIR       0x0800	// Asymmetric PAUSE support
+#define ANLPAR_PAUSE        0x0400	// Symmetric PAUSE Support
+#define ANLPAR_T4           0x0200	//
+#define ANLPAR_TXFD         0x0100	//
+#define ANLPAR_TX           0x0080	//
+#define ANLPAR_10FD         0x0040	//
+#define ANLPAR_10           0x0020	//
+
+//
+// Bits in the G1000CR register
+//
+#define G1000CR_1000FD      0x0200	// PHY is 1000-T Full-duplex capable
+#define G1000CR_1000        0x0100	// PHY is 1000-T Half-duplex capable
+
+//
+// Bits in the G1000SR register
+//
+#define G1000SR_1000FD      0x0800	// LP PHY is 1000-T Full-duplex capable
+#define G1000SR_1000        0x0400	// LP PHY is 1000-T Half-duplex capable
+
+#define TCSR_ECHODIS        0x2000	//
+#define AUXCR_MDPPS         0x0004	//
+
+// Bits in the PLED register
+#define PLED_LALBE			0x0004	//
+
+// Marvell 88E1000/88E1000S Bits in the PHY specific control register (10h)
+#define PSCR_ACRSTX         0x0800	// Assert CRS on Transmit
+
+#define PHYID_CICADA_CS8201 0x000FC410UL
+#define PHYID_VT3216_32BIT  0x000FC610UL
+#define PHYID_VT3216_64BIT  0x000FC600UL
+#define PHYID_MARVELL_1000  0x01410C50UL
+#define PHYID_MARVELL_1000S 0x01410C40UL
+
+#define PHYID_REV_ID_MASK   0x0000000FUL
+
+#define PHYID_GET_PHY_REV_ID(i)     ((i) & PHYID_REV_ID_MASK)
+#define PHYID_GET_PHY_ID(i)         ((i) & ~PHYID_REV_ID_MASK)
+
+#define MII_REG_BITS_ON(x,i,p) do {\
+    u16 w;\
+    velocity_mii_read((p),(i),&(w));\
+    (w)|=(x);\
+    velocity_mii_write((p),(i),(w));\
+} while (0)
+
+#define MII_REG_BITS_OFF(x,i,p) do {\
+    u16 w;\
+    velocity_mii_read((p),(i),&(w));\
+    (w)&=(~(x));\
+    velocity_mii_write((p),(i),(w));\
+} while (0)
+
+#define MII_REG_BITS_IS_ON(x,i,p) ({\
+    u16 w;\
+    velocity_mii_read((p),(i),&(w));\
+    ((int) ((w) & (x)));})
+
+#define MII_GET_PHY_ID(p) ({\
+    u32 id;\
+    velocity_mii_read((p),MII_REG_PHYID2,(u16 *) &id);\
+    velocity_mii_read((p),MII_REG_PHYID1,((u16 *) &id)+1);\
+    (id);})
+
+/*
+ * Inline debug routine
+ */
+
+
+enum velocity_msg_level {
+	MSG_LEVEL_ERR = 0,	//Errors that will cause abnormal operation.
+	MSG_LEVEL_NOTICE = 1,	//Some errors need users to be notified.
+	MSG_LEVEL_INFO = 2,	//Normal message.
+	MSG_LEVEL_VERBOSE = 3,	//Will report all trival errors.
+	MSG_LEVEL_DEBUG = 4	//Only for debug purpose.
+};
+
+#ifdef VELOCITY_DEBUG
+#define ASSERT(x) { \
+	if (!(x)) { \
+		printk(KERN_ERR "assertion %s failed: file %s line %d\n", #x,\
+			__FUNCTION__, __LINE__);\
+		BUG(); \
+	}\
+}
+#define VELOCITY_DBG(p,args...) printk(p, ##args)
+#else
+#define ASSERT(x)
+#define VELOCITY_DBG(x)
+#endif
+
+#define VELOCITY_PRT(l, p, args...) do {if (l<=msglevel) printk( p ,##args);} while (0)
+
+#define VELOCITY_PRT_CAMMASK(p,t) {\
+	int i;\
+	if ((t)==VELOCITY_MULTICAST_CAM) {\
+        	for (i=0;i<(MCAM_SIZE/8);i++)\
+			printk("%02X",(p)->mCAMmask[i]);\
+	}\
+	else {\
+		for (i=0;i<(VCAM_SIZE/8);i++)\
+			printk("%02X",(p)->vCAMmask[i]);\
+	}\
+	printk("\n");\
+}
+
+
+
+#define     VELOCITY_WOL_MAGIC             0x00000000UL
+#define     VELOCITY_WOL_PHY               0x00000001UL
+#define     VELOCITY_WOL_ARP               0x00000002UL
+#define     VELOCITY_WOL_UCAST             0x00000004UL
+#define     VELOCITY_WOL_BCAST             0x00000010UL
+#define     VELOCITY_WOL_MCAST             0x00000020UL
+#define     VELOCITY_WOL_MAGIC_SEC         0x00000040UL
+
+/*
+ *	Flags for options
+ */
+
+#define     VELOCITY_FLAGS_TAGGING         0x00000001UL
+#define     VELOCITY_FLAGS_TX_CSUM         0x00000002UL
+#define     VELOCITY_FLAGS_RX_CSUM         0x00000004UL
+#define     VELOCITY_FLAGS_IP_ALIGN        0x00000008UL
+#define     VELOCITY_FLAGS_VAL_PKT_LEN     0x00000010UL
+
+#define     VELOCITY_FLAGS_FLOW_CTRL       0x01000000UL
+
+/*
+ *	Flags for driver status
+ */
+
+#define     VELOCITY_FLAGS_OPENED          0x00010000UL
+#define     VELOCITY_FLAGS_VMNS_CONNECTED  0x00020000UL
+#define     VELOCITY_FLAGS_VMNS_COMMITTED  0x00040000UL
+#define     VELOCITY_FLAGS_WOL_ENABLED     0x00080000UL
+
+/*
+ *	Flags for MII status
+ */
+
+#define     VELOCITY_LINK_FAIL             0x00000001UL
+#define     VELOCITY_SPEED_10              0x00000002UL
+#define     VELOCITY_SPEED_100             0x00000004UL
+#define     VELOCITY_SPEED_1000            0x00000008UL
+#define     VELOCITY_DUPLEX_FULL           0x00000010UL
+#define     VELOCITY_AUTONEG_ENABLE        0x00000020UL
+#define     VELOCITY_FORCED_BY_EEPROM      0x00000040UL
+
+/*
+ *	For velocity_set_media_duplex
+ */
+
+#define     VELOCITY_LINK_CHANGE           0x00000001UL
+
+enum speed_opt {
+	SPD_DPX_AUTO = 0,
+	SPD_DPX_100_HALF = 1,
+	SPD_DPX_100_FULL = 2,
+	SPD_DPX_10_HALF = 3,
+	SPD_DPX_10_FULL = 4
+};
+
+enum velocity_init_type {
+	VELOCITY_INIT_COLD = 0,
+	VELOCITY_INIT_RESET,
+	VELOCITY_INIT_WOL
+};
+
+enum velocity_flow_cntl_type {
+	FLOW_CNTL_DEFAULT = 1,
+	FLOW_CNTL_TX,
+	FLOW_CNTL_RX,
+	FLOW_CNTL_TX_RX,
+	FLOW_CNTL_DISABLE,
+};
+
+struct velocity_opt {
+	int numrx;			/* Number of RX descriptors */
+	int numtx;			/* Number of TX descriptors */
+	enum speed_opt spd_dpx;		/* Media link mode */
+	int vid;			/* vlan id */
+	int DMA_length;			/* DMA length */
+	int rx_thresh;			/* RX_THRESH */
+	int flow_cntl;
+	int wol_opts;			/* Wake on lan options */
+	int td_int_count;
+	int int_works;
+	int rx_bandwidth_hi;
+	int rx_bandwidth_lo;
+	int rx_bandwidth_en;
+	u32 flags;
+};
+
+struct velocity_info {
+	struct velocity_info *next;
+	struct velocity_info *prev;
+
+	struct pci_dev *pdev;
+	struct net_device *dev;
+	struct net_device_stats stats;
+
+#if CONFIG_PM
+	u32 pci_state[16];
+#endif
+
+	dma_addr_t rd_pool_dma;
+	dma_addr_t td_pool_dma[TX_QUEUE_NO];
+
+	dma_addr_t tx_bufs_dma;
+	u8 *tx_bufs;
+
+	u8 ip_addr[4];
+	enum chip_type chip_id;
+
+	struct mac_regs * mac_regs;
+	unsigned long memaddr;
+	unsigned long ioaddr;
+	u32 io_size;
+
+	u8 rev_id;
+
+#define AVAIL_TD(p,q)   ((p)->options.numtx-((p)->td_used[(q)]))
+
+	int num_txq;
+
+	volatile int td_used[TX_QUEUE_NO];
+	int td_curr[TX_QUEUE_NO];
+	int td_tail[TX_QUEUE_NO];
+	struct tx_desc *td_rings[TX_QUEUE_NO];
+	struct velocity_td_info *td_infos[TX_QUEUE_NO];
+
+	int rd_curr;
+	int rd_used;
+	struct rx_desc *rd_ring;
+	struct velocity_rd_info *rd_info;	/* It's an array */
+
+#define GET_RD_BY_IDX(vptr, idx)   (vptr->rd_ring[idx])
+	u32 mib_counter[MAX_HW_MIB_COUNTER];
+	struct velocity_opt options;
+
+	u32 int_mask;
+
+	u32 flags;
+
+	int rx_buf_sz;
+	u32 mii_status;
+	u32 phy_id;
+	int multicast_limit;
+
+	u8 vCAMmask[(VCAM_SIZE / 8)];
+	u8 mCAMmask[(MCAM_SIZE / 8)];
+
+	spinlock_t lock;
+	spinlock_t xmit_lock;
+
+	int wol_opts;
+	u8 wol_passwd[6];
+
+	struct velocity_context context;
+
+	u32 ticks;
+	u32 rx_bytes;
+
+};
+
+/**
+ *	velocity_get_ip		-	find an IP address for the device
+ *	@vptr: Velocity to query
+ *
+ *	Dig out an IP address for this interface so that we can
+ *	configure wakeup with WOL for ARP. If there are multiple IP
+ *	addresses on this chain then we use the first - multi-IP WOL is not
+ *	supported.
+ *
+ *	CHECK ME: locking
+ */
+
+inline static int velocity_get_ip(struct velocity_info *vptr)
+{
+	struct in_device *in_dev = (struct in_device *) vptr->dev->ip_ptr;
+	struct in_ifaddr *ifa;
+
+	if (in_dev != NULL) {
+		ifa = (struct in_ifaddr *) in_dev->ifa_list;
+		if (ifa != NULL) {
+			memcpy(vptr->ip_addr, &ifa->ifa_address, 4);
+			return 0;
+		}
+	}
+	return -ENOENT;
+}
+
+/**
+ *	velocity_update_hw_mibs	-	fetch MIB counters from chip
+ *	@vptr: velocity to update
+ *
+ *	The velocity hardware keeps certain counters in the hardware
+ * 	side. We need to read these when the user asks for statistics
+ *	or when they overflow (causing an interrupt). The read of the
+ *	statistic clears it, so we keep running master counters in user
+ *	space.
+ */
+
+static inline void velocity_update_hw_mibs(struct velocity_info *vptr)
+{
+	u32 tmp;
+	int i;
+	BYTE_REG_BITS_ON(MIBCR_MIBFLSH, &(vptr->mac_regs->MIBCR));
+
+	while (BYTE_REG_BITS_IS_ON(MIBCR_MIBFLSH, &(vptr->mac_regs->MIBCR)));
+
+	BYTE_REG_BITS_ON(MIBCR_MPTRINI, &(vptr->mac_regs->MIBCR));
+	for (i = 0; i < HW_MIB_SIZE; i++) {
+		tmp = readl(&(vptr->mac_regs->MIBData)) & 0x00FFFFFFUL;
+		vptr->mib_counter[i] += tmp;
+	}
+}
+
+/**
+ *	init_flow_control_register 	-	set up flow control
+ *	@vptr: velocity to configure
+ *
+ *	Configure the flow control registers for this velocity device.
+ */
+
+static inline void init_flow_control_register(struct velocity_info *vptr)
+{
+	struct mac_regs * regs = vptr->mac_regs;
+
+	/* Set {XHITH1, XHITH0, XLTH1, XLTH0} in FlowCR1 to {1, 0, 1, 1}
+	   depend on RD=64, and Turn on XNOEN in FlowCR1 */
+	writel((CR0_XONEN | CR0_XHITH1 | CR0_XLTH1 | CR0_XLTH0), &regs->CR0Set);
+	writel((CR0_FDXTFCEN | CR0_FDXRFCEN | CR0_HDXFCEN | CR0_XHITH0), &regs->CR0Clr);
+
+	/* Set TxPauseTimer to 0xFFFF */
+	writew(0xFFFF, &regs->tx_pause_timer);
+
+	/* Initialize RBRDU to Rx buffer count. */
+	writew(vptr->options.numrx, &regs->RBRDU);
+}
+
+
+#endif
--- diff/drivers/perfctr/Kconfig	1970-01-01 01:00:00.000000000 +0100
+++ source/drivers/perfctr/Kconfig	2004-06-11 19:22:03.000000000 +0100
@@ -0,0 +1,45 @@
+# $Id: Kconfig,v 1.10 2004/05/24 11:00:55 mikpe Exp $
+# Performance-monitoring counters driver configuration
+#
+
+menu "Performance-monitoring counters support"
+
+config PERFCTR
+	bool "Performance monitoring counters support"
+	help
+	  This driver provides access to the performance-monitoring counter
+	  registers available in some (but not all) modern processors.
+	  These special-purpose registers can be programmed to count low-level
+	  performance-related events which occur during program execution,
+	  such as cache misses, pipeline stalls, etc.
+
+	  You can safely say Y here, even if you intend to run the kernel
+	  on a processor without performance-monitoring counters.
+
+config PERFCTR_INIT_TESTS
+	bool "Init-time hardware tests"
+	depends on PERFCTR
+	help
+	  This option makes the driver perform additional hardware tests
+	  during initialisation, and log their results in the kernel's
+	  message buffer. For most supported processors, these tests simply
+	  measure the runtime overheads of performance counter operations.
+
+	  If you have a less well-known processor (one not listed in the
+	  etc/costs/ directory in the user-space package), you should enable
+	  this option and email the results to the perfctr developers.
+
+	  If unsure, say N.
+
+config PERFCTR_VIRTUAL
+	bool "Virtual performance counters support"
+	depends on PERFCTR
+	help
+	  The processor's performance-monitoring counters are special-purpose
+	  global registers. This option adds support for virtual per-process
+	  performance-monitoring counters which only run when the process
+	  to which they belong is executing. This improves the accuracy of
+	  performance measurements by reducing "noise" from other processes.
+
+	  Say Y.
+endmenu
--- diff/drivers/perfctr/Makefile	1970-01-01 01:00:00.000000000 +0100
+++ source/drivers/perfctr/Makefile	2004-06-11 19:22:03.000000000 +0100
@@ -0,0 +1,16 @@
+# $Id: Makefile,v 1.26 2004/05/30 23:02:14 mikpe Exp $
+# Makefile for the Performance-monitoring counters driver.
+
+# This also covers x86_64.
+perfctr-objs-$(CONFIG_X86) := x86.o
+tests-objs-$(CONFIG_X86) := x86_tests.o
+
+perfctr-objs-$(CONFIG_PPC32) := ppc.o
+tests-objs-$(CONFIG_PPC32) := ppc_tests.o
+
+perfctr-objs-y += init.o
+perfctr-objs-$(CONFIG_PERFCTR_INIT_TESTS) += $(tests-objs-y)
+perfctr-objs-$(CONFIG_PERFCTR_VIRTUAL) += virtual.o
+
+perfctr-objs		:= $(perfctr-objs-y)
+obj-$(CONFIG_PERFCTR)	:= perfctr.o
--- diff/drivers/perfctr/cpumask.h	1970-01-01 01:00:00.000000000 +0100
+++ source/drivers/perfctr/cpumask.h	2004-06-11 19:22:03.000000000 +0100
@@ -0,0 +1,24 @@
+/* $Id: cpumask.h,v 1.7 2004/05/12 19:59:01 mikpe Exp $
+ * Performance-monitoring counters driver.
+ * Partial simulation of cpumask_t on non-cpumask_t kernels.
+ * Extension to allow inspecting a cpumask_t as array of ulong.
+ * Appropriate definition of perfctr_cpus_forbidden_mask.
+ *
+ * Copyright (C) 2003-2004  Mikael Pettersson
+ */
+
+#ifdef CPU_ARRAY_SIZE
+#define PERFCTR_CPUMASK_NRLONGS	CPU_ARRAY_SIZE
+#else
+#define PERFCTR_CPUMASK_NRLONGS	1
+#endif
+
+/* `perfctr_cpus_forbidden_mask' used to be defined in <asm/perfctr.h>,
+   but cpumask_t compatibility issues forced it to be moved here. */
+#ifdef PERFCTR_CPUS_FORBIDDEN_MASK_NEEDED
+extern cpumask_t perfctr_cpus_forbidden_mask;
+#define perfctr_cpu_is_forbidden(cpu)	cpu_isset((cpu), perfctr_cpus_forbidden_mask)
+#else
+#define perfctr_cpus_forbidden_mask	CPU_MASK_NONE
+#define perfctr_cpu_is_forbidden(cpu)	0 /* cpu_isset() needs an lvalue :-( */
+#endif
--- diff/drivers/perfctr/init.c	1970-01-01 01:00:00.000000000 +0100
+++ source/drivers/perfctr/init.c	2004-06-11 19:22:03.000000000 +0100
@@ -0,0 +1,97 @@
+/* $Id: init.c,v 1.76 2004/05/31 18:18:55 mikpe Exp $
+ * Performance-monitoring counters driver.
+ * Top-level initialisation code.
+ *
+ * Copyright (C) 1999-2004  Mikael Pettersson
+ */
+#include <linux/config.h>
+#include <linux/fs.h>
+#include <linux/init.h>
+#include <linux/sched.h>
+#include <linux/perfctr.h>
+
+#include <asm/uaccess.h>
+
+#include "cpumask.h"
+#include "virtual.h"
+#include "version.h"
+
+struct perfctr_info perfctr_info = {
+	.abi_version = PERFCTR_ABI_VERSION,
+	.driver_version = VERSION,
+};
+
+char *perfctr_cpu_name __initdata;
+
+static int cpus_copy_to_user(const cpumask_t *cpus, struct perfctr_cpu_mask *argp)
+{
+	const unsigned int k_nrwords = PERFCTR_CPUMASK_NRLONGS*(sizeof(long)/sizeof(int));
+	unsigned int u_nrwords;
+	unsigned int ui, ki, j;
+
+	if (get_user(u_nrwords, &argp->nrwords))
+		return -EFAULT;
+	if (put_user(k_nrwords, &argp->nrwords))
+		return -EFAULT;
+	if (u_nrwords < k_nrwords)
+		return -EOVERFLOW;
+	for(ui = 0, ki = 0; ki < PERFCTR_CPUMASK_NRLONGS; ++ki) {
+		unsigned long mask = cpus_addr(*cpus)[ki];
+		for(j = 0; j < sizeof(long)/sizeof(int); ++j) {
+			if (put_user((unsigned int)mask, &argp->mask[ui]))
+				return -EFAULT;
+			++ui;
+			mask = (mask >> (8*sizeof(int)-1)) >> 1;
+		}
+	}
+	return 0;
+}
+
+asmlinkage long sys_perfctr_info(struct perfctr_info *infop,
+				 struct perfctr_cpu_mask *cpusp,
+				 struct perfctr_cpu_mask *forbiddenp)
+{
+	if (infop && copy_to_user(infop, &perfctr_info, sizeof perfctr_info))
+		return -EFAULT;
+	if (cpusp) {
+		cpumask_t cpus = cpu_online_map;
+		int err = cpus_copy_to_user(&cpus, cpusp);
+		if (err)
+			return err;
+	}
+	if (forbiddenp) {
+		cpumask_t cpus = perfctr_cpus_forbidden_mask;
+		int err = cpus_copy_to_user(&cpus, forbiddenp);
+		if (err)
+			return err;
+	}
+	return 0;
+}
+
+int __init perfctr_init(void)
+{
+	int err;
+
+	err = perfctr_cpu_init();
+	if (err) {
+		printk(KERN_INFO "perfctr: not supported by this processor\n");
+		return err;
+	}
+	err = vperfctr_init();
+	if (err)
+		return err;
+	printk(KERN_INFO "perfctr: driver %s, cpu type %s at %u kHz\n",
+	       perfctr_info.driver_version,
+	       perfctr_cpu_name,
+	       perfctr_info.cpu_khz);
+	return 0;
+}
+
+void __exit perfctr_exit(void)
+{
+	vperfctr_exit();
+	perfctr_cpu_exit();
+}
+
+module_init(perfctr_init)
+module_exit(perfctr_exit)
--- diff/drivers/perfctr/ppc.c	1970-01-01 01:00:00.000000000 +0100
+++ source/drivers/perfctr/ppc.c	2004-06-11 19:22:03.000000000 +0100
@@ -0,0 +1,964 @@
+/* $Id: ppc.c,v 1.12 2004/05/31 18:13:42 mikpe Exp $
+ * PPC32 performance-monitoring counters driver.
+ *
+ * Copyright (C) 2004  Mikael Pettersson
+ */
+#include <linux/config.h>
+#include <linux/init.h>
+#include <linux/sched.h>
+#include <linux/fs.h>
+#include <linux/perfctr.h>
+#include <linux/seq_file.h>
+#include <asm/machdep.h>
+#include <asm/time.h>		/* tb_ticks_per_jiffy, get_tbl() */
+
+#include "ppc_tests.h"
+
+/* Support for lazy evntsel and perfctr SPR updates. */
+struct per_cpu_cache {	/* roughly a subset of perfctr_cpu_state */
+	union {
+		unsigned int id;	/* cache owner id */
+	} k1;
+	/* Physically indexed cache of the MMCRs. */
+	unsigned int ppc_mmcr[3];
+} ____cacheline_aligned;
+static DEFINE_PER_CPU(struct per_cpu_cache, per_cpu_cache);
+
+/* Structure for counter snapshots, as 32-bit values. */
+struct perfctr_low_ctrs {
+	unsigned int tsc;
+	unsigned int pmc[6];
+};
+
+enum pm_type {
+    PM_604,
+    PM_604e,
+    PM_750,	/* XXX: Minor event set diffs between IBM and Moto. */
+    PM_7400,
+    PM_7450,
+};
+static enum pm_type pm_type;
+
+/* Bits users shouldn't set in control.ppc.mmcr0:
+ * - PMXE because we don't yet support overflow interrupts
+ * - PMC1SEL/PMC2SEL because event selectors are in control.evntsel[]
+ */
+#define MMCR0_RESERVED		(MMCR0_PMXE | MMCR0_PMC1SEL | MMCR0_PMC2SEL)
+
+static unsigned int new_id(void)
+{
+	static spinlock_t lock = SPIN_LOCK_UNLOCKED;
+	static unsigned int counter;
+	int id;
+
+	spin_lock(&lock);
+	id = ++counter;
+	spin_unlock(&lock);
+	return id;
+}
+
+#ifdef PERFCTR_INTERRUPT_SUPPORT
+static void perfctr_default_ihandler(unsigned long pc)
+{
+}
+
+static perfctr_ihandler_t perfctr_ihandler = perfctr_default_ihandler;
+
+void do_perfctr_interrupt(struct pt_regs *regs)
+{
+	preempt_disable();
+	(*perfctr_ihandler)(regs->nip);
+	preempt_enable_no_resched();
+}
+
+void perfctr_cpu_set_ihandler(perfctr_ihandler_t ihandler)
+{
+	perfctr_ihandler = ihandler ? ihandler : perfctr_default_ihandler;
+}
+
+#else
+#define perfctr_cstatus_has_ictrs(cstatus)	0
+#endif
+
+#if defined(CONFIG_SMP) && defined(PERFCTR_INTERRUPT_SUPPORT)
+
+static inline void
+set_isuspend_cpu(struct perfctr_cpu_state *state, int cpu)
+{
+	state->k1.isuspend_cpu = cpu;
+}
+
+static inline int
+is_isuspend_cpu(const struct perfctr_cpu_state *state, int cpu)
+{
+	return state->k1.isuspend_cpu == cpu;
+}
+
+static inline void clear_isuspend_cpu(struct perfctr_cpu_state *state)
+{
+	state->k1.isuspend_cpu = NR_CPUS;
+}
+
+#else
+static inline void set_isuspend_cpu(struct perfctr_cpu_state *state, int cpu) { }
+static inline int is_isuspend_cpu(const struct perfctr_cpu_state *state, int cpu) { return 1; }
+static inline void clear_isuspend_cpu(struct perfctr_cpu_state *state) { }
+#endif
+
+/****************************************************************
+ *								*
+ * Driver procedures.						*
+ *								*
+ ****************************************************************/
+
+/*
+ * The PowerPC 604/750/74xx family.
+ *
+ * Common features
+ * ---------------
+ * - Per counter event selection data in subfields of control registers.
+ *   MMCR0 contains both global control and PMC1/PMC2 event selectors.
+ * - Overflow interrupt support is present in all processors, but an
+ *   erratum makes it difficult to use in 750/7400/7410 processors.
+ * - There is no concept of per-counter qualifiers:
+ *   - User-mode/supervisor-mode restrictions are global.
+ *   - Two groups of counters, PMC1 and PMC2-PMC<highest>. Each group
+ *     has a single overflow interrupt/event enable/disable flag.
+ * - The instructions used to read (mfspr) and write (mtspr) the control
+ *   and counter registers (SPRs) only support hardcoded register numbers.
+ *   There is no support for accessing an SPR via a runtime value.
+ * - Each counter supports its own unique set of events. However, events
+ *   0-1 are common for PMC1-PMC4, and events 2-4 are common for PMC1-PMC4.
+ * - There is no separate high-resolution core clock counter.
+ *   The time-base counter is available, but it typically runs an order of
+ *   magnitude slower than the core clock.
+ *   Any performance counter can be programmed to count core clocks, but
+ *   doing this (a) reserves one PMC, and (b) needs indirect accesses
+ *   since the SPR number in general isn't known at compile-time.
+ *
+ * Driver notes
+ * ------------
+ * - The driver currently does not support performance monitor interrupts,
+ *   mostly because of the 750/7400/7410 erratum. Working around it would
+ *   require disabling the decrementer interrupt, reserving a performance
+ *   counter and setting it up for TBL bit-flip events, and having the PMI
+ *   handler invoke the decrementer handler.
+ *
+ * 604
+ * ---
+ * 604 has MMCR0, PMC1, PMC2, SIA, and SDA.
+ *
+ * MMCR0[THRESHOLD] is not automatically multiplied.
+ *
+ * On the 604, software must always reset MMCR0[ENINT] after
+ * taking a PMI. This is not the case for the 604e.
+ *
+ * 604e
+ * ----
+ * 604e adds MMCR1, PMC3, and PMC4.
+ * Bus-to-core multiplier is available via HID1[PLL_CFG].
+ *
+ * MMCR0[THRESHOLD] is automatically multiplied by 4.
+ *
+ * When the 604e vectors to the PMI handler, it automatically
+ * clears any pending PMIs. Unlike the 604, the 604e does not
+ * require MMCR0[ENINT] to be cleared (and possibly reset)
+ * before external interrupts can be re-enabled.
+ *
+ * 750
+ * ---
+ * 750 adds user-readable MMCRn/PMCn/SIA registers, and removes SDA.
+ *
+ * MMCR0[THRESHOLD] is not automatically multiplied.
+ *
+ * Motorola MPC750UM.pdf, page C-78, states: "The performance monitor
+ * of the MPC755 functions the same as that of the MPC750, (...), except
+ * that for both the MPC750 and MPC755, no combination of the thermal
+ * assist unit, the decrementer register, and the performance monitor
+ * can be used at any one time. If exceptions for any two of these
+ * functional blocks are enabled together, multiple exceptions caused
+ * by any of these three blocks cause unpredictable results."
+ *
+ * IBM 750CXe_Err_DD2X.pdf, Erratum #13, states that a PMI which
+ * occurs immediately after a delayed decrementer exception can
+ * corrupt SRR0, causing the processor to hang. It also states that
+ * PMIs via TB bit transitions can be used to simulate the decrementer.
+ *
+ * 750FX adds dual-PLL support and programmable core frequency switching.
+ *
+ * 74xx
+ * ----
+ * 7400 adds MMCR2 and BAMR.
+ *
+ * MMCR0[THRESHOLD] is multiplied by 2 or 32, as specified
+ * by MMCR2[THRESHMULT].
+ *
+ * 74xx changes the semantics of several MMCR0 control bits,
+ * compared to 604/750.
+ *
+ * PPC7410 Erratum No. 10: Like the MPC750 TAU/DECR/PMI erratum.
+ * Erratum No. 14 marks TAU as unsupported in 7410, but this leaves
+ * perfmon and decrementer interrupts as being mutually exclusive.
+ * Affects PPC7410 1.0-1.2 (PVR 0x800C1100-0x800C1102). 1.3 and up
+ * (PVR 0x800C1103 up) are Ok.
+ *
+ * 7450 adds PMC5 and PMC6.
+ *
+ * 7455/7445 V3.3 (PVR 80010303) and later use the 7457 PLL table,
+ * earlier revisions use the 7450 PLL table
+ */
+
+static inline unsigned int read_pmc(unsigned int pmc)
+{
+	switch (pmc) {
+	default: /* impossible, but silences gcc warning */
+	case 0:
+		return mfspr(SPRN_PMC1);
+	case 1:
+		return mfspr(SPRN_PMC2);
+	case 2:
+		return mfspr(SPRN_PMC3);
+	case 3:
+		return mfspr(SPRN_PMC4);
+	case 4:
+		return mfspr(SPRN_PMC5);
+	case 5:
+		return mfspr(SPRN_PMC6);
+	}
+}
+
+static void ppc_read_counters(/*const*/ struct perfctr_cpu_state *state,
+			      struct perfctr_low_ctrs *ctrs)
+{
+	unsigned int cstatus, nrctrs, i;
+
+	cstatus = state->cstatus;
+	if (perfctr_cstatus_has_tsc(cstatus))
+		ctrs->tsc = get_tbl();
+	nrctrs = perfctr_cstatus_nractrs(cstatus);
+	for(i = 0; i < nrctrs; ++i) {
+		unsigned int pmc = state->pmc[i].map;
+		ctrs->pmc[i] = read_pmc(pmc);
+	}
+	/* handle MMCR0 changes due to FCECE or TRIGGER on 74xx */
+	if (state->cstatus & (1<<30)) {
+		unsigned int mmcr0 = mfspr(SPRN_MMCR0);
+		state->ppc_mmcr[0] = mmcr0;
+		__get_cpu_var(per_cpu_cache).ppc_mmcr[0] = mmcr0;
+	}
+}
+
+static unsigned int pmc_max_event(unsigned int pmc)
+{
+	switch (pmc) {
+	default: /* impossible, but silences gcc warning */
+	case 0:
+		return 127;
+	case 1:
+		return 63;
+	case 2:
+		return 31;
+	case 3:
+		return 31;
+	case 4:
+		return 31;
+	case 5:
+		return 63;
+	}
+}
+
+static unsigned int get_nr_pmcs(void)
+{
+	switch (pm_type) {
+	case PM_7450:
+		return 6;
+	case PM_7400:
+	case PM_750:
+	case PM_604e:
+		return 4;
+	default: /* impossible, but silences gcc warning */
+	case PM_604:
+		return 2;
+	}
+}
+
+static int ppc_check_control(struct perfctr_cpu_state *state)
+{
+	unsigned int i, nrctrs, pmc_mask, pmc;
+	unsigned int nr_pmcs, evntsel[6];
+
+	nr_pmcs = get_nr_pmcs();
+	nrctrs = state->control.nractrs;
+	if (state->control.nrictrs || nrctrs > nr_pmcs)
+		return -EINVAL;
+
+	pmc_mask = 0;
+	memset(evntsel, 0, sizeof evntsel);
+	for(i = 0; i < nrctrs; ++i) {
+		pmc = state->control.pmc_map[i];
+		state->pmc[i].map = pmc;
+		if (pmc >= nr_pmcs || (pmc_mask & (1<<pmc)))
+			return -EINVAL;
+		pmc_mask |= (1<<pmc);
+
+		evntsel[pmc] = state->control.evntsel[i];
+		if (evntsel[pmc] > pmc_max_event(pmc))
+			return -EINVAL;
+	}
+
+	switch (pm_type) {
+	case PM_7450:
+		if (state->control.ppc.mmcr2 & MMCR2_RESERVED)
+			return -EINVAL;
+		state->ppc_mmcr[2] = state->control.ppc.mmcr2;
+		break;
+	default:
+		if (state->control.ppc.mmcr2)
+			return -EINVAL;
+		state->ppc_mmcr[2] = 0;
+	}
+
+	if (state->control.ppc.mmcr0 & MMCR0_RESERVED)
+		return -EINVAL;
+	state->ppc_mmcr[0] = (state->control.ppc.mmcr0
+			      | (evntsel[0] << (31-25))
+			      | (evntsel[1] << (31-31)));
+
+	state->ppc_mmcr[1] = ((  evntsel[2] << (31-4))
+			      | (evntsel[3] << (31-9))
+			      | (evntsel[4] << (31-14))
+			      | (evntsel[5] << (31-20)));
+
+	state->k1.id = new_id();
+
+	/*
+	 * MMCR0[FC] and MMCR0[TRIGGER] may change on 74xx if FCECE or
+	 * TRIGGER is set. To avoid undoing those changes, we must read
+	 * MMCR0 back into state->ppc_mmcr[0] and the cache at suspends.
+	 */
+	switch (pm_type) {
+	case PM_7450:
+	case PM_7400:
+		if (state->ppc_mmcr[0] & (MMCR0_FCECE | MMCR0_TRIGGER))
+			state->cstatus |= (1<<30);
+	default:
+		;
+	}
+
+	return 0;
+}
+
+#ifdef PERFCTR_INTERRUPT_SUPPORT
+static void ppc_isuspend(struct perfctr_cpu_state *state)
+{
+	// XXX
+}
+
+static void ppc_iresume(const struct perfctr_cpu_state *state)
+{
+	// XXX
+}
+#endif
+
+static void ppc_write_control(const struct perfctr_cpu_state *state)
+{
+	struct per_cpu_cache *cache;
+	unsigned int value;
+
+	cache = &__get_cpu_var(per_cpu_cache);
+	if (cache->k1.id == state->k1.id)
+		return;
+	/*
+	 * Order matters here: update threshmult and event
+	 * selectors before updating global control, which
+	 * potentially enables PMIs.
+	 *
+	 * Since mtspr doesn't accept a runtime value for the
+	 * SPR number, unroll the loop so each mtspr targets
+	 * a constant SPR.
+	 *
+	 * For processors without MMCR2, we ensure that the
+	 * cache and the state indicate the same value for it,
+	 * preventing any actual mtspr to it. Ditto for MMCR1.
+	 */
+	value = state->ppc_mmcr[2];
+	if (value != cache->ppc_mmcr[2]) {
+		cache->ppc_mmcr[2] = value;
+		mtspr(SPRN_MMCR2, value);
+	}
+	value = state->ppc_mmcr[1];
+	if (value != cache->ppc_mmcr[1]) {
+		cache->ppc_mmcr[1] = value;
+		mtspr(SPRN_MMCR1, value);
+	}
+	value = state->ppc_mmcr[0];
+	if (value != cache->ppc_mmcr[0]) {
+		cache->ppc_mmcr[0] = value;
+		mtspr(SPRN_MMCR0, value);
+	}
+	cache->k1.id = state->k1.id;
+}
+
+static void ppc_clear_counters(void)
+{
+	switch (pm_type) {
+	case PM_7450:
+	case PM_7400:
+		mtspr(SPRN_MMCR2, 0);
+		mtspr(SPRN_BAMR, 0);
+	case PM_750:
+	case PM_604e:
+		mtspr(SPRN_MMCR1, 0);
+	case PM_604:
+		mtspr(SPRN_MMCR0, 0);
+	}
+	switch (pm_type) {
+	case PM_7450:
+		mtspr(SPRN_PMC6, 0);
+		mtspr(SPRN_PMC5, 0);
+	case PM_7400:
+	case PM_750:
+	case PM_604e:
+		mtspr(SPRN_PMC4, 0);
+		mtspr(SPRN_PMC3, 0);
+	case PM_604:
+		mtspr(SPRN_PMC2, 0);
+		mtspr(SPRN_PMC1, 0);
+	}
+}
+
+/*
+ * Driver methods, internal and exported.
+ */
+
+static void perfctr_cpu_write_control(const struct perfctr_cpu_state *state)
+{
+	return ppc_write_control(state);
+}
+
+static void perfctr_cpu_read_counters(/*const*/ struct perfctr_cpu_state *state,
+				      struct perfctr_low_ctrs *ctrs)
+{
+	return ppc_read_counters(state, ctrs);
+}
+
+#ifdef PERFCTR_INTERRUPT_SUPPORT
+static void perfctr_cpu_isuspend(struct perfctr_cpu_state *state)
+{
+	return ppc_isuspend(state);
+}
+
+static void perfctr_cpu_iresume(const struct perfctr_cpu_state *state)
+{
+	return ppc_iresume(state);
+}
+
+/* Call perfctr_cpu_ireload() just before perfctr_cpu_resume() to
+   bypass internal caching and force a reload if the I-mode PMCs. */
+void perfctr_cpu_ireload(struct perfctr_cpu_state *state)
+{
+#ifdef CONFIG_SMP
+	clear_isuspend_cpu(state);
+#else
+	__get_cpu_var(per_cpu_cache).k1.id = 0;
+#endif
+}
+
+/* PRE: the counters have been suspended and sampled by perfctr_cpu_suspend() */
+unsigned int perfctr_cpu_identify_overflow(struct perfctr_cpu_state *state)
+{
+	unsigned int cstatus, nrctrs, pmc, pmc_mask;
+
+	cstatus = state->cstatus;
+	pmc = perfctr_cstatus_nractrs(cstatus);
+	nrctrs = perfctr_cstatus_nrctrs(cstatus);
+
+	for(pmc_mask = 0; pmc < nrctrs; ++pmc) {
+		if ((int)state->pmc[pmc].start < 0) { /* PPC-specific */
+			/* XXX: "+=" to correct for overshots */
+			state->pmc[pmc].start = state->control.ireset[pmc];
+			pmc_mask |= (1 << pmc);
+		}
+	}
+	/* XXX: if pmc_mask == 0, then it must have been a TBL bit flip */
+	/* XXX: HW cleared MMCR0[ENINT]. We presumably cleared the entire
+	   MMCR0, so the re-enable occurs automatically later, no? */
+	return pmc_mask;
+}
+
+static inline int check_ireset(const struct perfctr_cpu_state *state)
+{
+	unsigned int nrctrs, i;
+
+	i = state->control.nractrs;
+	nrctrs = i + state->control.nrictrs;
+	for(; i < nrctrs; ++i)
+		if (state->control.ireset[i] < 0)	/* PPC-specific */
+			return -EINVAL;
+	return 0;
+}
+
+static inline void setup_imode_start_values(struct perfctr_cpu_state *state)
+{
+	unsigned int cstatus, nrctrs, i;
+
+	cstatus = state->cstatus;
+	nrctrs = perfctr_cstatus_nrctrs(cstatus);
+	for(i = perfctr_cstatus_nractrs(cstatus); i < nrctrs; ++i)
+		state->pmc[i].start = state->control.ireset[i];
+}
+
+#else	/* PERFCTR_INTERRUPT_SUPPORT */
+static inline void perfctr_cpu_isuspend(struct perfctr_cpu_state *state) { }
+static inline void perfctr_cpu_iresume(const struct perfctr_cpu_state *state) { }
+static inline int check_ireset(const struct perfctr_cpu_state *state) { return 0; }
+static inline void setup_imode_start_values(struct perfctr_cpu_state *state) { }
+#endif	/* PERFCTR_INTERRUPT_SUPPORT */
+
+static int check_control(struct perfctr_cpu_state *state)
+{
+	return ppc_check_control(state);
+}
+
+int perfctr_cpu_update_control(struct perfctr_cpu_state *state, int is_global)
+{
+	int err;
+
+	clear_isuspend_cpu(state);
+	state->cstatus = 0;
+
+	/* disallow i-mode counters if we cannot catch the interrupts */
+	if (!(perfctr_info.cpu_features & PERFCTR_FEATURE_PCINT)
+	    && state->control.nrictrs)
+		return -EPERM;
+
+	err = check_ireset(state);
+	if (err < 0)
+		return err;
+	err = check_control(state); /* may initialise state->cstatus */
+	if (err < 0)
+		return err;
+	state->cstatus |= perfctr_mk_cstatus(state->control.tsc_on,
+					     state->control.nractrs,
+					     state->control.nrictrs);
+	setup_imode_start_values(state);
+	return 0;
+}
+
+void perfctr_cpu_suspend(struct perfctr_cpu_state *state)
+{
+	unsigned int i, cstatus, nractrs;
+	struct perfctr_low_ctrs now;
+
+	if (perfctr_cstatus_has_ictrs(state->cstatus))
+	    perfctr_cpu_isuspend(state);
+	perfctr_cpu_read_counters(state, &now);
+	cstatus = state->cstatus;
+	if (perfctr_cstatus_has_tsc(cstatus))
+		state->tsc_sum += now.tsc - state->tsc_start;
+	nractrs = perfctr_cstatus_nractrs(cstatus);
+	for(i = 0; i < nractrs; ++i)
+		state->pmc[i].sum += now.pmc[i] - state->pmc[i].start;
+}
+
+void perfctr_cpu_resume(struct perfctr_cpu_state *state)
+{
+	if (perfctr_cstatus_has_ictrs(state->cstatus))
+	    perfctr_cpu_iresume(state);
+	perfctr_cpu_write_control(state);
+	//perfctr_cpu_read_counters(state, &state->start);
+	{
+		struct perfctr_low_ctrs now;
+		unsigned int i, cstatus, nrctrs;
+		perfctr_cpu_read_counters(state, &now);
+		cstatus = state->cstatus;
+		if (perfctr_cstatus_has_tsc(cstatus))
+			state->tsc_start = now.tsc;
+		nrctrs = perfctr_cstatus_nractrs(cstatus);
+		for(i = 0; i < nrctrs; ++i)
+			state->pmc[i].start = now.pmc[i];
+	}
+	/* XXX: if (SMP && start.tsc == now.tsc) ++now.tsc; */
+}
+
+void perfctr_cpu_sample(struct perfctr_cpu_state *state)
+{
+	unsigned int i, cstatus, nractrs;
+	struct perfctr_low_ctrs now;
+
+	perfctr_cpu_read_counters(state, &now);
+	cstatus = state->cstatus;
+	if (perfctr_cstatus_has_tsc(cstatus)) {
+		state->tsc_sum += now.tsc - state->tsc_start;
+		state->tsc_start = now.tsc;
+	}
+	nractrs = perfctr_cstatus_nractrs(cstatus);
+	for(i = 0; i < nractrs; ++i) {
+		state->pmc[i].sum += now.pmc[i] - state->pmc[i].start;
+		state->pmc[i].start = now.pmc[i];
+	}
+}
+
+static void perfctr_cpu_clear_counters(void)
+{
+	struct per_cpu_cache *cache;
+
+	cache = &__get_cpu_var(per_cpu_cache);
+	memset(cache, 0, sizeof *cache);
+	cache->k1.id = -1;
+
+	ppc_clear_counters();
+}
+
+/****************************************************************
+ *								*
+ * Processor detection and initialisation procedures.		*
+ *								*
+ ****************************************************************/
+
+/* Derive CPU core frequency from TB frequency and PLL_CFG. */
+
+enum pll_type {
+	PLL_NONE,	/* for e.g. 604 which has no HID1[PLL_CFG] */
+	PLL_604e,
+	PLL_750,
+	PLL_750FX,
+	PLL_7400,
+	PLL_7450,
+	PLL_7457,
+};
+
+/* These are the known bus-to-core ratios, indexed by PLL_CFG.
+   Multiplied by 2 since half-multiplier steps are present. */
+
+static unsigned char cfg_ratio_604e[16] __initdata = { // *2
+	2, 2, 14, 2, 4, 13, 5, 9,
+	6, 11, 8, 10, 3, 12, 7, 0
+};
+
+static unsigned char cfg_ratio_750[16] __initdata = { // *2
+	5, 15, 14, 2, 4, 13, 20, 9, // 0b0110 is 18 if L1_TSTCLK=0, but that is abnormal
+	6, 11, 8, 10, 16, 12, 7, 0
+};
+
+static unsigned char cfg_ratio_750FX[32] __initdata = { // *2
+	0, 0, 2, 2, 4, 5, 6, 7,
+	8, 9, 10, 11, 12, 13, 14, 15,
+	16, 17, 18, 19, 20, 22, 24, 26,
+	28, 30, 32, 34, 36, 38, 40, 0
+};
+
+static unsigned char cfg_ratio_7400[16] __initdata = { // *2
+	18, 15, 14, 2, 4, 13, 5, 9,
+	6, 11, 8, 10, 16, 12, 7, 0
+};
+
+static unsigned char cfg_ratio_7450[32] __initdata = { // *2
+	1, 0, 15, 30, 14, 0, 2, 0,
+	4, 0, 13, 26, 5, 0, 9, 18,
+	6, 0, 11, 22, 8, 20, 10, 24,
+	16, 28, 12, 32, 7, 0, 0, 0
+};
+
+static unsigned char cfg_ratio_7457[32] __initdata = { // *2
+	23, 34, 15, 30, 14, 36, 2, 40,
+	4, 42, 13, 26, 17, 48, 19, 18,
+	6, 21, 11, 22, 8, 20, 10, 24,
+	16, 28, 12, 32, 27, 56, 0, 25
+};
+
+static unsigned int __init tb_to_core_ratio(enum pll_type pll_type)
+{
+	unsigned char *cfg_ratio;
+	unsigned int shift = 28, mask = 0xF, hid1, pll_cfg, ratio;
+
+	switch (pll_type) {
+	case PLL_604e:
+		cfg_ratio = cfg_ratio_604e;
+		break;
+	case PLL_750:
+		cfg_ratio = cfg_ratio_750;
+		break;
+	case PLL_750FX:
+		cfg_ratio = cfg_ratio_750FX;
+		hid1 = mfspr(SPRN_HID1);
+		switch ((hid1 >> 16) & 0x3) { /* HID1[PI0,PS] */
+		case 0:		/* PLL0 with external config */
+			shift = 31-4;	/* access HID1[PCE] */
+			break;
+		case 2:		/* PLL0 with internal config */
+			shift = 31-20;	/* access HID1[PC0] */
+			break;
+		case 1: case 3:	/* PLL1 */
+			shift = 31-28;	/* access HID1[PC1] */
+			break;
+		}
+		mask = 0x1F;
+		break;
+	case PLL_7400:
+		cfg_ratio = cfg_ratio_7400;
+		break;
+	case PLL_7450:
+		cfg_ratio = cfg_ratio_7450;
+		shift = 12;
+		mask = 0x1F;
+		break;
+	case PLL_7457:
+		cfg_ratio = cfg_ratio_7457;
+		shift = 12;
+		mask = 0x1F;
+		break;
+	default:
+		return 0;
+	}
+	hid1 = mfspr(SPRN_HID1);
+	pll_cfg = (hid1 >> shift) & mask;
+	ratio = cfg_ratio[pll_cfg];
+	if (!ratio)
+		printk(KERN_WARNING "perfctr/%s: unknown PLL_CFG 0x%x\n",
+		       __FILE__, pll_cfg);
+	return (4/2) * ratio;
+}
+
+static unsigned int __init pll_to_core_khz(enum pll_type pll_type)
+{
+	unsigned int tb_to_core = tb_to_core_ratio(pll_type);
+	perfctr_info.tsc_to_cpu_mult = tb_to_core;
+	return tb_ticks_per_jiffy * tb_to_core * (HZ/10) / (1000/10);
+}
+
+/* Extract the CPU clock frequency from /proc/cpuinfo. */
+
+static unsigned int __init parse_clock_khz(struct seq_file *m)
+{
+	/* "/proc/cpuinfo" formats:
+	 *
+	 * "core clock\t: %d MHz\n"	// 8260 (show_percpuinfo)
+	 * "clock\t\t: %ldMHz\n"	// 4xx (show_percpuinfo)
+	 * "clock\t\t: %dMHz\n"		// oak (show_percpuinfo)
+	 * "clock\t\t: %ldMHz\n"	// prep (show_percpuinfo)
+	 * "clock\t\t: %dMHz\n"		// pmac (show_percpuinfo)
+	 * "clock\t\t: %dMHz\n"		// gemini (show_cpuinfo!)
+	 */
+	char *p;
+	unsigned int mhz;
+
+	p = m->buf;
+	p[m->count] = '\0';
+
+	for(;;) {		/* for each line */
+		if (strncmp(p, "core ", 5) == 0)
+			p += 5;
+		do {
+			if (strncmp(p, "clock\t", 6) != 0)
+				break;
+			p += 6;
+			while (*p == '\t')
+				++p;
+			if (*p != ':')
+				break;
+			do {
+				++p;
+			} while (*p == ' ');
+			mhz = simple_strtoul(p, 0, 10);
+			if (mhz)
+				return mhz * 1000;
+		} while (0);
+		for(;;) {	/* skip to next line */
+			switch (*p++) {
+			case '\n':
+				break;
+			case '\0':
+				return 0;
+			default:
+				continue;
+			}
+			break;
+		}
+	}
+}
+
+static unsigned int __init detect_cpu_khz(enum pll_type pll_type)
+{
+	char buf[512];
+	struct seq_file m;
+	unsigned int khz;
+
+	khz = pll_to_core_khz(pll_type);
+	if (khz)
+		return khz;
+
+	memset(&m, 0, sizeof m);
+	m.buf = buf;
+	m.size = (sizeof buf)-1;
+
+	m.count = 0;
+	if (ppc_md.show_percpuinfo != 0 &&
+	    ppc_md.show_percpuinfo(&m, 0) == 0 &&
+	    (khz = parse_clock_khz(&m)) != 0)
+		return khz;
+
+	m.count = 0;
+	if (ppc_md.show_cpuinfo != 0 &&
+	    ppc_md.show_cpuinfo(&m) == 0 &&
+	    (khz = parse_clock_khz(&m)) != 0)
+		return khz;
+
+	printk(KERN_WARNING "perfctr/%s: unable to determine CPU speed\n",
+	       __FILE__);
+	return 0;
+}
+
+static int __init generic_init(void)
+{
+	static char generic_name[] __initdata = "PowerPC 60x/7xx/74xx";
+	unsigned int features;
+	enum pll_type pll_type;
+	unsigned int pvr;
+
+	features = PERFCTR_FEATURE_RDTSC | PERFCTR_FEATURE_RDPMC;
+	pvr = mfspr(SPRN_PVR);
+	switch (PVR_VER(pvr)) {
+	case 0x0004: /* 604 */
+		pm_type = PM_604;
+		pll_type = PLL_NONE;
+		features = PERFCTR_FEATURE_RDTSC;
+		break;
+	case 0x0009: /* 604e;  */
+	case 0x000A: /* 604ev */
+		pm_type = PM_604e;
+		pll_type = PLL_604e;
+		features = PERFCTR_FEATURE_RDTSC;
+		break;
+	case 0x0008: /* 750/740 */
+		pm_type = PM_750;
+		pll_type = PLL_750;
+		break;
+	case 0x7000: case 0x7001: /* IBM750FX */
+	case 0x7002: /* IBM750GX */
+		pm_type = PM_750;
+		pll_type = PLL_750FX;
+		break;
+	case 0x000C: /* 7400 */
+		pm_type = PM_7400;
+		pll_type = PLL_7400;
+		break;
+	case 0x800C: /* 7410 */
+		pm_type = PM_7400;
+		pll_type = PLL_7400;
+		break;
+	case 0x8000: /* 7451/7441 */
+		pm_type = PM_7450;
+		pll_type = PLL_7450;
+		break;
+	case 0x8001: /* 7455/7445 */
+		pm_type = PM_7450;
+		pll_type = ((pvr & 0xFFFF) < 0x0303) ? PLL_7450 : PLL_7457;
+		break;
+	case 0x8002: /* 7457/7447 */
+		pm_type = PM_7450;
+		pll_type = PLL_7457;
+		break;
+	default:
+		printk(KERN_WARNING "perfctr/%s: unknown PowerPC with "
+		       "PVR 0x%08x -- bailing out\n", __FILE__, pvr);
+		return -ENODEV;
+	}
+	perfctr_info.cpu_features = features;
+	perfctr_info.cpu_type = 0; /* user-space should inspect PVR */
+	perfctr_cpu_name = generic_name;
+	perfctr_info.cpu_khz = detect_cpu_khz(pll_type);
+	perfctr_ppc_init_tests();
+	return 0;
+}
+
+static void __init perfctr_cpu_init_one(void *ignore)
+{
+	/* PREEMPT note: when called via smp_call_function(),
+	   this is in IRQ context with preemption disabled. */
+	perfctr_cpu_clear_counters();
+}
+
+static void __exit perfctr_cpu_exit_one(void *ignore)
+{
+	/* PREEMPT note: when called via smp_call_function(),
+	   this is in IRQ context with preemption disabled. */
+	perfctr_cpu_clear_counters();
+}
+
+static int init_done;
+
+int __init perfctr_cpu_init(void)
+{
+	int err;
+
+	preempt_disable();
+
+	perfctr_info.cpu_features = 0;
+
+	err = generic_init();
+	if (err)
+		goto out;
+
+	perfctr_cpu_init_one(NULL);
+	smp_call_function(perfctr_cpu_init_one, NULL, 1, 1);
+	perfctr_cpu_set_ihandler(NULL);
+	init_done = 1;
+ out:
+	preempt_enable();
+	return err;
+}
+
+void __exit perfctr_cpu_exit(void)
+{
+	preempt_disable();
+	perfctr_cpu_exit_one(NULL);
+	smp_call_function(perfctr_cpu_exit_one, NULL, 1, 1);
+	perfctr_cpu_set_ihandler(NULL);
+	preempt_enable();
+}
+
+/****************************************************************
+ *								*
+ * Hardware reservation.					*
+ *								*
+ ****************************************************************/
+
+static DECLARE_MUTEX(mutex);
+static const char *current_service = 0;
+
+const char *perfctr_cpu_reserve(const char *service)
+{
+	const char *ret;
+
+	if (!init_done)
+		return "unsupported hardware";
+	down(&mutex);
+	ret = current_service;
+	if (!ret)
+		current_service = service;
+	up(&mutex);
+	return ret;
+}
+
+static void perfctr_cpu_clear_one(void *ignore)
+{
+	/* PREEMPT note: when called via smp_call_function(),
+	   this is in IRQ context with preemption disabled. */
+	perfctr_cpu_clear_counters();
+}
+
+void perfctr_cpu_release(const char *service)
+{
+	down(&mutex);
+	if (service != current_service) {
+		printk(KERN_ERR "%s: attempt by %s to release while reserved by %s\n",
+		       __FUNCTION__, service, current_service);
+	} else {
+		/* power down the counters */
+		on_each_cpu(perfctr_cpu_clear_one, NULL, 1, 1);
+		perfctr_cpu_set_ihandler(NULL);
+		current_service = 0;
+	}
+	up(&mutex);
+}
--- diff/drivers/perfctr/ppc_tests.c	1970-01-01 01:00:00.000000000 +0100
+++ source/drivers/perfctr/ppc_tests.c	2004-06-11 19:22:03.000000000 +0100
@@ -0,0 +1,286 @@
+/* $Id: ppc_tests.c,v 1.4 2004/05/21 16:57:53 mikpe Exp $
+ * Performance-monitoring counters driver.
+ * Optional PPC32-specific init-time tests.
+ *
+ * Copyright (C) 2004  Mikael Pettersson
+ */
+#include <linux/config.h>
+#include <linux/init.h>
+#include <linux/sched.h>
+#include <linux/fs.h>
+#include <linux/perfctr.h>
+#include <asm/processor.h>
+#include <asm/time.h>	/* for tb_ticks_per_jiffy */
+#include "ppc_tests.h"
+
+#define NITER	256
+#define X2(S)	S"; "S
+#define X8(S)	X2(X2(X2(S)))
+
+static void __init do_read_tbl(unsigned int unused)
+{
+	unsigned int i, dummy;
+	for(i = 0; i < NITER/8; ++i)
+		__asm__ __volatile__(X8("mftbl %0") : "=r"(dummy));
+}
+
+static void __init do_read_pmc1(unsigned int unused)
+{
+	unsigned int i, dummy;
+	for(i = 0; i < NITER/8; ++i)
+		__asm__ __volatile__(X8("mfspr %0," __stringify(SPRN_PMC1)) : "=r"(dummy));
+}
+
+static void __init do_read_pmc2(unsigned int unused)
+{
+	unsigned int i, dummy;
+	for(i = 0; i < NITER/8; ++i)
+		__asm__ __volatile__(X8("mfspr %0," __stringify(SPRN_PMC2)) : "=r"(dummy));
+}
+
+static void __init do_read_pmc3(unsigned int unused)
+{
+	unsigned int i, dummy;
+	for(i = 0; i < NITER/8; ++i)
+		__asm__ __volatile__(X8("mfspr %0," __stringify(SPRN_PMC3)) : "=r"(dummy));
+}
+
+static void __init do_read_pmc4(unsigned int unused)
+{
+	unsigned int i, dummy;
+	for(i = 0; i < NITER/8; ++i)
+		__asm__ __volatile__(X8("mfspr %0," __stringify(SPRN_PMC4)) : "=r"(dummy));
+}
+
+static void __init do_read_mmcr0(unsigned int unused)
+{
+	unsigned int i, dummy;
+	for(i = 0; i < NITER/8; ++i)
+		__asm__ __volatile__(X8("mfspr %0," __stringify(SPRN_MMCR0)) : "=r"(dummy));
+}
+
+static void __init do_read_mmcr1(unsigned int unused)
+{
+	unsigned int i, dummy;
+	for(i = 0; i < NITER/8; ++i)
+		__asm__ __volatile__(X8("mfspr %0," __stringify(SPRN_MMCR1)) : "=r"(dummy));
+}
+
+static void __init do_write_pmc2(unsigned int arg)
+{
+	unsigned int i;
+	for(i = 0; i < NITER/8; ++i)
+		__asm__ __volatile__(X8("mtspr " __stringify(SPRN_PMC2) ",%0") : : "r"(arg));
+}
+
+static void __init do_write_pmc3(unsigned int arg)
+{
+	unsigned int i;
+	for(i = 0; i < NITER/8; ++i)
+		__asm__ __volatile__(X8("mtspr " __stringify(SPRN_PMC3) ",%0") : : "r"(arg));
+}
+
+static void __init do_write_pmc4(unsigned int arg)
+{
+	unsigned int i;
+	for(i = 0; i < NITER/8; ++i)
+		__asm__ __volatile__(X8("mtspr " __stringify(SPRN_PMC4) ",%0") : : "r"(arg));
+}
+
+static void __init do_write_mmcr1(unsigned int arg)
+{
+	unsigned int i;
+	for(i = 0; i < NITER/8; ++i)
+		__asm__ __volatile__(X8("mtspr " __stringify(SPRN_MMCR1) ",%0") : : "r"(arg));
+}
+
+static void __init do_write_mmcr0(unsigned int arg)
+{
+	unsigned int i;
+	for(i = 0; i < NITER/8; ++i)
+		__asm__ __volatile__(X8("mtspr " __stringify(SPRN_MMCR0) ",%0") : : "r"(arg));
+}
+
+static void __init do_empty_loop(unsigned int unused)
+{
+	unsigned i;
+	for(i = 0; i < NITER/8; ++i)
+		__asm__ __volatile__("" : : );
+}
+
+static unsigned __init run(void (*doit)(unsigned int), unsigned int arg)
+{
+	unsigned int start, stop;
+	start = mfspr(SPRN_PMC1);
+	(*doit)(arg);	/* should take < 2^32 cycles to complete */
+	stop = mfspr(SPRN_PMC1);
+	return stop - start;
+}
+
+static void __init init_tests_message(void)
+{
+	unsigned int pvr = mfspr(SPRN_PVR);
+	printk(KERN_INFO "Please email the following PERFCTR INIT lines "
+	       "to mikpe@csd.uu.se\n"
+	       KERN_INFO "To remove this message, rebuild the driver "
+	       "with CONFIG_PERFCTR_INIT_TESTS=n\n");
+	printk(KERN_INFO "PERFCTR INIT: PVR 0x%08x, CPU clock %u kHz, TB clock %u kHz\n",
+	       pvr,
+	       perfctr_info.cpu_khz,
+	       tb_ticks_per_jiffy*(HZ/10)/(1000/10));
+}
+
+static void __init clear(int have_mmcr1)
+{
+	mtspr(SPRN_MMCR0, 0);
+	mtspr(SPRN_PMC1, 0);
+	mtspr(SPRN_PMC2, 0);
+	if (have_mmcr1) {
+		mtspr(SPRN_MMCR1, 0);
+		mtspr(SPRN_PMC3, 0);
+		mtspr(SPRN_PMC4, 0);
+	}
+}
+
+static void __init check_fcece(unsigned int pmc1ce)
+{
+	unsigned int mmcr0;
+
+	/*
+	 * This test checks if MMCR0[FC] is set after PMC1 overflows
+	 * when MMCR0[FCECE] is set.
+	 * 74xx documentation states this behaviour, while documentation
+	 * for 604/750 processors doesn't mention this at all.
+	 *
+	 * Also output the value of PMC1 shortly after the overflow.
+	 * This tells us if PMC1 really was frozen. On 604/750, it may not
+	 * freeze since we don't enable PMIs. [No freeze confirmed on 750.]
+	 *
+	 * When pmc1ce == 0, MMCR0[PMC1CE] is zero. It's unclear whether
+	 * this masks all PMC1 overflow events or just PMC1 PMIs.
+	 *
+	 * PMC1 counts processor cycles, with 100 to go before overflowing.
+	 * FCECE is set.
+	 * PMC1CE is clear if !pmc1ce, otherwise set.
+	 */
+	mtspr(SPRN_PMC1, 0x80000000-100);
+	mmcr0 = (1<<(31-6)) | (0x01 << 6);
+	if (pmc1ce)
+		mmcr0 |= (1<<(31-16));
+	mtspr(SPRN_MMCR0, mmcr0);
+	do {
+		do_empty_loop(0);
+	} while (!(mfspr(SPRN_PMC1) & 0x80000000));
+	do_empty_loop(0);
+	printk(KERN_INFO "PERFCTR INIT: %s(%u): MMCR0[FC] is %u, PMC1 is %#x\n",
+	       __FUNCTION__, pmc1ce,
+	       !!(mfspr(SPRN_MMCR0) & (1<<(31-0))), mfspr(SPRN_PMC1));
+	mtspr(SPRN_MMCR0, 0);
+	mtspr(SPRN_PMC1, 0);
+}
+
+static void __init check_trigger(unsigned int pmc1ce)
+{
+	unsigned int mmcr0;
+
+	/*
+	 * This test checks if MMCR0[TRIGGER] is reset after PMC1 overflows.
+	 * 74xx documentation states this behaviour, while documentation
+	 * for 604/750 processors doesn't mention this at all.
+	 * [No reset confirmed on 750.]
+	 *
+	 * Also output the values of PMC1 and PMC2 shortly after the overflow.
+	 * PMC2 should be equal to PMC1-0x80000000.
+	 *
+	 * When pmc1ce == 0, MMCR0[PMC1CE] is zero. It's unclear whether
+	 * this masks all PMC1 overflow events or just PMC1 PMIs.
+	 *
+	 * PMC1 counts processor cycles, with 100 to go before overflowing.
+	 * PMC2 counts processor cycles, starting from 0.
+	 * TRIGGER is set, so PMC2 doesn't start until PMC1 overflows.
+	 * PMC1CE is clear if !pmc1ce, otherwise set.
+	 */
+	mtspr(SPRN_PMC2, 0);
+	mtspr(SPRN_PMC1, 0x80000000-100);
+	mmcr0 = (1<<(31-18)) | (0x01 << 6) | (0x01 << 0);
+	if (pmc1ce)
+		mmcr0 |= (1<<(31-16));
+	mtspr(SPRN_MMCR0, mmcr0);
+	do {
+		do_empty_loop(0);
+	} while (!(mfspr(SPRN_PMC1) & 0x80000000));
+	do_empty_loop(0);
+	printk(KERN_INFO "PERFCTR INIT: %s(%u): MMCR0[TRIGGER] is %u, PMC1 is %#x, PMC2 is %#x\n",
+	       __FUNCTION__, pmc1ce,
+	       !!(mfspr(SPRN_MMCR0) & (1<<(31-18))), mfspr(SPRN_PMC1), mfspr(SPRN_PMC2));
+	mtspr(SPRN_MMCR0, 0);
+	mtspr(SPRN_PMC1, 0);
+	mtspr(SPRN_PMC2, 0);
+}
+
+static void __init
+measure_overheads(int have_mmcr1)
+{
+	int i;
+	unsigned int mmcr0, loop, ticks[12];
+	const char *name[12];
+
+	clear(have_mmcr1);
+
+	/* PMC1 = "processor cycles",
+	   PMC2 = "completed instructions",
+	   not disabled in any mode,
+	   no interrupts */
+	mmcr0 = (0x01 << 6) | (0x02 << 0);
+	mtspr(SPRN_MMCR0, mmcr0);
+
+	name[0] = "mftbl";
+	ticks[0] = run(do_read_tbl, 0);
+	name[1] = "mfspr (pmc1)";
+	ticks[1] = run(do_read_pmc1, 0);
+	name[2] = "mfspr (pmc2)";
+	ticks[2] = run(do_read_pmc2, 0);
+	name[3] = "mfspr (pmc3)";
+	ticks[3] = have_mmcr1 ? run(do_read_pmc3, 0) : 0;
+	name[4] = "mfspr (pmc4)";
+	ticks[4] = have_mmcr1 ? run(do_read_pmc4, 0) : 0;
+	name[5] = "mfspr (mmcr0)";
+	ticks[5] = run(do_read_mmcr0, 0);
+	name[6] = "mfspr (mmcr1)";
+	ticks[6] = have_mmcr1 ? run(do_read_mmcr1, 0) : 0;
+	name[7] = "mtspr (pmc2)";
+	ticks[7] = run(do_write_pmc2, 0);
+	name[8] = "mtspr (pmc3)";
+	ticks[8] = have_mmcr1 ? run(do_write_pmc3, 0) : 0;
+	name[9] = "mtspr (pmc4)";
+	ticks[9] = have_mmcr1 ? run(do_write_pmc4, 0) : 0;
+	name[10] = "mtspr (mmcr1)";
+	ticks[10] = have_mmcr1 ? run(do_write_mmcr1, 0) : 0;
+	name[11] = "mtspr (mmcr0)";
+	ticks[11] = run(do_write_mmcr0, mmcr0);
+
+	loop = run(do_empty_loop, 0);
+
+	clear(have_mmcr1);
+
+	init_tests_message();
+	printk(KERN_INFO "PERFCTR INIT: NITER == %u\n", NITER);
+	printk(KERN_INFO "PERFCTR INIT: loop overhead is %u cycles\n", loop);
+	for(i = 0; i < ARRAY_SIZE(ticks); ++i) {
+		unsigned int x;
+		if (!ticks[i])
+			continue;
+		x = ((ticks[i] - loop) * 10) / NITER;
+		printk(KERN_INFO "PERFCTR INIT: %s cost is %u.%u cycles (%u total)\n",
+		       name[i], x/10, x%10, ticks[i]);
+	}
+	check_fcece(0);
+	check_fcece(1);
+	check_trigger(0);
+	check_trigger(1);
+}
+
+void __init perfctr_ppc_init_tests(void)
+{
+	measure_overheads(PVR_VER(mfspr(SPRN_PVR)) != 0x0004);
+}
--- diff/drivers/perfctr/ppc_tests.h	1970-01-01 01:00:00.000000000 +0100
+++ source/drivers/perfctr/ppc_tests.h	2004-06-11 19:22:03.000000000 +0100
@@ -0,0 +1,12 @@
+/* $Id: ppc_tests.h,v 1.1 2004/01/12 01:59:11 mikpe Exp $
+ * Performance-monitoring counters driver.
+ * Optional PPC32-specific init-time tests.
+ *
+ * Copyright (C) 2004  Mikael Pettersson
+ */
+
+#ifdef CONFIG_PERFCTR_INIT_TESTS
+extern void perfctr_ppc_init_tests(void);
+#else
+#define perfctr_ppc_init_tests()
+#endif
--- diff/drivers/perfctr/version.h	1970-01-01 01:00:00.000000000 +0100
+++ source/drivers/perfctr/version.h	2004-06-11 19:22:03.000000000 +0100
@@ -0,0 +1 @@
+#define VERSION "2.7.3"
--- diff/drivers/perfctr/virtual.c	1970-01-01 01:00:00.000000000 +0100
+++ source/drivers/perfctr/virtual.c	2004-06-11 19:22:03.000000000 +0100
@@ -0,0 +1,939 @@
+/* $Id: virtual.c,v 1.95 2004/05/31 20:36:37 mikpe Exp $
+ * Virtual per-process performance counters.
+ *
+ * Copyright (C) 1999-2004  Mikael Pettersson
+ */
+#include <linux/config.h>
+#include <linux/init.h>
+#include <linux/compiler.h>	/* for unlikely() in 2.4.18 and older */
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/ptrace.h>
+#include <linux/fs.h>
+#include <linux/file.h>
+#include <linux/perfctr.h>
+
+#include <asm/io.h>
+#include <asm/uaccess.h>
+
+#include "cpumask.h"
+#include "virtual.h"
+
+/****************************************************************
+ *								*
+ * Data types and macros.					*
+ *								*
+ ****************************************************************/
+
+struct vperfctr {
+/* User-visible fields: (must be first for mmap()) */
+	struct perfctr_cpu_state cpu_state;
+/* Kernel-private fields: */
+	int si_signo;
+	atomic_t count;
+	spinlock_t owner_lock;
+	struct task_struct *owner;
+	/* sampling_timer and bad_cpus_allowed are frequently
+	   accessed, so they get to share a cache line */
+	unsigned int sampling_timer ____cacheline_aligned;
+#ifdef PERFCTR_CPUS_FORBIDDEN_MASK_NEEDED
+	atomic_t bad_cpus_allowed;
+#endif
+#ifdef PERFCTR_INTERRUPT_SUPPORT
+	unsigned int iresume_cstatus;
+#endif
+};
+#define IS_RUNNING(perfctr)	perfctr_cstatus_enabled((perfctr)->cpu_state.cstatus)
+
+#ifdef PERFCTR_INTERRUPT_SUPPORT
+
+static void vperfctr_ihandler(unsigned long pc);
+
+static inline void vperfctr_set_ihandler(void)
+{
+	perfctr_cpu_set_ihandler(vperfctr_ihandler);
+}
+
+static inline void vperfctr_clear_iresume_cstatus(struct vperfctr *perfctr)
+{
+	perfctr->iresume_cstatus = 0;
+}
+
+#else
+static inline void vperfctr_set_ihandler(void) { }
+static inline void vperfctr_clear_iresume_cstatus(struct vperfctr *perfctr) { }
+#endif
+
+#ifdef PERFCTR_CPUS_FORBIDDEN_MASK_NEEDED
+
+static inline void vperfctr_init_bad_cpus_allowed(struct vperfctr *perfctr)
+{
+	atomic_set(&perfctr->bad_cpus_allowed, 0);
+}
+
+/* Concurrent set_cpus_allowed() is possible. The only lock it
+   can take is the task lock, so we have to take it as well.
+   task_lock/unlock also disables/enables preemption. */
+
+static inline void vperfctr_task_lock(struct task_struct *p)
+{
+	task_lock(p);
+}
+
+static inline void vperfctr_task_unlock(struct task_struct *p)
+{
+	task_unlock(p);
+}
+
+#else	/* !PERFCTR_CPUS_FORBIDDEN_MASK_NEEDED */
+
+static inline void vperfctr_init_bad_cpus_allowed(struct vperfctr *perfctr) { }
+
+/* Concurrent set_cpus_allowed() is impossible or irrelevant.
+   Disabling and enabling preemption suffices for an atomic region. */
+
+static inline void vperfctr_task_lock(struct task_struct *p)
+{
+	preempt_disable();
+}
+
+static inline void vperfctr_task_unlock(struct task_struct *p)
+{
+	preempt_enable();
+}
+
+#endif	/* !PERFCTR_CPUS_FORBIDDEN_MASK_NEEDED */
+
+/****************************************************************
+ *								*
+ * Resource management.						*
+ *								*
+ ****************************************************************/
+
+/* XXX: perhaps relax this to number of _live_ perfctrs */
+static spinlock_t nrctrs_lock = SPIN_LOCK_UNLOCKED;
+static int nrctrs;
+static const char this_service[] = __FILE__;
+
+static int inc_nrctrs(void)
+{
+	const char *other;
+
+	other = NULL;
+	spin_lock(&nrctrs_lock);
+	if (++nrctrs == 1) {
+		other = perfctr_cpu_reserve(this_service);
+		if (other)
+			nrctrs = 0;
+	}
+	spin_unlock(&nrctrs_lock);
+	if (other) {
+		printk(KERN_ERR __FILE__
+		       ": cannot operate, perfctr hardware taken by '%s'\n",
+		       other);
+		return -EBUSY;
+	}
+	vperfctr_set_ihandler();
+	return 0;
+}
+
+static void dec_nrctrs(void)
+{
+	spin_lock(&nrctrs_lock);
+	if (--nrctrs == 0)
+		perfctr_cpu_release(this_service);
+	spin_unlock(&nrctrs_lock);
+}
+
+static struct vperfctr *vperfctr_alloc(void)
+{
+	unsigned long page;
+
+	if (inc_nrctrs() != 0)
+		return ERR_PTR(-EBUSY);
+	page = get_zeroed_page(GFP_KERNEL);
+	if (!page) {
+		dec_nrctrs();
+		return ERR_PTR(-ENOMEM);
+	}
+	SetPageReserved(virt_to_page(page));
+	return (struct vperfctr*) page;
+}
+
+static void vperfctr_free(struct vperfctr *perfctr)
+{
+	ClearPageReserved(virt_to_page(perfctr));
+	free_page((unsigned long)perfctr);
+	dec_nrctrs();
+}
+
+static struct vperfctr *get_empty_vperfctr(void)
+{
+	struct vperfctr *perfctr = vperfctr_alloc();
+	if (!IS_ERR(perfctr)) {
+		atomic_set(&perfctr->count, 1);
+		vperfctr_init_bad_cpus_allowed(perfctr);
+		spin_lock_init(&perfctr->owner_lock);
+	}
+	return perfctr;
+}
+
+static void put_vperfctr(struct vperfctr *perfctr)
+{
+	if (atomic_dec_and_test(&perfctr->count))
+		vperfctr_free(perfctr);
+}
+
+/****************************************************************
+ *								*
+ * Basic counter operations.					*
+ * These must all be called by the owner process only.		*
+ * These must all be called with preemption disabled.		*
+ *								*
+ ****************************************************************/
+
+/* PRE: IS_RUNNING(perfctr)
+ * Suspend the counters.
+ * XXX: When called from switch_to(), perfctr belongs to 'prev'
+ * but current is 'next'.
+ */
+static inline void vperfctr_suspend(struct vperfctr *perfctr)
+{
+	perfctr_cpu_suspend(&perfctr->cpu_state);
+}
+
+static inline void vperfctr_reset_sampling_timer(struct vperfctr *perfctr)
+{
+	/* XXX: base the value on perfctr_info.cpu_khz instead! */
+	perfctr->sampling_timer = HZ/2;
+}
+
+/* PRE: perfctr == current->thread.perfctr && IS_RUNNING(perfctr)
+ * Restart the counters.
+ */
+static inline void vperfctr_resume(struct vperfctr *perfctr)
+{
+	perfctr_cpu_resume(&perfctr->cpu_state);
+	vperfctr_reset_sampling_timer(perfctr);
+}
+
+/* Sample the counters but do not suspend them. */
+static void vperfctr_sample(struct vperfctr *perfctr)
+{
+	if (IS_RUNNING(perfctr)) {
+		perfctr_cpu_sample(&perfctr->cpu_state);
+		vperfctr_reset_sampling_timer(perfctr);
+	}
+}
+
+#ifdef PERFCTR_INTERRUPT_SUPPORT
+/* vperfctr interrupt handler (XXX: add buffering support) */
+/* PREEMPT note: called in IRQ context with preemption disabled. */
+static void vperfctr_ihandler(unsigned long pc)
+{
+	struct task_struct *tsk = current;
+	struct vperfctr *perfctr;
+	unsigned int pmc_mask;
+	siginfo_t si;
+
+	perfctr = tsk->thread.perfctr;
+	if (!perfctr) {
+		printk(KERN_ERR "%s: BUG! pid %d has no vperfctr\n",
+		       __FUNCTION__, tsk->pid);
+		return;
+	}
+	if (!perfctr_cstatus_has_ictrs(perfctr->cpu_state.cstatus)) {
+		printk(KERN_ERR "%s: BUG! vperfctr has cstatus %#x (pid %d, comm %s)\n",
+		       __FUNCTION__, perfctr->cpu_state.cstatus, tsk->pid, tsk->comm);
+		return;
+	}
+	vperfctr_suspend(perfctr);
+	pmc_mask = perfctr_cpu_identify_overflow(&perfctr->cpu_state);
+	if (!pmc_mask) {
+		printk(KERN_ERR "%s: BUG! pid %d has unidentifiable overflow source\n",
+		       __FUNCTION__, tsk->pid);
+		return;
+	}
+	/* suspend a-mode and i-mode PMCs, leaving only TSC on */
+	/* XXX: some people also want to suspend the TSC */
+	perfctr->iresume_cstatus = perfctr->cpu_state.cstatus;
+	if (perfctr_cstatus_has_tsc(perfctr->iresume_cstatus)) {
+		perfctr->cpu_state.cstatus = perfctr_mk_cstatus(1, 0, 0);
+		vperfctr_resume(perfctr);
+	} else
+		perfctr->cpu_state.cstatus = 0;
+	si.si_signo = perfctr->si_signo;
+	si.si_errno = 0;
+	si.si_code = SI_PMC_OVF;
+	si.si_pmc_ovf_mask = pmc_mask;
+	if (!send_sig_info(si.si_signo, &si, tsk))
+		send_sig(si.si_signo, tsk, 1);
+}
+#endif
+
+/****************************************************************
+ *								*
+ * Process management operations.				*
+ * These must all, with the exception of vperfctr_unlink()	*
+ * and __vperfctr_set_cpus_allowed(), be called by the owner	*
+ * process only.						*
+ *								*
+ ****************************************************************/
+
+/* Called from exit_thread() or do_vperfctr_unlink().
+ * If the counters are running, stop them and sample their final values.
+ * Detach the vperfctr object from its owner task.
+ * PREEMPT note: exit_thread() does not run with preemption disabled.
+ */
+static void vperfctr_unlink(struct task_struct *owner, struct vperfctr *perfctr)
+{
+	/* this synchronises with sys_vperfctr() */
+	spin_lock(&perfctr->owner_lock);
+	perfctr->owner = NULL;
+	spin_unlock(&perfctr->owner_lock);
+
+	/* perfctr suspend+detach must be atomic wrt process suspend */
+	/* this also synchronises with perfctr_set_cpus_allowed() */
+	vperfctr_task_lock(owner);
+	if (IS_RUNNING(perfctr) && owner == current)
+		vperfctr_suspend(perfctr);
+	owner->thread.perfctr = NULL;
+	vperfctr_task_unlock(owner);
+
+	perfctr->cpu_state.cstatus = 0;
+	vperfctr_clear_iresume_cstatus(perfctr);
+	put_vperfctr(perfctr);
+}
+
+void __vperfctr_exit(struct vperfctr *perfctr)
+{
+	vperfctr_unlink(current, perfctr);
+}
+
+/* schedule() --> switch_to() --> .. --> __vperfctr_suspend().
+ * If the counters are running, suspend them.
+ * PREEMPT note: switch_to() runs with preemption disabled.
+ */
+void __vperfctr_suspend(struct vperfctr *perfctr)
+{
+	if (IS_RUNNING(perfctr))
+		vperfctr_suspend(perfctr);
+}
+
+/* schedule() --> switch_to() --> .. --> __vperfctr_resume().
+ * PRE: perfctr == current->thread.perfctr
+ * If the counters are runnable, resume them.
+ * PREEMPT note: switch_to() runs with preemption disabled.
+ */
+void __vperfctr_resume(struct vperfctr *perfctr)
+{
+	if (IS_RUNNING(perfctr)) {
+#ifdef PERFCTR_CPUS_FORBIDDEN_MASK_NEEDED
+		if (unlikely(atomic_read(&perfctr->bad_cpus_allowed)) &&
+		    perfctr_cstatus_nrctrs(perfctr->cpu_state.cstatus)) {
+			perfctr->cpu_state.cstatus = 0;
+			vperfctr_clear_iresume_cstatus(perfctr);
+			BUG_ON(current->state != TASK_RUNNING);
+			send_sig(SIGILL, current, 1);
+			return;
+		}
+#endif
+		vperfctr_resume(perfctr);
+	}
+}
+
+/* Called from update_one_process() [triggered by timer interrupt].
+ * PRE: perfctr == current->thread.perfctr.
+ * Sample the counters but do not suspend them.
+ * Needed to avoid precision loss due to multiple counter
+ * wraparounds between resume/suspend for CPU-bound processes.
+ * PREEMPT note: called in IRQ context with preemption disabled.
+ */
+void __vperfctr_sample(struct vperfctr *perfctr)
+{
+	if (--perfctr->sampling_timer == 0)
+		vperfctr_sample(perfctr);
+}
+
+#ifdef PERFCTR_CPUS_FORBIDDEN_MASK_NEEDED
+/* Called from set_cpus_allowed().
+ * PRE: current holds task_lock(owner)
+ * PRE: owner->thread.perfctr == perfctr
+ */
+void __vperfctr_set_cpus_allowed(struct task_struct *owner,
+				 struct vperfctr *perfctr,
+				 cpumask_t new_mask)
+{
+	cpumask_t tmp;
+
+	cpus_and(tmp, new_mask, perfctr_cpus_forbidden_mask);
+	if (!cpus_empty(tmp)) {
+		atomic_set(&perfctr->bad_cpus_allowed, 1);
+		printk(KERN_WARNING "perfctr: process %d (comm %s) issued unsafe"
+		       " set_cpus_allowed() on process %d (comm %s)\n",
+		       current->pid, current->comm, owner->pid, owner->comm);
+	} else
+		atomic_set(&perfctr->bad_cpus_allowed, 0);
+}
+#endif
+
+/****************************************************************
+ *								*
+ * Virtual perfctr system calls implementation.			*
+ * These can be called by the owner process (tsk == current),	*
+ * a monitor process which has the owner under ptrace ATTACH	*
+ * control (tsk && tsk != current), or anyone with a handle to	*
+ * an unlinked perfctr (!tsk).					*
+ *								*
+ ****************************************************************/
+
+static int do_vperfctr_control(struct vperfctr *perfctr,
+			       const struct vperfctr_control *argp,
+			       struct task_struct *tsk)
+{
+	struct vperfctr_control control;
+	int err;
+	unsigned int next_cstatus;
+	unsigned int nrctrs, i;
+
+	if (!tsk)
+		return -ESRCH;	/* attempt to update unlinked perfctr */
+
+	if (copy_from_user(&control, argp, sizeof control))
+		return -EFAULT;
+
+	if (control.cpu_control.nractrs || control.cpu_control.nrictrs) {
+		cpumask_t tmp, old_mask, new_mask, tmp1;
+
+		tmp = perfctr_cpus_forbidden_mask;
+		cpus_complement(tmp1, tmp);
+		tmp = tmp1;
+		old_mask = tsk->cpus_allowed;
+		cpus_and(new_mask, old_mask, tmp);
+
+		if (cpus_empty(new_mask))
+			return -EINVAL;
+		if (!cpus_equal(new_mask, old_mask))
+			set_cpus_allowed(tsk, new_mask);
+	}
+
+	/* PREEMPT note: preemption is disabled over the entire
+	   region since we're updating an active perfctr. */
+	preempt_disable();
+	if (IS_RUNNING(perfctr)) {
+		if (tsk == current)
+			vperfctr_suspend(perfctr);
+		perfctr->cpu_state.cstatus = 0;
+		vperfctr_clear_iresume_cstatus(perfctr);
+	}
+	perfctr->cpu_state.control = control.cpu_control;
+	/* remote access note: perfctr_cpu_update_control() is ok */
+	err = perfctr_cpu_update_control(&perfctr->cpu_state, 0);
+	if (err < 0)
+		goto out;
+	next_cstatus = perfctr->cpu_state.cstatus;
+	if (!perfctr_cstatus_enabled(next_cstatus))
+		goto out;
+
+	/* XXX: validate si_signo? */
+	perfctr->si_signo = control.si_signo;
+
+	if (!perfctr_cstatus_has_tsc(next_cstatus))
+		perfctr->cpu_state.tsc_sum = 0;
+
+	nrctrs = perfctr_cstatus_nrctrs(next_cstatus);
+	for(i = 0; i < nrctrs; ++i)
+		if (!(control.preserve & (1<<i)))
+			perfctr->cpu_state.pmc[i].sum = 0;
+
+	if (tsk == current)
+		vperfctr_resume(perfctr);
+
+ out:
+	preempt_enable();
+	return err;
+}
+
+static int do_vperfctr_iresume(struct vperfctr *perfctr, const struct task_struct *tsk)
+{
+#ifdef PERFCTR_INTERRUPT_SUPPORT
+	unsigned int iresume_cstatus;
+
+	if (!tsk)
+		return -ESRCH;	/* attempt to update unlinked perfctr */
+
+	iresume_cstatus = perfctr->iresume_cstatus;
+	if (!perfctr_cstatus_has_ictrs(iresume_cstatus))
+		return -EPERM;
+
+	/* PREEMPT note: preemption is disabled over the entire
+	   region because we're updating an active perfctr. */
+	preempt_disable();
+
+	if (IS_RUNNING(perfctr) && tsk == current)
+		vperfctr_suspend(perfctr);
+
+	perfctr->cpu_state.cstatus = iresume_cstatus;
+	perfctr->iresume_cstatus = 0;
+
+	/* remote access note: perfctr_cpu_ireload() is ok */
+	perfctr_cpu_ireload(&perfctr->cpu_state);
+
+	if (tsk == current)
+		vperfctr_resume(perfctr);
+
+	preempt_enable();
+
+	return 0;
+#else
+	return -ENOSYS;
+#endif
+}
+
+static int do_vperfctr_unlink(struct vperfctr *perfctr, struct task_struct *tsk)
+{
+	if (tsk)
+		vperfctr_unlink(tsk, perfctr);
+	return 0;
+}
+
+static int do_vperfctr_read(struct vperfctr *perfctr,
+			    struct perfctr_sum_ctrs *sump,
+			    struct vperfctr_control *controlp,
+			    const struct task_struct *tsk)
+{
+	struct perfctr_sum_ctrs sum;
+	struct vperfctr_control control;
+
+	/* PREEMPT note: While we're reading our own control, another
+	   process may ptrace ATTACH to us and update our control.
+	   Disable preemption to ensure we get a consistent copy.
+	   Not needed for other cases since the perfctr is either
+	   unlinked or its owner is ptrace ATTACH suspended by us. */
+	if (tsk == current) {
+		preempt_disable();
+		if (sump)
+			vperfctr_sample(perfctr);
+	}
+	if (sump) { //sum = perfctr->cpu_state.sum;
+		int j;
+		sum.tsc = perfctr->cpu_state.tsc_sum;
+		for(j = 0; j < ARRAY_SIZE(sum.pmc); ++j)
+			sum.pmc[j] = perfctr->cpu_state.pmc[j].sum;
+	}
+	if (controlp) {
+		control.si_signo = perfctr->si_signo;
+		control.cpu_control = perfctr->cpu_state.control;
+		control.preserve = 0;
+	}
+	if (tsk == current)
+		preempt_enable();
+	if (sump && copy_to_user(sump, &sum, sizeof sum))
+		return -EFAULT;
+	if (controlp && copy_to_user(controlp, &control, sizeof control))
+		return -EFAULT;
+	return 0;
+}
+
+/****************************************************************
+ *								*
+ * Virtual perfctr file operations.				*
+ *								*
+ ****************************************************************/
+
+static int vperfctr_mmap(struct file *filp, struct vm_area_struct *vma)
+{
+	struct vperfctr *perfctr;
+
+	/* Only allow read-only mapping of first page. */
+	if ((vma->vm_end - vma->vm_start) != PAGE_SIZE ||
+	    vma->vm_pgoff != 0 ||
+	    (pgprot_val(vma->vm_page_prot) & _PAGE_RW) ||
+	    (vma->vm_flags & (VM_WRITE | VM_MAYWRITE)))
+		return -EPERM;
+	perfctr = filp->private_data;
+	if (!perfctr)
+		return -EPERM;
+	return remap_page_range(vma, vma->vm_start, virt_to_phys(perfctr),
+				PAGE_SIZE, vma->vm_page_prot);
+}
+
+static int vperfctr_release(struct inode *inode, struct file *filp)
+{
+	struct vperfctr *perfctr = filp->private_data;
+	filp->private_data = NULL;
+	if (perfctr)
+		put_vperfctr(perfctr);
+	return 0;
+}
+
+static struct file_operations vperfctr_file_ops = {
+	.mmap = vperfctr_mmap,
+	.release = vperfctr_release,
+};
+
+/****************************************************************
+ *								*
+ * File system for virtual perfctrs. Based on pipefs.		*
+ *								*
+ ****************************************************************/
+
+#define VPERFCTRFS_MAGIC (('V'<<24)|('P'<<16)|('M'<<8)|('C'))
+
+/* The code to set up a `struct file_system_type' for a pseudo fs
+   is unfortunately not the same in 2.4 and 2.6. */
+#include <linux/mount.h> /* needed for 2.6, included by fs.h in 2.4 */
+
+static struct super_block *
+vperfctrfs_get_sb(struct file_system_type *fs_type,
+		  int flags, const char *dev_name, void *data)
+{
+	return get_sb_pseudo(fs_type, "vperfctr:", NULL, VPERFCTRFS_MAGIC);
+}
+
+static struct file_system_type vperfctrfs_type = {
+	.name		= "vperfctrfs",
+	.get_sb		= vperfctrfs_get_sb,
+	.kill_sb	= kill_anon_super,
+};
+
+/* XXX: check if s/vperfctr_mnt/vperfctrfs_type.kern_mnt/ would work */
+static struct vfsmount *vperfctr_mnt;
+#define vperfctr_fs_init_done()	(vperfctr_mnt != NULL)
+
+static int __init vperfctrfs_init(void)
+{
+	int err = register_filesystem(&vperfctrfs_type);
+	if (!err) {
+		vperfctr_mnt = kern_mount(&vperfctrfs_type);
+		if (!IS_ERR(vperfctr_mnt))
+			return 0;
+		err = PTR_ERR(vperfctr_mnt);
+		unregister_filesystem(&vperfctrfs_type);
+		vperfctr_mnt = NULL;
+	}
+	return err;
+}
+
+static void __exit vperfctrfs_exit(void)
+{
+	unregister_filesystem(&vperfctrfs_type);
+	mntput(vperfctr_mnt);
+}
+
+static struct inode *vperfctr_get_inode(void)
+{
+	struct inode *inode;
+
+	inode = new_inode(vperfctr_mnt->mnt_sb);
+	if (!inode)
+		return NULL;
+	inode->i_fop = &vperfctr_file_ops;
+	inode->i_state = I_DIRTY;
+	inode->i_mode = S_IFCHR | S_IRUSR | S_IWUSR;
+	inode->i_uid = current->fsuid;
+	inode->i_gid = current->fsgid;
+	inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME;
+	inode->i_blksize = 0;
+	return inode;
+}
+
+static int vperfctrfs_delete_dentry(struct dentry *dentry)
+{
+	return 1;
+}
+
+static struct dentry_operations vperfctrfs_dentry_operations = {
+	.d_delete	= vperfctrfs_delete_dentry,
+};
+
+static struct dentry *vperfctr_d_alloc_root(struct inode *inode)
+{
+	struct qstr this;
+	char name[32];
+	struct dentry *dentry;
+
+	sprintf(name, "[%lu]", inode->i_ino);
+	this.name = name;
+	this.len = strlen(name);
+	this.hash = inode->i_ino; /* will go */
+	dentry = d_alloc(vperfctr_mnt->mnt_sb->s_root, &this);
+	if (dentry) {
+		dentry->d_op = &vperfctrfs_dentry_operations;
+		d_add(dentry, inode);
+	}
+	return dentry;
+}
+
+static struct file *vperfctr_get_filp(void)
+{
+	struct file *filp;
+	struct inode *inode;
+	struct dentry *dentry;
+
+	filp = get_empty_filp();
+	if (!filp)
+		goto out;
+	inode = vperfctr_get_inode();
+	if (!inode)
+		goto out_filp;
+	dentry = vperfctr_d_alloc_root(inode);
+	if (!dentry)
+		goto out_inode;
+
+	filp->f_vfsmnt = mntget(vperfctr_mnt);
+	filp->f_dentry = dentry;
+	filp->f_mapping = dentry->d_inode->i_mapping;
+
+	filp->f_pos = 0;
+	filp->f_flags = 0;
+	filp->f_op = &vperfctr_file_ops; /* fops_get() if MODULE */
+	filp->f_mode = FMODE_READ;
+	filp->f_version = 0;
+
+	return filp;
+
+ out_inode:
+	iput(inode);
+ out_filp:
+	put_filp(filp);	/* doesn't run ->release() like fput() does */
+ out:
+	return NULL;
+}
+
+/****************************************************************
+ *								*
+ * Virtual perfctr actual system calls.				*
+ *								*
+ ****************************************************************/
+
+/* tid is the actual task/thread id (née pid, stored as ->pid),
+   pid/tgid is that 2.6 thread group id crap (stored as ->tgid) */
+asmlinkage long sys_vperfctr_open(int tid, int creat)
+{
+	struct file *filp;
+	struct task_struct *tsk;
+	struct vperfctr *perfctr;
+	int err;
+	int fd;
+
+	if (!vperfctr_fs_init_done())
+		return -ENODEV;
+	filp = vperfctr_get_filp();
+	if (!filp)
+		return -ENOMEM;
+	err = fd = get_unused_fd();
+	if (err < 0)
+		goto err_filp;
+	perfctr = NULL;
+	if (creat) {
+		perfctr = get_empty_vperfctr(); /* may sleep */
+		if (IS_ERR(perfctr)) {
+			err = PTR_ERR(perfctr);
+			goto err_fd;
+		}
+	}
+	tsk = current;
+	if (tid != 0 && tid != tsk->pid) { /* remote? */
+		read_lock(&tasklist_lock);
+		tsk = find_task_by_pid(tid);
+		if (tsk)
+			get_task_struct(tsk);
+		read_unlock(&tasklist_lock);
+		err = -ESRCH;
+		if (!tsk)
+			goto err_perfctr;
+		err = ptrace_check_attach(tsk, 0);
+		if (err < 0)
+			goto err_tsk;
+	}
+	if (creat) {
+		/* check+install must be atomic to prevent remote-control races */
+		vperfctr_task_lock(tsk);
+		if (!tsk->thread.perfctr) {
+			perfctr->owner = tsk;
+			tsk->thread.perfctr = perfctr;
+			err = 0;
+		} else
+			err = -EEXIST;
+		vperfctr_task_unlock(tsk);
+		if (err)
+			goto err_tsk;
+	} else {
+		perfctr = tsk->thread.perfctr;
+		/* XXX: Old API needed to allow NULL perfctr here.
+		   Do we want to keep or change that rule? */
+	}
+	filp->private_data = perfctr;
+	if (perfctr)
+		atomic_inc(&perfctr->count);
+	if (tsk != current)
+		put_task_struct(tsk);
+	fd_install(fd, filp);
+	return fd;
+ err_tsk:
+	if (tsk != current)
+		put_task_struct(tsk);
+ err_perfctr:
+	if (perfctr)	/* can only occur if creat != 0 */
+		put_vperfctr(perfctr);
+ err_fd:
+	put_unused_fd(fd);
+ err_filp:
+	fput(filp);
+	return err;
+}
+
+static struct vperfctr *fd_get_vperfctr(int fd)
+{
+	struct vperfctr *perfctr;
+	struct file *filp;
+	int err;
+
+	err = -EBADF;
+	filp = fget(fd);
+	if (!filp)
+		goto out;
+	err = -EINVAL;
+	if (filp->f_op != &vperfctr_file_ops)
+		goto out_filp;
+	perfctr = filp->private_data;
+	if (!perfctr)
+		goto out_filp;
+	atomic_inc(&perfctr->count);
+	fput(filp);
+	return perfctr;
+ out_filp:
+	fput(filp);
+ out:
+	return ERR_PTR(err);
+}
+
+static struct task_struct *vperfctr_get_tsk(struct vperfctr *perfctr)
+{
+	struct task_struct *tsk;
+
+	tsk = current;
+	if (perfctr != current->thread.perfctr) {
+		/* this synchronises with vperfctr_unlink() and itself */
+		spin_lock(&perfctr->owner_lock);
+		tsk = perfctr->owner;
+		if (tsk)
+			get_task_struct(tsk);
+		spin_unlock(&perfctr->owner_lock);
+		if (tsk) {
+			int ret = ptrace_check_attach(tsk, 0);
+			if (ret < 0) {
+				put_task_struct(tsk);
+				return ERR_PTR(ret);
+			}
+		}
+	}
+	return tsk;
+}
+
+static void vperfctr_put_tsk(struct task_struct *tsk)
+{
+	if (tsk && tsk != current)
+		put_task_struct(tsk);
+}
+
+asmlinkage long sys_vperfctr_control(int fd, const struct vperfctr_control *control)
+{
+	struct vperfctr *perfctr;
+	struct task_struct *tsk;
+	int ret;
+
+	perfctr = fd_get_vperfctr(fd);
+	if (IS_ERR(perfctr))
+		return PTR_ERR(perfctr);
+	tsk = vperfctr_get_tsk(perfctr);
+	if (IS_ERR(tsk)) {
+		ret = PTR_ERR(tsk);
+		goto out;
+	}
+	ret = do_vperfctr_control(perfctr, control, tsk);
+	vperfctr_put_tsk(tsk);
+ out:
+	put_vperfctr(perfctr);
+	return ret;
+}
+
+asmlinkage long sys_vperfctr_unlink(int fd)
+{
+	struct vperfctr *perfctr;
+	struct task_struct *tsk;
+	int ret;
+
+	perfctr = fd_get_vperfctr(fd);
+	if (IS_ERR(perfctr))
+		return PTR_ERR(perfctr);
+	tsk = vperfctr_get_tsk(perfctr);
+	if (IS_ERR(tsk)) {
+		ret = PTR_ERR(tsk);
+		goto out;
+	}
+	ret = do_vperfctr_unlink(perfctr, tsk);
+	vperfctr_put_tsk(tsk);
+ out:
+	put_vperfctr(perfctr);
+	return ret;
+}
+
+asmlinkage long sys_vperfctr_iresume(int fd)
+{
+	struct vperfctr *perfctr;
+	struct task_struct *tsk;
+	int ret;
+
+	perfctr = fd_get_vperfctr(fd);
+	if (IS_ERR(perfctr))
+		return PTR_ERR(perfctr);
+	tsk = vperfctr_get_tsk(perfctr);
+	if (IS_ERR(tsk)) {
+		ret = PTR_ERR(tsk);
+		goto out;
+	}
+	ret = do_vperfctr_iresume(perfctr, tsk);
+	vperfctr_put_tsk(tsk);
+ out:
+	put_vperfctr(perfctr);
+	return ret;
+}
+
+asmlinkage long sys_vperfctr_read(int fd, struct perfctr_sum_ctrs *sum, struct vperfctr_control *control)
+{
+	struct vperfctr *perfctr;
+	struct task_struct *tsk;
+	int ret;
+
+	perfctr = fd_get_vperfctr(fd);
+	if (IS_ERR(perfctr))
+		return PTR_ERR(perfctr);
+	tsk = vperfctr_get_tsk(perfctr);
+	if (IS_ERR(tsk)) {
+		ret = PTR_ERR(tsk);
+		goto out;
+	}
+	ret = do_vperfctr_read(perfctr, sum, control, tsk);
+	vperfctr_put_tsk(tsk);
+ out:
+	put_vperfctr(perfctr);
+	return ret;
+}
+
+/****************************************************************
+ *								*
+ * module_init/exit						*
+ *								*
+ ****************************************************************/
+
+int __init vperfctr_init(void)
+{
+	return vperfctrfs_init();
+}
+
+void __exit vperfctr_exit(void)
+{
+	vperfctrfs_exit();
+}
--- diff/drivers/perfctr/virtual.h	1970-01-01 01:00:00.000000000 +0100
+++ source/drivers/perfctr/virtual.h	2004-06-11 19:22:03.000000000 +0100
@@ -0,0 +1,13 @@
+/* $Id: virtual.h,v 1.13 2004/05/31 18:18:55 mikpe Exp $
+ * Virtual per-process performance counters.
+ *
+ * Copyright (C) 1999-2004  Mikael Pettersson
+ */
+
+#ifdef CONFIG_PERFCTR_VIRTUAL
+extern int vperfctr_init(void);
+extern void vperfctr_exit(void);
+#else
+static inline int vperfctr_init(void) { return 0; }
+static inline void vperfctr_exit(void) { }
+#endif
--- diff/drivers/perfctr/x86.c	1970-01-01 01:00:00.000000000 +0100
+++ source/drivers/perfctr/x86.c	2004-06-11 19:22:03.000000000 +0100
@@ -0,0 +1,1626 @@
+/* $Id: x86.c,v 1.141 2004/05/31 18:13:42 mikpe Exp $
+ * x86/x86_64 performance-monitoring counters driver.
+ *
+ * Copyright (C) 1999-2004  Mikael Pettersson
+ */
+#include <linux/config.h>
+#include <linux/init.h>
+#include <linux/sched.h>
+#include <linux/interrupt.h>
+#include <linux/perfctr.h>
+
+#include <asm/msr.h>
+#undef MSR_P6_PERFCTR0
+#undef MSR_IA32_MISC_ENABLE
+#include <asm/fixmap.h>
+#include <asm/apic.h>
+struct hw_interrupt_type;
+#include <asm/hw_irq.h>
+#include <asm/timex.h>	/* cpu_khz */
+
+#include "cpumask.h"
+#include "x86_tests.h"
+
+/* Support for lazy evntsel and perfctr MSR updates. */
+struct per_cpu_cache {	/* roughly a subset of perfctr_cpu_state */
+	union {
+		unsigned int p5_cesr;
+		unsigned int id;	/* cache owner id */
+	} k1;
+	struct {
+		/* NOTE: these caches have physical indices, not virtual */
+		unsigned int evntsel[18];
+		unsigned int escr[0x3E2-0x3A0];
+		unsigned int pebs_enable;
+		unsigned int pebs_matrix_vert;
+	} control;
+} ____cacheline_aligned;
+static DEFINE_PER_CPU(struct per_cpu_cache, per_cpu_cache);
+
+/* Structure for counter snapshots, as 32-bit values. */
+struct perfctr_low_ctrs {
+	unsigned int tsc;
+	unsigned int pmc[18];
+};
+
+/* Intel P5, Cyrix 6x86MX/MII/III, Centaur WinChip C6/2/3 */
+#define MSR_P5_CESR		0x11
+#define MSR_P5_CTR0		0x12		/* .. 0x13 */
+#define P5_CESR_CPL		0x00C0
+#define P5_CESR_RESERVED	(~0x01FF)
+#define MII_CESR_RESERVED	(~0x05FF)
+#define C6_CESR_RESERVED	(~0x00FF)
+
+/* Intel P6, VIA C3 */
+#define MSR_P6_PERFCTR0		0xC1		/* .. 0xC2 */
+#define MSR_P6_EVNTSEL0		0x186		/* .. 0x187 */
+#define P6_EVNTSEL_ENABLE	0x00400000
+#define P6_EVNTSEL_INT		0x00100000
+#define P6_EVNTSEL_CPL		0x00030000
+#define P6_EVNTSEL_RESERVED	0x00280000
+#define VC3_EVNTSEL1_RESERVED	(~0x1FF)
+
+/* AMD K7 */
+#define MSR_K7_EVNTSEL0		0xC0010000	/* .. 0xC0010003 */
+#define MSR_K7_PERFCTR0		0xC0010004	/* .. 0xC0010007 */
+
+/* Intel P4, Intel Pentium M */
+#define MSR_IA32_MISC_ENABLE	0x1A0
+#define MSR_IA32_MISC_ENABLE_PERF_AVAIL (1<<7)	/* read-only status bit */
+#define MSR_IA32_MISC_ENABLE_PEBS_UNAVAIL (1<<12) /* read-only status bit */
+
+/* Intel P4 */
+#define MSR_P4_PERFCTR0		0x300		/* .. 0x311 */
+#define MSR_P4_CCCR0		0x360		/* .. 0x371 */
+#define MSR_P4_ESCR0		0x3A0		/* .. 0x3E1, with some gaps */
+
+#define MSR_P4_PEBS_ENABLE	0x3F1
+#define P4_PE_REPLAY_TAG_BITS	0x00000607
+#define P4_PE_UOP_TAG		0x01000000
+#define P4_PE_RESERVED		0xFEFFF9F8	/* only allow ReplayTagging */
+
+#define MSR_P4_PEBS_MATRIX_VERT	0x3F2
+#define P4_PMV_REPLAY_TAG_BITS	0x00000003
+#define P4_PMV_RESERVED		0xFFFFFFFC
+
+#define P4_CCCR_OVF		0x80000000
+#define P4_CCCR_CASCADE		0x40000000
+#define P4_CCCR_OVF_PMI_T1	0x08000000
+#define P4_CCCR_OVF_PMI_T0	0x04000000
+#define P4_CCCR_FORCE_OVF	0x02000000
+#define P4_CCCR_ACTIVE_THREAD	0x00030000
+#define P4_CCCR_ENABLE		0x00001000
+#define P4_CCCR_ESCR_SELECT(X)	(((X) >> 13) & 0x7)
+#define P4_CCCR_EXTENDED_CASCADE	0x00000800
+#define P4_CCCR_RESERVED	(0x300007FF|P4_CCCR_OVF|P4_CCCR_OVF_PMI_T1)
+
+#define P4_ESCR_CPL_T1		0x00000003
+#define P4_ESCR_CPL_T0		0x0000000C
+#define P4_ESCR_TAG_ENABLE	0x00000010
+#define P4_ESCR_RESERVED	(0x80000000)
+
+#define P4_FAST_RDPMC		0x80000000
+#define P4_MASK_FAST_RDPMC	0x0000001F	/* we only need low 5 bits */
+
+/* missing from <asm-i386/cpufeature.h> */
+#define cpu_has_msr	boot_cpu_has(X86_FEATURE_MSR)
+
+#define rdmsr_low(msr,low) \
+	__asm__ __volatile__("rdmsr" : "=a"(low) : "c"(msr) : "edx")
+#define rdpmc_low(ctr,low) \
+	__asm__ __volatile__("rdpmc" : "=a"(low) : "c"(ctr) : "edx")
+
+static void clear_msr_range(unsigned int base, unsigned int n)
+{
+	unsigned int i;
+
+	for(i = 0; i < n; ++i)
+		wrmsr(base+i, 0, 0);
+}
+
+static inline void set_in_cr4_local(unsigned int mask)
+{
+	write_cr4(read_cr4() | mask);
+}
+
+static inline void clear_in_cr4_local(unsigned int mask)
+{
+	write_cr4(read_cr4() & ~mask);
+}
+
+static unsigned int new_id(void)
+{
+	static spinlock_t lock = SPIN_LOCK_UNLOCKED;
+	static unsigned int counter;
+	int id;
+
+	spin_lock(&lock);
+	id = ++counter;
+	spin_unlock(&lock);
+	return id;
+}
+
+#ifdef PERFCTR_INTERRUPT_SUPPORT
+static void perfctr_default_ihandler(unsigned long pc)
+{
+}
+
+static perfctr_ihandler_t perfctr_ihandler = perfctr_default_ihandler;
+
+asmlinkage void smp_perfctr_interrupt(struct pt_regs *regs)
+{
+	/* PREEMPT note: invoked via an interrupt gate, which
+	   masks interrupts. We're still on the originating CPU. */
+	/* XXX: recursive interrupts? delay the ACK, mask LVTPC, or queue? */
+	ack_APIC_irq();
+	irq_enter();
+	(*perfctr_ihandler)(instruction_pointer(regs));
+	irq_exit();
+}
+
+void perfctr_cpu_set_ihandler(perfctr_ihandler_t ihandler)
+{
+	perfctr_ihandler = ihandler ? ihandler : perfctr_default_ihandler;
+}
+
+#else
+#define perfctr_cstatus_has_ictrs(cstatus)	0
+#undef cpu_has_apic
+#define cpu_has_apic				0
+#undef apic_write
+#define apic_write(reg,vector)			do{}while(0)
+#endif
+
+#if defined(CONFIG_SMP) && defined(PERFCTR_INTERRUPT_SUPPORT)
+
+static inline void
+set_isuspend_cpu(struct perfctr_cpu_state *state, int cpu)
+{
+	state->k1.isuspend_cpu = cpu;
+}
+
+static inline int
+is_isuspend_cpu(const struct perfctr_cpu_state *state, int cpu)
+{
+	return state->k1.isuspend_cpu == cpu;
+}
+
+static inline void clear_isuspend_cpu(struct perfctr_cpu_state *state)
+{
+	state->k1.isuspend_cpu = NR_CPUS;
+}
+
+#else
+static inline void set_isuspend_cpu(struct perfctr_cpu_state *state, int cpu) { }
+static inline int is_isuspend_cpu(const struct perfctr_cpu_state *state, int cpu) { return 1; }
+static inline void clear_isuspend_cpu(struct perfctr_cpu_state *state) { }
+#endif
+
+/****************************************************************
+ *								*
+ * Driver procedures.						*
+ *								*
+ ****************************************************************/
+
+/*
+ * Intel P5 family (Pentium, family code 5).
+ * - One TSC and two 40-bit PMCs.
+ * - A single 32-bit CESR (MSR 0x11) controls both PMCs.
+ *   CESR has two halves, each controlling one PMC.
+ *   To keep the API reasonably clean, the user puts 16 bits of
+ *   control data in each counter's evntsel; the driver combines
+ *   these to a single 32-bit CESR value.
+ * - Overflow interrupts are not available.
+ * - Pentium MMX added the RDPMC instruction. RDPMC has lower
+ *   overhead than RDMSR and it can be used in user-mode code.
+ * - The MMX events are not symmetric: some events are only available
+ *   for some PMC, and some event codes denote different events
+ *   depending on which PMCs they control.
+ */
+
+/* shared with MII and C6 */
+static int p5_like_check_control(struct perfctr_cpu_state *state,
+				 unsigned int reserved_bits, int is_c6)
+{
+	unsigned short cesr_half[2];
+	unsigned int pmc, evntsel, i;
+
+	if (state->control.nrictrs != 0 || state->control.nractrs > 2)
+		return -EINVAL;
+	cesr_half[0] = 0;
+	cesr_half[1] = 0;
+	for(i = 0; i < state->control.nractrs; ++i) {
+		pmc = state->control.pmc_map[i];
+		state->pmc[i].map = pmc;
+		if (pmc > 1 || cesr_half[pmc] != 0)
+			return -EINVAL;
+		evntsel = state->control.evntsel[i];
+		/* protect reserved bits */
+		if ((evntsel & reserved_bits) != 0)
+			return -EPERM;
+		/* the CPL field (if defined) must be non-zero */
+		if (!is_c6 && !(evntsel & P5_CESR_CPL))
+			return -EINVAL;
+		cesr_half[pmc] = evntsel;
+	}
+	state->k1.id = (cesr_half[1] << 16) | cesr_half[0];
+	return 0;
+}
+
+static int p5_check_control(struct perfctr_cpu_state *state, int is_global)
+{
+	return p5_like_check_control(state, P5_CESR_RESERVED, 0);
+}
+
+/* shared with MII but not C6 */
+static void p5_write_control(const struct perfctr_cpu_state *state)
+{
+	struct per_cpu_cache *cache;
+	unsigned int cesr;
+
+	cesr = state->k1.id;
+	if (!cesr)	/* no PMC is on (this test doesn't work on C6) */
+		return;
+	cache = &__get_cpu_var(per_cpu_cache);
+	if (cache->k1.p5_cesr != cesr) {
+		cache->k1.p5_cesr = cesr;
+		wrmsr(MSR_P5_CESR, cesr, 0);
+	}
+}
+
+static void p5_read_counters(const struct perfctr_cpu_state *state,
+			     struct perfctr_low_ctrs *ctrs)
+{
+	unsigned int cstatus, nrctrs, i;
+
+	/* The P5 doesn't allocate a cache line on a write miss, so do
+	   a dummy read to avoid a write miss here _and_ a read miss
+	   later in our caller. */
+	asm("" : : "r"(ctrs->tsc));
+
+	cstatus = state->cstatus;
+	if (perfctr_cstatus_has_tsc(cstatus))
+		rdtscl(ctrs->tsc);
+	nrctrs = perfctr_cstatus_nractrs(cstatus);
+	for(i = 0; i < nrctrs; ++i) {
+		unsigned int pmc = state->pmc[i].map;
+		rdmsr_low(MSR_P5_CTR0+pmc, ctrs->pmc[i]);
+	}
+}
+
+/* used by all except pre-MMX P5 */
+static void rdpmc_read_counters(const struct perfctr_cpu_state *state,
+				struct perfctr_low_ctrs *ctrs)
+{
+	unsigned int cstatus, nrctrs, i;
+
+	cstatus = state->cstatus;
+	if (perfctr_cstatus_has_tsc(cstatus))
+		rdtscl(ctrs->tsc);
+	nrctrs = perfctr_cstatus_nractrs(cstatus);
+	for(i = 0; i < nrctrs; ++i) {
+		unsigned int pmc = state->pmc[i].map;
+		rdpmc_low(pmc, ctrs->pmc[i]);
+	}
+}
+
+/* shared with MII and C6 */
+static void p5_clear_counters(void)
+{
+	clear_msr_range(MSR_P5_CESR, 1+2);
+}
+
+/*
+ * Cyrix 6x86/MII/III.
+ * - Same MSR assignments as P5 MMX. Has RDPMC and two 48-bit PMCs.
+ * - Event codes and CESR formatting as in the plain P5 subset.
+ * - Many but not all P5 MMX event codes are implemented.
+ * - Cyrix adds a few more event codes. The event code is widened
+ *   to 7 bits, and Cyrix puts the high bit in CESR bit 10
+ *   (and CESR bit 26 for PMC1).
+ */
+
+static int mii_check_control(struct perfctr_cpu_state *state, int is_global)
+{
+	return p5_like_check_control(state, MII_CESR_RESERVED, 0);
+}
+
+/*
+ * Centaur WinChip C6/2/3.
+ * - Same MSR assignments as P5 MMX. Has RDPMC and two 40-bit PMCs.
+ * - CESR is formatted with two halves, like P5. However, there
+ *   are no defined control fields for e.g. CPL selection, and
+ *   there is no defined method for stopping the counters.
+ * - Only a few event codes are defined.
+ * - The 64-bit TSC is synthesised from the low 32 bits of the
+ *   two PMCs, and CESR has to be set up appropriately.
+ *   Reprogramming CESR causes RDTSC to yield invalid results.
+ *   (The C6 may also hang in this case, due to C6 erratum I-13.)
+ *   Therefore, using the PMCs on any of these processors requires
+ *   that the TSC is not accessed at all:
+ *   1. The kernel must be configured or a TSC-less processor, i.e.
+ *      generic 586 or less.
+ *   2. The "notsc" boot parameter must be passed to the kernel.
+ *   3. User-space libraries and code must also be configured and
+ *      compiled for a generic 586 or less.
+ */
+
+#if !defined(CONFIG_X86_TSC)
+static int c6_check_control(struct perfctr_cpu_state *state, int is_global)
+{
+	if (state->control.tsc_on)
+		return -EINVAL;
+	return p5_like_check_control(state, C6_CESR_RESERVED, 1);
+}
+
+static void c6_write_control(const struct perfctr_cpu_state *state)
+{
+	struct per_cpu_cache *cache;
+	unsigned int cesr;
+
+	if (perfctr_cstatus_nractrs(state->cstatus) == 0) /* no PMC is on */
+		return;
+	cache = &__get_cpu_var(per_cpu_cache);
+	cesr = state->k1.id;
+	if (cache->k1.p5_cesr != cesr) {
+		cache->k1.p5_cesr = cesr;
+		wrmsr(MSR_P5_CESR, cesr, 0);
+	}
+}
+#endif
+
+/*
+ * Intel P6 family (Pentium Pro, Pentium II, and Pentium III cores,
+ * and Xeon and Celeron versions of Pentium II and III cores).
+ * - One TSC and two 40-bit PMCs.
+ * - One 32-bit EVNTSEL MSR for each PMC.
+ * - EVNTSEL0 contains a global enable/disable bit.
+ *   That bit is reserved in EVNTSEL1.
+ * - Each EVNTSEL contains a CPL field.
+ * - Overflow interrupts are possible, but requires that the
+ *   local APIC is available. Some Mobile P6s have no local APIC.
+ * - The PMCs cannot be initialised with arbitrary values, since
+ *   wrmsr fills the high bits by sign-extending from bit 31.
+ * - Most events are symmetric, but a few are not.
+ */
+
+/* shared with K7 */
+static int p6_like_check_control(struct perfctr_cpu_state *state, int is_k7)
+{
+	unsigned int evntsel, i, nractrs, nrctrs, pmc_mask, pmc;
+
+	nractrs = state->control.nractrs;
+	nrctrs = nractrs + state->control.nrictrs;
+	if (nrctrs < nractrs || nrctrs > (is_k7 ? 4 : 2))
+		return -EINVAL;
+
+	pmc_mask = 0;
+	for(i = 0; i < nrctrs; ++i) {
+		pmc = state->control.pmc_map[i];
+		state->pmc[i].map = pmc;
+		if (pmc >= (is_k7 ? 4 : 2) || (pmc_mask & (1<<pmc)))
+			return -EINVAL;
+		pmc_mask |= (1<<pmc);
+		evntsel = state->control.evntsel[i];
+		/* protect reserved bits */
+		if (evntsel & P6_EVNTSEL_RESERVED)
+			return -EPERM;
+		/* check ENable bit */
+		if (is_k7) {
+			/* ENable bit must be set in each evntsel */
+			if (!(evntsel & P6_EVNTSEL_ENABLE))
+				return -EINVAL;
+		} else {
+			/* only evntsel[0] has the ENable bit */
+			if (evntsel & P6_EVNTSEL_ENABLE) {
+				if (pmc > 0)
+					return -EPERM;
+			} else {
+				if (pmc == 0)
+					return -EINVAL;
+			}
+		}
+		/* the CPL field must be non-zero */
+		if (!(evntsel & P6_EVNTSEL_CPL))
+			return -EINVAL;
+		/* INT bit must be off for a-mode and on for i-mode counters */
+		if (evntsel & P6_EVNTSEL_INT) {
+			if (i < nractrs)
+				return -EINVAL;
+		} else {
+			if (i >= nractrs)
+				return -EINVAL;
+		}
+	}
+	state->k1.id = new_id();
+	return 0;
+}
+
+static int p6_check_control(struct perfctr_cpu_state *state, int is_global)
+{
+	return p6_like_check_control(state, 0);
+}
+
+#ifdef PERFCTR_INTERRUPT_SUPPORT
+/* PRE: perfctr_cstatus_has_ictrs(state->cstatus) != 0 */
+/* shared with K7 and P4 */
+static void p6_like_isuspend(struct perfctr_cpu_state *state,
+			     unsigned int msr_evntsel0)
+{
+	struct per_cpu_cache *cache;
+	unsigned int cstatus, nrctrs, i;
+	int cpu;
+
+	cpu = smp_processor_id();
+	set_isuspend_cpu(state, cpu); /* early to limit cpu's live range */
+	cache = &per_cpu(per_cpu_cache, cpu);
+	cstatus = state->cstatus;
+	nrctrs = perfctr_cstatus_nrctrs(cstatus);
+	for(i = perfctr_cstatus_nractrs(cstatus); i < nrctrs; ++i) {
+		unsigned int pmc_raw, pmc_idx, now;
+		pmc_raw = state->pmc[i].map;
+		/* Note: P4_MASK_FAST_RDPMC is a no-op for P6 and K7.
+		   We don't need to make it into a parameter. */
+		pmc_idx = pmc_raw & P4_MASK_FAST_RDPMC;
+		cache->control.evntsel[pmc_idx] = 0;
+		/* On P4 this intensionally also clears the CCCR.OVF flag. */
+		wrmsr(msr_evntsel0+pmc_idx, 0, 0);
+		/* P4 erratum N17 does not apply since we read only low 32 bits. */
+		rdpmc_low(pmc_raw, now);
+		state->pmc[i].sum += now - state->pmc[i].start;
+		state->pmc[i].start = now;
+	}
+	/* cache->k1.id is still == state->k1.id */
+}
+
+/* PRE: perfctr_cstatus_has_ictrs(state->cstatus) != 0 */
+/* shared with K7 and P4 */
+static void p6_like_iresume(const struct perfctr_cpu_state *state,
+			    unsigned int msr_evntsel0,
+			    unsigned int msr_perfctr0)
+{
+	struct per_cpu_cache *cache;
+	unsigned int cstatus, nrctrs, i;
+	int cpu;
+
+	cpu = smp_processor_id();
+	cache = &per_cpu(per_cpu_cache, cpu);
+	if (cache->k1.id == state->k1.id) {
+		cache->k1.id = 0; /* force reload of cleared EVNTSELs */
+		if (is_isuspend_cpu(state, cpu))
+			return; /* skip reload of PERFCTRs */
+	}
+	cstatus = state->cstatus;
+	nrctrs = perfctr_cstatus_nrctrs(cstatus);
+	for(i = perfctr_cstatus_nractrs(cstatus); i < nrctrs; ++i) {
+		/* Note: P4_MASK_FAST_RDPMC is a no-op for P6 and K7.
+		   We don't need to make it into a parameter. */
+		unsigned int pmc = state->pmc[i].map & P4_MASK_FAST_RDPMC;
+		/* If the control wasn't ours we must disable the evntsels
+		   before reinitialising the counters, to prevent unexpected
+		   counter increments and missed overflow interrupts. */
+		if (cache->control.evntsel[pmc]) {
+			cache->control.evntsel[pmc] = 0;
+			wrmsr(msr_evntsel0+pmc, 0, 0);
+		}
+		/* P4 erratum N15 does not apply since the CCCR is disabled. */
+		wrmsr(msr_perfctr0+pmc, state->pmc[i].start, -1);
+	}
+	/* cache->k1.id remains != state->k1.id */
+}
+
+static void p6_isuspend(struct perfctr_cpu_state *state)
+{
+	p6_like_isuspend(state, MSR_P6_EVNTSEL0);
+}
+
+static void p6_iresume(const struct perfctr_cpu_state *state)
+{
+	p6_like_iresume(state, MSR_P6_EVNTSEL0, MSR_P6_PERFCTR0);
+}
+#endif	/* PERFCTR_INTERRUPT_SUPPORT */
+
+/* shared with K7 and VC3 */
+static void p6_like_write_control(const struct perfctr_cpu_state *state,
+				  unsigned int msr_evntsel0)
+{
+	struct per_cpu_cache *cache;
+	unsigned int nrctrs, i;
+
+	cache = &__get_cpu_var(per_cpu_cache);
+	if (cache->k1.id == state->k1.id)
+		return;
+	nrctrs = perfctr_cstatus_nrctrs(state->cstatus);
+	for(i = 0; i < nrctrs; ++i) {
+		unsigned int evntsel = state->control.evntsel[i];
+		unsigned int pmc = state->pmc[i].map;
+		if (evntsel != cache->control.evntsel[pmc]) {
+			cache->control.evntsel[pmc] = evntsel;
+			wrmsr(msr_evntsel0+pmc, evntsel, 0);
+		}
+	}
+	cache->k1.id = state->k1.id;
+}
+
+/* shared with VC3, Generic*/
+static void p6_write_control(const struct perfctr_cpu_state *state)
+{
+	p6_like_write_control(state, MSR_P6_EVNTSEL0);
+}
+
+static void p6_clear_counters(void)
+{
+	clear_msr_range(MSR_P6_EVNTSEL0, 2);
+	clear_msr_range(MSR_P6_PERFCTR0, 2);
+}
+
+/*
+ * AMD K7 family (Athlon, Duron).
+ * - Somewhat similar to the Intel P6 family.
+ * - Four 48-bit PMCs.
+ * - Four 32-bit EVNTSEL MSRs with similar layout as in P6.
+ * - Completely different MSR assignments :-(
+ * - Fewer countable events defined :-(
+ * - The events appear to be completely symmetric.
+ * - The EVNTSEL MSRs are symmetric since each has its own enable bit.
+ * - Publicly available documentation is incomplete.
+ * - K7 model 1 does not have a local APIC. AMD Document #22007
+ *   Revision J hints that it may use debug interrupts instead.
+ *
+ * The K8 has the same hardware layout as the K7. It also has
+ * better documentation and a different set of available events.
+ */
+
+static int k7_check_control(struct perfctr_cpu_state *state, int is_global)
+{
+	return p6_like_check_control(state, 1);
+}
+
+#ifdef PERFCTR_INTERRUPT_SUPPORT
+static void k7_isuspend(struct perfctr_cpu_state *state)
+{
+	p6_like_isuspend(state, MSR_K7_EVNTSEL0);
+}
+
+static void k7_iresume(const struct perfctr_cpu_state *state)
+{
+	p6_like_iresume(state, MSR_K7_EVNTSEL0, MSR_K7_PERFCTR0);
+}
+#endif	/* PERFCTR_INTERRUPT_SUPPORT */
+
+static void k7_write_control(const struct perfctr_cpu_state *state)
+{
+	p6_like_write_control(state, MSR_K7_EVNTSEL0);
+}
+
+static void k7_clear_counters(void)
+{
+	clear_msr_range(MSR_K7_EVNTSEL0, 4+4);
+}
+
+/*
+ * VIA C3 family.
+ * - A Centaur design somewhat similar to the P6/Celeron.
+ * - PERFCTR0 is an alias for the TSC, and EVNTSEL0 is read-only.
+ * - PERFCTR1 is 32 bits wide.
+ * - EVNTSEL1 has no defined control fields, and there is no
+ *   defined method for stopping the counter.
+ * - According to testing, the reserved fields in EVNTSEL1 have
+ *   no function. We always fill them with zeroes.
+ * - Only a few event codes are defined.
+ * - No local APIC or interrupt-mode support.
+ * - pmc_map[0] must be 1, if nractrs == 1.
+ */
+static int vc3_check_control(struct perfctr_cpu_state *state, int is_global)
+{
+	if (state->control.nrictrs || state->control.nractrs > 1)
+		return -EINVAL;
+	if (state->control.nractrs == 1) {
+		if (state->control.pmc_map[0] != 1)
+			return -EINVAL;
+		state->pmc[0].map = 1;
+		if (state->control.evntsel[0] & VC3_EVNTSEL1_RESERVED)
+			return -EPERM;
+		state->k1.id = state->control.evntsel[0];
+	} else
+		state->k1.id = 0;
+	return 0;
+}
+
+static void vc3_clear_counters(void)
+{
+	/* Not documented, but seems to be default after boot. */
+	wrmsr(MSR_P6_EVNTSEL0+1, 0x00070079, 0);
+}
+
+/*
+ * Intel Pentium 4.
+ * Current implementation restrictions:
+ * - No DS/PEBS support.
+ *
+ * Known quirks:
+ * - OVF_PMI+FORCE_OVF counters must have an ireset value of -1.
+ *   This allows the regular overflow check to also handle FORCE_OVF
+ *   counters. Not having this restriction would lead to MAJOR
+ *   complications in the driver's "detect overflow counters" code.
+ *   There is no loss of functionality since the ireset value doesn't
+ *   affect the counter's PMI rate for FORCE_OVF counters.
+ * - In experiments with FORCE_OVF counters, and regular OVF_PMI
+ *   counters with small ireset values between -8 and -1, it appears
+ *   that the faulting instruction is subjected to a new PMI before
+ *   it can complete, ad infinitum. This occurs even though the driver
+ *   clears the CCCR (and in testing also the ESCR) and invokes a
+ *   user-space signal handler before restoring the CCCR and resuming
+ *   the instruction.
+ */
+
+/*
+ * Table 15-4 in the IA32 Volume 3 manual contains a 18x8 entry mapping
+ * from counter/CCCR number (0-17) and ESCR SELECT value (0-7) to the
+ * actual ESCR MSR number. This mapping contains some repeated patterns,
+ * so we can compact it to a 4x8 table of MSR offsets:
+ *
+ * 1. CCCRs 16 and 17 are mapped just like CCCRs 13 and 14, respectively.
+ *    Thus, we only consider the 16 CCCRs 0-15.
+ * 2. The CCCRs are organised in pairs, and both CCCRs in a pair use the
+ *    same mapping. Thus, we only consider the 8 pairs 0-7.
+ * 3. In each pair of pairs, the second odd-numbered pair has the same domain
+ *    as the first even-numbered pair, and the range is 1+ the range of the
+ *    the first even-numbered pair. For example, CCCR(0) and (1) map ESCR
+ *    SELECT(7) to 0x3A0, and CCCR(2) and (3) map it to 0x3A1.
+ *    The only exception is that pair (7) [CCCRs 14 and 15] does not have
+ *    ESCR SELECT(3) in its domain, like pair (6) [CCCRs 12 and 13] has.
+ *    NOTE: Revisions of IA32 Volume 3 older than #245472-007 had an error
+ *    in this table: CCCRs 12, 13, and 16 had their mappings for ESCR SELECT
+ *    values 2 and 3 swapped.
+ * 4. All MSR numbers are on the form 0x3??. Instead of storing these as
+ *    16-bit numbers, the table only stores the 8-bit offsets from 0x300.
+ */
+
+static const unsigned char p4_cccr_escr_map[4][8] = {
+	/* 0x00 and 0x01 as is, 0x02 and 0x03 are +1 */
+	[0x00/4] {	[7] 0xA0,
+			[6] 0xA2,
+			[2] 0xAA,
+			[4] 0xAC,
+			[0] 0xB2,
+			[1] 0xB4,
+			[3] 0xB6,
+			[5] 0xC8, },
+	/* 0x04 and 0x05 as is, 0x06 and 0x07 are +1 */
+	[0x04/4] {	[0] 0xC0,
+			[2] 0xC2,
+			[1] 0xC4, },
+	/* 0x08 and 0x09 as is, 0x0A and 0x0B are +1 */
+	[0x08/4] {	[1] 0xA4,
+			[0] 0xA6,
+			[5] 0xA8,
+			[2] 0xAE,
+			[3] 0xB0, },
+	/* 0x0C, 0x0D, and 0x10 as is,
+	   0x0E, 0x0F, and 0x11 are +1 except [3] is not in the domain */
+	[0x0C/4] {	[4] 0xB8,
+			[5] 0xCC,
+			[6] 0xE0,
+			[0] 0xBA,
+			[2] 0xBC,
+			[3] 0xBE,
+			[1] 0xCA, },
+};
+
+static unsigned int p4_escr_addr(unsigned int pmc, unsigned int cccr_val)
+{
+	unsigned int escr_select, pair, escr_offset;
+
+	escr_select = P4_CCCR_ESCR_SELECT(cccr_val);
+	if (pmc > 0x11)
+		return 0;	/* pmc range error */
+	if (pmc > 0x0F)
+		pmc -= 3;	/* 0 <= pmc <= 0x0F */
+	pair = pmc / 2;		/* 0 <= pair <= 7 */
+	escr_offset = p4_cccr_escr_map[pair / 2][escr_select];
+	if (!escr_offset || (pair == 7 && escr_select == 3))
+		return 0;	/* ESCR SELECT range error */
+	return escr_offset + (pair & 1) + 0x300;
+};
+
+static int p4_IQ_ESCR_ok;	/* only models <= 2 can use IQ_ESCR{0,1} */
+static int p4_is_ht;		/* affects several CCCR & ESCR fields */
+static int p4_extended_cascade_ok;	/* only models >= 2 can use extended cascading */
+
+static int p4_check_control(struct perfctr_cpu_state *state, int is_global)
+{
+	unsigned int i, nractrs, nrctrs, pmc_mask;
+
+	nractrs = state->control.nractrs;
+	nrctrs = nractrs + state->control.nrictrs;
+	if (nrctrs < nractrs || nrctrs > 18)
+		return -EINVAL;
+
+	pmc_mask = 0;
+	for(i = 0; i < nrctrs; ++i) {
+		unsigned int pmc, cccr_val, escr_val, escr_addr;
+		/* check that pmc_map[] is well-defined;
+		   pmc_map[i] is what we pass to RDPMC, the PMC itself
+		   is extracted by masking off the FAST_RDPMC flag */
+		pmc = state->control.pmc_map[i] & ~P4_FAST_RDPMC;
+		state->pmc[i].map = state->control.pmc_map[i];
+		if (pmc >= 18 || (pmc_mask & (1<<pmc)))
+			return -EINVAL;
+		pmc_mask |= (1<<pmc);
+		/* check CCCR contents */
+		cccr_val = state->control.evntsel[i];
+		if (cccr_val & P4_CCCR_RESERVED)
+			return -EPERM;
+		if (cccr_val & P4_CCCR_EXTENDED_CASCADE) {
+			if (!p4_extended_cascade_ok)
+				return -EPERM;
+			if (!(pmc == 12 || pmc >= 15))
+				return -EPERM;
+		}
+		if ((cccr_val & P4_CCCR_ACTIVE_THREAD) != P4_CCCR_ACTIVE_THREAD && !p4_is_ht)
+			return -EINVAL;
+		if (!(cccr_val & (P4_CCCR_ENABLE | P4_CCCR_CASCADE | P4_CCCR_EXTENDED_CASCADE)))
+			return -EINVAL;
+		if (cccr_val & P4_CCCR_OVF_PMI_T0) {
+			if (i < nractrs)
+				return -EINVAL;
+			if ((cccr_val & P4_CCCR_FORCE_OVF) &&
+			    state->control.ireset[i] != -1)
+				return -EINVAL;
+		} else {
+			if (i >= nractrs)
+				return -EINVAL;
+		}
+		/* check ESCR contents */
+		escr_val = state->control.p4.escr[i];
+		if (escr_val & P4_ESCR_RESERVED)
+			return -EPERM;
+		if ((escr_val & P4_ESCR_CPL_T1) && (!p4_is_ht || !is_global))
+			return -EINVAL;
+		/* compute and cache ESCR address */
+		escr_addr = p4_escr_addr(pmc, cccr_val);
+		if (!escr_addr)
+			return -EINVAL;		/* ESCR SELECT range error */
+		/* IQ_ESCR0 and IQ_ESCR1 only exist in models <= 2 */
+		if ((escr_addr & ~0x001) == 0x3BA && !p4_IQ_ESCR_ok)
+			return -EINVAL;
+		/* XXX: Two counters could map to the same ESCR. Should we
+		   check that they use the same ESCR value? */
+		state->p4_escr_map[i] = escr_addr - MSR_P4_ESCR0;
+	}
+	/* check ReplayTagging control (PEBS_ENABLE and PEBS_MATRIX_VERT) */
+	if (state->control.p4.pebs_enable) {
+		if (!nrctrs)
+			return -EPERM;
+		if (state->control.p4.pebs_enable & P4_PE_RESERVED)
+			return -EPERM;
+		if (!(state->control.p4.pebs_enable & P4_PE_UOP_TAG))
+			return -EINVAL;
+		if (!(state->control.p4.pebs_enable & P4_PE_REPLAY_TAG_BITS))
+			return -EINVAL;
+		if (state->control.p4.pebs_matrix_vert & P4_PMV_RESERVED)
+			return -EPERM;
+		if (!(state->control.p4.pebs_matrix_vert & P4_PMV_REPLAY_TAG_BITS))
+			return -EINVAL;
+	} else if (state->control.p4.pebs_matrix_vert)
+		return -EPERM;
+	state->k1.id = new_id();
+	return 0;
+}
+
+#ifdef PERFCTR_INTERRUPT_SUPPORT
+static void p4_isuspend(struct perfctr_cpu_state *state)
+{
+	return p6_like_isuspend(state, MSR_P4_CCCR0);
+}
+
+static void p4_iresume(const struct perfctr_cpu_state *state)
+{
+	return p6_like_iresume(state, MSR_P4_CCCR0, MSR_P4_PERFCTR0);
+}
+#endif	/* PERFCTR_INTERRUPT_SUPPORT */
+
+static void p4_write_control(const struct perfctr_cpu_state *state)
+{
+	struct per_cpu_cache *cache;
+	unsigned int nrctrs, i;
+
+	cache = &__get_cpu_var(per_cpu_cache);
+	if (cache->k1.id == state->k1.id)
+		return;
+	nrctrs = perfctr_cstatus_nrctrs(state->cstatus);
+	for(i = 0; i < nrctrs; ++i) {
+		unsigned int escr_val, escr_off, cccr_val, pmc;
+		escr_val = state->control.p4.escr[i];
+		escr_off = state->p4_escr_map[i];
+		if (escr_val != cache->control.escr[escr_off]) {
+			cache->control.escr[escr_off] = escr_val;
+			wrmsr(MSR_P4_ESCR0+escr_off, escr_val, 0);
+		}
+		cccr_val = state->control.evntsel[i];
+		pmc = state->pmc[i].map & P4_MASK_FAST_RDPMC;
+		if (cccr_val != cache->control.evntsel[pmc]) {
+			cache->control.evntsel[pmc] = cccr_val;
+			wrmsr(MSR_P4_CCCR0+pmc, cccr_val, 0);
+		}
+	}
+	if (state->control.p4.pebs_enable != cache->control.pebs_enable) {
+		cache->control.pebs_enable = state->control.p4.pebs_enable;
+		wrmsr(MSR_P4_PEBS_ENABLE, state->control.p4.pebs_enable, 0);
+	}
+	if (state->control.p4.pebs_matrix_vert != cache->control.pebs_matrix_vert) {
+		cache->control.pebs_matrix_vert = state->control.p4.pebs_matrix_vert;
+		wrmsr(MSR_P4_PEBS_MATRIX_VERT, state->control.p4.pebs_matrix_vert, 0);
+	}
+	cache->k1.id = state->k1.id;
+}
+
+static void p4_clear_counters(void)
+{
+	/* MSR 0x3F0 seems to have a default value of 0xFC00, but current
+	   docs doesn't fully define it, so leave it alone for now. */
+	/* clear PEBS_ENABLE and PEBS_MATRIX_VERT; they handle both PEBS
+	   and ReplayTagging, and should exist even if PEBS is disabled */
+	clear_msr_range(0x3F1, 2);
+	clear_msr_range(0x3A0, 31);
+	clear_msr_range(0x3C0, 6);
+	clear_msr_range(0x3C8, 6);
+	clear_msr_range(0x3E0, 2);
+	clear_msr_range(MSR_P4_CCCR0, 18);
+	clear_msr_range(MSR_P4_PERFCTR0, 18);
+}
+
+/*
+ * Generic driver for any x86 with a working TSC.
+ */
+
+static int generic_check_control(struct perfctr_cpu_state *state, int is_global)
+{
+	if (state->control.nractrs || state->control.nrictrs)
+		return -EINVAL;
+	return 0;
+}
+
+static void generic_clear_counters(void)
+{
+}
+
+/*
+ * Driver methods, internal and exported.
+ *
+ * Frequently called functions (write_control, read_counters,
+ * isuspend and iresume) are back-patched to invoke the correct
+ * processor-specific methods directly, thereby saving the
+ * overheads of indirect function calls.
+ *
+ * Backpatchable call sites must have been "finalised" after
+ * initialisation. The reason for this is that unsynchronised code
+ * modification doesn't work in multiprocessor systems, due to
+ * Intel P6 errata. Consequently, all backpatchable call sites
+ * must be known and local to this file.
+ *
+ * Backpatchable calls must initially be to 'noinline' stubs.
+ * Otherwise the compiler may inline the stubs, which breaks
+ * redirect_call() and finalise_backpatching().
+ */
+
+static int redirect_call_disable;
+
+static noinline void redirect_call(void *ra, void *to)
+{
+	/* XXX: make this function __init later */
+	if (redirect_call_disable)
+		printk(KERN_ERR __FILE__ ":%s: unresolved call to %p at %p\n",
+		       __FUNCTION__, to, ra);
+	/* we can only redirect `call near relative' instructions */
+	if (*((unsigned char*)ra - 5) != 0xE8) {
+		printk(KERN_WARNING __FILE__ ":%s: unable to redirect caller %p to %p\n",
+		       __FUNCTION__, ra, to);
+		return;
+	}
+	*(int*)((char*)ra - 4) = (char*)to - (char*)ra;
+}
+
+static void (*write_control)(const struct perfctr_cpu_state*);
+static noinline void perfctr_cpu_write_control(const struct perfctr_cpu_state *state)
+{
+	redirect_call(__builtin_return_address(0), write_control);
+	return write_control(state);
+}
+
+static void (*read_counters)(const struct perfctr_cpu_state*,
+			     struct perfctr_low_ctrs*);
+static noinline void perfctr_cpu_read_counters(const struct perfctr_cpu_state *state,
+					       struct perfctr_low_ctrs *ctrs)
+{
+	redirect_call(__builtin_return_address(0), read_counters);
+	return read_counters(state, ctrs);
+}
+
+#ifdef PERFCTR_INTERRUPT_SUPPORT
+static void (*cpu_isuspend)(struct perfctr_cpu_state*);
+static noinline void perfctr_cpu_isuspend(struct perfctr_cpu_state *state)
+{
+	redirect_call(__builtin_return_address(0), cpu_isuspend);
+	return cpu_isuspend(state);
+}
+
+static void (*cpu_iresume)(const struct perfctr_cpu_state*);
+static noinline void perfctr_cpu_iresume(const struct perfctr_cpu_state *state)
+{
+	redirect_call(__builtin_return_address(0), cpu_iresume);
+	return cpu_iresume(state);
+}
+
+/* Call perfctr_cpu_ireload() just before perfctr_cpu_resume() to
+   bypass internal caching and force a reload if the I-mode PMCs. */
+void perfctr_cpu_ireload(struct perfctr_cpu_state *state)
+{
+#ifdef CONFIG_SMP
+	clear_isuspend_cpu(state);
+#else
+	__get_cpu_var(per_cpu_cache).k1.id = 0;
+#endif
+}
+
+/* PRE: the counters have been suspended and sampled by perfctr_cpu_suspend() */
+static int lvtpc_reinit_needed;
+unsigned int perfctr_cpu_identify_overflow(struct perfctr_cpu_state *state)
+{
+	unsigned int cstatus, nrctrs, pmc, pmc_mask;
+
+	cstatus = state->cstatus;
+	pmc = perfctr_cstatus_nractrs(cstatus);
+	nrctrs = perfctr_cstatus_nrctrs(cstatus);
+
+	for(pmc_mask = 0; pmc < nrctrs; ++pmc) {
+		if ((int)state->pmc[pmc].start >= 0) { /* XXX: ">" ? */
+			/* XXX: "+=" to correct for overshots */
+			state->pmc[pmc].start = state->control.ireset[pmc];
+			pmc_mask |= (1 << pmc);
+			/* On a P4 we should now clear the OVF flag in the
+			   counter's CCCR. However, p4_isuspend() already
+			   did that as a side-effect of clearing the CCCR
+			   in order to stop the i-mode counters. */
+		}
+	}
+	if (lvtpc_reinit_needed)
+		apic_write(APIC_LVTPC, LOCAL_PERFCTR_VECTOR);
+	return pmc_mask;
+}
+
+static inline int check_ireset(const struct perfctr_cpu_state *state)
+{
+	unsigned int nrctrs, i;
+
+	i = state->control.nractrs;
+	nrctrs = i + state->control.nrictrs;
+	for(; i < nrctrs; ++i)
+		if (state->control.ireset[i] >= 0)
+			return -EINVAL;
+	return 0;
+}
+
+static inline void setup_imode_start_values(struct perfctr_cpu_state *state)
+{
+	unsigned int cstatus, nrctrs, i;
+
+	cstatus = state->cstatus;
+	nrctrs = perfctr_cstatus_nrctrs(cstatus);
+	for(i = perfctr_cstatus_nractrs(cstatus); i < nrctrs; ++i)
+		state->pmc[i].start = state->control.ireset[i];
+}
+
+#else	/* PERFCTR_INTERRUPT_SUPPORT */
+static inline void perfctr_cpu_isuspend(struct perfctr_cpu_state *state) { }
+static inline void perfctr_cpu_iresume(const struct perfctr_cpu_state *state) { }
+static inline int check_ireset(const struct perfctr_cpu_state *state) { return 0; }
+static inline void setup_imode_start_values(struct perfctr_cpu_state *state) { }
+#endif	/* PERFCTR_INTERRUPT_SUPPORT */
+
+static int (*check_control)(struct perfctr_cpu_state*, int);
+int perfctr_cpu_update_control(struct perfctr_cpu_state *state, int is_global)
+{
+	int err;
+
+	clear_isuspend_cpu(state);
+	state->cstatus = 0;
+
+	/* disallow i-mode counters if we cannot catch the interrupts */
+	if (!(perfctr_info.cpu_features & PERFCTR_FEATURE_PCINT)
+	    && state->control.nrictrs)
+		return -EPERM;
+
+	err = check_control(state, is_global);
+	if (err < 0)
+		return err;
+	err = check_ireset(state);
+	if (err < 0)
+		return err;
+	state->cstatus = perfctr_mk_cstatus(state->control.tsc_on,
+					    state->control.nractrs,
+					    state->control.nrictrs);
+	setup_imode_start_values(state);
+	return 0;
+}
+
+void perfctr_cpu_suspend(struct perfctr_cpu_state *state)
+{
+	unsigned int i, cstatus, nractrs;
+	struct perfctr_low_ctrs now;
+
+	if (perfctr_cstatus_has_ictrs(state->cstatus))
+	    perfctr_cpu_isuspend(state);
+	perfctr_cpu_read_counters(state, &now);
+	cstatus = state->cstatus;
+	if (perfctr_cstatus_has_tsc(cstatus))
+		state->tsc_sum += now.tsc - state->tsc_start;
+	nractrs = perfctr_cstatus_nractrs(cstatus);
+	for(i = 0; i < nractrs; ++i)
+		state->pmc[i].sum += now.pmc[i] - state->pmc[i].start;
+	/* perfctr_cpu_disable_rdpmc(); */	/* not for x86 */
+}
+
+void perfctr_cpu_resume(struct perfctr_cpu_state *state)
+{
+	if (perfctr_cstatus_has_ictrs(state->cstatus))
+	    perfctr_cpu_iresume(state);
+	/* perfctr_cpu_enable_rdpmc(); */	/* not for x86 or global-mode */
+	perfctr_cpu_write_control(state);
+	//perfctr_cpu_read_counters(state, &state->start);
+	{
+		struct perfctr_low_ctrs now;
+		unsigned int i, cstatus, nrctrs;
+		perfctr_cpu_read_counters(state, &now);
+		cstatus = state->cstatus;
+		if (perfctr_cstatus_has_tsc(cstatus))
+			state->tsc_start = now.tsc;
+		nrctrs = perfctr_cstatus_nractrs(cstatus);
+		for(i = 0; i < nrctrs; ++i)
+			state->pmc[i].start = now.pmc[i];
+	}
+	/* XXX: if (SMP && start.tsc == now.tsc) ++now.tsc; */
+}
+
+void perfctr_cpu_sample(struct perfctr_cpu_state *state)
+{
+	unsigned int i, cstatus, nractrs;
+	struct perfctr_low_ctrs now;
+
+	perfctr_cpu_read_counters(state, &now);
+	cstatus = state->cstatus;
+	if (perfctr_cstatus_has_tsc(cstatus)) {
+		state->tsc_sum += now.tsc - state->tsc_start;
+		state->tsc_start = now.tsc;
+	}
+	nractrs = perfctr_cstatus_nractrs(cstatus);
+	for(i = 0; i < nractrs; ++i) {
+		state->pmc[i].sum += now.pmc[i] - state->pmc[i].start;
+		state->pmc[i].start = now.pmc[i];
+	}
+}
+
+static void (*clear_counters)(void);
+static void perfctr_cpu_clear_counters(void)
+{
+	return clear_counters();
+}
+
+/****************************************************************
+ *								*
+ * Processor detection and initialisation procedures.		*
+ *								*
+ ****************************************************************/
+
+static inline void clear_perfctr_cpus_forbidden_mask(void)
+{
+#if !defined(perfctr_cpus_forbidden_mask)
+	cpus_clear(perfctr_cpus_forbidden_mask);
+#endif
+}
+
+static inline void set_perfctr_cpus_forbidden_mask(cpumask_t mask)
+{
+#if !defined(perfctr_cpus_forbidden_mask)
+	perfctr_cpus_forbidden_mask = mask;
+#endif
+}
+
+/* see comment above at redirect_call() */
+static void __init finalise_backpatching(void)
+{
+	struct per_cpu_cache *cache;
+	struct perfctr_cpu_state state;
+	cpumask_t old_mask;
+
+	old_mask = perfctr_cpus_forbidden_mask;
+	clear_perfctr_cpus_forbidden_mask();
+
+	cache = &__get_cpu_var(per_cpu_cache);
+	memset(cache, 0, sizeof *cache);
+	memset(&state, 0, sizeof state);
+	state.cstatus =
+		(perfctr_info.cpu_features & PERFCTR_FEATURE_PCINT)
+		? perfctr_mk_cstatus(0, 0, 1)
+		: 0;
+	perfctr_cpu_sample(&state);
+	perfctr_cpu_resume(&state);
+	perfctr_cpu_suspend(&state);
+
+	set_perfctr_cpus_forbidden_mask(old_mask);
+
+	redirect_call_disable = 1;
+}
+
+#ifdef CONFIG_SMP
+
+cpumask_t perfctr_cpus_forbidden_mask;
+
+static void __init p4_ht_mask_setup_cpu(void *forbidden)
+{
+	unsigned int local_apic_physical_id = cpuid_ebx(1) >> 24;
+	unsigned int logical_processor_id = local_apic_physical_id & 1;
+	if (logical_processor_id != 0)
+		/* We rely on cpu_set() being atomic! */
+		cpu_set(smp_processor_id(), *(cpumask_t*)forbidden);
+}
+
+static int __init p4_ht_smp_init(void)
+{
+	cpumask_t forbidden;
+	unsigned int cpu;
+
+	cpus_clear(forbidden);
+	smp_call_function(p4_ht_mask_setup_cpu, &forbidden, 1, 1);
+	p4_ht_mask_setup_cpu(&forbidden);
+	if (cpus_empty(forbidden))
+		return 0;
+	perfctr_cpus_forbidden_mask = forbidden;
+	printk(KERN_INFO "perfctr/x86.c: hyper-threaded P4s detected:"
+	       " restricting access for CPUs");
+	for(cpu = 0; cpu < NR_CPUS; ++cpu)
+		if (cpu_isset(cpu, forbidden))
+			printk(" %u", cpu);
+	printk("\n");
+	return 0;
+}
+#else /* SMP */
+#define p4_ht_smp_init()	(0)
+#endif /* SMP */
+
+static int __init p4_ht_init(void)
+{
+	unsigned int nr_siblings;
+
+	if (!cpu_has_ht)
+		return 0;
+	nr_siblings = (cpuid_ebx(1) >> 16) & 0xFF;
+	if (nr_siblings > 2) {
+		printk(KERN_WARNING "perfctr/x86.c: hyper-threaded P4s detected:"
+		       " unsupported number of siblings: %u -- bailing out\n",
+		       nr_siblings);
+		return -ENODEV;
+	}
+	if (nr_siblings < 2)
+		return 0;
+	p4_is_ht = 1;	/* needed even in a UP kernel */
+	return p4_ht_smp_init();
+}
+
+static int __init intel_init(void)
+{
+	static char p5_name[] __initdata = "Intel P5";
+	static char p6_name[] __initdata = "Intel P6";
+	static char p4_name[] __initdata = "Intel P4";
+	unsigned int misc_enable;
+
+	if (!cpu_has_tsc)
+		return -ENODEV;
+	switch (current_cpu_data.x86) {
+	case 5:
+		if (cpu_has_mmx) {
+			read_counters = rdpmc_read_counters;
+
+			/* Avoid Pentium Erratum 74. */
+			if (current_cpu_data.x86_model == 4 &&
+			    (current_cpu_data.x86_mask == 4 ||
+			     (current_cpu_data.x86_mask == 3 &&
+			      ((cpuid_eax(1) >> 12) & 0x3) == 1)))
+				perfctr_info.cpu_features &= ~PERFCTR_FEATURE_RDPMC;
+		} else {
+			perfctr_info.cpu_features &= ~PERFCTR_FEATURE_RDPMC;
+			read_counters = p5_read_counters;
+		}
+		perfctr_set_tests_type(PTT_P5);
+		perfctr_cpu_name = p5_name;
+		write_control = p5_write_control;
+		check_control = p5_check_control;
+		clear_counters = p5_clear_counters;
+		return 0;
+	case 6:
+		if (current_cpu_data.x86_model == 9) {	/* Pentium M */
+			/* Pentium M added the MISC_ENABLE MSR from P4. */
+			rdmsr_low(MSR_IA32_MISC_ENABLE, misc_enable);
+			if (!(misc_enable & MSR_IA32_MISC_ENABLE_PERF_AVAIL))
+				break;
+			/* Erratum Y3 probably does not apply since we
+			   read only the low 32 bits. */
+		} else if (current_cpu_data.x86_model < 3) {	/* Pentium Pro */
+			/* Avoid Pentium Pro Erratum 26. */
+			if (current_cpu_data.x86_mask < 9)
+				perfctr_info.cpu_features &= ~PERFCTR_FEATURE_RDPMC;
+		}
+		perfctr_set_tests_type(PTT_P6);
+		perfctr_cpu_name = p6_name;
+		read_counters = rdpmc_read_counters;
+		write_control = p6_write_control;
+		check_control = p6_check_control;
+		clear_counters = p6_clear_counters;
+#ifdef PERFCTR_INTERRUPT_SUPPORT
+		if (cpu_has_apic) {
+			perfctr_info.cpu_features |= PERFCTR_FEATURE_PCINT;
+			cpu_isuspend = p6_isuspend;
+			cpu_iresume = p6_iresume;
+			/* P-M apparently inherited P4's LVTPC auto-masking :-( */
+			if (current_cpu_data.x86_model == 9)
+				lvtpc_reinit_needed = 1;
+		}
+#endif
+		return 0;
+	case 15:	/* Pentium 4 */
+		rdmsr_low(MSR_IA32_MISC_ENABLE, misc_enable);
+		if (!(misc_enable & MSR_IA32_MISC_ENABLE_PERF_AVAIL))
+			break;
+		if (p4_ht_init() != 0)
+			break;
+		if (current_cpu_data.x86_model <= 2)
+			p4_IQ_ESCR_ok = 1;
+		if (current_cpu_data.x86_model >= 2)
+			p4_extended_cascade_ok = 1;
+		perfctr_set_tests_type(PTT_P4);
+		perfctr_cpu_name = p4_name;
+		read_counters = rdpmc_read_counters;
+		write_control = p4_write_control;
+		check_control = p4_check_control;
+		clear_counters = p4_clear_counters;
+#ifdef PERFCTR_INTERRUPT_SUPPORT
+		if (cpu_has_apic) {
+			perfctr_info.cpu_features |= PERFCTR_FEATURE_PCINT;
+			cpu_isuspend = p4_isuspend;
+			cpu_iresume = p4_iresume;
+			lvtpc_reinit_needed = 1;
+		}
+#endif
+		return 0;
+	}
+	return -ENODEV;
+}
+
+static int __init amd_init(void)
+{
+	static char amd_name[] __initdata = "AMD K7/K8";
+
+	if (!cpu_has_tsc)
+		return -ENODEV;
+	switch (current_cpu_data.x86) {
+	case 6: /* K7 */
+	case 15: /* K8. Like a K7 with a different event set. */
+		break;
+	default:
+		return -ENODEV;
+	}
+	perfctr_set_tests_type(PTT_AMD);
+	perfctr_cpu_name = amd_name;
+	read_counters = rdpmc_read_counters;
+	write_control = k7_write_control;
+	check_control = k7_check_control;
+	clear_counters = k7_clear_counters;
+#ifdef PERFCTR_INTERRUPT_SUPPORT
+	if (cpu_has_apic) {
+		perfctr_info.cpu_features |= PERFCTR_FEATURE_PCINT;
+		cpu_isuspend = k7_isuspend;
+		cpu_iresume = k7_iresume;
+	}
+#endif
+	return 0;
+}
+
+static int __init cyrix_init(void)
+{
+	static char mii_name[] __initdata = "Cyrix 6x86MX/MII/III";
+	if (!cpu_has_tsc)
+		return -ENODEV;
+	switch (current_cpu_data.x86) {
+	case 6:	/* 6x86MX, MII, or III */
+		perfctr_set_tests_type(PTT_P5);
+		perfctr_cpu_name = mii_name;
+		read_counters = rdpmc_read_counters;
+		write_control = p5_write_control;
+		check_control = mii_check_control;
+		clear_counters = p5_clear_counters;
+		return 0;
+	}
+	return -ENODEV;
+}
+
+static int __init centaur_init(void)
+{
+#if !defined(CONFIG_X86_TSC)
+	static char winchip_name[] __initdata = "WinChip C6/2/3";
+#endif
+	static char vc3_name[] __initdata = "VIA C3";
+	switch (current_cpu_data.x86) {
+#if !defined(CONFIG_X86_TSC)
+	case 5:
+		switch (current_cpu_data.x86_model) {
+		case 4: /* WinChip C6 */
+		case 8: /* WinChip 2, 2A, or 2B */
+		case 9: /* WinChip 3, a 2A with larger cache and lower voltage */
+			break;
+		default:
+			return -ENODEV;
+		}
+		perfctr_set_tests_type(PTT_WINCHIP);
+		perfctr_cpu_name = winchip_name;
+		/*
+		 * TSC must be inaccessible for perfctrs to work.
+		 */
+		if (!(read_cr4() & X86_CR4_TSD) || cpu_has_tsc)
+			return -ENODEV;
+		perfctr_info.cpu_features &= ~PERFCTR_FEATURE_RDTSC;
+		read_counters = rdpmc_read_counters;
+		write_control = c6_write_control;
+		check_control = c6_check_control;
+		clear_counters = p5_clear_counters;
+		return 0;
+#endif
+	case 6: /* VIA C3 */
+		if (!cpu_has_tsc)
+			return -ENODEV;
+		switch (current_cpu_data.x86_model) {
+		case 6:	/* Cyrix III */
+		case 7:	/* Samuel 2, Ezra (steppings >= 8) */
+		case 8:	/* Ezra-T */
+		case 9: /* Antaur/Nehemiah */
+			break;
+		default:
+			return -ENODEV;
+		}
+		perfctr_set_tests_type(PTT_VC3);
+		perfctr_cpu_name = vc3_name;
+		read_counters = rdpmc_read_counters;
+		write_control = p6_write_control;
+		check_control = vc3_check_control;
+		clear_counters = vc3_clear_counters;
+		return 0;
+	}
+	return -ENODEV;
+}
+
+static int __init generic_init(void)
+{
+	static char generic_name[] __initdata = "Generic x86 with TSC";
+	if (!cpu_has_tsc)
+		return -ENODEV;
+	perfctr_info.cpu_features &= ~PERFCTR_FEATURE_RDPMC;
+	perfctr_set_tests_type(PTT_GENERIC);
+	perfctr_cpu_name = generic_name;
+	check_control = generic_check_control;
+	write_control = p6_write_control;
+	read_counters = rdpmc_read_counters;
+	clear_counters = generic_clear_counters;
+	return 0;
+}
+
+static void perfctr_cpu_invalidate_cache(void)
+{
+	/*
+	 * per_cpu_cache[] is initialised to contain "impossible"
+	 * evntsel values guaranteed to differ from anything accepted
+	 * by perfctr_cpu_update_control().
+	 * All-bits-one works for all currently supported processors.
+	 * The memset also sets the ids to -1, which is intentional.
+	 */
+	memset(&__get_cpu_var(per_cpu_cache), ~0,
+	       sizeof(struct per_cpu_cache));
+}
+
+static void perfctr_cpu_init_one(void *ignore)
+{
+	/* PREEMPT note: when called via smp_call_function(),
+	   this is in IRQ context with preemption disabled. */
+	perfctr_cpu_clear_counters();
+	perfctr_cpu_invalidate_cache();
+	if (cpu_has_apic)
+		apic_write(APIC_LVTPC, LOCAL_PERFCTR_VECTOR);
+	if (perfctr_info.cpu_features & PERFCTR_FEATURE_RDPMC)
+		set_in_cr4_local(X86_CR4_PCE);
+}
+
+static void perfctr_cpu_exit_one(void *ignore)
+{
+	/* PREEMPT note: when called via smp_call_function(),
+	   this is in IRQ context with preemption disabled. */
+	perfctr_cpu_clear_counters();
+	perfctr_cpu_invalidate_cache();
+	if (cpu_has_apic)
+		apic_write(APIC_LVTPC, APIC_DM_NMI | APIC_LVT_MASKED);
+	if (perfctr_info.cpu_features & PERFCTR_FEATURE_RDPMC)
+		clear_in_cr4_local(X86_CR4_PCE);
+}
+
+#if defined(CONFIG_X86_LOCAL_APIC) && defined(CONFIG_PM)
+
+static void perfctr_pm_suspend(void)
+{
+	/* XXX: clear control registers */
+	printk("perfctr/x86: PM suspend\n");
+}
+
+static void perfctr_pm_resume(void)
+{
+	/* XXX: reload control registers */
+	printk("perfctr/x86: PM resume\n");
+}
+
+#include <linux/sysdev.h>
+
+static int perfctr_device_suspend(struct sys_device *dev, u32 state)
+{
+	perfctr_pm_suspend();
+	return 0;
+}
+
+static int perfctr_device_resume(struct sys_device *dev)
+{
+	perfctr_pm_resume();
+	return 0;
+}
+
+static struct sysdev_class perfctr_sysclass = {
+	set_kset_name("perfctr"),
+	.resume		= perfctr_device_resume,
+	.suspend	= perfctr_device_suspend,
+};
+
+static struct sys_device device_perfctr = {
+	.id	= 0,
+	.cls	= &perfctr_sysclass,
+};
+
+static void x86_pm_init(void)
+{
+	if (sysdev_class_register(&perfctr_sysclass) == 0)
+		sysdev_register(&device_perfctr);
+}
+
+static void x86_pm_exit(void)
+{
+	sysdev_unregister(&device_perfctr);
+	sysdev_class_unregister(&perfctr_sysclass);
+}
+
+#else
+
+static inline void x86_pm_init(void) { }
+static inline void x86_pm_exit(void) { }
+
+#endif	/* CONFIG_X86_LOCAL_APIC && CONFIG_PM */
+
+#if !defined(CONFIG_X86_LOCAL_APIC)
+static inline int reserve_lapic_nmi(void) { return 0; }
+static inline void release_lapic_nmi(void) { }
+#endif
+
+static void do_init_tests(void)
+{
+#ifdef CONFIG_PERFCTR_INIT_TESTS
+	if (reserve_lapic_nmi() >= 0) {
+		perfctr_x86_init_tests();
+		release_lapic_nmi();
+	}
+#endif
+}
+
+static int init_done;
+
+int __init perfctr_cpu_init(void)
+{
+	int err = -ENODEV;
+
+	preempt_disable();
+
+	/* RDPMC and RDTSC are on by default. They will be disabled
+	   by the init procedures if necessary. */
+	perfctr_info.cpu_features = PERFCTR_FEATURE_RDPMC | PERFCTR_FEATURE_RDTSC;
+
+	if (cpu_has_msr) {
+		switch (current_cpu_data.x86_vendor) {
+		case X86_VENDOR_INTEL:
+			err = intel_init();
+			break;
+		case X86_VENDOR_AMD:
+			err = amd_init();
+			break;
+		case X86_VENDOR_CYRIX:
+			err = cyrix_init();
+			break;
+		case X86_VENDOR_CENTAUR:
+			err = centaur_init();
+		}
+	}
+	if (err) {
+		err = generic_init();	/* last resort */
+		if (err)
+			goto out;
+	}
+	do_init_tests();
+	finalise_backpatching();
+
+	perfctr_info.cpu_khz = cpu_khz;
+	perfctr_info.tsc_to_cpu_mult = 1;
+	init_done = 1;
+
+ out:
+	preempt_enable();
+	return err;
+}
+
+void __exit perfctr_cpu_exit(void)
+{
+}
+
+/****************************************************************
+ *								*
+ * Hardware reservation.					*
+ *								*
+ ****************************************************************/
+
+static DECLARE_MUTEX(mutex);
+static const char *current_service = 0;
+
+const char *perfctr_cpu_reserve(const char *service)
+{
+	const char *ret;
+
+	if (!init_done)
+		return "unsupported hardware";
+	down(&mutex);
+	ret = current_service;
+	if (ret)
+		goto out_up;
+	ret = "unknown driver (oprofile?)";
+	if (reserve_lapic_nmi() < 0)
+		goto out_up;
+	current_service = service;
+	if (perfctr_info.cpu_features & PERFCTR_FEATURE_RDPMC)
+		mmu_cr4_features |= X86_CR4_PCE;
+	on_each_cpu(perfctr_cpu_init_one, NULL, 1, 1);
+	perfctr_cpu_set_ihandler(NULL);
+	x86_pm_init();
+	ret = NULL;
+ out_up:
+	up(&mutex);
+	return ret;
+}
+
+void perfctr_cpu_release(const char *service)
+{
+	down(&mutex);
+	if (service != current_service) {
+		printk(KERN_ERR "%s: attempt by %s to release while reserved by %s\n",
+		       __FUNCTION__, service, current_service);
+		goto out_up;
+	}
+	/* power down the counters */
+	if (perfctr_info.cpu_features & PERFCTR_FEATURE_RDPMC)
+		mmu_cr4_features &= ~X86_CR4_PCE;
+	on_each_cpu(perfctr_cpu_exit_one, NULL, 1, 1);
+	perfctr_cpu_set_ihandler(NULL);
+	x86_pm_exit();
+	current_service = 0;
+	release_lapic_nmi();
+ out_up:
+	up(&mutex);
+}
--- diff/drivers/perfctr/x86_tests.c	1970-01-01 01:00:00.000000000 +0100
+++ source/drivers/perfctr/x86_tests.c	2004-06-11 19:22:03.000000000 +0100
@@ -0,0 +1,275 @@
+/* $Id: x86_tests.c,v 1.28 2004/05/23 23:22:44 mikpe Exp $
+ * Performance-monitoring counters driver.
+ * Optional x86/x86_64-specific init-time tests.
+ *
+ * Copyright (C) 1999-2004  Mikael Pettersson
+ */
+#include <linux/config.h>
+#include <linux/init.h>
+#include <linux/sched.h>
+#include <linux/fs.h>
+#include <linux/perfctr.h>
+#include <asm/msr.h>
+#undef MSR_P6_PERFCTR0
+#undef MSR_P4_IQ_CCCR0
+#undef MSR_P4_CRU_ESCR0
+#include <asm/fixmap.h>
+#include <asm/apic.h>
+#include <asm/timex.h>	/* cpu_khz */
+#include "x86_tests.h"
+
+#define MSR_P5_CESR		0x11
+#define MSR_P5_CTR0		0x12
+#define P5_CESR_VAL		(0x16 | (3<<6))
+#define MSR_P6_PERFCTR0		0xC1
+#define MSR_P6_EVNTSEL0		0x186
+#define P6_EVNTSEL0_VAL		(0xC0 | (3<<16) | (1<<22))
+#define MSR_K7_EVNTSEL0		0xC0010000
+#define MSR_K7_PERFCTR0		0xC0010004
+#define K7_EVNTSEL0_VAL		(0xC0 | (3<<16) | (1<<22))
+#define VC3_EVNTSEL1_VAL	0xC0
+#define MSR_P4_IQ_COUNTER0	0x30C
+#define MSR_P4_IQ_CCCR0		0x36C
+#define MSR_P4_CRU_ESCR0	0x3B8
+#define P4_CRU_ESCR0_VAL	((2<<25) | (1<<9) | (0x3<<2))
+#define P4_IQ_CCCR0_VAL		((0x3<<16) | (4<<13) | (1<<12))
+
+#define NITER	64
+#define X2(S)	S";"S
+#define X8(S)	X2(X2(X2(S)))
+
+#ifdef __x86_64__
+#define CR4MOV	"movq"
+#else
+#define CR4MOV	"movl"
+#endif
+
+static void __init do_rdpmc(unsigned pmc, unsigned unused2)
+{
+	unsigned i;
+	for(i = 0; i < NITER/8; ++i)
+		__asm__ __volatile__(X8("rdpmc") : : "c"(pmc) : "eax", "edx");
+}
+
+static void __init do_rdmsr(unsigned msr, unsigned unused2)
+{
+	unsigned i;
+	for(i = 0; i < NITER/8; ++i)
+		__asm__ __volatile__(X8("rdmsr") : : "c"(msr) : "eax", "edx");
+}
+
+static void __init do_wrmsr(unsigned msr, unsigned data)
+{
+	unsigned i;
+	for(i = 0; i < NITER/8; ++i)
+		__asm__ __volatile__(X8("wrmsr") : : "c"(msr), "a"(data), "d"(0));
+}
+
+static void __init do_rdcr4(unsigned unused1, unsigned unused2)
+{
+	unsigned i;
+	unsigned long dummy;
+	for(i = 0; i < NITER/8; ++i)
+		__asm__ __volatile__(X8(CR4MOV" %%cr4,%0") : "=r"(dummy));
+}
+
+static void __init do_wrcr4(unsigned cr4, unsigned unused2)
+{
+	unsigned i;
+	for(i = 0; i < NITER/8; ++i)
+		__asm__ __volatile__(X8(CR4MOV" %0,%%cr4") : : "r"((long)cr4));
+}
+
+static void __init do_rdtsc(unsigned unused1, unsigned unused2)
+{
+	unsigned i;
+	for(i = 0; i < NITER/8; ++i)
+		__asm__ __volatile__(X8("rdtsc") : : : "eax", "edx");
+}
+
+static void __init do_wrlvtpc(unsigned val, unsigned unused2)
+{
+	unsigned i;
+	for(i = 0; i < NITER/8; ++i) {
+		apic_write(APIC_LVTPC, val);
+		apic_write(APIC_LVTPC, val);
+		apic_write(APIC_LVTPC, val);
+		apic_write(APIC_LVTPC, val);
+		apic_write(APIC_LVTPC, val);
+		apic_write(APIC_LVTPC, val);
+		apic_write(APIC_LVTPC, val);
+		apic_write(APIC_LVTPC, val);
+	}
+}
+
+static void __init do_empty_loop(unsigned unused1, unsigned unused2)
+{
+	unsigned i;
+	for(i = 0; i < NITER/8; ++i)
+		__asm__ __volatile__("" : : "c"(0));
+}
+
+static unsigned __init run(void (*doit)(unsigned, unsigned),
+			   unsigned arg1, unsigned arg2)
+{
+	unsigned start, dummy, stop;
+	rdtsc(start, dummy);
+	(*doit)(arg1, arg2);	/* should take < 2^32 cycles to complete */
+	rdtsc(stop, dummy);
+	return stop - start;
+}
+
+static void __init init_tests_message(void)
+{
+	printk(KERN_INFO "Please email the following PERFCTR INIT lines "
+	       "to mikpe@csd.uu.se\n"
+	       KERN_INFO "To remove this message, rebuild the driver "
+	       "with CONFIG_PERFCTR_INIT_TESTS=n\n");
+	printk(KERN_INFO "PERFCTR INIT: vendor %u, family %u, model %u, stepping %u, clock %u kHz\n",
+	       current_cpu_data.x86_vendor,
+	       current_cpu_data.x86,
+	       current_cpu_data.x86_model,
+	       current_cpu_data.x86_mask,
+	       (unsigned int)cpu_khz);
+}
+
+static void __init
+measure_overheads(unsigned msr_evntsel0, unsigned evntsel0, unsigned msr_perfctr0,
+		  unsigned msr_cccr, unsigned cccr_val)
+{
+	int i;
+	unsigned int loop, ticks[12];
+	const char *name[12];
+
+	if (msr_evntsel0)
+		wrmsr(msr_evntsel0, 0, 0);
+	if (msr_cccr)
+		wrmsr(msr_cccr, 0, 0);
+
+	name[0] = "rdtsc";
+	ticks[0] = run(do_rdtsc, 0, 0);
+	name[1] = "rdpmc";
+	ticks[1] = (perfctr_info.cpu_features & PERFCTR_FEATURE_RDPMC)
+		? run(do_rdpmc,1,0) : 0;
+	name[2] = "rdmsr (counter)";
+	ticks[2] = msr_perfctr0 ? run(do_rdmsr, msr_perfctr0, 0) : 0;
+	name[3] = msr_cccr ? "rdmsr (escr)" : "rdmsr (evntsel)";
+	ticks[3] = msr_evntsel0 ? run(do_rdmsr, msr_evntsel0, 0) : 0;
+	name[4] = "wrmsr (counter)";
+	ticks[4] = msr_perfctr0 ? run(do_wrmsr, msr_perfctr0, 0) : 0;
+	name[5] = msr_cccr ? "wrmsr (escr)" : "wrmsr (evntsel)";
+	ticks[5] = msr_evntsel0 ? run(do_wrmsr, msr_evntsel0, evntsel0) : 0;
+	name[6] = "read cr4";
+	ticks[6] = run(do_rdcr4, 0, 0);
+	name[7] = "write cr4";
+	ticks[7] = run(do_wrcr4, read_cr4(), 0);
+	name[8] = "rdpmc (fast)";
+	ticks[8] = msr_cccr ? run(do_rdpmc, 0x80000001, 0) : 0;
+	name[9] = "rdmsr (cccr)";
+	ticks[9] = msr_cccr ? run(do_rdmsr, msr_cccr, 0) : 0;
+	name[10] = "wrmsr (cccr)";
+	ticks[10] = msr_cccr ? run(do_wrmsr, msr_cccr, cccr_val) : 0;
+	name[11] = "write LVTPC";
+	ticks[11] = (perfctr_info.cpu_features & PERFCTR_FEATURE_PCINT)
+		? run(do_wrlvtpc, APIC_DM_NMI|APIC_LVT_MASKED, 0) : 0;
+
+	loop = run(do_empty_loop, 0, 0);
+
+	if (msr_evntsel0)
+		wrmsr(msr_evntsel0, 0, 0);
+	if (msr_cccr)
+		wrmsr(msr_cccr, 0, 0);
+
+	init_tests_message();
+	printk(KERN_INFO "PERFCTR INIT: NITER == %u\n", NITER);
+	printk(KERN_INFO "PERFCTR INIT: loop overhead is %u cycles\n", loop);
+	for(i = 0; i < ARRAY_SIZE(ticks); ++i) {
+		unsigned int x;
+		if (!ticks[i])
+			continue;
+		x = ((ticks[i] - loop) * 10) / NITER;
+		printk(KERN_INFO "PERFCTR INIT: %s cost is %u.%u cycles (%u total)\n",
+		       name[i], x/10, x%10, ticks[i]);
+	}
+}
+
+#ifndef __x86_64__
+static inline void perfctr_p5_init_tests(void)
+{
+	measure_overheads(MSR_P5_CESR, P5_CESR_VAL, MSR_P5_CTR0, 0, 0);
+}
+
+static inline void perfctr_p6_init_tests(void)
+{
+	measure_overheads(MSR_P6_EVNTSEL0, P6_EVNTSEL0_VAL, MSR_P6_PERFCTR0, 0, 0);
+}
+
+#if !defined(CONFIG_X86_TSC)
+static inline void perfctr_c6_init_tests(void)
+{
+	unsigned int cesr, dummy;
+
+	rdmsr(MSR_P5_CESR, cesr, dummy);
+	init_tests_message();
+	printk(KERN_INFO "PERFCTR INIT: boot CESR == %#08x\n", cesr);
+}
+#endif
+
+static inline void perfctr_vc3_init_tests(void)
+{
+	measure_overheads(MSR_P6_EVNTSEL0+1, VC3_EVNTSEL1_VAL, MSR_P6_PERFCTR0+1, 0, 0);
+}
+
+static inline void perfctr_p4_init_tests(void)
+{
+	measure_overheads(MSR_P4_CRU_ESCR0, P4_CRU_ESCR0_VAL, MSR_P4_IQ_COUNTER0,
+			  MSR_P4_IQ_CCCR0, P4_IQ_CCCR0_VAL);
+}
+#endif /* !__x86_64__ */
+
+static inline void perfctr_k7_init_tests(void)
+{
+	measure_overheads(MSR_K7_EVNTSEL0, K7_EVNTSEL0_VAL, MSR_K7_PERFCTR0, 0, 0);
+}
+
+static inline void perfctr_generic_init_tests(void)
+{
+	measure_overheads(0, 0, 0, 0, 0);
+}
+
+enum perfctr_x86_tests_type perfctr_x86_tests_type __initdata = PTT_UNKNOWN;
+
+void __init perfctr_x86_init_tests(void)
+{
+	switch (perfctr_x86_tests_type) {
+#ifndef __x86_64__
+	case PTT_P5: /* Intel P5, P5MMX; Cyrix 6x86MX, MII, III */
+		perfctr_p5_init_tests();
+		break;
+	case PTT_P6: /* Intel PPro, PII, PIII, PENTM */
+		perfctr_p6_init_tests();
+		break;
+#if !defined(CONFIG_X86_TSC)
+	case PTT_WINCHIP: /* WinChip C6, 2, 3 */
+		perfctr_c6_init_tests();
+		break;
+#endif
+	case PTT_VC3: /* VIA C3 */
+		perfctr_vc3_init_tests();
+		break;
+	case PTT_P4: /* Intel P4 */
+		perfctr_p4_init_tests();
+		break;
+#endif /* !__x86_64__ */
+	case PTT_AMD: /* AMD K7, K8 */
+		perfctr_k7_init_tests();
+		break;
+	case PTT_GENERIC:
+		perfctr_generic_init_tests();
+		break;
+	default:
+		printk(KERN_INFO "%s: unknown CPU type %u\n",
+		       __FUNCTION__, perfctr_x86_tests_type);
+		break;
+	}
+}
--- diff/drivers/perfctr/x86_tests.h	1970-01-01 01:00:00.000000000 +0100
+++ source/drivers/perfctr/x86_tests.h	2004-06-11 19:22:03.000000000 +0100
@@ -0,0 +1,30 @@
+/* $Id: x86_tests.h,v 1.10 2004/05/22 20:48:57 mikpe Exp $
+ * Performance-monitoring counters driver.
+ * Optional x86/x86_64-specific init-time tests.
+ *
+ * Copyright (C) 1999-2004  Mikael Pettersson
+ */
+
+/* 'enum perfctr_x86_tests_type' classifies CPUs according
+   to relevance for perfctr_x86_init_tests(). */
+enum perfctr_x86_tests_type {
+	PTT_UNKNOWN,
+	PTT_GENERIC,
+	PTT_P5,
+	PTT_P6,
+	PTT_P4,
+	PTT_AMD,
+	PTT_WINCHIP,
+	PTT_VC3,
+};
+
+extern enum perfctr_x86_tests_type perfctr_x86_tests_type;
+
+static inline void perfctr_set_tests_type(enum perfctr_x86_tests_type t)
+{
+#ifdef CONFIG_PERFCTR_INIT_TESTS
+	perfctr_x86_tests_type = t;
+#endif
+}
+
+extern void perfctr_x86_init_tests(void);
--- diff/drivers/scsi/3w-9xxx.c	1970-01-01 01:00:00.000000000 +0100
+++ source/drivers/scsi/3w-9xxx.c	2004-06-11 19:22:03.000000000 +0100
@@ -0,0 +1,2153 @@
+/*
+   3w-9xxx.c -- 3ware 9000 Storage Controller device driver for Linux.
+
+   Written By: Adam Radford <linuxraid@amcc.com>
+
+   Copyright (C) 2004 Applied Micro Circuits Corporation.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; version 2 of the License.
+
+   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.
+
+   NO WARRANTY
+   THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR
+   CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT
+   LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT,
+   MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is
+   solely responsible for determining the appropriateness of using and
+   distributing the Program and assumes all risks associated with its
+   exercise of rights under this Agreement, including but not limited to
+   the risks and costs of program errors, damage to or loss of data,
+   programs or equipment, and unavailability or interruption of operations.
+
+   DISCLAIMER OF LIABILITY
+   NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY
+   DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+   DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND
+   ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
+   TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
+   USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED
+   HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES
+
+   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
+
+   Bugs/Comments/Suggestions should be mailed to:
+   linuxraid@amcc.com
+
+   For more information, goto:
+   http://www.amcc.com
+
+   Note: This version of the driver does not contain a bundled firmware
+         image.
+
+   History
+   -------
+   2.26.02.000 - Driver cleanup for kernel submission.
+   2.26.02.001 - Replace schedule_timeout() calls with msleep().
+*/
+
+#include <linux/module.h>
+#include <linux/reboot.h>
+#include <linux/spinlock.h>
+#include <linux/interrupt.h>
+#include <linux/moduleparam.h>
+#include <linux/errno.h>
+#include <linux/types.h>
+#include <linux/delay.h>
+#include <linux/pci.h>
+#include <linux/time.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/uaccess.h>
+#include <scsi/scsi.h>
+#include <scsi/scsi_host.h>
+#include <scsi/scsi_tcq.h>
+#include <scsi/scsi_cmnd.h>
+#include "3w-9xxx.h"
+
+/* Globals */
+static const char *twa_driver_version="2.26.02.001";
+static TW_Device_Extension *twa_device_extension_list[TW_MAX_SLOT];
+static unsigned int twa_device_extension_count;
+static int twa_major = -1;
+extern struct timezone sys_tz;
+
+/* Module parameters */
+MODULE_AUTHOR ("AMCC");
+MODULE_DESCRIPTION ("3ware 9000 Storage Controller Linux Driver");
+MODULE_LICENSE("GPL");
+
+/* Function prototypes */
+static void twa_aen_queue_event(TW_Device_Extension *tw_dev, TW_Command_Apache_Header *header);
+static int twa_aen_read_queue(TW_Device_Extension *tw_dev, int request_id);
+static char *twa_aen_severity_lookup(unsigned char severity_code);
+static void twa_aen_sync_time(TW_Device_Extension *tw_dev, int request_id);
+static int twa_chrdev_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg);
+static int twa_chrdev_open(struct inode *inode, struct file *file);
+static int twa_fill_sense(TW_Device_Extension *tw_dev, int request_id, int copy_sense, int print_host);
+static void twa_free_request_id(TW_Device_Extension *tw_dev,int request_id);
+static void twa_get_request_id(TW_Device_Extension *tw_dev, int *request_id);
+static int twa_initconnection(TW_Device_Extension *tw_dev, int message_credits,
+ 			      u32 set_features, unsigned short current_fw_srl, 
+			      unsigned short current_fw_arch_id, 
+			      unsigned short current_fw_branch, 
+			      unsigned short current_fw_build, 
+			      unsigned short *fw_on_ctlr_srl, 
+			      unsigned short *fw_on_ctlr_arch_id, 
+			      unsigned short *fw_on_ctlr_branch, 
+			      unsigned short *fw_on_ctlr_build, 
+			      u32 *init_connect_result);
+static void twa_load_sgl(TW_Command_Full *full_command_packet, int request_id, dma_addr_t dma_handle, int length);
+static int twa_poll_response(TW_Device_Extension *tw_dev, int request_id, int seconds);
+static int twa_poll_status_gone(TW_Device_Extension *tw_dev, u32 flag, int seconds);
+static int twa_post_command_packet(TW_Device_Extension *tw_dev, int request_id, char internal);
+static int twa_reset_device_extension(TW_Device_Extension *tw_dev);
+static int twa_reset_sequence(TW_Device_Extension *tw_dev, int soft_reset);
+static int twa_scsiop_execute_scsi(TW_Device_Extension *tw_dev, int request_id, char *cdb, int use_sg, TW_SG_Apache *sglistarg);
+static void twa_scsiop_execute_scsi_complete(TW_Device_Extension *tw_dev, int request_id);
+static char *twa_string_lookup(twa_message_type *table, unsigned int aen_code);
+static void twa_unmap_scsi_data(TW_Device_Extension *tw_dev, int request_id);
+
+/* Functions */
+
+/* Show some statistics about the card */
+static ssize_t twa_show_stats(struct class_device *class_dev, char *buf)
+{
+	struct Scsi_Host *host = class_to_shost(class_dev);
+	TW_Device_Extension *tw_dev = (TW_Device_Extension *)host->hostdata;
+	unsigned long flags = 0;
+	ssize_t len;
+
+	spin_lock_irqsave(tw_dev->host->host_lock, flags);
+	len = snprintf(buf, PAGE_SIZE, "Driver version: %s\n"
+		       "Current commands posted:   %4d\n"
+		       "Max commands posted:       %4d\n"
+		       "Current pending commands:  %4d\n"
+		       "Max pending commands:      %4d\n"
+		       "Last sgl length:           %4d\n"
+		       "Max sgl length:            %4d\n"
+		       "Last sector count:         %4d\n"
+		       "Max sector count:          %4d\n"
+		       "SCSI Host Resets:          %4d\n"
+		       "SCSI Aborts/Timeouts:      %4d\n"
+		       "AEN's:                     %4d\n", 
+		       twa_driver_version,
+		       tw_dev->posted_request_count,
+		       tw_dev->max_posted_request_count,
+		       tw_dev->pending_request_count,
+		       tw_dev->max_pending_request_count,
+		       tw_dev->sgl_entries,
+		       tw_dev->max_sgl_entries,
+		       tw_dev->sector_count,
+		       tw_dev->max_sector_count,
+		       tw_dev->num_resets,
+		       tw_dev->num_aborts,
+		       tw_dev->aen_count);
+	spin_unlock_irqrestore(tw_dev->host->host_lock, flags);
+	return len;
+} /* End twa_show_stats() */
+
+/* This function will set a devices queue depth */
+static ssize_t twa_store_queue_depth(struct device *dev, const char *buf, size_t count)
+{
+	int queue_depth;
+	struct scsi_device *sdev = to_scsi_device(dev);
+
+	queue_depth = simple_strtoul(buf, NULL, 0);
+	if (queue_depth > TW_Q_LENGTH-2)
+		return -EINVAL;
+	scsi_adjust_queue_depth(sdev, MSG_ORDERED_TAG, queue_depth);
+
+	return count;
+} /* End twa_store_queue_depth() */
+
+/* Create sysfs 'queue_depth' entry */
+static struct device_attribute twa_queue_depth_attr = {
+	.attr = {
+		.name =		"queue_depth",
+		.mode =		S_IRUSR | S_IWUSR,
+	},
+	.store = twa_store_queue_depth
+};
+
+/* Device attributes initializer */
+static struct device_attribute *twa_dev_attrs[] = {
+	&twa_queue_depth_attr,
+	NULL,
+};
+
+/* Create sysfs 'stats' entry */
+static struct class_device_attribute twa_host_stats_attr = {
+	.attr = {
+		.name = 	"stats",
+		.mode =		S_IRUGO,
+	},
+	.show = twa_show_stats
+};
+
+/* Host attributes initializer */
+static struct class_device_attribute *twa_host_attrs[] = {
+	&twa_host_stats_attr,
+	NULL,
+};
+
+/* File operations struct for character device */
+static struct file_operations twa_fops = {
+	.owner		= THIS_MODULE,
+	.ioctl		= twa_chrdev_ioctl,
+	.open		= twa_chrdev_open,
+	.release	= NULL
+};
+
+/* This function will complete an aen request from the isr */
+static int twa_aen_complete(TW_Device_Extension *tw_dev, int request_id)
+{
+	TW_Command_Full *full_command_packet;
+	TW_Command *command_packet;
+	TW_Command_Apache_Header *header;
+	unsigned short aen;
+	int retval = 1;
+
+	header = (TW_Command_Apache_Header *)tw_dev->generic_buffer_virt[request_id];
+	tw_dev->posted_request_count--;
+	aen = header->status_block.error;
+	full_command_packet = tw_dev->command_packet_virt[request_id];
+	command_packet = &full_command_packet->command.oldcommand;
+
+	/* First check for internal completion of set param for time sync */
+	if (TW_OP_OUT(command_packet->opcode__sgloffset) == TW_OP_SET_PARAM) {
+		/* Keep reading the queue in case there are more aen's */
+		if (twa_aen_read_queue(tw_dev, request_id))
+			goto out2;
+	        else {
+			retval = 0;
+			goto out;
+		}
+	}
+
+	switch (aen) {
+	case TW_AEN_QUEUE_EMPTY:
+		/* Quit reading the queue if this is the last one */
+		break;
+	case TW_AEN_SYNC_TIME_WITH_HOST:
+		twa_aen_sync_time(tw_dev, request_id);
+		retval = 0;
+		goto out;
+	default:
+		twa_aen_queue_event(tw_dev, header);
+
+		/* If there are more aen's, keep reading the queue */
+		if (twa_aen_read_queue(tw_dev, request_id))
+			goto out2;
+		else {
+			retval = 0;
+			goto out;
+		}
+	}
+	retval = 0;
+out2:
+	tw_dev->state[request_id] = TW_S_COMPLETED;
+	twa_free_request_id(tw_dev, request_id);
+	clear_bit(TW_IN_ATTENTION_LOOP, &tw_dev->flags);
+out:
+	return retval;
+} /* End twa_aen_complete() */
+
+/* This function will drain aen queue */
+static int twa_aen_drain_queue(TW_Device_Extension *tw_dev, int no_check_reset)
+{
+	int request_id = 0;
+	char cdb[TW_MAX_CDB_LEN];
+	TW_SG_Apache sglist[1];
+	int finished = 0, count = 0;
+	TW_Command_Full *full_command_packet;
+	TW_Command_Apache_Header *header;
+	unsigned short aen;
+	int first_reset = 0, queue = 0, retval = 1;
+
+	if (no_check_reset)
+		first_reset = 0;
+	else
+		first_reset = 1;
+
+	full_command_packet = tw_dev->command_packet_virt[request_id];
+	memset(full_command_packet, 0, sizeof(TW_Command_Full));
+
+	/* Initialize cdb */
+	memset(&cdb, 0, TW_MAX_CDB_LEN);
+	cdb[0] = REQUEST_SENSE; /* opcode */
+	cdb[4] = TW_ALLOCATION_LENGTH; /* allocation length */
+
+	/* Initialize sglist */
+	memset(&sglist, 0, sizeof(TW_SG_Apache));
+	sglist[0].length = TW_SECTOR_SIZE;
+	sglist[0].address = tw_dev->generic_buffer_phys[request_id];
+
+	if (sglist[0].address & TW_ALIGNMENT_9000_SGL) {
+		TW_PRINTK(tw_dev->host, TW_DRIVER, 0x1, "Found unaligned address during AEN drain");
+		goto out;
+	}
+
+	/* Mark internal command */
+	tw_dev->srb[request_id] = NULL;
+
+	do {
+		/* Send command to the board */
+		if (twa_scsiop_execute_scsi(tw_dev, request_id, cdb, 1, sglist)) {
+			TW_PRINTK(tw_dev->host, TW_DRIVER, 0x2, "Error posting request sense");
+			goto out;
+		}
+
+		/* Now poll for completion */
+		if (twa_poll_response(tw_dev, request_id, 30)) {
+			TW_PRINTK(tw_dev->host, TW_DRIVER, 0x3, "No valid response while draining AEN queue");
+			tw_dev->posted_request_count--;
+			goto out;
+		}
+
+		tw_dev->posted_request_count--;
+		header = (TW_Command_Apache_Header *)tw_dev->generic_buffer_virt[request_id];
+		aen = header->status_block.error;
+		queue = 0;
+		count++;
+
+		switch (aen) {
+		case TW_AEN_QUEUE_EMPTY:
+			if (first_reset != 1)
+				goto out;
+			else
+				finished = 1;
+			break;
+		case TW_AEN_SOFT_RESET:
+			if (first_reset == 0)
+				first_reset = 1;
+			else
+				queue = 1;
+			break;
+		case TW_AEN_SYNC_TIME_WITH_HOST:
+			break;
+		default:
+			queue = 1;
+		}
+
+		/* Now queue an event info */
+		if (queue)
+			twa_aen_queue_event(tw_dev, header);
+	} while ((finished == 0) && (count < TW_MAX_AEN_DRAIN));
+
+	if (count == TW_MAX_AEN_DRAIN)
+		goto out;
+
+	retval = 0;
+out:
+	tw_dev->state[request_id] = TW_S_INITIAL;
+	return retval;
+} /* End twa_aen_drain_queue() */
+
+/* This function will queue an event */
+static void twa_aen_queue_event(TW_Device_Extension *tw_dev, TW_Command_Apache_Header *header)
+{
+	u32 local_time;
+	struct timeval time;
+	TW_Event *event;
+	unsigned short aen;
+	char host[16];
+
+	tw_dev->aen_count++;
+
+	/* Fill out event info */
+	event = tw_dev->event_queue[tw_dev->error_index];
+
+	/* Check for clobber */
+	host[0] = '\0';
+	if (tw_dev->host) {
+		sprintf(host, " scsi%d:", tw_dev->host->host_no);
+		if (event->retrieved == TW_AEN_NOT_RETRIEVED)
+			tw_dev->aen_clobber = 1;
+	}
+
+	aen = header->status_block.error;
+	memset(event, 0, sizeof(TW_Event));
+
+	event->severity = TW_SEV_OUT(header->status_block.severity__reserved);
+	do_gettimeofday(&time);
+	local_time = (u32)(time.tv_sec - (sys_tz.tz_minuteswest * 60));
+	event->time_stamp_sec = local_time;
+	event->aen_code = aen;
+	event->retrieved = TW_AEN_NOT_RETRIEVED;
+	event->sequence_id = tw_dev->error_sequence_id;
+	tw_dev->error_sequence_id++;
+
+	header->err_specific_desc[sizeof(header->err_specific_desc) - 1] = '\0';
+	event->parameter_len = strlen(header->err_specific_desc);
+	memcpy(event->parameter_data, header->err_specific_desc, event->parameter_len);
+	if (event->severity != TW_AEN_SEVERITY_DEBUG)
+		printk(KERN_WARNING "3w-9xxx:%s AEN: %s (0x%02X:0x%04X): %s:%s.\n",
+		       host,
+		       twa_aen_severity_lookup(TW_SEV_OUT(header->status_block.severity__reserved)),
+		       TW_MESSAGE_SOURCE_CONTROLLER_EVENT, aen,
+		       twa_string_lookup(twa_aen_table, aen),
+		       header->err_specific_desc);
+	else
+		tw_dev->aen_count--;
+
+	if ((tw_dev->error_index + 1) == TW_Q_LENGTH)
+		tw_dev->event_queue_wrapped = 1;
+	tw_dev->error_index = (tw_dev->error_index + 1 ) % TW_Q_LENGTH;
+} /* End twa_aen_queue_event() */
+
+/* This function will read the aen queue from the isr */
+static int twa_aen_read_queue(TW_Device_Extension *tw_dev, int request_id)
+{
+	char cdb[TW_MAX_CDB_LEN];
+	TW_SG_Apache sglist[1];
+	TW_Command_Full *full_command_packet;
+	int retval = 1;
+
+	full_command_packet = tw_dev->command_packet_virt[request_id];
+	memset(full_command_packet, 0, sizeof(TW_Command_Full));
+
+	/* Initialize cdb */
+	memset(&cdb, 0, TW_MAX_CDB_LEN);
+	cdb[0] = REQUEST_SENSE; /* opcode */
+	cdb[4] = TW_ALLOCATION_LENGTH; /* allocation length */
+
+	/* Initialize sglist */
+	memset(&sglist, 0, sizeof(TW_SG_Apache));
+	sglist[0].length = TW_SECTOR_SIZE;
+	sglist[0].address = tw_dev->generic_buffer_phys[request_id];
+
+	/* Mark internal command */
+	tw_dev->srb[request_id] = NULL;
+
+	/* Now post the command packet */
+	if (twa_scsiop_execute_scsi(tw_dev, request_id, cdb, 1, sglist)) {
+		TW_PRINTK(tw_dev->host, TW_DRIVER, 0x4, "Post failed while reading AEN queue");
+		goto out;
+	}
+	retval = 0;
+out:
+	return retval;
+} /* End twa_aen_read_queue() */
+
+/* This function will look up an AEN severity string */
+static char *twa_aen_severity_lookup(unsigned char severity_code)
+{
+	char *retval = NULL;
+
+	if ((severity_code < (unsigned char) TW_AEN_SEVERITY_ERROR) ||
+	    (severity_code > (unsigned char) TW_AEN_SEVERITY_DEBUG))
+		goto out;
+
+	retval = twa_aen_severity_table[severity_code];
+out:
+	return retval;
+} /* End twa_aen_severity_lookup() */
+
+/* This function will sync firmware time with the host time */
+static void twa_aen_sync_time(TW_Device_Extension *tw_dev, int request_id)
+{
+	u32 schedulertime;
+	struct timeval utc;
+	TW_Command_Full *full_command_packet;
+	TW_Command *command_packet;
+	TW_Param_Apache *param;
+	u32 local_time;
+
+	/* Fill out the command packet */
+	full_command_packet = tw_dev->command_packet_virt[request_id];
+	memset(full_command_packet, 0, sizeof(TW_Command_Full));
+	command_packet = &full_command_packet->command.oldcommand;
+	command_packet->opcode__sgloffset = TW_OPSGL_IN(2, TW_OP_SET_PARAM);
+	command_packet->request_id = request_id;
+	command_packet->byte8_offset.param.sgl[0].address = tw_dev->generic_buffer_phys[request_id];
+	command_packet->byte8_offset.param.sgl[0].length = TW_SECTOR_SIZE;
+	command_packet->size = TW_COMMAND_SIZE;
+	command_packet->byte6_offset.parameter_count = 1;
+
+	/* Setup the param */
+	param = (TW_Param_Apache *)tw_dev->generic_buffer_virt[request_id];
+	memset(param, 0, TW_SECTOR_SIZE);
+	param->table_id = TW_TIMEKEEP_TABLE | 0x8000; /* Controller time keep table */
+	param->parameter_id = 0x3; /* SchedulerTime */
+	param->parameter_size_bytes = 4;
+
+	/* Convert system time in UTC to local time seconds since last 
+           Sunday 12:00AM */
+	do_gettimeofday(&utc);
+	local_time = (u32)(utc.tv_sec - (sys_tz.tz_minuteswest * 60));
+	schedulertime = local_time - (3 * 86400);
+	schedulertime = schedulertime % 604800;
+
+	memcpy(param->data, &schedulertime, sizeof(u32));
+
+	/* Mark internal command */
+	tw_dev->srb[request_id] = NULL;
+
+	/* Now post the command */
+	twa_post_command_packet(tw_dev, request_id, 1);
+} /* End twa_aen_sync_time() */
+
+/* This function will allocate memory and check if it is correctly aligned */
+static int twa_allocate_memory(TW_Device_Extension *tw_dev, int size, int which)
+{
+	int i;
+	dma_addr_t dma_handle;
+	unsigned long *cpu_addr;
+	int retval = 1;
+
+	cpu_addr = pci_alloc_consistent(tw_dev->tw_pci_dev, size*TW_Q_LENGTH, &dma_handle);
+	if (!cpu_addr) {
+		TW_PRINTK(tw_dev->host, TW_DRIVER, 0x5, "Memory allocation failed");
+		goto out;
+	}
+
+	if ((unsigned long)cpu_addr % (TW_ALIGNMENT_9000)) {
+		TW_PRINTK(tw_dev->host, TW_DRIVER, 0x6, "Failed to allocate correctly aligned memory");
+		pci_free_consistent(tw_dev->tw_pci_dev, size*TW_Q_LENGTH, cpu_addr, dma_handle);
+		goto out;
+	}
+
+	memset(cpu_addr, 0, size*TW_Q_LENGTH);
+
+	for (i = 0; i < TW_Q_LENGTH; i++) {
+		switch(which) {
+		case 0:
+			tw_dev->command_packet_phys[i] = dma_handle+(i*size);
+			tw_dev->command_packet_virt[i] = (TW_Command_Full *)((unsigned char *)cpu_addr + (i*size));
+			break;
+		case 1:
+			tw_dev->generic_buffer_phys[i] = dma_handle+(i*size);
+			tw_dev->generic_buffer_virt[i] = (unsigned long *)((unsigned char *)cpu_addr + (i*size));
+			break;
+		}
+	}
+	retval = 0;
+out:
+	return retval;
+} /* End twa_allocate_memory() */
+
+/* This function will check the status register for unexpected bits */
+static int twa_check_bits(u32 status_reg_value)
+{
+	int retval = 1;
+
+	if ((status_reg_value & TW_STATUS_EXPECTED_BITS) != TW_STATUS_EXPECTED_BITS)
+		goto out;
+	if ((status_reg_value & TW_STATUS_UNEXPECTED_BITS) != 0)
+		goto out;
+
+	retval = 0;
+out:
+	return retval;
+} /* End twa_check_bits() */
+
+/* This function will check the srl and decide if we are compatible  */
+static int twa_check_srl(TW_Device_Extension *tw_dev, int *flashed)
+{
+	int retval = 1;
+	unsigned short fw_on_ctlr_srl = 0, fw_on_ctlr_arch_id = 0;
+	unsigned short fw_on_ctlr_branch = 0, fw_on_ctlr_build = 0;
+	u32 init_connect_result = 0;
+
+	if (twa_initconnection(tw_dev, TW_INIT_MESSAGE_CREDITS,
+			       TW_EXTENDED_INIT_CONNECT, TW_CURRENT_FW_SRL,
+			       TW_9000_ARCH_ID, TW_CURRENT_FW_BRANCH,
+			       TW_CURRENT_FW_BUILD, &fw_on_ctlr_srl,
+			       &fw_on_ctlr_arch_id, &fw_on_ctlr_branch,
+			       &fw_on_ctlr_build, &init_connect_result)) {
+		TW_PRINTK(tw_dev->host, TW_DRIVER, 0x7, "Initconnection failed while checking SRL");
+		goto out;
+	}
+
+	tw_dev->working_srl = TW_CURRENT_FW_SRL;
+	tw_dev->working_branch = TW_CURRENT_FW_BRANCH;
+	tw_dev->working_build = TW_CURRENT_FW_BUILD;
+
+	/* Try base mode compatibility */
+	if (!(init_connect_result & TW_CTLR_FW_COMPATIBLE)) {
+		if (twa_initconnection(tw_dev, TW_INIT_MESSAGE_CREDITS,
+				       TW_EXTENDED_INIT_CONNECT,
+				       TW_BASE_FW_SRL, TW_9000_ARCH_ID,
+				       TW_BASE_FW_BRANCH, TW_BASE_FW_BUILD,
+				       &fw_on_ctlr_srl, &fw_on_ctlr_arch_id,
+				       &fw_on_ctlr_branch, &fw_on_ctlr_build,
+				       &init_connect_result)) {
+			TW_PRINTK(tw_dev->host, TW_DRIVER, 0xa, "Initconnection (base mode) failed while checking SRL");
+			goto out;
+		}
+		if (!(init_connect_result & TW_CTLR_FW_COMPATIBLE)) {
+			if (TW_CURRENT_FW_SRL > fw_on_ctlr_srl) {
+				TW_PRINTK(tw_dev->host, TW_DRIVER, 0x32, "Firmware and driver incompatibility: please upgrade firmware");
+			} else {
+				TW_PRINTK(tw_dev->host, TW_DRIVER, 0x33, "Firmware and driver incompatibility: please upgrade driver");
+			}
+			goto out;
+		}
+		tw_dev->working_srl = TW_BASE_FW_SRL;
+		tw_dev->working_branch = TW_BASE_FW_BRANCH;
+		tw_dev->working_build = TW_BASE_FW_BUILD;
+	}
+	retval = 0;
+out:
+	return retval;
+} /* End twa_check_srl() */
+
+/* This function handles ioctl for the character device */
+static int twa_chrdev_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
+{
+	long timeout;
+	unsigned long *cpu_addr, data_buffer_length_adjusted = 0, flags = 0;
+	dma_addr_t dma_handle;
+	int request_id = 0;
+	unsigned int sequence_id = 0;
+	unsigned char event_index, start_index;
+	TW_Ioctl_Driver_Command driver_command;
+	TW_Ioctl_Buf_Apache *tw_ioctl;
+	TW_Lock *tw_lock;
+	TW_Command_Full *full_command_packet;
+	TW_Compatibility_Info *tw_compat_info;
+	TW_Event *event;
+	struct timeval current_time;
+	u32 current_time_ms;
+	TW_Device_Extension *tw_dev = twa_device_extension_list[iminor(inode)];
+	int retval = TW_IOCTL_ERROR_OS_EFAULT;
+
+	/* Only let one of these through at a time */
+	if (down_interruptible(&tw_dev->ioctl_sem)) {
+		retval = TW_IOCTL_ERROR_OS_EINTR;
+		goto out;
+	}
+
+	/* First copy down the driver command */
+	if (copy_from_user(&driver_command, (void *)arg, sizeof(TW_Ioctl_Driver_Command)))
+		goto out2;
+
+	/* Check data buffer size */
+	if (driver_command.buffer_length > TW_MAX_SECTORS * 512) {
+		retval = TW_IOCTL_ERROR_OS_EINVAL;
+		goto out2;
+	}
+
+	/* Hardware can only do multiple of 512 byte transfers */
+	data_buffer_length_adjusted = (driver_command.buffer_length + 511) & ~511;
+
+	/* Now allocate ioctl buf memory */
+	cpu_addr = pci_alloc_consistent(tw_dev->tw_pci_dev, data_buffer_length_adjusted+sizeof(TW_Ioctl_Buf_Apache) - 1, &dma_handle);
+	if (!cpu_addr) {
+		retval = TW_IOCTL_ERROR_OS_ENOMEM;
+		goto out2;
+	}
+
+	tw_ioctl = (TW_Ioctl_Buf_Apache *)cpu_addr;
+
+	/* Now copy down the entire ioctl */
+	if (copy_from_user(tw_ioctl, (void *)arg, driver_command.buffer_length + sizeof(TW_Ioctl_Buf_Apache) - 1))
+		goto out3;
+
+	/* See which ioctl we are doing */
+	switch (cmd) {
+	case TW_IOCTL_FIRMWARE_PASS_THROUGH:
+		spin_lock_irqsave(tw_dev->host->host_lock, flags);
+		twa_get_request_id(tw_dev, &request_id);
+
+		/* Flag internal command */
+		tw_dev->srb[request_id] = 0;
+
+		/* Flag chrdev ioctl */
+		tw_dev->chrdev_request_id = request_id;
+
+		full_command_packet = &tw_ioctl->firmware_command;
+
+		/* Load request id and sglist for both command types */
+		twa_load_sgl(full_command_packet, request_id, dma_handle, data_buffer_length_adjusted);
+
+		memcpy(tw_dev->command_packet_virt[request_id], &(tw_ioctl->firmware_command), sizeof(TW_Command_Full));
+
+		/* Now post the command packet to the controller */
+		twa_post_command_packet(tw_dev, request_id, 1);
+		spin_unlock_irqrestore(tw_dev->host->host_lock, flags);
+
+		timeout = TW_IOCTL_CHRDEV_TIMEOUT*HZ;
+
+		/* Now wait for command to complete */
+		timeout = wait_event_interruptible_timeout(tw_dev->ioctl_wqueue, tw_dev->chrdev_request_id == TW_IOCTL_CHRDEV_FREE, timeout);
+
+		/* Check if we timed out, got a signal, or didn't get
+                   an interrupt */
+		if ((timeout <= 0) && (tw_dev->chrdev_request_id != TW_IOCTL_CHRDEV_FREE)) {
+			/* Now we need to reset the board */
+			if (timeout == TW_IOCTL_ERROR_OS_ERESTARTSYS) {
+				retval = timeout;
+			} else {
+				printk(KERN_WARNING "3w-9xxx: scsi%d: WARNING: (0x%02X:0x%04X): Character ioctl (0x%x) timed out, resetting card.\n",
+				       tw_dev->host->host_no, TW_DRIVER, 0xc,
+				       cmd);
+				retval = TW_IOCTL_ERROR_OS_EIO;
+			}
+			spin_lock_irqsave(tw_dev->host->host_lock, flags);
+			tw_dev->state[request_id] = TW_S_COMPLETED;
+			twa_free_request_id(tw_dev, request_id);
+			tw_dev->posted_request_count--;
+			twa_reset_device_extension(tw_dev);
+			spin_unlock_irqrestore(tw_dev->host->host_lock, flags);
+			goto out3;
+		}
+
+		/* Now copy in the command packet response */
+		memcpy(&(tw_ioctl->firmware_command), tw_dev->command_packet_virt[request_id], sizeof(TW_Command_Full));
+		
+		/* Now complete the io */
+		spin_lock_irqsave(tw_dev->host->host_lock, flags);
+		tw_dev->posted_request_count--;
+		tw_dev->state[request_id] = TW_S_COMPLETED;
+		twa_free_request_id(tw_dev, request_id);
+		spin_unlock_irqrestore(tw_dev->host->host_lock, flags);
+		break;
+	case TW_IOCTL_GET_COMPATIBILITY_INFO:
+		tw_ioctl->driver_command.status = 0;
+		/* Copy compatiblity struct into ioctl data buffer */
+		tw_compat_info = (TW_Compatibility_Info *)tw_ioctl->data_buffer;
+		strncpy(tw_compat_info->driver_version, twa_driver_version, strlen(twa_driver_version));
+		tw_compat_info->working_srl = tw_dev->working_srl;
+		tw_compat_info->working_branch = tw_dev->working_branch;
+		tw_compat_info->working_build = tw_dev->working_build;
+		break;
+	case TW_IOCTL_GET_LAST_EVENT:
+		if (tw_dev->event_queue_wrapped) {
+			if (tw_dev->aen_clobber) {
+				tw_ioctl->driver_command.status = TW_IOCTL_ERROR_STATUS_AEN_CLOBBER;
+				tw_dev->aen_clobber = 0;
+			} else
+				tw_ioctl->driver_command.status = 0;
+		} else {
+			if (!tw_dev->error_index) {
+				tw_ioctl->driver_command.status = TW_IOCTL_ERROR_STATUS_NO_MORE_EVENTS;
+				break;
+			}
+			tw_ioctl->driver_command.status = 0;
+		}
+		event_index = (tw_dev->error_index - 1 + TW_Q_LENGTH) % TW_Q_LENGTH;
+		memcpy(tw_ioctl->data_buffer, tw_dev->event_queue[event_index], sizeof(TW_Event));
+		tw_dev->event_queue[event_index]->retrieved = TW_AEN_RETRIEVED;
+		break;
+	case TW_IOCTL_GET_FIRST_EVENT:
+		if (tw_dev->event_queue_wrapped) {
+			if (tw_dev->aen_clobber) {
+				tw_ioctl->driver_command.status = TW_IOCTL_ERROR_STATUS_AEN_CLOBBER;
+				tw_dev->aen_clobber = 0;
+			} else 
+				tw_ioctl->driver_command.status = 0;
+			event_index = tw_dev->error_index;
+		} else {
+			if (!tw_dev->error_index) {
+				tw_ioctl->driver_command.status = TW_IOCTL_ERROR_STATUS_NO_MORE_EVENTS;
+				break;
+			}
+			tw_ioctl->driver_command.status = 0;
+			event_index = 0;
+		}
+		memcpy(tw_ioctl->data_buffer, tw_dev->event_queue[event_index], sizeof(TW_Event));
+		tw_dev->event_queue[event_index]->retrieved = TW_AEN_RETRIEVED;
+		break;
+	case TW_IOCTL_GET_NEXT_EVENT:
+		event = (TW_Event *)tw_ioctl->data_buffer;
+		sequence_id = event->sequence_id;
+		tw_ioctl->driver_command.status = 0;
+
+		if (tw_dev->event_queue_wrapped) {
+			if (tw_dev->aen_clobber) {
+				tw_ioctl->driver_command.status = TW_IOCTL_ERROR_STATUS_AEN_CLOBBER;
+				tw_dev->aen_clobber = 0;
+			}
+			start_index = tw_dev->error_index;
+		} else {
+			if (!tw_dev->error_index) {
+				tw_ioctl->driver_command.status = TW_IOCTL_ERROR_STATUS_NO_MORE_EVENTS;
+				break;
+			}
+			start_index = 0;
+		}
+		event_index = (start_index + sequence_id - tw_dev->event_queue[start_index]->sequence_id + 1) % TW_Q_LENGTH;
+
+		if (!(tw_dev->event_queue[event_index]->sequence_id > sequence_id)) {
+			if (tw_ioctl->driver_command.status == TW_IOCTL_ERROR_STATUS_AEN_CLOBBER)
+				tw_dev->aen_clobber = 1;
+			tw_ioctl->driver_command.status = TW_IOCTL_ERROR_STATUS_NO_MORE_EVENTS;
+			break;
+		}
+		memcpy(tw_ioctl->data_buffer, tw_dev->event_queue[event_index], sizeof(TW_Event));
+		tw_dev->event_queue[event_index]->retrieved = TW_AEN_RETRIEVED;
+		break;
+	case TW_IOCTL_GET_PREVIOUS_EVENT:
+		event = (TW_Event *)tw_ioctl->data_buffer;
+		sequence_id = event->sequence_id;
+		tw_ioctl->driver_command.status = 0;
+
+		if (tw_dev->event_queue_wrapped) {
+			if (tw_dev->aen_clobber) {
+				tw_ioctl->driver_command.status = TW_IOCTL_ERROR_STATUS_AEN_CLOBBER;
+				tw_dev->aen_clobber = 0;
+			}
+			start_index = tw_dev->error_index;
+		} else {
+			if (!tw_dev->error_index) {
+				tw_ioctl->driver_command.status = TW_IOCTL_ERROR_STATUS_NO_MORE_EVENTS;
+				break;
+			}
+			start_index = 0;
+		}
+		event_index = (start_index + sequence_id - tw_dev->event_queue[start_index]->sequence_id - 1) % TW_Q_LENGTH;
+
+		if (!(tw_dev->event_queue[event_index]->sequence_id < sequence_id)) {
+			if (tw_ioctl->driver_command.status == TW_IOCTL_ERROR_STATUS_AEN_CLOBBER)
+				tw_dev->aen_clobber = 1;
+			tw_ioctl->driver_command.status = TW_IOCTL_ERROR_STATUS_NO_MORE_EVENTS;
+			break;
+		}
+		memcpy(tw_ioctl->data_buffer, tw_dev->event_queue[event_index], sizeof(TW_Event));
+		tw_dev->event_queue[event_index]->retrieved = TW_AEN_RETRIEVED;
+		break;
+	case TW_IOCTL_GET_LOCK:
+		tw_lock = (TW_Lock *)tw_ioctl->data_buffer;
+		do_gettimeofday(&current_time);
+		current_time_ms = (current_time.tv_sec * 1000) + (current_time.tv_usec / 1000);
+
+		if ((tw_lock->force_flag == 1) || (tw_dev->ioctl_sem_lock == 0) || (current_time_ms >= tw_dev->ioctl_msec)) {
+			tw_dev->ioctl_sem_lock = 1;
+			tw_dev->ioctl_msec = current_time_ms + tw_lock->timeout_msec;
+			tw_ioctl->driver_command.status = 0;
+			tw_lock->time_remaining_msec = tw_lock->timeout_msec;
+		} else {
+			tw_ioctl->driver_command.status = TW_IOCTL_ERROR_STATUS_LOCKED;
+			tw_lock->time_remaining_msec = tw_dev->ioctl_msec - current_time_ms;
+		}
+		break;
+	case TW_IOCTL_RELEASE_LOCK:
+		if (tw_dev->ioctl_sem_lock == 1) {
+			tw_dev->ioctl_sem_lock = 0;
+			tw_ioctl->driver_command.status = 0;
+		} else {
+			tw_ioctl->driver_command.status = TW_IOCTL_ERROR_STATUS_NOT_LOCKED;
+		}
+		break;
+	default:
+		retval = TW_IOCTL_ERROR_OS_ENOTTY;
+		goto out3;
+	}
+
+	/* Now copy the entire response to userspace */
+	if (copy_to_user((void *)arg, tw_ioctl, sizeof(TW_Ioctl_Buf_Apache) + driver_command.buffer_length - 1) == 0)
+		retval = 0;
+out3:
+	/* Now free ioctl buf memory */
+	pci_free_consistent(tw_dev->tw_pci_dev, data_buffer_length_adjusted+sizeof(TW_Ioctl_Buf_Apache) - 1, cpu_addr, dma_handle);
+out2:
+	up(&tw_dev->ioctl_sem);
+out:
+	return retval;
+} /* End twa_chrdev_ioctl() */
+
+/* This function handles open for the character device */
+static int twa_chrdev_open(struct inode *inode, struct file *file)
+{
+	unsigned int minor_number;
+	int retval = TW_IOCTL_ERROR_OS_ENODEV;
+
+	minor_number = iminor(inode);
+	if (minor_number >= twa_device_extension_count)
+		goto out;
+	retval = 0;
+out:
+	return retval;
+} /* End twa_chrdev_open() */
+
+/* This function will print readable messages from status register errors */
+static int twa_decode_bits(TW_Device_Extension *tw_dev, u32 status_reg_value)
+{
+	int retval = 1;
+
+	/* Check for various error conditions and handle them appropriately */
+	if (status_reg_value & TW_STATUS_PCI_PARITY_ERROR) {
+		TW_PRINTK(tw_dev->host, TW_DRIVER, 0xc, "PCI Parity Error: clearing");
+		writel(TW_CONTROL_CLEAR_PARITY_ERROR, TW_CONTROL_REG_ADDR(tw_dev));
+	}
+
+	if (status_reg_value & TW_STATUS_PCI_ABORT) {
+		TW_PRINTK(tw_dev->host, TW_DRIVER, 0xd, "PCI Abort: clearing");
+		writel(TW_CONTROL_CLEAR_PCI_ABORT, TW_CONTROL_REG_ADDR(tw_dev));
+		pci_write_config_word(tw_dev->tw_pci_dev, PCI_STATUS, TW_PCI_CLEAR_PCI_ABORT);
+	}
+
+	if (status_reg_value & TW_STATUS_QUEUE_ERROR) {
+		TW_PRINTK(tw_dev->host, TW_DRIVER, 0xe, "Controller Queue Error: clearing");
+		writel(TW_CONTROL_CLEAR_QUEUE_ERROR, TW_CONTROL_REG_ADDR(tw_dev));
+	}
+
+	if (status_reg_value & TW_STATUS_SBUF_WRITE_ERROR) {
+		TW_PRINTK(tw_dev->host, TW_DRIVER, 0xf, "SBUF Write Error: clearing");
+		writel(TW_CONTROL_CLEAR_SBUF_WRITE_ERROR, TW_CONTROL_REG_ADDR(tw_dev));
+	}
+
+	if (status_reg_value & TW_STATUS_MICROCONTROLLER_ERROR) {
+		if (tw_dev->reset_print == 0) {
+			TW_PRINTK(tw_dev->host, TW_DRIVER, 0x10, "Microcontroller Error: clearing");
+			tw_dev->reset_print = 1;
+		}
+		goto out;
+	}
+	retval = 0;
+out:
+	return retval;
+} /* End twa_decode_bits() */
+
+/* This function will empty the response queue */
+static int twa_empty_response_queue(TW_Device_Extension *tw_dev)
+{
+	u32 status_reg_value, response_que_value;
+	int count = 0, retval = 1;
+
+	status_reg_value = readl(TW_STATUS_REG_ADDR(tw_dev));
+
+	while (((status_reg_value & TW_STATUS_RESPONSE_QUEUE_EMPTY) == 0) && (count < TW_MAX_RESPONSE_DRAIN)) {
+		response_que_value = readl(TW_RESPONSE_QUEUE_REG_ADDR(tw_dev));
+		status_reg_value = readl(TW_STATUS_REG_ADDR(tw_dev));
+		count++;
+	}
+	if (count == TW_MAX_RESPONSE_DRAIN)
+		goto out;
+
+	retval = 0;
+out:
+	return retval;
+} /* End twa_empty_response_queue() */
+
+/* This function passes sense keys from firmware to scsi layer */
+static int twa_fill_sense(TW_Device_Extension *tw_dev, int request_id, int copy_sense, int print_host)
+{
+	TW_Command_Full *full_command_packet;
+	unsigned short error;
+	int retval = 1;
+
+	full_command_packet = tw_dev->command_packet_virt[request_id];
+	/* Don't print error for Logical unit not supported during rollcall */
+	error = full_command_packet->header.status_block.error;
+	if ((error != TW_ERROR_LOGICAL_UNIT_NOT_SUPPORTED) && (error != TW_ERROR_UNIT_OFFLINE)) {
+		if (print_host)
+			printk(KERN_WARNING "3w-9xxx: scsi%d: ERROR: (0x%02X:0x%04X): %s:%s.\n",
+			       tw_dev->host->host_no,
+			       TW_MESSAGE_SOURCE_CONTROLLER_ERROR,
+			       full_command_packet->header.status_block.error,
+			       twa_string_lookup(twa_error_table,
+						 full_command_packet->header.status_block.error),
+			       full_command_packet->header.err_specific_desc);
+		else
+			printk(KERN_WARNING "3w-9xxx: ERROR: (0x%02X:0x%04X): %s:%s.\n",
+			       TW_MESSAGE_SOURCE_CONTROLLER_ERROR,
+			       full_command_packet->header.status_block.error,
+			       twa_string_lookup(twa_error_table,
+						 full_command_packet->header.status_block.error),
+			       full_command_packet->header.err_specific_desc);
+	}
+
+	if (copy_sense) {
+		memcpy(tw_dev->srb[request_id]->sense_buffer, full_command_packet->header.sense_data, TW_SENSE_DATA_LENGTH);
+		tw_dev->srb[request_id]->result = (full_command_packet->command.newcommand.status << 1);
+		retval = TW_ISR_DONT_RESULT;
+		goto out;
+	}
+	retval = 0;
+out:
+	return retval;
+} /* End twa_fill_sense() */
+
+/* This function will free up device extension resources */
+static void twa_free_device_extension(TW_Device_Extension *tw_dev)
+{
+	if (tw_dev->command_packet_virt[0])
+		pci_free_consistent(tw_dev->tw_pci_dev,
+				    sizeof(TW_Command_Full)*TW_Q_LENGTH,
+				    tw_dev->command_packet_virt[0],
+				    tw_dev->command_packet_phys[0]);
+
+	if (tw_dev->generic_buffer_virt[0])
+		pci_free_consistent(tw_dev->tw_pci_dev,
+				    TW_SECTOR_SIZE*TW_Q_LENGTH,
+				    tw_dev->generic_buffer_virt[0],
+				    tw_dev->generic_buffer_phys[0]);
+
+	if (tw_dev->event_queue[0])
+		kfree(tw_dev->event_queue[0]);
+} /* End twa_free_device_extension() */
+
+/* This function will free a request id */
+static void twa_free_request_id(TW_Device_Extension *tw_dev, int request_id)
+{
+	tw_dev->free_queue[tw_dev->free_tail] = request_id;
+	tw_dev->state[request_id] = TW_S_FINISHED;
+	tw_dev->free_tail = (tw_dev->free_tail + 1) % TW_Q_LENGTH;
+} /* End twa_free_request_id() */
+
+/* This function will get parameter table entires from the firmware */
+static void *twa_get_param(TW_Device_Extension *tw_dev, int request_id, int table_id, int parameter_id, int parameter_size_bytes)
+{
+	TW_Command_Full *full_command_packet;
+	TW_Command *command_packet;
+	TW_Param_Apache *param;
+	unsigned long param_value;
+	void *retval = NULL;
+
+	/* Setup the command packet */
+	full_command_packet = tw_dev->command_packet_virt[request_id];
+	memset(full_command_packet, 0, sizeof(TW_Command_Full));
+	command_packet = &full_command_packet->command.oldcommand;
+
+	command_packet->opcode__sgloffset = TW_OPSGL_IN(2, TW_OP_GET_PARAM);
+	command_packet->size              = TW_COMMAND_SIZE;
+	command_packet->request_id        = request_id;
+	command_packet->byte6_offset.block_count = 1;
+
+	/* Now setup the param */
+	param = (TW_Param_Apache *)tw_dev->generic_buffer_virt[request_id];
+	memset(param, 0, TW_SECTOR_SIZE);
+	param->table_id = table_id | 0x8000;
+	param->parameter_id = parameter_id;
+	param->parameter_size_bytes = parameter_size_bytes;
+	param_value = tw_dev->generic_buffer_phys[request_id];
+
+	command_packet->byte8_offset.param.sgl[0].address = param_value;
+	command_packet->byte8_offset.param.sgl[0].length = TW_SECTOR_SIZE;
+
+	/* Post the command packet to the board */
+	twa_post_command_packet(tw_dev, request_id, 1);
+
+	/* Poll for completion */
+	if (twa_poll_response(tw_dev, request_id, 30))
+		TW_PRINTK(tw_dev->host, TW_DRIVER, 0x13, "No valid response during get param")
+	else
+		retval = (void *)&(param->data[0]);
+
+	tw_dev->posted_request_count--;
+	tw_dev->state[request_id] = TW_S_INITIAL;
+
+	return retval;
+} /* End twa_get_param() */
+
+/* This function will assign an available request id */
+static void twa_get_request_id(TW_Device_Extension *tw_dev, int *request_id)
+{
+	*request_id = tw_dev->free_queue[tw_dev->free_head];
+	tw_dev->free_head = (tw_dev->free_head + 1) % TW_Q_LENGTH;
+	tw_dev->state[*request_id] = TW_S_STARTED;
+} /* End twa_get_request_id() */
+
+/* This function will send an initconnection command to controller */
+static int twa_initconnection(TW_Device_Extension *tw_dev, int message_credits,
+ 			      u32 set_features, unsigned short current_fw_srl, 
+			      unsigned short current_fw_arch_id, 
+			      unsigned short current_fw_branch, 
+			      unsigned short current_fw_build, 
+			      unsigned short *fw_on_ctlr_srl, 
+			      unsigned short *fw_on_ctlr_arch_id, 
+			      unsigned short *fw_on_ctlr_branch, 
+			      unsigned short *fw_on_ctlr_build, 
+			      u32 *init_connect_result)
+{
+	TW_Command_Full *full_command_packet;
+	TW_Initconnect *tw_initconnect;
+	int request_id = 0, retval = 1;
+
+	/* Initialize InitConnection command packet */
+	full_command_packet = tw_dev->command_packet_virt[request_id];
+	memset(full_command_packet, 0, sizeof(TW_Command_Full));
+	full_command_packet->header.header_desc.size_header = 128;
+	
+	tw_initconnect = (TW_Initconnect *)&full_command_packet->command.oldcommand;
+	tw_initconnect->opcode__reserved = TW_OPRES_IN(0, TW_OP_INIT_CONNECTION);
+	tw_initconnect->request_id = request_id;
+	tw_initconnect->message_credits = message_credits;
+	tw_initconnect->features = set_features;
+#if BITS_PER_LONG > 32
+	/* Turn on 64-bit sgl support */
+	tw_initconnect->features |= 1;
+#endif
+
+	if (set_features & TW_EXTENDED_INIT_CONNECT) {
+		tw_initconnect->size = TW_INIT_COMMAND_PACKET_SIZE_EXTENDED;
+		tw_initconnect->fw_srl = current_fw_srl;
+		tw_initconnect->fw_arch_id = current_fw_arch_id;
+		tw_initconnect->fw_branch = current_fw_branch;
+		tw_initconnect->fw_build = current_fw_build;
+	} else 
+		tw_initconnect->size = TW_INIT_COMMAND_PACKET_SIZE;
+
+	/* Send command packet to the board */
+	twa_post_command_packet(tw_dev, request_id, 1);
+
+	/* Poll for completion */
+	if (twa_poll_response(tw_dev, request_id, 30)) {
+		TW_PRINTK(tw_dev->host, TW_DRIVER, 0x15, "No valid response during init connection");
+	} else {
+		if (set_features & TW_EXTENDED_INIT_CONNECT) {
+			*fw_on_ctlr_srl = tw_initconnect->fw_srl;
+			*fw_on_ctlr_arch_id = tw_initconnect->fw_arch_id;
+			*fw_on_ctlr_branch = tw_initconnect->fw_branch;
+			*fw_on_ctlr_build = tw_initconnect->fw_build;
+			*init_connect_result = tw_initconnect->result;
+		}
+		retval = 0;
+	}
+
+	tw_dev->posted_request_count--;
+	tw_dev->state[request_id] = TW_S_INITIAL;
+
+	return retval;
+} /* End twa_initconnection() */
+
+/* This function will initialize the fields of a device extension */
+static int twa_initialize_device_extension(TW_Device_Extension *tw_dev)
+{
+	int i, retval = 1;
+
+	/* Initialize command packet buffers */
+	if (twa_allocate_memory(tw_dev, sizeof(TW_Command_Full), 0)) {
+		TW_PRINTK(tw_dev->host, TW_DRIVER, 0x16, "Command packet memory allocation failed");
+		goto out;
+	}
+
+	/* Initialize generic buffer */
+	if (twa_allocate_memory(tw_dev, TW_SECTOR_SIZE, 1)) {
+		TW_PRINTK(tw_dev->host, TW_DRIVER, 0x17, "Generic memory allocation failed");
+		goto out;
+	}
+
+	/* Allocate event info space */
+	tw_dev->event_queue[0] = kmalloc(sizeof(TW_Event) * TW_Q_LENGTH, GFP_KERNEL);
+	if (!tw_dev->event_queue[0]) {
+		TW_PRINTK(tw_dev->host, TW_DRIVER, 0x18, "Event info memory allocation failed");
+		goto out;
+	}
+
+	memset(tw_dev->event_queue[0], 0, sizeof(TW_Event) * TW_Q_LENGTH);
+
+	for (i = 0; i < TW_Q_LENGTH; i++) {
+		tw_dev->event_queue[i] = (TW_Event *)((unsigned char *)tw_dev->event_queue[0] + (i * sizeof(TW_Event)));
+		tw_dev->free_queue[i] = i;
+		tw_dev->state[i] = TW_S_INITIAL;
+	}
+
+	tw_dev->pending_head = TW_Q_START;
+	tw_dev->pending_tail = TW_Q_START;
+	tw_dev->free_head = TW_Q_START;
+	tw_dev->free_tail = TW_Q_START;
+	tw_dev->error_sequence_id = 1;
+	tw_dev->chrdev_request_id = TW_IOCTL_CHRDEV_FREE;
+
+	init_MUTEX(&tw_dev->ioctl_sem);
+	init_waitqueue_head(&tw_dev->ioctl_wqueue);
+
+	retval = 0;
+out:
+	return retval;
+} /* End twa_initialize_device_extension() */
+
+/* This function is the interrupt service routine */
+static irqreturn_t twa_interrupt(int irq, void *dev_instance, struct pt_regs *regs)
+{
+	int request_id, error = 0;
+	u32 status_reg_value;
+	TW_Response_Queue response_que;
+	TW_Command_Full *full_command_packet;
+	TW_Command *command_packet;
+	TW_Device_Extension *tw_dev = (TW_Device_Extension *)dev_instance;
+	int handled = 0;
+
+	/* Get the per adapter lock */
+	spin_lock(tw_dev->host->host_lock);
+
+	/* See if the interrupt matches this instance */
+	if (tw_dev->tw_pci_dev->irq == (unsigned int)irq) {
+
+		handled = 1;
+
+		/* Read the registers */
+		status_reg_value = readl(TW_STATUS_REG_ADDR(tw_dev));
+
+		/* Check if this is our interrupt, otherwise bail */
+		if (!(status_reg_value & TW_STATUS_VALID_INTERRUPT))
+			goto twa_interrupt_bail;
+
+		/* Check controller for errors */
+		if (twa_check_bits(status_reg_value)) {
+			if (twa_decode_bits(tw_dev, status_reg_value)) {
+				TW_CLEAR_ALL_INTERRUPTS(tw_dev);
+				goto twa_interrupt_bail;
+			}
+		}
+
+		/* Handle host interrupt */
+		if (status_reg_value & TW_STATUS_HOST_INTERRUPT)
+			TW_CLEAR_HOST_INTERRUPT(tw_dev);
+
+		/* Handle attention interrupt */
+		if (status_reg_value & TW_STATUS_ATTENTION_INTERRUPT) {
+			TW_CLEAR_ATTENTION_INTERRUPT(tw_dev);
+			if (!(test_and_set_bit(TW_IN_ATTENTION_LOOP, &tw_dev->flags))) {
+				twa_get_request_id(tw_dev, &request_id);
+
+				error = twa_aen_read_queue(tw_dev, request_id);
+				if (error) {
+					tw_dev->state[request_id] = TW_S_COMPLETED;
+					twa_free_request_id(tw_dev, request_id);
+					clear_bit(TW_IN_ATTENTION_LOOP, &tw_dev->flags);
+				}
+			}
+		}
+
+		/* Handle command interrupt */
+		if (status_reg_value & TW_STATUS_COMMAND_INTERRUPT) {
+			TW_MASK_COMMAND_INTERRUPT(tw_dev);
+			/* Drain as many pending commands as we can */
+			while (tw_dev->pending_request_count > 0) {
+				request_id = tw_dev->pending_queue[tw_dev->pending_head];
+				if (tw_dev->state[request_id] != TW_S_PENDING) {
+					TW_PRINTK(tw_dev->host, TW_DRIVER, 0x19, "Found request id that wasn't pending");
+					TW_CLEAR_ALL_INTERRUPTS(tw_dev);
+					goto twa_interrupt_bail;
+				}
+				if (twa_post_command_packet(tw_dev, request_id, 1)==0) {
+					tw_dev->pending_head = (tw_dev->pending_head + 1) % TW_Q_LENGTH;
+					tw_dev->pending_request_count--;
+				} else {
+					/* If we get here, we will continue re-posting on the next command interrupt */
+					break;
+				}
+			}
+		}
+
+		/* Handle response interrupt */
+		if (status_reg_value & TW_STATUS_RESPONSE_INTERRUPT) {
+
+			/* Drain the response queue from the board */
+			while ((status_reg_value & TW_STATUS_RESPONSE_QUEUE_EMPTY) == 0) {
+				/* Complete the response */
+				response_que.value = readl(TW_RESPONSE_QUEUE_REG_ADDR(tw_dev));
+				request_id = TW_RESID_OUT(response_que.response_id);
+				full_command_packet = tw_dev->command_packet_virt[request_id];
+				error = 0;
+				command_packet = &full_command_packet->command.oldcommand;
+				/* Check for command packet errors */
+				if (full_command_packet->command.newcommand.status != 0) {
+					if (tw_dev->srb[request_id] != 0) {
+						error = twa_fill_sense(tw_dev, request_id, 1, 1);
+					} else {
+						/* Skip ioctl error prints */
+						if (request_id != tw_dev->chrdev_request_id) {
+							error = twa_fill_sense(tw_dev, request_id, 0, 1);
+						}
+					}
+				}
+
+				/* Check for correct state */
+				if (tw_dev->state[request_id] != TW_S_POSTED) {
+					if (tw_dev->srb[request_id] != 0) {
+						TW_PRINTK(tw_dev->host, TW_DRIVER, 0x1a, "Received a request id that wasn't posted");
+					        TW_CLEAR_ALL_INTERRUPTS(tw_dev);
+						goto twa_interrupt_bail;
+					}
+				}
+
+				/* Check for internal command completion */
+				if (tw_dev->srb[request_id] == 0) {
+					if (request_id != tw_dev->chrdev_request_id) {
+						if (twa_aen_complete(tw_dev, request_id))
+							TW_PRINTK(tw_dev->host, TW_DRIVER, 0x1b, "Error completing AEN during attention interrupt");
+					} else {
+						tw_dev->chrdev_request_id = TW_IOCTL_CHRDEV_FREE;
+						wake_up(&tw_dev->ioctl_wqueue);
+					}
+				} else {
+					twa_scsiop_execute_scsi_complete(tw_dev, request_id);
+					/* If no error command was a success */
+					if (error == 0) {
+						tw_dev->srb[request_id]->result = (DID_OK << 16);
+					}
+
+					/* If error, command failed */
+					if (error == 1) {
+						/* Ask for a host reset */
+						tw_dev->srb[request_id]->result = (DID_OK << 16) | (CHECK_CONDITION << 1);
+					}
+
+					/* Now complete the io */
+					tw_dev->state[request_id] = TW_S_COMPLETED;
+					twa_free_request_id(tw_dev, request_id);
+					tw_dev->posted_request_count--;
+					tw_dev->srb[request_id]->scsi_done(tw_dev->srb[request_id]);
+					twa_unmap_scsi_data(tw_dev, request_id);
+				}
+
+				/* Check for valid status after each drain */
+				status_reg_value = readl(TW_STATUS_REG_ADDR(tw_dev));
+				if (twa_check_bits(status_reg_value)) {
+					if (twa_decode_bits(tw_dev, status_reg_value)) {
+						TW_CLEAR_ALL_INTERRUPTS(tw_dev);
+						goto twa_interrupt_bail;
+					}
+				}
+			}
+		}
+	}
+twa_interrupt_bail:
+	spin_unlock(tw_dev->host->host_lock);
+	return IRQ_RETVAL(handled);
+} /* End twa_interrupt() */
+
+/* This function will load the request id and various sgls for ioctls */
+static void twa_load_sgl(TW_Command_Full *full_command_packet, int request_id, dma_addr_t dma_handle, int length)
+{
+	TW_Command *oldcommand;
+	TW_Command_Apache *newcommand;
+	TW_SG_Entry *sgl;
+
+	if (TW_OP_OUT(full_command_packet->command.newcommand.opcode__reserved) == TW_OP_EXECUTE_SCSI) {
+		newcommand = &full_command_packet->command.newcommand;
+		newcommand->request_id = request_id;
+		newcommand->sg_list[0].address = dma_handle + sizeof(TW_Ioctl_Buf_Apache) - 1;
+		newcommand->sg_list[0].length = length;
+	} else {
+		oldcommand = &full_command_packet->command.oldcommand;
+		oldcommand->request_id = request_id;
+
+		if (TW_SGL_OUT(oldcommand->opcode__sgloffset)) {
+			/* Load the sg list */
+			sgl = (TW_SG_Entry *)((u32 *)oldcommand+TW_SGL_OUT(oldcommand->opcode__sgloffset));
+			sgl->address = dma_handle + sizeof(TW_Ioctl_Buf_Apache) - 1;
+			sgl->length = length;
+		}
+	}
+} /* End twa_load_sgl() */
+
+/* This function will perform a pci-dma mapping for a scatter gather list */
+static int twa_map_scsi_sg_data(TW_Device_Extension *tw_dev, int request_id)
+{
+	int use_sg;
+	struct scsi_cmnd *cmd = tw_dev->srb[request_id];
+	struct pci_dev *pdev = tw_dev->tw_pci_dev;
+	int retval = 0;
+
+	if (cmd->use_sg == 0)
+		goto out;
+
+	use_sg = pci_map_sg(pdev, cmd->buffer, cmd->use_sg, DMA_BIDIRECTIONAL);
+
+	if (use_sg == 0) {
+		TW_PRINTK(tw_dev->host, TW_DRIVER, 0x1c, "Failed to map scatter gather list");
+		goto out;
+	}
+
+	cmd->SCp.phase = TW_PHASE_SGLIST;
+	cmd->SCp.have_data_in = use_sg;
+	retval = use_sg;
+out:
+	return retval;
+} /* End twa_map_scsi_sg_data() */
+
+/* This function will perform a pci-dma map for a single buffer */
+static dma_addr_t twa_map_scsi_single_data(TW_Device_Extension *tw_dev, int request_id)
+{
+	dma_addr_t mapping;
+	struct scsi_cmnd *cmd = tw_dev->srb[request_id];
+	struct pci_dev *pdev = tw_dev->tw_pci_dev;
+	int retval = 0;
+
+	if (cmd->request_bufflen == 0) {
+		retval = 0;
+		goto out;
+	}
+
+	mapping = pci_map_single(pdev, cmd->request_buffer, cmd->request_bufflen, DMA_BIDIRECTIONAL);
+
+	if (mapping == 0) {
+		TW_PRINTK(tw_dev->host, TW_DRIVER, 0x1d, "Failed to map page");
+		goto out;
+	}
+
+	cmd->SCp.phase = TW_PHASE_SINGLE;
+	cmd->SCp.have_data_in = mapping;
+	retval = mapping;
+out:
+	return retval;
+} /* End twa_map_scsi_single_data() */
+
+/* This function will poll for a response interrupt of a request */
+static int twa_poll_response(TW_Device_Extension *tw_dev, int request_id, int seconds)
+{
+	int retval = 1, found = 0, response_request_id;
+	TW_Response_Queue response_queue;
+	TW_Command_Full *full_command_packet = tw_dev->command_packet_virt[request_id];
+
+	if (twa_poll_status_gone(tw_dev, TW_STATUS_RESPONSE_QUEUE_EMPTY, seconds) == 0) {
+		response_queue.value = readl(TW_RESPONSE_QUEUE_REG_ADDR(tw_dev));
+		response_request_id = TW_RESID_OUT(response_queue.response_id);
+		if (request_id != response_request_id) {
+			TW_PRINTK(tw_dev->host, TW_DRIVER, 0x1e, "Found unexpected request id while polling for response");
+			goto out;
+		}
+		if (TW_OP_OUT(full_command_packet->command.newcommand.opcode__reserved) == TW_OP_EXECUTE_SCSI) {
+			if (full_command_packet->command.newcommand.status != 0) {
+				/* bad response */
+				twa_fill_sense(tw_dev, request_id, 0, 0);
+				goto out;
+			}
+			found = 1;
+		} else {
+			if (full_command_packet->command.oldcommand.status != 0) {
+				/* bad response */
+				twa_fill_sense(tw_dev, request_id, 0, 0);
+				goto out;
+			}
+			found = 1;
+		}
+	}
+
+	if (found)
+		retval = 0;
+out:
+	return retval;
+} /* End twa_poll_response() */
+
+/* This function will poll the status register for a flag */
+static int twa_poll_status(TW_Device_Extension *tw_dev, u32 flag, int seconds)
+{
+	u32 status_reg_value; 
+	unsigned long before;
+	int retval = 1;
+
+	status_reg_value = readl(TW_STATUS_REG_ADDR(tw_dev));
+	before = jiffies;
+
+	if (twa_check_bits(status_reg_value))
+		twa_decode_bits(tw_dev, status_reg_value);
+
+	while ((status_reg_value & flag) != flag) {
+		status_reg_value = readl(TW_STATUS_REG_ADDR(tw_dev));
+
+		if (twa_check_bits(status_reg_value))
+			twa_decode_bits(tw_dev, status_reg_value);
+
+		if (time_after(jiffies, before + HZ * seconds))
+			goto out;
+
+		msleep(50);
+	}
+	retval = 0;
+out:
+	return retval;
+} /* End twa_poll_status() */
+
+/* This function will poll the status register for disappearance of a flag */
+static int twa_poll_status_gone(TW_Device_Extension *tw_dev, u32 flag, int seconds)
+{
+	u32 status_reg_value;
+	unsigned long before;
+	int retval = 1;
+
+	status_reg_value = readl(TW_STATUS_REG_ADDR(tw_dev));
+	before = jiffies;
+
+	if (twa_check_bits(status_reg_value))
+		twa_decode_bits(tw_dev, status_reg_value);
+
+	while ((status_reg_value & flag) != 0) {
+		status_reg_value = readl(TW_STATUS_REG_ADDR(tw_dev));
+		if (twa_check_bits(status_reg_value))
+			twa_decode_bits(tw_dev, status_reg_value);
+
+		if (time_after(jiffies, before + HZ * seconds))
+			goto out;
+
+		msleep(50);
+	}
+	retval = 0;
+out:
+	return retval;
+} /* End twa_poll_status_gone() */
+
+/* This function will attempt to post a command packet to the board */
+static int twa_post_command_packet(TW_Device_Extension *tw_dev, int request_id, char internal)
+{
+	u32 status_reg_value;
+	unsigned long command_que_value;
+	int retval = 1;
+
+	command_que_value = tw_dev->command_packet_phys[request_id];
+	status_reg_value = readl(TW_STATUS_REG_ADDR(tw_dev));
+
+	if (twa_check_bits(status_reg_value))
+		twa_decode_bits(tw_dev, status_reg_value);
+
+	if (((tw_dev->pending_request_count > 0) && (tw_dev->state[request_id] != TW_S_PENDING)) || (status_reg_value & TW_STATUS_COMMAND_QUEUE_FULL)) {
+
+		/* Only pend internal driver commands */
+		if (!internal) {
+			retval = SCSI_MLQUEUE_HOST_BUSY;
+			goto out;
+		}
+
+		/* Couldn't post the command packet, so we do it later */
+		if (tw_dev->state[request_id] != TW_S_PENDING) {
+			tw_dev->state[request_id] = TW_S_PENDING;
+			tw_dev->pending_request_count++;
+			if (tw_dev->pending_request_count > tw_dev->max_pending_request_count) {
+				tw_dev->max_pending_request_count = tw_dev->pending_request_count;
+			}
+			tw_dev->pending_queue[tw_dev->pending_tail] = request_id;
+			tw_dev->pending_tail = (tw_dev->pending_tail + 1) % TW_Q_LENGTH;
+		}
+		TW_UNMASK_COMMAND_INTERRUPT(tw_dev);
+		goto out;
+	} else {
+		/* We successfully posted the command packet */
+#if BITS_PER_LONG > 32
+		writeq(TW_COMMAND_OFFSET + command_que_value, TW_COMMAND_QUEUE_REG_ADDR(tw_dev));
+#else
+		writel(TW_COMMAND_OFFSET + command_que_value, TW_COMMAND_QUEUE_REG_ADDR(tw_dev));
+#endif
+		tw_dev->state[request_id] = TW_S_POSTED;
+		tw_dev->posted_request_count++;
+		if (tw_dev->posted_request_count > tw_dev->max_posted_request_count) {
+			tw_dev->max_posted_request_count = tw_dev->posted_request_count;
+		}
+	}
+	retval = 0;
+out:
+	return retval;
+} /* End twa_post_command_packet() */
+
+/* This function will reset a device extension */
+static int twa_reset_device_extension(TW_Device_Extension *tw_dev)
+{
+	int i = 0;
+	int retval = 1;
+
+	/* Abort all requests that are in progress */
+	for (i = 0; i < TW_Q_LENGTH; i++) {
+		if ((tw_dev->state[i] != TW_S_FINISHED) &&
+		    (tw_dev->state[i] != TW_S_INITIAL) &&
+		    (tw_dev->state[i] != TW_S_COMPLETED)) {
+			if (tw_dev->srb[i]) {
+				tw_dev->srb[i]->result = (DID_RESET << 16);
+				tw_dev->srb[i]->scsi_done(tw_dev->srb[i]);
+				twa_unmap_scsi_data(tw_dev, i);
+			}
+		}
+	}
+
+	/* Reset queues and counts */
+	for (i = 0; i < TW_Q_LENGTH; i++) {
+		tw_dev->free_queue[i] = i;
+		tw_dev->state[i] = TW_S_INITIAL;
+	}
+	tw_dev->free_head = TW_Q_START;
+	tw_dev->free_tail = TW_Q_START;
+	tw_dev->posted_request_count = 0;
+	tw_dev->pending_request_count = 0;
+	tw_dev->pending_head = TW_Q_START;
+	tw_dev->pending_tail = TW_Q_START;
+	tw_dev->reset_print = 0;
+	tw_dev->chrdev_request_id = TW_IOCTL_CHRDEV_FREE;
+	tw_dev->flags = 0;
+
+	TW_DISABLE_INTERRUPTS(tw_dev);
+
+	if (twa_reset_sequence(tw_dev, 1))
+		goto out;
+
+        TW_ENABLE_AND_CLEAR_INTERRUPTS(tw_dev);
+
+	retval = 0;
+out:
+	return retval;
+} /* End twa_reset_device_extension() */
+
+/* This function will reset a controller */
+static int twa_reset_sequence(TW_Device_Extension *tw_dev, int soft_reset)
+{
+	int tries = 0, retval = 1, flashed = 0, do_soft_reset = soft_reset;
+
+	while (tries < TW_MAX_RESET_TRIES) {
+		if (do_soft_reset)
+			TW_SOFT_RESET(tw_dev);
+
+		/* Make sure controller is in a good state */
+		if (twa_poll_status(tw_dev, TW_STATUS_MICROCONTROLLER_READY | (do_soft_reset == 1 ? TW_STATUS_ATTENTION_INTERRUPT : 0), 30)) {
+			TW_PRINTK(tw_dev->host, TW_DRIVER, 0x1f, "Microcontroller not ready during reset sequence");
+			do_soft_reset = 1;
+			tries++;
+			continue;
+		}
+
+		/* Empty response queue */
+		if (twa_empty_response_queue(tw_dev)) {
+			TW_PRINTK(tw_dev->host, TW_DRIVER, 0x20, "Response queue empty failed during reset sequence");
+			do_soft_reset = 1;
+			tries++;
+			continue;
+		}
+
+		flashed = 0;
+
+		/* Check for compatibility/flash */
+		if (twa_check_srl(tw_dev, &flashed)) {
+			TW_PRINTK(tw_dev->host, TW_DRIVER, 0x21, "Compatibility check failed during reset sequence");
+			do_soft_reset = 1;
+			tries++;
+			continue;
+		} else {
+			if (flashed) {
+				tries++;
+				continue;
+			}
+		}
+
+		/* Drain the AEN queue */
+		if (twa_aen_drain_queue(tw_dev, soft_reset)) {
+			TW_PRINTK(tw_dev->host, TW_DRIVER, 0x22, "AEN drain failed during reset sequence");
+			do_soft_reset = 1;
+			tries++;
+			continue;
+		}
+
+		/* If we got here, controller is in a good state */
+		retval = 0;
+		goto out;
+	}
+out:
+	return retval;
+} /* End twa_reset_sequence() */
+
+/* This funciton returns unit geometry in cylinders/heads/sectors */
+static int twa_scsi_biosparam(struct scsi_device *sdev, struct block_device *bdev, sector_t capacity, int geom[])
+{
+	int heads, sectors, cylinders;
+	TW_Device_Extension *tw_dev;
+
+	tw_dev = (TW_Device_Extension *)sdev->host->hostdata;
+
+	if (capacity >= 0x200000) {
+		heads = 255;
+		sectors = 63;
+		cylinders = sector_div(capacity, heads * sectors);
+	} else {
+		heads = 64;
+		sectors = 32;
+		cylinders = sector_div(capacity, heads * sectors);
+	}
+
+	geom[0] = heads;
+	geom[1] = sectors;
+	geom[2] = cylinders;
+
+	return 0;
+} /* End twa_scsi_biosparam() */
+
+/* This is the new scsi eh abort function */
+static int twa_scsi_eh_abort(struct scsi_cmnd *SCpnt)
+{
+	int i;
+	TW_Device_Extension *tw_dev = NULL;
+	int retval = FAILED;
+
+	tw_dev = (TW_Device_Extension *)SCpnt->device->host->hostdata;
+
+	spin_unlock_irq(tw_dev->host->host_lock);
+
+	tw_dev->num_aborts++;
+
+	/* If we find any IO's in process, we have to reset the card */
+	for (i = 0; i < TW_Q_LENGTH; i++) {
+		if ((tw_dev->state[i] != TW_S_FINISHED) && (tw_dev->state[i] != TW_S_INITIAL)) {
+			printk(KERN_WARNING "3w-9xxx: scsi%d: WARNING: (0x%02X:0x%04X): Unit #%d: Command (0x%x) timed out, resetting card.\n",
+			       tw_dev->host->host_no, TW_DRIVER, 0x2c,
+			       SCpnt->device->id, SCpnt->cmnd[0]);
+			if (twa_reset_device_extension(tw_dev)) {
+				TW_PRINTK(tw_dev->host, TW_DRIVER, 0x2a, "Controller reset failed during scsi abort");
+				goto out;
+			}
+			break;
+		}
+	}
+	retval = SUCCESS;
+out:
+	spin_lock_irq(tw_dev->host->host_lock);
+	return retval;
+} /* End twa_scsi_eh_abort() */
+
+/* This is the new scsi eh reset function */
+static int twa_scsi_eh_reset(struct scsi_cmnd *SCpnt)
+{
+	TW_Device_Extension *tw_dev = NULL;
+	int retval = FAILED;
+
+	tw_dev = (TW_Device_Extension *)SCpnt->device->host->hostdata;
+
+	spin_unlock_irq(tw_dev->host->host_lock);
+
+	tw_dev->num_resets++;
+
+	printk(KERN_WARNING "3w-9xxx: scsi%d: SCSI host reset started.\n", tw_dev->host->host_no);
+
+	/* Now reset the card and some of the device extension data */
+	if (twa_reset_device_extension(tw_dev)) {
+		TW_PRINTK(tw_dev->host, TW_DRIVER, 0x2b, "Controller reset failed during scsi host reset");
+		goto out;
+	}
+	printk(KERN_WARNING "3w-9xxx: scsi%d: SCSI host reset succeeded.\n", tw_dev->host->host_no);
+	retval = SUCCESS;
+out:
+	spin_lock_irq(tw_dev->host->host_lock);
+	return retval;
+} /* End twa_scsi_eh_reset() */
+
+/* This is the main scsi queue function to handle scsi opcodes */
+static int twa_scsi_queue(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *))
+{
+	int request_id, retval;
+	TW_Device_Extension *tw_dev = (TW_Device_Extension *)SCpnt->device->host->hostdata;
+
+	/* Save done function into scsi_cmnd struct */
+	SCpnt->scsi_done = done;
+		
+	/* Get a free request id */
+	twa_get_request_id(tw_dev, &request_id);
+
+	/* Save the scsi command for use by the ISR */
+	tw_dev->srb[request_id] = SCpnt;
+
+	/* Initialize phase to zero */
+	SCpnt->SCp.phase = TW_PHASE_INITIAL;
+
+	retval = twa_scsiop_execute_scsi(tw_dev, request_id, NULL, 0, NULL);
+	switch (retval) {
+	case SCSI_MLQUEUE_HOST_BUSY:
+		twa_free_request_id(tw_dev, request_id);
+		break;
+	case 1:
+		tw_dev->state[request_id] = TW_S_COMPLETED;
+		twa_free_request_id(tw_dev, request_id);
+		SCpnt->result = (DID_ERROR << 16);
+		done(SCpnt);
+	}
+
+	return retval;
+} /* End twa_scsi_queue() */
+
+/* This function hands scsi cdb's to the firmware */
+static int twa_scsiop_execute_scsi(TW_Device_Extension *tw_dev, int request_id, char *cdb, int use_sg, TW_SG_Apache *sglistarg)
+{
+	TW_Command_Full *full_command_packet;
+	TW_Command_Apache *command_packet;
+	u32 num_sectors = 0x0;
+	int i, sg_count;
+	struct scsi_cmnd *srb = NULL;
+	struct scatterlist *sglist = NULL;
+	u32 buffaddr = 0x0;
+	int retval = 1;
+
+	if (tw_dev->srb[request_id]) {
+		if (tw_dev->srb[request_id]->request_buffer) {
+			sglist = (struct scatterlist *)tw_dev->srb[request_id]->request_buffer;
+		}
+		srb = tw_dev->srb[request_id];
+	}
+
+	/* Initialize command packet */
+	full_command_packet = tw_dev->command_packet_virt[request_id];
+	full_command_packet->header.header_desc.size_header = 128;
+	full_command_packet->header.status_block.error = 0;
+	full_command_packet->header.status_block.severity__reserved = 0;
+
+	command_packet = &full_command_packet->command.newcommand;
+	command_packet->status = 0;
+	command_packet->opcode__reserved = TW_OPRES_IN(0, TW_OP_EXECUTE_SCSI);
+
+	/* We forced 16 byte cdb use earlier */
+	if (!cdb)
+		memcpy(command_packet->cdb, srb->cmnd, TW_MAX_CDB_LEN);
+	else
+		memcpy(command_packet->cdb, cdb, TW_MAX_CDB_LEN);
+
+	if (srb)
+		command_packet->unit = srb->device->id;
+	else
+		command_packet->unit = 0;
+
+	command_packet->request_id = request_id;
+	command_packet->sgl_offset = 16;
+
+	if (!sglistarg) {
+		/* Map sglist from scsi layer to cmd packet */
+		if (tw_dev->srb[request_id]->use_sg == 0) {
+			if (tw_dev->srb[request_id]->request_bufflen < TW_MIN_SGL_LENGTH) {
+				command_packet->sg_list[0].address = tw_dev->generic_buffer_phys[request_id];
+				command_packet->sg_list[0].length = TW_MIN_SGL_LENGTH;
+			} else {
+				buffaddr = twa_map_scsi_single_data(tw_dev, request_id);
+				if (buffaddr == 0)
+					goto out;
+
+				command_packet->sg_list[0].address = buffaddr;
+				command_packet->sg_list[0].length = tw_dev->srb[request_id]->request_bufflen;
+			}
+			command_packet->sgl_entries = 1;
+
+			if (command_packet->sg_list[0].address & TW_ALIGNMENT_9000_SGL) {
+				TW_PRINTK(tw_dev->host, TW_DRIVER, 0x2d, "Found unaligned address during execute scsi");
+				goto out;
+			}
+		}
+
+		if (tw_dev->srb[request_id]->use_sg > 0) {
+			sg_count = twa_map_scsi_sg_data(tw_dev, request_id);
+			if (sg_count == 0)
+				goto out;
+
+			for (i = 0; i < sg_count; i++) {
+				command_packet->sg_list[i].address = sg_dma_address(&sglist[i]);
+				command_packet->sg_list[i].length = sg_dma_len(&sglist[i]);
+				if (command_packet->sg_list[i].address & TW_ALIGNMENT_9000_SGL) {
+					TW_PRINTK(tw_dev->host, TW_DRIVER, 0x2e, "Found unaligned sgl address during execute scsi");
+					goto out;
+				}
+			}
+			command_packet->sgl_entries = tw_dev->srb[request_id]->use_sg;
+		}
+	} else {
+		/* Internal cdb post */
+		for (i = 0; i < use_sg; i++) {
+			command_packet->sg_list[i].address = sglistarg[i].address;
+			command_packet->sg_list[i].length = sglistarg[i].length;
+			if (command_packet->sg_list[i].address & TW_ALIGNMENT_9000_SGL) {
+				TW_PRINTK(tw_dev->host, TW_DRIVER, 0x2f, "Found unaligned sgl address during internal post");
+				goto out;
+			}
+		}
+		command_packet->sgl_entries = use_sg;
+	}
+
+	if (srb) {
+		if (srb->cmnd[0] == READ_6 || srb->cmnd[0] == WRITE_6)
+			num_sectors = (u32)srb->cmnd[4];
+
+		if (srb->cmnd[0] == READ_10 || srb->cmnd[0] == WRITE_10)
+			num_sectors = (u32)srb->cmnd[8] | ((u32)srb->cmnd[7] << 8);
+	}
+
+	/* Update sector statistic */
+	tw_dev->sector_count = num_sectors;
+	if (tw_dev->sector_count > tw_dev->max_sector_count)
+		tw_dev->max_sector_count = tw_dev->sector_count;
+
+	/* Update SG statistics */
+	if (srb) {
+		tw_dev->sgl_entries = tw_dev->srb[request_id]->use_sg;
+		if (tw_dev->sgl_entries > tw_dev->max_sgl_entries)
+			tw_dev->max_sgl_entries = tw_dev->sgl_entries;
+	}
+
+	/* Now post the command to the board */
+	if (srb) {
+		retval = twa_post_command_packet(tw_dev, request_id, 0);
+	} else {
+		twa_post_command_packet(tw_dev, request_id, 1);
+		retval = 0;
+	}
+out:
+	return retval;
+} /* End twa_scsiop_execute_scsi() */
+
+/* This function completes an execute scsi operation */
+static void twa_scsiop_execute_scsi_complete(TW_Device_Extension *tw_dev, int request_id)
+{
+	/* Copy the response if too small */
+	if ((tw_dev->srb[request_id]->request_buffer) && (tw_dev->srb[request_id]->request_bufflen < TW_MIN_SGL_LENGTH)) {
+		memcpy(tw_dev->srb[request_id]->request_buffer,
+		       tw_dev->generic_buffer_virt[request_id],
+		       tw_dev->srb[request_id]->request_bufflen);
+	}
+} /* End twa_scsiop_execute_scsi_complete() */
+
+/* This function tells the controller to shut down */
+static void __twa_shutdown(TW_Device_Extension *tw_dev)
+{
+	/* Disable interrupts */
+	TW_DISABLE_INTERRUPTS(tw_dev);
+
+	printk(KERN_WARNING "3w-9xxx: Shutting down host %d.\n", tw_dev->host->host_no);
+
+	/* Tell the card we are shutting down */
+	if (twa_initconnection(tw_dev, 1, 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL, NULL)) {
+		TW_PRINTK(tw_dev->host, TW_DRIVER, 0x31, "Connection shutdown failed");
+	} else {
+		printk(KERN_WARNING "3w-9xxx: Shutdown complete.\n");
+	}
+
+	/* Clear all interrupts just before exit */
+	TW_ENABLE_AND_CLEAR_INTERRUPTS(tw_dev);
+} /* End __twa_shutdown() */
+
+/* Wrapper for __twa_shutdown */
+static void twa_shutdown(struct device *dev)
+{
+	struct Scsi_Host *host = pci_get_drvdata(to_pci_dev(dev));
+	TW_Device_Extension *tw_dev = (TW_Device_Extension *)host->hostdata;
+
+	__twa_shutdown(tw_dev);
+} /* End twa_shutdown() */
+
+/* This function will look up a string */
+static char *twa_string_lookup(twa_message_type *table, unsigned int code)
+{
+	int index;
+
+	for (index = 0; ((code != table[index].code) &&
+		      (table[index].text != (char *)0)); index++);
+	return(table[index].text);
+} /* End twa_string_lookup() */
+
+/* This function will perform a pci-dma unmap */
+static void twa_unmap_scsi_data(TW_Device_Extension *tw_dev, int request_id)
+{
+	struct scsi_cmnd *cmd = tw_dev->srb[request_id];
+	struct pci_dev *pdev = tw_dev->tw_pci_dev;
+
+	switch(cmd->SCp.phase) {
+	case TW_PHASE_SINGLE:
+		pci_unmap_single(pdev, cmd->SCp.have_data_in, cmd->request_bufflen, DMA_BIDIRECTIONAL);
+		break;
+	case TW_PHASE_SGLIST:
+		pci_unmap_sg(pdev, cmd->request_buffer, cmd->use_sg, DMA_BIDIRECTIONAL);
+		break;
+	}
+} /* End twa_unmap_scsi_data() */
+
+/* scsi_host_template initializer */
+static struct scsi_host_template driver_template = {
+	.module			= THIS_MODULE,
+	.name			= "3ware 9000 Storage Controller",
+	.queuecommand		= twa_scsi_queue,
+	.eh_abort_handler	= twa_scsi_eh_abort,
+	.eh_host_reset_handler	= twa_scsi_eh_reset,
+	.bios_param		= twa_scsi_biosparam,
+	.can_queue		= TW_Q_LENGTH-2,
+	.this_id		= -1,
+	.sg_tablesize		= TW_APACHE_MAX_SGL_LENGTH,
+	.max_sectors		= TW_MAX_SECTORS,
+	.cmd_per_lun		= TW_MAX_CMDS_PER_LUN,
+	.use_clustering		= ENABLE_CLUSTERING,
+	.shost_attrs		= twa_host_attrs,
+	.sdev_attrs		= twa_dev_attrs,
+	.emulated		= 1
+};
+
+/* This function will probe and initialize a card */
+static int __devinit twa_probe(struct pci_dev *pdev, const struct pci_device_id *dev_id)
+{
+	struct Scsi_Host *host = NULL;
+	TW_Device_Extension *tw_dev;
+	u32 mem_addr;
+	int retval = -ENODEV;
+
+	retval = pci_enable_device(pdev);
+	if (retval) {
+		TW_PRINTK(host, TW_DRIVER, 0x34, "Failed to enable pci device");
+		goto out_disable_device;
+	}
+
+	pci_set_master(pdev);
+
+	retval = pci_set_dma_mask(pdev, TW_DMA_MASK);
+	if (retval) {
+		TW_PRINTK(host, TW_DRIVER, 0x23, "Failed to set dma mask");
+		goto out_disable_device;
+	}
+
+	host = scsi_host_alloc(&driver_template, sizeof(TW_Device_Extension));
+	if (!host) {
+		TW_PRINTK(host, TW_DRIVER, 0x24, "Failed to allocate memory for device extension");
+		retval = -ENOMEM;
+		goto out_disable_device;
+	}
+	tw_dev = (TW_Device_Extension *)host->hostdata;
+
+	memset(tw_dev, 0, sizeof(TW_Device_Extension));
+
+	/* Save values to device extension */
+	tw_dev->host = host;
+	tw_dev->tw_pci_dev = pdev;
+
+	if (twa_initialize_device_extension(tw_dev)) {
+		TW_PRINTK(tw_dev->host, TW_DRIVER, 0x25, "Failed to initialize device extension");
+		goto out_free_device_extension;
+	}
+
+	/* Request IO regions */
+	retval = pci_request_regions(pdev, "3w-9xxx");
+	if (retval) {
+		TW_PRINTK(tw_dev->host, TW_DRIVER, 0x26, "Failed to get mem region");
+		goto out_free_device_extension;
+	}
+
+	mem_addr = pci_resource_start(pdev, 1);
+
+	/* Save base address */
+	tw_dev->base_addr = ioremap(mem_addr, PAGE_SIZE);
+	if (!tw_dev->base_addr) {
+		TW_PRINTK(tw_dev->host, TW_DRIVER, 0x35, "Failed to ioremap");
+		goto out_release_mem_region;
+	}
+
+	/* Disable interrupts on the card */
+	TW_DISABLE_INTERRUPTS(tw_dev);
+
+	/* Initialize the card */
+	if (twa_reset_sequence(tw_dev, 0))
+		goto out_release_mem_region;
+
+	/* Set host specific parameters */
+	host->max_id = TW_MAX_UNITS;
+	host->max_cmd_len = TW_MAX_CDB_LEN;
+
+	/* Luns and channels aren't supported by adapter */
+	host->max_lun = 0;
+	host->max_channel = 0;
+
+	/* Register the card with the kernel SCSI layer */
+	retval = scsi_add_host(host, &pdev->dev);
+	if (retval) {
+		TW_PRINTK(tw_dev->host, TW_DRIVER, 0x27, "scsi add host failed");
+		goto out_release_mem_region;
+	}
+
+	pci_set_drvdata(pdev, host);
+
+	printk(KERN_WARNING "3w-9xxx: scsi%d: Found a 3ware 9000 Storage Controller at 0x%x, IRQ: %d.\n",
+	       host->host_no, mem_addr, pdev->irq);
+	printk(KERN_WARNING "3w-9xxx: scsi%d: Firmware %s, BIOS %s, Ports: %d.\n",
+	       host->host_no,
+	       (char *)twa_get_param(tw_dev, 0, TW_VERSION_TABLE,
+				     TW_PARAM_FWVER, TW_PARAM_FWVER_LENGTH),
+	       (char *)twa_get_param(tw_dev, 1, TW_VERSION_TABLE,
+				     TW_PARAM_BIOSVER, TW_PARAM_BIOSVER_LENGTH),
+	       *(int *)twa_get_param(tw_dev, 2, TW_INFORMATION_TABLE,
+				     TW_PARAM_PORTCOUNT, TW_PARAM_PORTCOUNT_LENGTH));
+
+	/* Now setup the interrupt handler */
+	retval = request_irq(pdev->irq, twa_interrupt, SA_SHIRQ, "3w-9xxx", tw_dev);
+	if (retval) {
+		TW_PRINTK(tw_dev->host, TW_DRIVER, 0x30, "Error requesting IRQ");
+		goto out_remove_host;
+	}
+
+	twa_device_extension_list[twa_device_extension_count] = tw_dev;
+	twa_device_extension_count++;
+
+	/* Re-enable interrupts on the card */
+	TW_ENABLE_AND_CLEAR_INTERRUPTS(tw_dev);
+
+	/* Finally, scan the host */
+	scsi_scan_host(host);
+
+	if (twa_major == -1) {
+		if ((twa_major = register_chrdev (0, "twa", &twa_fops)) < 0)
+			TW_PRINTK(host, TW_DRIVER, 0x29, "Failed to register character device");
+	}
+	return 0;
+
+out_remove_host:
+	scsi_remove_host(host);
+out_release_mem_region:
+	pci_release_regions(pdev);
+out_free_device_extension:
+	twa_free_device_extension(tw_dev);
+	scsi_host_put(host);
+out_disable_device:
+	pci_disable_device(pdev);
+
+	return retval;
+} /* End twa_probe() */
+
+/* This function is called to remove a device */
+static void twa_remove(struct pci_dev *pdev)
+{
+	struct Scsi_Host *host = pci_get_drvdata(pdev);
+	TW_Device_Extension *tw_dev = (TW_Device_Extension *)host->hostdata;
+
+	scsi_remove_host(tw_dev->host);
+
+	__twa_shutdown(tw_dev);
+
+	/* Free up the IRQ */
+	free_irq(tw_dev->tw_pci_dev->irq, tw_dev);
+
+	/* Free up the mem region */
+	pci_release_regions(pdev);
+
+	/* Free up device extension resources */
+	twa_free_device_extension(tw_dev);
+
+	/* Unregister character device */
+	if (twa_major >= 0) {
+		unregister_chrdev(twa_major, "twa");
+		twa_major = -1;
+	}
+
+	scsi_host_put(tw_dev->host);
+	pci_disable_device(pdev);
+	twa_device_extension_count--;
+} /* End twa_remove() */
+
+/* PCI Devices supported by this driver */
+static struct pci_device_id twa_pci_tbl[] __devinitdata = {
+	{ PCI_VENDOR_ID_3WARE, PCI_DEVICE_ID_3WARE_9000,
+	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{ }
+};
+MODULE_DEVICE_TABLE(pci, twa_pci_tbl);
+
+/* pci_driver initializer */
+static struct pci_driver twa_driver = {
+	.name		= "3w-9xxx",
+	.id_table	= twa_pci_tbl,
+	.probe		= twa_probe,
+	.remove		= twa_remove,
+	.driver		= {
+		.shutdown = twa_shutdown
+	}
+};
+
+/* This function is called on driver initialization */
+static int __init twa_init(void)
+{
+	printk(KERN_WARNING "3ware 9000 Storage Controller device driver for Linux v%s.\n", twa_driver_version);
+
+	return pci_module_init(&twa_driver);
+} /* End twa_init() */
+
+/* This function is called on driver exit */
+static void __exit twa_exit(void)
+{
+	pci_unregister_driver(&twa_driver);
+} /* End twa_exit() */
+
+module_init(twa_init);
+module_exit(twa_exit);
+
--- diff/drivers/scsi/3w-9xxx.h	1970-01-01 01:00:00.000000000 +0100
+++ source/drivers/scsi/3w-9xxx.h	2004-06-11 19:22:03.000000000 +0100
@@ -0,0 +1,704 @@
+/*
+   3w-9xxx.h -- 3ware 9000 Storage Controller device driver for Linux.
+
+   Written By: Adam Radford <linuxraid@amcc.com>
+
+   Copyright (C) 2004 Applied Micro Circuits Corporation.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; version 2 of the License.
+
+   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.
+
+   NO WARRANTY
+   THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR
+   CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT
+   LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT,
+   MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is
+   solely responsible for determining the appropriateness of using and
+   distributing the Program and assumes all risks associated with its
+   exercise of rights under this Agreement, including but not limited to
+   the risks and costs of program errors, damage to or loss of data,
+   programs or equipment, and unavailability or interruption of operations.
+
+   DISCLAIMER OF LIABILITY
+   NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY
+   DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+   DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND
+   ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
+   TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
+   USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED
+   HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES
+
+   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
+
+   Bugs/Comments/Suggestions should be mailed to:
+   linuxraid@amcc.com
+
+   For more information, goto:
+   http://www.amcc.com
+*/
+
+#ifndef _3W_9XXX_H
+#define _3W_9XXX_H
+
+/* AEN string type */
+typedef struct TAG_twa_message_type {
+  unsigned int   code;
+  char*          text;
+} twa_message_type;
+
+/* AEN strings */
+static twa_message_type twa_aen_table[] = {
+	{0x0000, "AEN queue empty"},
+	{0x0001, "Controller reset occurred"},
+	{0x0002, "Degraded unit detected"},
+	{0x0003, "Controller error occured"},
+	{0x0004, "Background rebuild failed"},
+	{0x0005, "Background rebuild done"},
+	{0x0006, "Incomplete unit detected"},
+	{0x0007, "Background initialize done"},
+	{0x0008, "Unclean shutdown detected"},
+	{0x0009, "Drive timeout detected"},
+	{0x000A, "Drive error detected"},
+	{0x000B, "Rebuild started"},
+	{0x000C, "Background initialize started"},
+	{0x000D, "Entire logical unit was deleted"},
+	{0x000E, "Background initialize failed"},
+	{0x000F, "SMART attribute exceeded threshold"},
+	{0x0010, "Power supply reported AC under range"},
+	{0x0011, "Power supply reported DC out of range"},
+	{0x0012, "Power supply reported a malfunction"},
+	{0x0013, "Power supply predicted malfunction"},
+	{0x0014, "Battery charge is below threshold"},
+	{0x0015, "Fan speed is below threshold"},
+	{0x0016, "Temperature sensor is above threshold"},
+	{0x0017, "Power supply was removed"},
+	{0x0018, "Power supply was inserted"},
+	{0x0019, "Drive was removed from a bay"},
+	{0x001A, "Drive was inserted into a bay"},
+	{0x001B, "Drive bay cover door was opened"},
+	{0x001C, "Drive bay cover door was closed"},
+	{0x001D, "Product case was opened"},
+	{0x0020, "Prepare for shutdown (power-off)"},
+	{0x0021, "Downgrade UDMA mode to lower speed"},
+	{0x0022, "Upgrade UDMA mode to higher speed"},
+	{0x0023, "Sector repair completed"},
+	{0x0024, "Sbuf memory test failed"},
+	{0x0025, "Error flushing cached write data to array"},
+	{0x0026, "Drive reported data ECC error"},
+	{0x0027, "DCB has checksum error"},
+	{0x0028, "DCB version is unsupported"},
+	{0x0029, "Background verify started"},
+	{0x002A, "Background verify failed"},
+	{0x002B, "Background verify done"},
+	{0x002C, "Bad sector overwritten during rebuild"},
+	{0x002D, "Background rebuild error on source drive"},
+	{0x002E, "Replace failed because replacement drive too small"},
+	{0x002F, "Verify failed because array was never initialized"},
+	{0x0030, "Unsupported ATA drive"},
+	{0x0031, "Synchronize host/controller time"},
+	{0x0032, "Spare capacity is inadequate for some units"},
+	{0x0033, "Background migration started"},
+	{0x0034, "Background migration failed"},
+	{0x0035, "Background migration done"},
+	{0x0036, "Verify detected and fixed data/parity mismatch"},
+	{0x0037, "SO-DIMM incompatible"},
+	{0x0038, "SO-DIMM not detected"},
+	{0x0039, "Corrected Sbuf ECC error"},
+	{0x003A, "Drive power on reset detected"},
+	{0x003B, "Background rebuild paused"},
+	{0x003C, "Background initialize paused"},
+	{0x003D, "Background verify paused"},
+	{0x003E, "Background migration paused"},
+	{0x003F, "Corrupt flash file system detected"},
+	{0x0040, "Flash file system repaired"},
+	{0x0041, "Unit number assignments were lost"},
+	{0x0042, "Error during read of primary DCB"},
+	{0x0043, "Latent error found in backup DCB"},
+	{0x00FC, "Recovered/finished array membership update"},
+	{0x00FD, "Handler lockup"},
+	{0x00FE, "Retrying PCI transfer"},
+	{0x00FF, "AEN queue is full"},
+	{0xFFFFFFFF, (char*) 0}
+};
+
+/* AEN severity table */
+static char *twa_aen_severity_table[] =
+{
+	"None", "ERROR", "WARNING", "INFO", "DEBUG", (char*) 0
+};
+
+/* Error strings */
+static twa_message_type twa_error_table[] = {
+	{0x0100, "SGL entry contains zero data"},
+	{0x0101, "Invalid command opcode"},
+	{0x0102, "SGL entry has unaligned address"},
+	{0x0103, "SGL size does not match command"},
+	{0x0104, "SGL entry has illegal length"},
+	{0x0105, "Command packet is not aligned"},
+	{0x0106, "Invalid request ID"},
+	{0x0107, "Duplicate request ID"},
+	{0x0108, "ID not locked"},
+	{0x0109, "LBA out of range"},
+	{0x010A, "Logical unit not supported"},
+	{0x010B, "Parameter table does not exist"},
+	{0x010C, "Parameter index does not exist"},
+	{0x010D, "Invalid field in CDB"},
+	{0x010E, "Specified port has invalid drive"},
+	{0x010F, "Parameter item size mismatch"},
+	{0x0110, "Failed memory allocation"},
+	{0x0111, "Memory request too large"},
+	{0x0112, "Out of memory segments"},
+	{0x0113, "Invalid address to deallocate"},
+	{0x0114, "Out of memory"},
+	{0x0115, "Out of heap"},
+	{0x0120, "Double degrade"},
+	{0x0121, "Drive not degraded"},
+	{0x0122, "Reconstruct error"},
+	{0x0123, "Replace not accepted"},
+	{0x0124, "Replace drive capacity too small"},
+	{0x0125, "Sector count not allowed"},
+	{0x0126, "No spares left"},
+	{0x0127, "Reconstruct error"},
+	{0x0128, "Unit is offline"},
+	{0x0129, "Cannot update status to DCB"},
+	{0x0130, "Invalid stripe handle"},
+	{0x0131, "Handle that was not locked"},
+	{0x0132, "Handle that was not empty"},
+	{0x0133, "Handle has different owner"},
+	{0x0140, "IPR has parent"},
+	{0x0150, "Illegal Pbuf address alignment"},
+	{0x0151, "Illegal Pbuf transfer length"},
+	{0x0152, "Illegal Sbuf address alignment"},
+	{0x0153, "Illegal Sbuf transfer length"},
+	{0x0160, "Command packet too large"},
+	{0x0161, "SGL exceeds maximum length"},
+	{0x0162, "SGL has too many entries"},
+	{0x0170, "Insufficient resources for rebuilder"},
+	{0x0171, "Verify error (data != parity)"},
+	{0x0180, "Requested segment not in directory of this DCB"},
+	{0x0181, "DCB segment has unsupported version"},
+	{0x0182, "DCB segment has checksum error"},
+	{0x0183, "DCB support (settings) segment invalid"},
+	{0x0184, "DCB UDB (unit descriptor block) segment invalid"},
+	{0x0185, "DCB GUID (globally unique identifier) segment invalid"},
+	{0x01A0, "Could not clear Sbuf"},
+	{0x01C0, "Flash identify failed"},
+	{0x01C1, "Flash out of bounds"},
+	{0x01C2, "Flash verify error"},
+	{0x01C3, "Flash file object not found"},
+	{0x01C4, "Flash file already present"},
+	{0x01C5, "Flash file system full"},
+	{0x01C6, "Flash file not present"},
+	{0x01C7, "Flash file size error"},
+	{0x01C8, "Bad flash file checksum"},
+	{0x01CA, "Corrupt flash file system detected"},
+	{0x01D0, "Invalid field in parameter list"},
+	{0x01D1, "Parameter list length error"},
+	{0x01D2, "Parameter item is not changeable"},
+	{0x01D3, "Parameter item is not saveable"},
+	{0x0200, "UDMA CRC error"},
+	{0x0201, "Internal CRC error"},
+	{0x0202, "Data ECC error"},
+	{0x0203, "ADP level 1 error"},
+	{0x0204, "Port timeout"},
+	{0x0205, "Drive power on reset"},
+	{0x0206, "ADP level 2 error"},
+	{0x0207, "Soft reset failed"},
+	{0x0208, "Drive not ready"},
+	{0x0209, "Unclassified port error"},
+	{0x020A, "Drive aborted command"},
+	{0x0210, "Internal CRC error"},
+	{0x0211, "PCI abort error"},
+	{0x0212, "PCI parity error"},
+	{0x0213, "Port handler error"},
+	{0x0214, "Token interrupt count error"},
+	{0x0215, "Timeout waiting for PCI transfer"},
+	{0x0216, "Corrected buffer ECC"},
+	{0x0217, "Uncorrected buffer ECC"},
+	{0x0230, "Unsupported command during flash recovery"},
+	{0x0231, "Next image buffer expected"},
+	{0x0232, "Binary image architecture incompatible"},
+	{0x0233, "Binary image has no signature"},
+	{0x0234, "Binary image has bad checksum"},
+	{0x0235, "Image downloaded overflowed buffer"},
+	{0x0240, "I2C device not found"},
+	{0x0241, "I2C transaction aborted"},
+	{0x0242, "SO-DIMM parameter(s) incompatible using defaults"},
+	{0x0243, "SO-DIMM unsupported"},
+	{0x0248, "SPI transfer status error"},
+	{0x0249, "SPI transfer timeout error"},
+	{0x0250, "Invalid unit descriptor size in CreateUnit"},
+	{0x0251, "Unit descriptor size exceeds data buffer in CreateUnit"},
+	{0x0252, "Invalid value in CreateUnit descriptor"},
+	{0x0253, "Inadequate disk space to support descriptor in CreateUnit"},
+	{0x0254, "Unable to create data channel for this unit descriptor"},
+	{0x0255, "CreateUnit descriptor specifies a drive already in use"},
+	{0x0256, "Unable to write configuration to all disks during CreateUnit"},
+	{0x0257, "CreateUnit does not support this descriptor version"},
+	{0x0258, "Invalid subunit for RAID 0 or 5 in CreateUnit"},
+	{0x0259, "Too many descriptors in CreateUnit"},
+	{0x025A, "Invalid configuration specified in CreateUnit descriptor"},
+	{0x025B, "Invalid LBA offset specified in CreateUnit descriptor"},
+	{0x025C, "Invalid stripelet size specified in CreateUnit descriptor"},
+	{0x0260, "SMART attribute exceeded threshold"},
+	{0xFFFFFFFF, (char*) 0}
+};
+
+/* Control register bit definitions */
+#define TW_CONTROL_CLEAR_HOST_INTERRUPT	       0x00080000
+#define TW_CONTROL_CLEAR_ATTENTION_INTERRUPT   0x00040000
+#define TW_CONTROL_MASK_COMMAND_INTERRUPT      0x00020000
+#define TW_CONTROL_MASK_RESPONSE_INTERRUPT     0x00010000
+#define TW_CONTROL_UNMASK_COMMAND_INTERRUPT    0x00008000
+#define TW_CONTROL_UNMASK_RESPONSE_INTERRUPT   0x00004000
+#define TW_CONTROL_CLEAR_ERROR_STATUS	       0x00000200
+#define TW_CONTROL_ISSUE_SOFT_RESET	       0x00000100
+#define TW_CONTROL_ENABLE_INTERRUPTS	       0x00000080
+#define TW_CONTROL_DISABLE_INTERRUPTS	       0x00000040
+#define TW_CONTROL_ISSUE_HOST_INTERRUPT	       0x00000020
+#define TW_CONTROL_CLEAR_PARITY_ERROR          0x00800000
+#define TW_CONTROL_CLEAR_QUEUE_ERROR           0x00400000
+#define TW_CONTROL_CLEAR_PCI_ABORT             0x00100000
+#define TW_CONTROL_CLEAR_SBUF_WRITE_ERROR      0x00000008
+
+/* Status register bit definitions */
+#define TW_STATUS_MAJOR_VERSION_MASK	       0xF0000000
+#define TW_STATUS_MINOR_VERSION_MASK	       0x0F000000
+#define TW_STATUS_PCI_PARITY_ERROR	       0x00800000
+#define TW_STATUS_QUEUE_ERROR		       0x00400000
+#define TW_STATUS_MICROCONTROLLER_ERROR	       0x00200000
+#define TW_STATUS_PCI_ABORT		       0x00100000
+#define TW_STATUS_HOST_INTERRUPT	       0x00080000
+#define TW_STATUS_ATTENTION_INTERRUPT	       0x00040000
+#define TW_STATUS_COMMAND_INTERRUPT	       0x00020000
+#define TW_STATUS_RESPONSE_INTERRUPT	       0x00010000
+#define TW_STATUS_COMMAND_QUEUE_FULL	       0x00008000
+#define TW_STATUS_RESPONSE_QUEUE_EMPTY	       0x00004000
+#define TW_STATUS_MICROCONTROLLER_READY	       0x00002000
+#define TW_STATUS_COMMAND_QUEUE_EMPTY	       0x00001000
+#define TW_STATUS_EXPECTED_BITS		       0x00002000
+#define TW_STATUS_UNEXPECTED_BITS	       0x00F00008
+#define TW_STATUS_SBUF_WRITE_ERROR             0x00000008
+#define TW_STATUS_VALID_INTERRUPT              0x00DF0008
+
+/* RESPONSE QUEUE BIT DEFINITIONS */
+#define TW_RESPONSE_ID_MASK		       0x00000FF0
+
+/* PCI related defines */
+#define TW_DEVICE_NAME			       "3w-9xxx"
+#define TW_NUMDEVICES 1
+#define TW_PCI_CLEAR_PARITY_ERRORS 0xc100
+#define TW_PCI_CLEAR_PCI_ABORT     0x2000
+
+/* Command packet opcodes used by the driver */
+#define TW_OP_INIT_CONNECTION 0x1
+#define TW_OP_GET_PARAM	      0x12
+#define TW_OP_SET_PARAM	      0x13
+#define TW_OP_EXECUTE_SCSI    0x10
+#define TW_OP_DOWNLOAD_FIRMWARE 0x16
+#define TW_OP_RESET             0x1C
+
+/* Asynchronous Event Notification (AEN) codes used by the driver */
+#define TW_AEN_QUEUE_EMPTY       0x0000
+#define TW_AEN_SOFT_RESET        0x0001
+#define TW_AEN_SYNC_TIME_WITH_HOST 0x031
+#define TW_AEN_SEVERITY_ERROR    0x1
+#define TW_AEN_SEVERITY_DEBUG    0x4
+#define TW_AEN_NOT_RETRIEVED 0x1
+#define TW_AEN_RETRIEVED 0x2
+
+/* Command state defines */
+#define TW_S_INITIAL   0x1  /* Initial state */
+#define TW_S_STARTED   0x2  /* Id in use */
+#define TW_S_POSTED    0x4  /* Posted to the controller */
+#define TW_S_PENDING   0x8  /* Waiting to be posted in isr */
+#define TW_S_COMPLETED 0x10 /* Completed by isr */
+#define TW_S_FINISHED  0x20 /* I/O completely done */
+
+/* Compatibility defines */
+#define TW_9000_ARCH_ID 0x5
+#define TW_CURRENT_FW_SRL 24
+#define TW_CURRENT_FW_BUILD 5
+#define TW_CURRENT_FW_BRANCH 1
+
+/* Phase defines */
+#define TW_PHASE_INITIAL 0
+#define TW_PHASE_SINGLE  1
+#define TW_PHASE_SGLIST  2
+
+/* Misc defines */
+#define TW_SECTOR_SIZE                        512
+#define TW_ALIGNMENT_9000                     4  /* 4 bytes */
+#define TW_ALIGNMENT_9000_SGL                 0x3
+#define TW_MAX_UNITS			      16
+#define TW_INIT_MESSAGE_CREDITS		      0x100
+#define TW_INIT_COMMAND_PACKET_SIZE	      0x3
+#define TW_INIT_COMMAND_PACKET_SIZE_EXTENDED  0x6
+#define TW_EXTENDED_INIT_CONNECT	      0x2
+#define TW_BUNDLED_FW_SAFE_TO_FLASH	      0x4
+#define TW_CTLR_FW_RECOMMENDS_FLASH	      0x8
+#define TW_CTLR_FW_COMPATIBLE		      0x2
+#define TW_BASE_FW_SRL			      0x17
+#define TW_BASE_FW_BRANCH		      0
+#define TW_BASE_FW_BUILD		      1
+#if BITS_PER_LONG > 32
+#define TW_APACHE_MAX_SGL_LENGTH 72
+#define TW_ESCALADE_MAX_SGL_LENGTH 41
+#define TW_APACHE_CMD_PKT_SIZE 5
+#else
+#define TW_APACHE_MAX_SGL_LENGTH 109
+#define TW_ESCALADE_MAX_SGL_LENGTH 62
+#define TW_APACHE_CMD_PKT_SIZE 4
+#endif
+#define TW_ATA_PASS_SGL_MAX                   60
+#define TW_Q_LENGTH			      256
+#define TW_Q_START			      0
+#define TW_MAX_SLOT			      32
+#define TW_MAX_RESET_TRIES		      2
+#define TW_MAX_CMDS_PER_LUN		      254
+#define TW_MAX_RESPONSE_DRAIN		      256
+#define TW_MAX_AEN_DRAIN		      40
+#define TW_IN_IOCTL                           2
+#define TW_IN_CHRDEV_IOCTL                    3
+#define TW_IN_ATTENTION_LOOP		      4
+#define TW_MAX_SECTORS                        256
+#define TW_AEN_WAIT_TIME                      1000
+#define TW_IOCTL_WAIT_TIME                    (1 * HZ) /* 1 second */
+#define TW_MAX_CDB_LEN                        16
+#define TW_ISR_DONT_COMPLETE                  2
+#define TW_ISR_DONT_RESULT                    3
+#define TW_IOCTL_CHRDEV_TIMEOUT               60 /* 60 seconds */
+#define TW_IOCTL_CHRDEV_FREE                  -1
+#define TW_COMMAND_OFFSET                     128 /* 128 bytes */
+#define TW_VERSION_TABLE                      0x0402
+#define TW_TIMEKEEP_TABLE		      0x040A
+#define TW_INFORMATION_TABLE		      0x0403
+#define TW_PARAM_FWVER			      3
+#define TW_PARAM_FWVER_LENGTH		      16
+#define TW_PARAM_BIOSVER		      4
+#define TW_PARAM_BIOSVER_LENGTH		      16
+#define TW_PARAM_PORTCOUNT		      3
+#define TW_PARAM_PORTCOUNT_LENGTH	      1
+#define TW_MIN_SGL_LENGTH                     0x200 /* 512 bytes */
+#define TW_MAX_SENSE_LENGTH                   256
+#define TW_EVENT_SOURCE_AEN                   0x1000
+#define TW_EVENT_SOURCE_COMMAND               0x1001
+#define TW_EVENT_SOURCE_PCHIP                 0x1002
+#define TW_EVENT_SOURCE_DRIVER                0x1003
+#define TW_IOCTL_GET_COMPATIBILITY_INFO	      0x101
+#define TW_IOCTL_GET_LAST_EVENT               0x102
+#define TW_IOCTL_GET_FIRST_EVENT              0x103
+#define TW_IOCTL_GET_NEXT_EVENT               0x104
+#define TW_IOCTL_GET_PREVIOUS_EVENT           0x105
+#define TW_IOCTL_GET_LOCK                     0x106
+#define TW_IOCTL_RELEASE_LOCK                 0x107
+#define TW_IOCTL_FIRMWARE_PASS_THROUGH        0x108
+#define TW_IOCTL_ERROR_STATUS_NOT_LOCKED      0x1001 // Not locked
+#define TW_IOCTL_ERROR_STATUS_LOCKED          0x1002 // Already locked
+#define TW_IOCTL_ERROR_STATUS_NO_MORE_EVENTS  0x1003 // No more events
+#define TW_IOCTL_ERROR_STATUS_AEN_CLOBBER     0x1004 // AEN clobber occurred
+#define TW_IOCTL_ERROR_OS_EFAULT	      -EFAULT // Bad address
+#define TW_IOCTL_ERROR_OS_EINTR		      -EINTR  // Interrupted system call
+#define TW_IOCTL_ERROR_OS_EINVAL	      -EINVAL // Invalid argument
+#define TW_IOCTL_ERROR_OS_ENOMEM	      -ENOMEM // Out of memory
+#define TW_IOCTL_ERROR_OS_ERESTARTSYS	      -ERESTARTSYS // Restart system call
+#define TW_IOCTL_ERROR_OS_EIO		      -EIO // I/O error
+#define TW_IOCTL_ERROR_OS_ENOTTY	      -ENOTTY // Not a typewriter
+#define TW_IOCTL_ERROR_OS_ENODEV	      -ENODEV // No such device
+#define TW_ALLOCATION_LENGTH		      128
+#define TW_SENSE_DATA_LENGTH		      18
+#define TW_STATUS_CHECK_CONDITION	      2
+#define TW_ERROR_LOGICAL_UNIT_NOT_SUPPORTED   0x10a
+#define TW_ERROR_UNIT_OFFLINE                 0x128
+#define TW_MESSAGE_SOURCE_CONTROLLER_ERROR    3
+#define TW_MESSAGE_SOURCE_CONTROLLER_EVENT    4
+#define TW_MESSAGE_SOURCE_LINUX_DRIVER        6
+#define TW_DRIVER TW_MESSAGE_SOURCE_LINUX_DRIVER
+#define TW_MESSAGE_SOURCE_LINUX_OS            9
+#define TW_OS TW_MESSAGE_SOURCE_LINUX_OS
+#if BITS_PER_LONG > 32
+#define TW_COMMAND_SIZE			      5
+#define TW_DMA_MASK			      DMA_64BIT_MASK
+#else
+#define TW_COMMAND_SIZE			      4
+#define TW_DMA_MASK			      DMA_32BIT_MASK
+#endif
+#ifndef PCI_DEVICE_ID_3WARE_9000
+#define PCI_DEVICE_ID_3WARE_9000 0x1002
+#endif
+
+/* Bitmask macros to eliminate bitfields */
+
+/* opcode: 5, reserved: 3 */
+#define TW_OPRES_IN(x,y) ((x << 5) | (y & 0x1f))
+#define TW_OP_OUT(x) (x & 0x1f)
+
+/* opcode: 5, sgloffset: 3 */
+#define TW_OPSGL_IN(x,y) ((x << 5) | (y & 0x1f))
+#define TW_SGL_OUT(x) ((x >> 5) & 0x7)
+
+/* severity: 3, reserved: 5 */
+#define TW_SEV_OUT(x) (x & 0x7)
+
+/* reserved_1: 4, response_id: 8, reserved_2: 20 */
+#define TW_RESID_OUT(x) ((x >> 4) & 0xff)
+
+/* Macros */
+#define TW_CONTROL_REG_ADDR(x) (x->base_addr)
+#define TW_STATUS_REG_ADDR(x) ((unsigned char *)x->base_addr + 0x4)
+#if BITS_PER_LONG > 32
+#define TW_COMMAND_QUEUE_REG_ADDR(x) ((unsigned char *)x->base_addr + 0x20)
+#else
+#define TW_COMMAND_QUEUE_REG_ADDR(x) ((unsigned char *)x->base_addr + 0x8)
+#endif
+#define TW_RESPONSE_QUEUE_REG_ADDR(x) ((unsigned char *)x->base_addr + 0xC)
+#define TW_CLEAR_ALL_INTERRUPTS(x) (writel(TW_STATUS_VALID_INTERRUPT, TW_CONTROL_REG_ADDR(x)))
+#define TW_CLEAR_ATTENTION_INTERRUPT(x) (writel(TW_CONTROL_CLEAR_ATTENTION_INTERRUPT, TW_CONTROL_REG_ADDR(x)))
+#define TW_CLEAR_HOST_INTERRUPT(x) (writel(TW_CONTROL_CLEAR_HOST_INTERRUPT, TW_CONTROL_REG_ADDR(x)))
+#define TW_DISABLE_INTERRUPTS(x) (writel(TW_CONTROL_DISABLE_INTERRUPTS, TW_CONTROL_REG_ADDR(x)))
+#define TW_ENABLE_AND_CLEAR_INTERRUPTS(x) (writel(TW_CONTROL_CLEAR_ATTENTION_INTERRUPT | TW_CONTROL_UNMASK_RESPONSE_INTERRUPT | TW_CONTROL_ENABLE_INTERRUPTS, TW_CONTROL_REG_ADDR(x)))
+#define TW_MASK_COMMAND_INTERRUPT(x) (writel(TW_CONTROL_MASK_COMMAND_INTERRUPT, TW_CONTROL_REG_ADDR(x)))
+#define TW_UNMASK_COMMAND_INTERRUPT(x) (writel(TW_CONTROL_UNMASK_COMMAND_INTERRUPT, TW_CONTROL_REG_ADDR(x)))
+#define TW_SOFT_RESET(x) (writel(TW_CONTROL_ISSUE_SOFT_RESET | \
+			TW_CONTROL_CLEAR_HOST_INTERRUPT | \
+			TW_CONTROL_CLEAR_ATTENTION_INTERRUPT | \
+			TW_CONTROL_MASK_COMMAND_INTERRUPT | \
+			TW_CONTROL_MASK_RESPONSE_INTERRUPT | \
+			TW_CONTROL_CLEAR_ERROR_STATUS | \
+			TW_CONTROL_DISABLE_INTERRUPTS, TW_CONTROL_REG_ADDR(x)))
+#define TW_PRINTK(h,a,b,c) { \
+if (h) \
+printk(KERN_WARNING "3w-9xxx: scsi%d: ERROR: (0x%02X:0x%04X): %s.\n",h->host_no,a,b,c); \
+else \
+printk(KERN_WARNING "3w-9xxx: ERROR: (0x%02X:0x%04X): %s.\n",a,b,c); \
+}
+
+#pragma pack(1)
+
+/* Scatter Gather List Entry */
+typedef struct TAG_TW_SG_Entry {
+	unsigned long address;
+	u32 length;
+} TW_SG_Entry;
+
+/* Command Packet */
+typedef struct TW_Command {
+	unsigned char opcode__sgloffset;
+	unsigned char size;
+	unsigned char request_id;
+	unsigned char unit__hostid;
+	/* Second DWORD */
+	unsigned char status;
+	unsigned char flags;
+	union {
+		unsigned short block_count;
+		unsigned short parameter_count;
+	} byte6_offset;
+	union {
+		struct {
+			u32 lba;
+			TW_SG_Entry sgl[TW_ESCALADE_MAX_SGL_LENGTH];
+#if BITS_PER_LONG > 32
+			u32 padding[2];	/* pad to 512 bytes */
+#else
+			u32 padding;
+#endif
+		} io;
+		struct {
+			TW_SG_Entry sgl[TW_ESCALADE_MAX_SGL_LENGTH];
+#if BITS_PER_LONG > 32
+			u32 padding[3];
+#else
+			u32 padding[2];
+#endif
+		} param;
+	} byte8_offset;
+} TW_Command;
+
+/* Scatter gather element for 9000+ controllers */
+typedef struct TAG_TW_SG_Apache {
+	unsigned long address;
+	u32 length;
+} TW_SG_Apache;
+
+/* Command Packet for 9000+ controllers */
+typedef struct TAG_TW_Command_Apache {
+	unsigned char opcode__reserved;
+	unsigned char unit;
+	unsigned short request_id;
+	unsigned char status;
+	unsigned char sgl_offset;
+	unsigned short sgl_entries;
+	unsigned char cdb[16];
+	TW_SG_Apache sg_list[TW_APACHE_MAX_SGL_LENGTH];
+#if BITS_PER_LONG > 32
+	unsigned char padding[8];
+#endif
+} TW_Command_Apache;
+
+/* New command packet header */
+typedef struct TAG_TW_Command_Apache_Header {
+	unsigned char sense_data[TW_SENSE_DATA_LENGTH];
+	struct {
+		char reserved[4];
+		unsigned short error;
+		unsigned char padding;
+		unsigned char severity__reserved;
+	} status_block;
+	unsigned char err_specific_desc[98];
+	struct {
+		unsigned char size_header;
+		unsigned short reserved;
+		unsigned char size_sense;
+	} header_desc;
+} TW_Command_Apache_Header;
+
+/* This struct is a union of the 2 command packets */
+typedef struct TAG_TW_Command_Full {
+	TW_Command_Apache_Header header;
+	union {
+		TW_Command oldcommand;
+		TW_Command_Apache newcommand;
+	} command;
+} TW_Command_Full;
+
+/* Initconnection structure */
+typedef struct TAG_TW_Initconnect {
+	unsigned char opcode__reserved;
+	unsigned char size;
+	unsigned char request_id;
+	unsigned char res2;
+	unsigned char status;
+	unsigned char flags;
+	unsigned short message_credits;
+	u32 features;
+	unsigned short fw_srl;
+	unsigned short fw_arch_id;
+	unsigned short fw_branch;
+	unsigned short fw_build;
+	u32 result;
+} TW_Initconnect;
+
+/* Event info structure */
+typedef struct TAG_TW_Event
+{
+	unsigned int sequence_id;
+	unsigned int time_stamp_sec;
+	unsigned short aen_code;
+	unsigned char severity;
+	unsigned char retrieved;
+	unsigned char repeat_count;
+	unsigned char parameter_len;
+	unsigned char parameter_data[98];
+} TW_Event;
+
+typedef struct TAG_TW_Ioctl_Driver_Command {
+	unsigned int control_code;
+	unsigned int status;
+	unsigned int unique_id;
+	unsigned int sequence_id;
+	unsigned int os_specific;
+	unsigned int buffer_length;
+} TW_Ioctl_Driver_Command;
+
+typedef struct TAG_TW_Ioctl_Apache {
+	TW_Ioctl_Driver_Command driver_command;
+        char padding[488];
+	TW_Command_Full firmware_command;
+	char data_buffer[1];
+} TW_Ioctl_Buf_Apache;
+
+/* Lock structure for ioctl get/release lock */
+typedef struct TAG_TW_Lock {
+	unsigned long timeout_msec;
+	unsigned long time_remaining_msec;
+	unsigned long force_flag;
+} TW_Lock;
+
+/* GetParam descriptor */
+typedef struct {
+	unsigned short	table_id;
+	unsigned short	parameter_id;
+	unsigned short	parameter_size_bytes;
+	unsigned short  actual_parameter_size_bytes;
+	unsigned char	data[1];
+} TW_Param_Apache, *PTW_Param_Apache;
+
+/* Response queue */
+typedef union TAG_TW_Response_Queue {
+	u32 response_id;
+	u32 value;
+} TW_Response_Queue;
+
+typedef struct TAG_TW_Info {
+	char *buffer;
+	int length;
+	int offset;
+	int position;
+} TW_Info;
+
+/* Compatibility information structure */
+typedef struct TAG_TW_Compatibility_Info
+{
+	char driver_version[32];
+	unsigned short working_srl;
+	unsigned short working_branch;
+	unsigned short working_build;
+} TW_Compatibility_Info;
+
+typedef struct TAG_TW_Device_Extension {
+	u32                     *base_addr;
+	unsigned long	       	*generic_buffer_virt[TW_Q_LENGTH];
+	unsigned long	       	generic_buffer_phys[TW_Q_LENGTH];
+	TW_Command_Full	       	*command_packet_virt[TW_Q_LENGTH];
+	unsigned long		command_packet_phys[TW_Q_LENGTH];
+	struct pci_dev		*tw_pci_dev;
+	struct scsi_cmnd	*srb[TW_Q_LENGTH];
+	unsigned char		free_queue[TW_Q_LENGTH];
+	unsigned char		free_head;
+	unsigned char		free_tail;
+	unsigned char		pending_queue[TW_Q_LENGTH];
+	unsigned char		pending_head;
+	unsigned char		pending_tail;
+	int     		state[TW_Q_LENGTH];
+	unsigned int		posted_request_count;
+	unsigned int		max_posted_request_count;
+	unsigned int	        pending_request_count;
+	unsigned int		max_pending_request_count;
+	unsigned int		max_sgl_entries;
+	unsigned int		sgl_entries;
+	unsigned int		num_aborts;
+	unsigned int		num_resets;
+	unsigned int		sector_count;
+	unsigned int		max_sector_count;
+	unsigned int		aen_count;
+	struct Scsi_Host	*host;
+	long			flags;
+	int			reset_print;
+	TW_Event                *event_queue[TW_Q_LENGTH];
+	unsigned char           error_index;
+	unsigned char		event_queue_wrapped;
+	unsigned int            error_sequence_id;
+	int                     ioctl_sem_lock;
+	u32                     ioctl_msec;
+	int			chrdev_request_id;
+	wait_queue_head_t	ioctl_wqueue;
+	struct semaphore	ioctl_sem;
+	char			aen_clobber;
+	unsigned short		working_srl;
+	unsigned short		working_branch;
+	unsigned short		working_build;
+} TW_Device_Extension;
+
+#pragma pack()
+
+#endif /* _3W_9XXX_H */
+
--- diff/drivers/usb/class/cdc-acm.h	1970-01-01 01:00:00.000000000 +0100
+++ source/drivers/usb/class/cdc-acm.h	2004-06-11 19:22:04.000000000 +0100
@@ -0,0 +1,115 @@
+/*
+ *
+ * Includes for cdc-acm.c
+ *
+ * Mainly take from usbnet's cdc-ether part
+ *
+ */
+
+/*
+ * CMSPAR, some architectures can't have space and mark parity.
+ */
+
+#ifndef CMSPAR
+#define CMSPAR			0
+#endif
+
+/*
+ * Major and minor numbers.
+ */
+
+#define ACM_TTY_MAJOR		166
+#define ACM_TTY_MINORS		32
+
+/*
+ * Requests.
+ */
+
+#define USB_RT_ACM		(USB_TYPE_CLASS | USB_RECIP_INTERFACE)
+
+#define ACM_REQ_COMMAND		0x00
+#define ACM_REQ_RESPONSE	0x01
+#define ACM_REQ_SET_FEATURE	0x02
+#define ACM_REQ_GET_FEATURE	0x03
+#define ACM_REQ_CLEAR_FEATURE	0x04
+
+#define ACM_REQ_SET_LINE	0x20
+#define ACM_REQ_GET_LINE	0x21
+#define ACM_REQ_SET_CONTROL	0x22
+#define ACM_REQ_SEND_BREAK	0x23
+
+/*
+ * IRQs.
+ */
+
+#define ACM_IRQ_NETWORK		0x00
+#define ACM_IRQ_LINE_STATE	0x20
+
+/*
+ * Output control lines.
+ */
+
+#define ACM_CTRL_DTR		0x01
+#define ACM_CTRL_RTS		0x02
+
+/*
+ * Input control lines and line errors.
+ */
+
+#define ACM_CTRL_DCD		0x01
+#define ACM_CTRL_DSR		0x02
+#define ACM_CTRL_BRK		0x04
+#define ACM_CTRL_RI		0x08
+
+#define ACM_CTRL_FRAMING	0x10
+#define ACM_CTRL_PARITY		0x20
+#define ACM_CTRL_OVERRUN	0x40
+
+/*
+ * Line speed and caracter encoding.
+ */
+
+struct acm_line {
+	__u32 speed;
+	__u8 stopbits;
+	__u8 parity;
+	__u8 databits;
+} __attribute__ ((packed));
+
+/*
+ * Internal driver structures.
+ */
+
+struct acm {
+	struct usb_device *dev;				/* the corresponding usb device */
+	struct usb_interface *control;			/* control interface */
+	struct usb_interface *data;			/* data interface */
+	struct tty_struct *tty;				/* the corresponding tty */
+	struct urb *ctrlurb, *readurb, *writeurb;	/* urbs */
+	struct acm_line line;				/* line coding (bits, stop, parity) */
+	struct work_struct work;			/* work queue entry for line discipline waking up */
+	struct tasklet_struct bh;			/* rx processing */
+	unsigned int ctrlin;				/* input control lines (DCD, DSR, RI, break, overruns) */
+	unsigned int ctrlout;				/* output control lines (DTR, RTS) */
+	unsigned int writesize;				/* max packet size for the output bulk endpoint */
+	unsigned int used;				/* someone has this acm's device open */
+	unsigned int minor;				/* acm minor number */
+	unsigned char throttle;				/* throttled by tty layer */
+	unsigned char clocal;				/* termios CLOCAL */
+	unsigned char ready_for_write;			/* write urb can be used */
+};
+
+/* "Union Functional Descriptor" from CDC spec 5.2.3.X */
+struct union_desc {
+	u8	bLength;
+	u8	bDescriptorType;
+	u8	bDescriptorSubType;
+
+	u8	bMasterInterface0;
+	u8	bSlaveInterface0;
+	/* ... and there could be other slave interfaces */
+} __attribute__ ((packed));
+
+#define CDC_UNION_TYPE		0x06
+#define CDC_DATA_INTERFACE_TYPE	0x0a
+
--- diff/fs/isofs/export.c	1970-01-01 01:00:00.000000000 +0100
+++ source/fs/isofs/export.c	2004-06-11 19:22:05.000000000 +0100
@@ -0,0 +1,228 @@
+/*
+ * fs/isofs/export.c
+ *
+ *  (C) 2004  Paul Serice - The new inode scheme requires switching
+ *                          from iget() to iget5_locked() which means
+ *                          the NFS export operations have to be hand
+ *                          coded because the default routines rely on
+ *                          iget().
+ *
+ * The following files are helpful:
+ *
+ *     Documentation/filesystems/Exporting
+ *     fs/exportfs/expfs.c.
+ */
+
+#include <linux/buffer_head.h>
+#include <linux/errno.h>
+#include <linux/fs.h>
+#include <linux/iso_fs.h>
+#include <linux/kernel.h>
+
+static struct dentry *
+isofs_export_iget(struct super_block *sb,
+		  unsigned long block,
+		  unsigned long offset,
+		  __u32 generation)
+{
+	struct inode *inode;
+	struct dentry *result;
+	if (block == 0)
+		return ERR_PTR(-ESTALE);
+	inode = isofs_iget(sb, block, offset);
+	if (inode == NULL)
+		return ERR_PTR(-ENOMEM);
+	if (is_bad_inode(inode)
+	    || (generation && inode->i_generation != generation))
+	{
+		iput(inode);
+		return ERR_PTR(-ESTALE);
+	}
+	result = d_alloc_anon(inode);
+	if (!result) {
+		iput(inode);
+		return ERR_PTR(-ENOMEM);
+	}
+	return result;
+}
+
+static struct dentry *
+isofs_export_get_dentry(struct super_block *sb, void *vobjp)
+{
+	__u32 *objp = vobjp;
+	unsigned long block = objp[0];
+	unsigned long offset = objp[1];
+	__u32 generation = objp[2];
+	return isofs_export_iget(sb, block, offset, generation);
+}
+
+/* This function is surprisingly simple.  The trick is understanding
+ * that "child" is always a directory. So, to find its parent, you
+ * simply need to find its ".." entry, normalize its block and offset,
+ * and return the underlying inode.  See the comments for
+ * isofs_normalize_block_and_offset(). */
+static struct dentry *isofs_export_get_parent(struct dentry *child)
+{
+	unsigned long parent_block = 0;
+	unsigned long parent_offset = 0;
+	struct inode *child_inode = child->d_inode;
+	struct iso_inode_info *e_child_inode = ISOFS_I(child_inode);
+	struct inode *parent_inode = NULL;
+	struct iso_directory_record *de = NULL;
+	struct buffer_head * bh = NULL;
+	struct dentry *rv = NULL;
+
+	/* "child" must always be a directory. */
+	if (!S_ISDIR(child_inode->i_mode)) {
+		printk(KERN_ERR "isofs: isofs_export_get_parent(): "
+		       "child is not a directory!\n");
+		rv = ERR_PTR(-EACCES);
+		goto out;
+	}
+
+	/* It is an invariant that the directory offset is zero.  If
+	 * it is not zero, it means the directory failed to be
+	 * normalized for some reason. */
+	if (e_child_inode->i_iget5_offset != 0) {
+		printk(KERN_ERR "isofs: isofs_export_get_parent(): "
+		       "child directory not normalized!\n");
+		rv = ERR_PTR(-EACCES);
+		goto out;
+	}
+
+	/* The child inode has been normalized such that its
+	 * i_iget5_block value points to the "." entry.  Fortunately,
+	 * the ".." entry is located in the same block. */
+	parent_block = e_child_inode->i_iget5_block;
+
+	/* Get the block in question. */
+	bh = sb_bread(child_inode->i_sb, parent_block);
+	if (bh == NULL) {
+		rv = ERR_PTR(-EACCES);
+		goto out;
+	}
+
+	/* This is the "." entry. */
+	de = (struct iso_directory_record*)bh->b_data;
+
+	/* The ".." entry is always the second entry. */
+	parent_offset = (unsigned long)isonum_711(de->length);
+	de = (struct iso_directory_record*)(bh->b_data + parent_offset);
+
+	/* Verify it is in fact the ".." entry. */
+	if ((isonum_711(de->name_len) != 1) || (de->name[0] != 1)) {
+		printk(KERN_ERR "isofs: Unable to find the \"..\" "
+		       "directory for NFS.\n");
+		rv = ERR_PTR(-EACCES);
+		goto out;
+	}
+
+	/* Normalize */
+	isofs_normalize_block_and_offset(de, &parent_block, &parent_offset);
+
+	/* Get the inode. */
+	parent_inode = isofs_iget(child_inode->i_sb,
+				  parent_block,
+				  parent_offset);
+	if (parent_inode == NULL) {
+		rv = ERR_PTR(-EACCES);
+		goto out;
+	}
+
+	/* Allocate the dentry. */
+	rv = d_alloc_anon(parent_inode);
+	if (rv == NULL) {
+		rv = ERR_PTR(-ENOMEM);
+		goto out;
+	}
+
+ out:
+	if (bh) {
+		brelse(bh);
+	}
+	return rv;
+}
+
+static int
+isofs_export_encode_fh(struct dentry *dentry,
+		       __u32 *fh32,
+		       int *max_len,
+		       int connectable)
+{
+	struct inode * inode = dentry->d_inode;
+	struct iso_inode_info * ei = ISOFS_I(inode);
+	int len = *max_len;
+	int type = 1;
+	__u16 *fh16 = (__u16*)fh32;
+
+	/*
+	 * WARNING: max_len is 5 for NFSv2.  Because of this
+	 * limitation, we use the lower 16 bits of fh32[1] to hold the
+	 * offset of the inode and the upper 16 bits of fh32[1] to
+	 * hold the offset of the parent.
+	 */
+
+	if (len < 3 || (connectable && len < 5))
+		return 255;
+
+	len = 3;
+	fh32[0] = ei->i_iget5_block;
+ 	fh16[2] = (__u16)ei->i_iget5_offset;  /* fh16 [sic] */
+	fh32[2] = inode->i_generation;
+	if (connectable && !S_ISDIR(inode->i_mode)) {
+		struct inode *parent;
+		struct iso_inode_info *eparent;
+		spin_lock(&dentry->d_lock);
+		parent = dentry->d_parent->d_inode;
+		eparent = ISOFS_I(parent);
+		fh32[3] = eparent->i_iget5_block;
+		fh16[3] = (__u16)eparent->i_iget5_offset;  /* fh16 [sic] */
+		fh32[4] = parent->i_generation;
+		spin_unlock(&dentry->d_lock);
+		len = 5;
+		type = 2;
+	}
+	*max_len = len;
+	return type;
+}
+
+
+static struct dentry *
+isofs_export_decode_fh(struct super_block *sb,
+		       __u32 *fh32,
+		       int fh_len,
+		       int fileid_type,
+		       int (*acceptable)(void *context, struct dentry *de),
+		       void *context)
+{
+	__u16 *fh16 = (__u16*)fh32;
+	__u32 child[3];   /* The child is what triggered all this. */
+	__u32 parent[3];  /* The parent is just along for the ride. */
+
+	if (fh_len < 3 || fileid_type > 2)
+		return NULL;
+
+	child[0] = fh32[0];
+	child[1] = fh16[2];  /* fh16 [sic] */
+	child[2] = fh32[2];
+
+	parent[0] = 0;
+	parent[1] = 0;
+	parent[2] = 0;
+	if (fileid_type == 2) {
+		if (fh_len > 2) parent[0] = fh32[3];
+		parent[1] = fh16[3];  /* fh16 [sic] */
+		if (fh_len > 4) parent[2] = fh32[4];
+	}
+
+	return sb->s_export_op->find_exported_dentry(sb, child, parent,
+						     acceptable, context);
+}
+
+
+struct export_operations isofs_export_ops = {
+	.decode_fh	= isofs_export_decode_fh,
+	.encode_fh	= isofs_export_encode_fh,
+	.get_dentry	= isofs_export_get_dentry,
+	.get_parent     = isofs_export_get_parent,
+};
--- diff/include/asm-alpha/lockmeter.h	1970-01-01 01:00:00.000000000 +0100
+++ source/include/asm-alpha/lockmeter.h	2004-06-11 19:22:06.000000000 +0100
@@ -0,0 +1,84 @@
+/*
+ *  Written by John Hawkes (hawkes@sgi.com)
+ *  Based on klstat.h by Jack Steiner (steiner@sgi.com)
+ *
+ *  Modified by Peter Rival (frival@zk3.dec.com)
+ */
+
+#ifndef _ALPHA_LOCKMETER_H
+#define _ALPHA_LOCKMETER_H
+
+#include <asm/hwrpb.h>
+#define CPU_CYCLE_FREQUENCY	hwrpb->cycle_freq
+
+#define get_cycles64()		get_cycles()
+
+#define THIS_CPU_NUMBER		smp_processor_id()
+
+#include <linux/version.h>
+
+#define SPINLOCK_MAGIC_INIT /**/
+
+/*
+ * Macros to cache and retrieve an index value inside of a lock
+ * these macros assume that there are less than 65536 simultaneous
+ * (read mode) holders of a rwlock.
+ * We also assume that the hash table has less than 32767 entries.
+ * the high order bit is used for write locking a rw_lock
+ * Note: although these defines and macros are the same as what is being used
+ *       in include/asm-i386/lockmeter.h, they are present here to easily
+ *	 allow an alternate Alpha implementation.
+ */
+/*
+ * instrumented spinlock structure -- never used to allocate storage
+ * only used in macros below to overlay a spinlock_t
+ */
+typedef struct inst_spinlock_s {
+	/* remember, Alpha is little endian */
+	unsigned short lock;
+	unsigned short index;
+} inst_spinlock_t;
+#define PUT_INDEX(lock_ptr,indexv)	((inst_spinlock_t *)(lock_ptr))->index = indexv
+#define GET_INDEX(lock_ptr)		((inst_spinlock_t *)(lock_ptr))->index
+
+/*
+ * macros to cache and retrieve an index value in a read/write lock
+ * as well as the cpu where a reader busy period started
+ * we use the 2nd word (the debug word) for this, so require the
+ * debug word to be present
+ */
+/*
+ * instrumented rwlock structure -- never used to allocate storage
+ * only used in macros below to overlay a rwlock_t
+ */
+typedef struct inst_rwlock_s {
+	volatile int lock;
+	unsigned short index;
+	unsigned short cpu;
+} inst_rwlock_t;
+#define PUT_RWINDEX(rwlock_ptr,indexv)	((inst_rwlock_t *)(rwlock_ptr))->index = indexv
+#define GET_RWINDEX(rwlock_ptr)		((inst_rwlock_t *)(rwlock_ptr))->index
+#define PUT_RW_CPU(rwlock_ptr,cpuv)	((inst_rwlock_t *)(rwlock_ptr))->cpu = cpuv
+#define GET_RW_CPU(rwlock_ptr)		((inst_rwlock_t *)(rwlock_ptr))->cpu
+
+/*
+ * return true if rwlock is write locked
+ * (note that other lock attempts can cause the lock value to be negative)
+ */
+#define RWLOCK_IS_WRITE_LOCKED(rwlock_ptr) (((inst_rwlock_t *)rwlock_ptr)->lock & 1)
+#define IABS(x) ((x) > 0 ? (x) : -(x))
+
+#define RWLOCK_READERS(rwlock_ptr)	rwlock_readers(rwlock_ptr)
+extern inline int rwlock_readers(rwlock_t *rwlock_ptr)
+{
+	int tmp = (int) ((inst_rwlock_t *)rwlock_ptr)->lock;
+	/* readers subtract 2, so we have to:		*/
+	/* 	- andnot off a possible writer (bit 0)	*/
+	/*	- get the absolute value		*/
+	/*	- divide by 2 (right shift by one)	*/
+	/* to find the number of readers		*/
+	if (tmp == 0) return(0);
+	else return(IABS(tmp & ~1)>>1);
+}
+
+#endif /* _ALPHA_LOCKMETER_H */
--- diff/include/asm-alpha/setup.h	1970-01-01 01:00:00.000000000 +0100
+++ source/include/asm-alpha/setup.h	2004-06-11 19:22:06.000000000 +0100
@@ -0,0 +1,6 @@
+#ifndef __ALPHA_SETUP_H
+#define __ALPHA_SETUP_H
+
+#define COMMAND_LINE_SIZE	256
+
+#endif
--- diff/include/asm-i386/kgdb.h	1970-01-01 01:00:00.000000000 +0100
+++ source/include/asm-i386/kgdb.h	2004-06-11 19:22:06.000000000 +0100
@@ -0,0 +1,69 @@
+#ifndef __KGDB
+#define __KGDB
+
+/*
+ * This file should not include ANY others.  This makes it usable
+ * most anywhere without the fear of include order or inclusion.
+ * Make it so!
+ *
+ * This file may be included all the time.  It is only active if
+ * CONFIG_KGDB is defined, otherwise it stubs out all the macros
+ * and entry points.
+ */
+#if defined(CONFIG_KGDB) && !defined(__ASSEMBLY__)
+
+extern void breakpoint(void);
+#define INIT_KGDB_INTS kgdb_enable_ints()
+
+#ifndef BREAKPOINT
+#define BREAKPOINT   asm("   int $3")
+#endif
+
+extern void kgdb_schedule_breakpoint(void);
+extern void kgdb_process_breakpoint(void);
+
+extern int kgdb_tty_hook(void);
+extern int kgdb_eth_hook(void);
+extern int kgdboe;
+
+/*
+ * GDB debug stub (or any debug stub) can point the 'linux_debug_hook'
+ * pointer to its routine and it will be entered as the first thing
+ * when a trap occurs.
+ *
+ * Return values are, at present, undefined.
+ *
+ * The debug hook routine does not necessarily return to its caller.
+ * It has the register image and thus may choose to resume execution
+ * anywhere it pleases.
+ */
+struct pt_regs;
+
+extern int kgdb_handle_exception(int trapno,
+				 int signo, int err_code, struct pt_regs *regs);
+extern int in_kgdb(struct pt_regs *regs);
+
+#ifdef CONFIG_KGDB_TS
+void kgdb_tstamp(int line, char *source, int data0, int data1);
+/*
+ * This is the time stamp function.  The macro adds the source info and
+ * does a cast on the data to allow most any 32-bit value.
+ */
+
+#define kgdb_ts(data0,data1) kgdb_tstamp(__LINE__,__FILE__,(int)data0,(int)data1)
+#else
+#define kgdb_ts(data0,data1)
+#endif
+#else				/* CONFIG_KGDB  && ! __ASSEMBLY__ ,stubs follow... */
+#ifndef BREAKPOINT
+#define BREAKPOINT
+#endif
+#define kgdb_ts(data0,data1)
+#define in_kgdb
+#define kgdb_handle_exception
+#define breakpoint
+#define INIT_KGDB_INTS
+#define kgdb_process_breakpoint() do {} while(0)
+
+#endif
+#endif				/* __KGDB */
--- diff/include/asm-i386/kgdb_local.h	1970-01-01 01:00:00.000000000 +0100
+++ source/include/asm-i386/kgdb_local.h	2004-06-11 19:22:06.000000000 +0100
@@ -0,0 +1,102 @@
+#ifndef __KGDB_LOCAL
+#define ___KGDB_LOCAL
+#include <linux/config.h>
+#include <linux/types.h>
+#include <linux/serial.h>
+#include <linux/serialP.h>
+#include <linux/spinlock.h>
+#include <asm/processor.h>
+#include <asm/msr.h>
+#include <asm/kgdb.h>
+
+#define PORT 0x3f8
+#ifdef CONFIG_KGDB_PORT
+#undef PORT
+#define PORT CONFIG_KGDB_PORT
+#endif
+#define IRQ 4
+#ifdef CONFIG_KGDB_IRQ
+#undef IRQ
+#define IRQ CONFIG_KGDB_IRQ
+#endif
+#define SB_CLOCK 1843200
+#define SB_BASE (SB_CLOCK/16)
+#define SB_BAUD9600 SB_BASE/9600
+#define SB_BAUD192  SB_BASE/19200
+#define SB_BAUD384  SB_BASE/38400
+#define SB_BAUD576  SB_BASE/57600
+#define SB_BAUD1152 SB_BASE/115200
+#ifdef CONFIG_KGDB_9600BAUD
+#define SB_BAUD SB_BAUD9600
+#endif
+#ifdef CONFIG_KGDB_19200BAUD
+#define SB_BAUD SB_BAUD192
+#endif
+#ifdef CONFIG_KGDB_38400BAUD
+#define SB_BAUD SB_BAUD384
+#endif
+#ifdef CONFIG_KGDB_57600BAUD
+#define SB_BAUD SB_BAUD576
+#endif
+#ifdef CONFIG_KGDB_115200BAUD
+#define SB_BAUD SB_BAUD1152
+#endif
+#ifndef SB_BAUD
+#define SB_BAUD SB_BAUD1152	/* Start with this if not given */
+#endif
+
+#ifndef CONFIG_X86_TSC
+#undef rdtsc
+#define rdtsc(a,b) if (a++ > 10000){a = 0; b++;}
+#undef rdtscll
+#define rdtscll(s) s++
+#endif
+
+#ifdef _raw_read_unlock		/* must use a name that is "define"ed, not an inline */
+#undef spin_lock
+#undef spin_trylock
+#undef spin_unlock
+#define spin_lock	 _raw_spin_lock
+#define spin_trylock	 _raw_spin_trylock
+#define spin_unlock	 _raw_spin_unlock
+#else
+#endif
+#undef spin_unlock_wait
+#define spin_unlock_wait(x)  do { cpu_relax(); barrier();} \
+                                     while(spin_is_locked(x))
+
+#define SB_IER 1
+#define SB_MCR UART_MCR_OUT2 | UART_MCR_DTR | UART_MCR_RTS
+
+#define FLAGS 0
+#define SB_STATE { \
+     magic: SSTATE_MAGIC, \
+     baud_base: SB_BASE,  \
+     port:      PORT,     \
+     irq:       IRQ,      \
+     flags:     FLAGS,    \
+     custom_divisor:SB_BAUD}
+#define SB_INFO  { \
+      magic: SERIAL_MAGIC, \
+      port:  PORT,0,FLAGS, \
+      state: &state,       \
+      tty:   (struct tty_struct *)&state, \
+      IER:   SB_IER,       \
+      MCR:   SB_MCR}
+extern void putDebugChar(int);
+/* RTAI support needs us to really stop/start interrupts */
+
+#define kgdb_sti() __asm__ __volatile__("sti": : :"memory")
+#define kgdb_cli() __asm__ __volatile__("cli": : :"memory")
+#define kgdb_local_save_flags(x) __asm__ __volatile__(\
+                                   "pushfl ; popl %0":"=g" (x): /* no input */)
+#define kgdb_local_irq_restore(x) __asm__ __volatile__(\
+                                   "pushl %0 ; popfl": \
+                                     /* no output */ :"g" (x):"memory", "cc")
+#define kgdb_local_irq_save(x) kgdb_local_save_flags(x); kgdb_cli()
+
+#ifdef CONFIG_SERIAL
+extern void shutdown_for_kgdb(struct async_struct *info);
+#endif
+#define INIT_KDEBUG putDebugChar("+");
+#endif				/* __KGDB_LOCAL */
--- diff/include/asm-i386/lockmeter.h	1970-01-01 01:00:00.000000000 +0100
+++ source/include/asm-i386/lockmeter.h	2004-06-11 19:22:06.000000000 +0100
@@ -0,0 +1,115 @@
+/*
+ *  Copyright (C) 1999,2000 Silicon Graphics, Inc.
+ *
+ *  Written by John Hawkes (hawkes@sgi.com)
+ *  Based on klstat.h by Jack Steiner (steiner@sgi.com)
+ *
+ *  Modified by Ray Bryant (raybry@us.ibm.com)
+ *  Changes Copyright (C) 2000 IBM, Inc.
+ *  Added save of index in spinlock_t to improve efficiency
+ *  of "hold" time reporting for spinlocks.
+ *  Added support for hold time statistics for read and write
+ *  locks.
+ *  Moved machine dependent code here from include/lockmeter.h.
+ *
+ */
+
+#ifndef _I386_LOCKMETER_H
+#define _I386_LOCKMETER_H
+
+#include <asm/spinlock.h>
+#include <asm/rwlock.h>
+
+#include <linux/version.h>
+
+#ifdef __KERNEL__
+extern unsigned long cpu_khz;
+#define CPU_CYCLE_FREQUENCY	(cpu_khz * 1000)
+#else
+#define CPU_CYCLE_FREQUENCY	450000000
+#endif
+
+#define THIS_CPU_NUMBER		smp_processor_id()
+
+/*
+ * macros to cache and retrieve an index value inside of a spin lock
+ * these macros assume that there are less than 65536 simultaneous
+ * (read mode) holders of a rwlock.  Not normally a problem!!
+ * we also assume that the hash table has less than 65535 entries.
+ */
+/*
+ * instrumented spinlock structure -- never used to allocate storage
+ * only used in macros below to overlay a spinlock_t
+ */
+typedef struct inst_spinlock_s {
+	/* remember, Intel is little endian */
+	unsigned short lock;
+	unsigned short index;
+} inst_spinlock_t;
+#define PUT_INDEX(lock_ptr,indexv) ((inst_spinlock_t *)(lock_ptr))->index = indexv
+#define GET_INDEX(lock_ptr)        ((inst_spinlock_t *)(lock_ptr))->index
+
+/*
+ * macros to cache and retrieve an index value in a read/write lock
+ * as well as the cpu where a reader busy period started
+ * we use the 2nd word (the debug word) for this, so require the
+ * debug word to be present
+ */
+/*
+ * instrumented rwlock structure -- never used to allocate storage
+ * only used in macros below to overlay a rwlock_t
+ */
+typedef struct inst_rwlock_s {
+	volatile int lock;
+	unsigned short index;
+	unsigned short cpu;
+} inst_rwlock_t;
+#define PUT_RWINDEX(rwlock_ptr,indexv) ((inst_rwlock_t *)(rwlock_ptr))->index = indexv
+#define GET_RWINDEX(rwlock_ptr)        ((inst_rwlock_t *)(rwlock_ptr))->index
+#define PUT_RW_CPU(rwlock_ptr,cpuv)    ((inst_rwlock_t *)(rwlock_ptr))->cpu = cpuv
+#define GET_RW_CPU(rwlock_ptr)         ((inst_rwlock_t *)(rwlock_ptr))->cpu
+
+/*
+ * return the number of readers for a rwlock_t
+ */
+#define RWLOCK_READERS(rwlock_ptr)   rwlock_readers(rwlock_ptr)
+
+extern inline int rwlock_readers(rwlock_t *rwlock_ptr)
+{
+	int tmp = (int) rwlock_ptr->lock;
+	/* read and write lock attempts may cause the lock value to temporarily */
+	/* be negative.  Until it is >= 0 we know nothing (i. e. can't tell if  */
+	/* is -1 because it was write locked and somebody tried to read lock it */
+	/* or if it is -1 because it was read locked and somebody tried to write*/
+	/* lock it. ........................................................... */
+	do {
+		tmp = (int) rwlock_ptr->lock;
+	} while (tmp < 0);
+	if (tmp == 0) return(0);
+	else return(RW_LOCK_BIAS-tmp);
+}
+
+/*
+ * return true if rwlock is write locked
+ * (note that other lock attempts can cause the lock value to be negative)
+ */
+#define RWLOCK_IS_WRITE_LOCKED(rwlock_ptr) ((rwlock_ptr)->lock <= 0)
+#define IABS(x) ((x) > 0 ? (x) : -(x))
+#define RWLOCK_IS_READ_LOCKED(rwlock_ptr)  ((IABS((rwlock_ptr)->lock) % RW_LOCK_BIAS) != 0)
+
+/* this is a lot of typing just to get gcc to emit "rdtsc" */
+static inline long long get_cycles64 (void)
+{
+	union longlong_u {
+		long long intlong;
+		struct intint_s {
+			uint32_t eax;
+			uint32_t edx;
+		} intint;
+	} longlong;
+
+	rdtsc(longlong.intint.eax,longlong.intint.edx);
+	return longlong.intlong;
+}
+
+#endif /* _I386_LOCKMETER_H */
--- diff/include/asm-i386/perfctr.h	1970-01-01 01:00:00.000000000 +0100
+++ source/include/asm-i386/perfctr.h	2004-06-11 19:22:06.000000000 +0100
@@ -0,0 +1,200 @@
+/* $Id: perfctr.h,v 1.52 2004/05/23 22:36:34 mikpe Exp $
+ * x86/x86_64 Performance-Monitoring Counters driver
+ *
+ * Copyright (C) 1999-2004  Mikael Pettersson
+ */
+#ifndef _ASM_I386_PERFCTR_H
+#define _ASM_I386_PERFCTR_H
+
+/* cpu_type values */
+#define PERFCTR_X86_GENERIC	0	/* any x86 with rdtsc */
+#define PERFCTR_X86_INTEL_P5	1	/* no rdpmc */
+#define PERFCTR_X86_INTEL_P5MMX	2
+#define PERFCTR_X86_INTEL_P6	3
+#define PERFCTR_X86_INTEL_PII	4
+#define PERFCTR_X86_INTEL_PIII	5
+#define PERFCTR_X86_CYRIX_MII	6
+#define PERFCTR_X86_WINCHIP_C6	7	/* no rdtsc */
+#define PERFCTR_X86_WINCHIP_2	8	/* no rdtsc */
+#define PERFCTR_X86_AMD_K7	9
+#define PERFCTR_X86_VIA_C3	10	/* no pmc0 */
+#define PERFCTR_X86_INTEL_P4	11	/* model 0 and 1 */
+#define PERFCTR_X86_INTEL_P4M2	12	/* model 2 */
+#define PERFCTR_X86_AMD_K8	13
+#define PERFCTR_X86_INTEL_PENTM	14	/* Pentium M */
+#define PERFCTR_X86_AMD_K8C	15	/* Revision C */
+#define PERFCTR_X86_INTEL_P4M3	16	/* model 3 and above */
+
+struct perfctr_sum_ctrs {
+	unsigned long long tsc;
+	unsigned long long pmc[18];
+};
+
+struct perfctr_cpu_control {
+	unsigned int tsc_on;
+	unsigned int nractrs;		/* # of a-mode counters */
+	unsigned int nrictrs;		/* # of i-mode counters */
+	unsigned int pmc_map[18];
+	unsigned int evntsel[18];	/* one per counter, even on P5 */
+	struct {
+		unsigned int escr[18];
+		unsigned int pebs_enable;	/* for replay tagging */
+		unsigned int pebs_matrix_vert;	/* for replay tagging */
+	} p4;
+	int ireset[18];			/* < 0, for i-mode counters */
+	unsigned int _reserved1;
+	unsigned int _reserved2;
+	unsigned int _reserved3;
+	unsigned int _reserved4;
+};
+
+struct perfctr_cpu_state {
+	unsigned int cstatus;
+	struct {	/* k1 is opaque in the user ABI */
+		unsigned int id;
+		int isuspend_cpu;
+	} k1;
+	/* The two tsc fields must be inlined. Placing them in a
+	   sub-struct causes unwanted internal padding on x86-64. */
+	unsigned int tsc_start;
+	unsigned long long tsc_sum;
+	struct {
+		unsigned int map;
+		unsigned int start;
+		unsigned long long sum;
+	} pmc[18];	/* the size is not part of the user ABI */
+#ifdef __KERNEL__
+	struct perfctr_cpu_control control;
+	unsigned int p4_escr_map[18];
+#endif
+};
+
+/* cstatus is a re-encoding of control.tsc_on/nractrs/nrictrs
+   which should have less overhead in most cases */
+
+static inline
+unsigned int perfctr_mk_cstatus(unsigned int tsc_on, unsigned int nractrs,
+				unsigned int nrictrs)
+{
+	return (tsc_on<<31) | (nrictrs<<16) | ((nractrs+nrictrs)<<8) | nractrs;
+}
+
+static inline unsigned int perfctr_cstatus_enabled(unsigned int cstatus)
+{
+	return cstatus;
+}
+
+static inline int perfctr_cstatus_has_tsc(unsigned int cstatus)
+{
+	return (int)cstatus < 0;	/* test and jump on sign */
+}
+
+static inline unsigned int perfctr_cstatus_nractrs(unsigned int cstatus)
+{
+	return cstatus & 0x7F;		/* and with imm8 */
+}
+
+static inline unsigned int perfctr_cstatus_nrctrs(unsigned int cstatus)
+{
+	return (cstatus >> 8) & 0x7F;
+}
+
+static inline unsigned int perfctr_cstatus_has_ictrs(unsigned int cstatus)
+{
+	return cstatus & (0x7F << 16);
+}
+
+/*
+ * 'struct siginfo' support for perfctr overflow signals.
+ * In unbuffered mode, si_code is set to SI_PMC_OVF and a bitmask
+ * describing which perfctrs overflowed is put in si_pmc_ovf_mask.
+ * A bitmask is used since more than one perfctr can have overflowed
+ * by the time the interrupt handler runs.
+ *
+ * glibc's <signal.h> doesn't seem to define __SI_FAULT or __SI_CODE(),
+ * and including <asm/siginfo.h> as well may cause redefinition errors,
+ * so the user and kernel values are different #defines here.
+ */
+#ifdef __KERNEL__
+#define SI_PMC_OVF	(__SI_FAULT|'P')
+#else
+#define SI_PMC_OVF	('P')
+#endif
+#define si_pmc_ovf_mask	_sifields._pad[0] /* XXX: use an unsigned field later */
+
+/* version number for user-visible CPU-specific data */
+#define PERFCTR_CPU_VERSION	0x0500	/* 5.0 */
+
+#ifdef __KERNEL__
+
+#if defined(CONFIG_PERFCTR)
+
+/* Driver init/exit. */
+extern int perfctr_cpu_init(void);
+extern void perfctr_cpu_exit(void);
+
+/* CPU type name. */
+extern char *perfctr_cpu_name;
+
+/* Hardware reservation. */
+extern const char *perfctr_cpu_reserve(const char *service);
+extern void perfctr_cpu_release(const char *service);
+
+/* PRE: state has no running interrupt-mode counters.
+   Check that the new control data is valid.
+   Update the driver's private control data.
+   is_global should be zero for per-process counters and non-zero
+   for global-mode counters. This matters for HT P4s, alas.
+   Returns a negative error code if the control data is invalid. */
+extern int perfctr_cpu_update_control(struct perfctr_cpu_state *state, int is_global);
+
+/* Read a-mode counters. Subtract from start and accumulate into sums.
+   Must be called with preemption disabled. */
+extern void perfctr_cpu_suspend(struct perfctr_cpu_state *state);
+
+/* Write control registers. Read a-mode counters into start.
+   Must be called with preemption disabled. */
+extern void perfctr_cpu_resume(struct perfctr_cpu_state *state);
+
+/* Perform an efficient combined suspend/resume operation.
+   Must be called with preemption disabled. */
+extern void perfctr_cpu_sample(struct perfctr_cpu_state *state);
+
+/* The type of a perfctr overflow interrupt handler.
+   It will be called in IRQ context, with preemption disabled. */
+typedef void (*perfctr_ihandler_t)(unsigned long pc);
+
+#if defined(CONFIG_X86_LOCAL_APIC)
+#define PERFCTR_INTERRUPT_SUPPORT 1
+#endif
+
+#if PERFCTR_INTERRUPT_SUPPORT
+extern void perfctr_cpu_set_ihandler(perfctr_ihandler_t);
+extern void perfctr_cpu_ireload(struct perfctr_cpu_state*);
+extern unsigned int perfctr_cpu_identify_overflow(struct perfctr_cpu_state*);
+#else
+static inline void perfctr_cpu_set_ihandler(perfctr_ihandler_t x) { }
+#endif
+
+#if defined(CONFIG_SMP)
+/* CPUs in `perfctr_cpus_forbidden_mask' must not use the
+   performance-monitoring counters. TSC use is unrestricted.
+   This is needed to prevent resource conflicts on hyper-threaded P4s.
+   The declaration of `perfctr_cpus_forbidden_mask' is in the driver's
+   private compat.h, since it needs to handle cpumask_t incompatibilities. */
+#define PERFCTR_CPUS_FORBIDDEN_MASK_NEEDED 1
+#endif
+
+#endif	/* CONFIG_PERFCTR */
+
+#if defined(CONFIG_PERFCTR) && PERFCTR_INTERRUPT_SUPPORT
+asmlinkage void perfctr_interrupt(struct pt_regs*);
+#define perfctr_vector_init()	\
+	set_intr_gate(LOCAL_PERFCTR_VECTOR, perfctr_interrupt)
+#else
+#define perfctr_vector_init()	do{}while(0)
+#endif
+
+#endif	/* __KERNEL__ */
+
+#endif	/* _ASM_I386_PERFCTR_H */
--- diff/include/asm-ia64/kgdb.h	1970-01-01 01:00:00.000000000 +0100
+++ source/include/asm-ia64/kgdb.h	2004-06-11 19:22:06.000000000 +0100
@@ -0,0 +1,69 @@
+#ifndef __KGDB
+#define __KGDB
+
+/*
+ * This file should not include ANY others.  This makes it usable
+ * most anywhere without the fear of include order or inclusion.
+ * Make it so!
+ *
+ * This file may be included all the time.  It is only active if
+ * CONFIG_KGDB is defined, otherwise it stubs out all the macros
+ * and entry points.
+ */
+#if defined(CONFIG_KGDB) && !defined(__ASSEMBLY__)
+
+extern void breakpoint(void);
+#define INIT_KGDB_INTS kgdb_enable_ints()
+
+#ifndef BREAKPOINT
+#define BREAKPOINT   asm volatile ("break.m 0x6665")
+#endif
+
+extern void kgdb_schedule_breakpoint(void);
+extern void kgdb_process_breakpoint(void);
+
+extern int kgdb_tty_hook(void);
+extern int kgdb_eth_hook(void);
+extern int kgdboe;
+
+struct kgdb_serial {
+	unsigned long	iobase;
+	unsigned long	shift;
+	int		line;
+	int		iotype;
+	int		claimed;
+};
+
+/*
+ * GDB debug stub (or any debug stub) can point the 'linux_debug_hook'
+ * pointer to its routine and it will be entered as the first thing
+ * when a trap occurs.
+ *
+ * Return values are, at present, undefined.
+ *
+ * The debug hook routine does not necessarily return to its caller.
+ * It has the register image and thus may choose to resume execution
+ * anywhere it pleases.
+ */
+struct pt_regs;
+
+extern int kgdb_handle_exception(int trapno,
+				 int signo, unsigned long err_code, struct pt_regs *regs);
+struct unw_frame_info;
+extern int in_kgdb(struct pt_regs *regs, struct unw_frame_info *);
+#ifdef	CONFIG_KGDB_EARLY
+extern void __init kgdb_serial_init(void);
+#endif
+
+#else				/* CONFIG_KGDB  && ! __ASSEMBLY__ ,stubs follow... */
+#ifndef BREAKPOINT
+#define BREAKPOINT
+#endif
+#define in_kgdb
+#define kgdb_handle_exception
+#define breakpoint
+#define INIT_KGDB_INTS
+#define kgdb_process_breakpoint() do {} while(0)
+
+#endif
+#endif				/* __KGDB */
--- diff/include/asm-ia64/kgdb_local.h	1970-01-01 01:00:00.000000000 +0100
+++ source/include/asm-ia64/kgdb_local.h	2004-06-11 19:22:06.000000000 +0100
@@ -0,0 +1,114 @@
+#ifndef __KGDB_LOCAL
+#define ___KGDB_LOCAL
+#include <linux/config.h>
+#include <linux/types.h>
+#include <linux/serial.h>
+#include <linux/serialP.h>
+#include <linux/spinlock.h>
+#include <asm/processor.h>
+#include <asm/kgdb.h>
+
+#define PORT 0x0
+#ifdef CONFIG_KGDB_PORT
+#undef PORT
+#define PORT CONFIG_KGDB_PORT
+#define IOTYPE SERIAL_IO_PORT
+#endif
+
+#define	IOMEM 0x0
+#ifdef	CONFIG_KGDB_IOMEM
+#undef	IOMEM
+#define	IOMEM CONFIG_KGDB_IOMEM
+#define	IOTYPE SERIAL_IO_MEM
+#endif
+
+#define IRQ 4
+#ifdef CONFIG_KGDB_IRQ
+#undef IRQ
+#define IRQ CONFIG_KGDB_IRQ
+#endif
+
+#define	IOMEM_REG_SHIFT 0
+#ifdef	CONFIG_IOMEM_REG_SHIFT
+#undef	IOMEM_REG_SHIFT
+#define	IOMEM_REG_SHIFT CONFIG_IOMEM_REG_SHIFT
+#endif
+
+
+#define SB_CLOCK 1843200
+#define SB_BASE (SB_CLOCK/16)
+#define SB_BAUD9600 SB_BASE/9600
+#define SB_BAUD192  SB_BASE/19200
+#define SB_BAUD384  SB_BASE/38400
+#define SB_BAUD576  SB_BASE/57600
+#define SB_BAUD1152 SB_BASE/115200
+#ifdef CONFIG_KGDB_9600BAUD
+#define SB_BAUD SB_BAUD9600
+#endif
+#ifdef CONFIG_KGDB_19200BAUD
+#define SB_BAUD SB_BAUD192
+#endif
+#ifdef CONFIG_KGDB_38400BAUD
+#define SB_BAUD SB_BAUD384
+#endif
+#ifdef CONFIG_KGDB_57600BAUD
+#define SB_BAUD SB_BAUD576
+#endif
+#ifdef CONFIG_KGDB_115200BAUD
+#define SB_BAUD SB_BAUD1152
+#endif
+#ifndef SB_BAUD
+#define SB_BAUD SB_BAUD1152	/* Start with this if not given */
+#endif
+
+
+#ifdef _raw_read_unlock		/* must use a name that is "define"ed, not an inline */
+#undef spin_lock
+#undef spin_trylock
+#undef spin_unlock
+#define spin_lock	 _raw_spin_lock
+#define spin_trylock	 _raw_spin_trylock
+#define spin_unlock	 _raw_spin_unlock
+#else
+#endif
+#undef spin_unlock_wait
+#define spin_unlock_wait(x)  do { cpu_relax(); barrier();} \
+                                     while(spin_is_locked(x))
+
+#define SB_IER 1
+#define SB_MCR UART_MCR_OUT2 | UART_MCR_DTR | UART_MCR_RTS
+
+#define FLAGS 0
+#define SB_STATE { \
+     magic: SSTATE_MAGIC, \
+     baud_base: SB_BASE,  \
+     port:      PORT,     \
+     iomem_base:(u8 *) IOMEM,    \
+     iomem_reg_shift: IOMEM_REG_SHIFT,\
+     io_type: IOTYPE,	\
+     irq:       IRQ,      \
+     flags:     FLAGS,    \
+     custom_divisor:SB_BAUD}
+#define SB_INFO  { \
+      magic: SERIAL_MAGIC, \
+      port:  PORT,0,FLAGS, \
+      io_type: IOTYPE,	   \
+      iomem_base: (u8 *) IOMEM,   \
+      iomem_reg_shift: IOMEM_REG_SHIFT, \
+      state: &state,       \
+      tty:   (struct tty_struct *)&state, \
+      IER:   SB_IER,       \
+      MCR:   SB_MCR}
+extern void putDebugChar(int);
+/* RTAI support needs us to really stop/start interrupts */
+
+#define kgdb_local_save_flags(x) 	local_save_flags(x)
+#define kgdb_local_irq_restore(x) 	local_irq_restore(x)
+#define kgdb_local_irq_save(x) 		local_irq_save(x)
+
+#ifdef CONFIG_SERIAL
+extern void shutdown_for_kgdb(struct async_struct *info);
+extern void kgdb_serial_setup(struct uart_port *);
+#endif
+#define INIT_KDEBUG putDebugChar("+");
+#endif				/* __KGDB_LOCAL */
--- diff/include/asm-ia64/lockmeter.h	1970-01-01 01:00:00.000000000 +0100
+++ source/include/asm-ia64/lockmeter.h	2004-06-11 19:22:06.000000000 +0100
@@ -0,0 +1,72 @@
+/*
+ *  Copyright (C) 1999,2000 Silicon Graphics, Inc.
+ *
+ *  Written by John Hawkes (hawkes@sgi.com)
+ *  Based on klstat.h by Jack Steiner (steiner@sgi.com)
+ */
+
+#ifndef _IA64_LOCKMETER_H
+#define _IA64_LOCKMETER_H
+
+#ifdef local_cpu_data
+#define CPU_CYCLE_FREQUENCY	local_cpu_data->itc_freq
+#else
+#define CPU_CYCLE_FREQUENCY	my_cpu_data.itc_freq
+#endif
+#define get_cycles64()		get_cycles()
+
+#define THIS_CPU_NUMBER		smp_processor_id()
+
+/*
+ * macros to cache and retrieve an index value inside of a lock
+ * these macros assume that there are less than 65536 simultaneous
+ * (read mode) holders of a rwlock.
+ * we also assume that the hash table has less than 32767 entries.
+ */
+/*
+ * instrumented spinlock structure -- never used to allocate storage
+ * only used in macros below to overlay a spinlock_t
+ */
+typedef struct inst_spinlock_s {
+	/* remember, Intel is little endian */
+	volatile unsigned short lock;
+	volatile unsigned short index;
+} inst_spinlock_t;
+#define PUT_INDEX(lock_ptr,indexv) ((inst_spinlock_t *)(lock_ptr))->index = indexv
+#define GET_INDEX(lock_ptr)        ((inst_spinlock_t *)(lock_ptr))->index
+
+/*
+ * macros to cache and retrieve an index value in a read/write lock
+ * as well as the cpu where a reader busy period started
+ * we use the 2nd word (the debug word) for this, so require the
+ * debug word to be present
+ */
+/*
+ * instrumented rwlock structure -- never used to allocate storage
+ * only used in macros below to overlay a rwlock_t
+ */
+typedef struct inst_rwlock_s {
+	volatile int read_counter:31;
+	volatile int write_lock:1;
+	volatile unsigned short index;
+	volatile unsigned short cpu;
+} inst_rwlock_t;
+#define PUT_RWINDEX(rwlock_ptr,indexv) ((inst_rwlock_t *)(rwlock_ptr))->index = indexv
+#define GET_RWINDEX(rwlock_ptr)        ((inst_rwlock_t *)(rwlock_ptr))->index
+#define PUT_RW_CPU(rwlock_ptr,cpuv)    ((inst_rwlock_t *)(rwlock_ptr))->cpu = cpuv
+#define GET_RW_CPU(rwlock_ptr)         ((inst_rwlock_t *)(rwlock_ptr))->cpu
+
+/*
+ * return the number of readers for a rwlock_t
+ */
+#define RWLOCK_READERS(rwlock_ptr)	((rwlock_ptr)->read_counter)
+
+/*
+ * return true if rwlock is write locked
+ * (note that other lock attempts can cause the lock value to be negative)
+ */
+#define RWLOCK_IS_WRITE_LOCKED(rwlock_ptr) ((rwlock_ptr)->write_lock)
+#define RWLOCK_IS_READ_LOCKED(rwlock_ptr)  ((rwlock_ptr)->read_counter)
+
+#endif /* _IA64_LOCKMETER_H */
+
--- diff/include/asm-ia64/setup.h	1970-01-01 01:00:00.000000000 +0100
+++ source/include/asm-ia64/setup.h	2004-06-11 19:22:06.000000000 +0100
@@ -0,0 +1,6 @@
+#ifndef __IA64_SETUP_H
+#define __IA64_SETUP_H
+
+#define COMMAND_LINE_SIZE	512
+
+#endif
--- diff/include/asm-mips/lockmeter.h	1970-01-01 01:00:00.000000000 +0100
+++ source/include/asm-mips/lockmeter.h	2004-06-11 19:22:06.000000000 +0100
@@ -0,0 +1,126 @@
+/*
+ *  Copyright (C) 1999,2000 Silicon Graphics, Inc.
+ *
+ *  Written by John Hawkes (hawkes@sgi.com)
+ *  Based on klstat.h by Jack Steiner (steiner@sgi.com)
+ *  Ported to mips32 for Asita Technologies
+ *   by D.J. Barrow ( dj.barrow@asitatechnologies.com )
+ */
+#ifndef _ASM_LOCKMETER_H
+#define _ASM_LOCKMETER_H
+
+/* do_gettimeoffset is a function pointer on mips */
+/* & it is not included by <linux/time.h> */
+#include <asm/time.h>
+#include <linux/time.h>
+#include <asm/div64.h>
+
+#define SPINLOCK_MAGIC_INIT	/* */
+
+#define CPU_CYCLE_FREQUENCY	get_cpu_cycle_frequency()
+
+#define THIS_CPU_NUMBER		smp_processor_id()
+
+static uint32_t cpu_cycle_frequency = 0;
+
+static uint32_t get_cpu_cycle_frequency(void)
+{
+    /* a total hack, slow and invasive, but ... it works */
+    int sec;
+    uint32_t start_cycles;
+    struct timeval tv;
+
+    if (cpu_cycle_frequency == 0) {	/* uninitialized */
+	do_gettimeofday(&tv);
+	sec = tv.tv_sec;	/* set up to catch the tv_sec rollover */
+	while (sec == tv.tv_sec) { do_gettimeofday(&tv); }
+	sec = tv.tv_sec;	/* rolled over to a new sec value */
+	start_cycles = get_cycles();
+	while (sec == tv.tv_sec) { do_gettimeofday(&tv); }
+	cpu_cycle_frequency = get_cycles() - start_cycles;
+    }
+
+    return cpu_cycle_frequency;
+}
+
+extern struct timeval xtime;
+
+static uint64_t get_cycles64(void)
+{
+    static uint64_t last_get_cycles64 = 0;
+    uint64_t ret;
+    unsigned long sec;
+    unsigned long usec, usec_offset;
+
+again:
+    sec  = xtime.tv_sec;
+    usec = xtime.tv_usec;
+    usec_offset = do_gettimeoffset();
+    if ((xtime.tv_sec != sec)  ||
+	(xtime.tv_usec != usec)||
+	(usec_offset >= 20000))
+	goto again;
+
+    ret = ((uint64_t)(usec + usec_offset) * cpu_cycle_frequency);
+    /* We can't do a normal 64 bit division on mips without libgcc.a */
+    do_div(ret,1000000);
+    ret +=  ((uint64_t)sec * cpu_cycle_frequency);
+
+    /* XXX why does time go backwards?  do_gettimeoffset?  general time adj? */
+    if (ret <= last_get_cycles64)
+	ret  = last_get_cycles64+1;
+    last_get_cycles64 = ret;
+
+    return ret;
+}
+
+/*
+ * macros to cache and retrieve an index value inside of a lock
+ * these macros assume that there are less than 65536 simultaneous
+ * (read mode) holders of a rwlock.
+ * we also assume that the hash table has less than 32767 entries.
+ * the high order bit is used for write locking a rw_lock
+ */
+#define INDEX_MASK   0x7FFF0000
+#define READERS_MASK 0x0000FFFF
+#define INDEX_SHIFT 16
+#define PUT_INDEX(lockp,index)   \
+        lockp->lock = (((lockp->lock) & ~INDEX_MASK) | (index) << INDEX_SHIFT)
+#define GET_INDEX(lockp) \
+        (((lockp->lock) & INDEX_MASK) >> INDEX_SHIFT)
+
+/*
+ * macros to cache and retrieve an index value in a read/write lock
+ * as well as the cpu where a reader busy period started
+ * we use the 2nd word (the debug word) for this, so require the
+ * debug word to be present
+ */
+/*
+ * instrumented rwlock structure -- never used to allocate storage
+ * only used in macros below to overlay a rwlock_t
+ */
+typedef struct inst_rwlock_s {
+	volatile int lock;
+	unsigned short index;
+	unsigned short cpu;
+} inst_rwlock_t;
+#define PUT_RWINDEX(rwlock_ptr,indexv) ((inst_rwlock_t *)(rwlock_ptr))->index = indexv
+#define GET_RWINDEX(rwlock_ptr)        ((inst_rwlock_t *)(rwlock_ptr))->index
+#define PUT_RW_CPU(rwlock_ptr,cpuv)    ((inst_rwlock_t *)(rwlock_ptr))->cpu = cpuv
+#define GET_RW_CPU(rwlock_ptr)         ((inst_rwlock_t *)(rwlock_ptr))->cpu
+
+/*
+ * return the number of readers for a rwlock_t
+ */
+#define RWLOCK_READERS(rwlock_ptr)   rwlock_readers(rwlock_ptr)
+
+extern inline int rwlock_readers(rwlock_t *rwlock_ptr)
+{
+	int tmp = (int) rwlock_ptr->lock;
+	return (tmp >= 0) ? tmp : 0;
+}
+
+#define RWLOCK_IS_WRITE_LOCKED(rwlock_ptr) ((rwlock_ptr)->lock < 0)
+#define RWLOCK_IS_READ_LOCKED(rwlock_ptr)  ((rwlock_ptr)->lock > 0)
+
+#endif /* _ASM_LOCKMETER_H */
--- diff/include/asm-mips/setup.h	1970-01-01 01:00:00.000000000 +0100
+++ source/include/asm-mips/setup.h	2004-06-11 19:22:06.000000000 +0100
@@ -0,0 +1,8 @@
+#ifdef __KERNEL__
+#ifndef _MIPS_SETUP_H
+#define _MIPS_SETUP_H
+
+#define COMMAND_LINE_SIZE	256
+
+#endif /* __SETUP_H */
+#endif /* __KERNEL__ */
--- diff/include/asm-ppc/fsl_ocp.h	1970-01-01 01:00:00.000000000 +0100
+++ source/include/asm-ppc/fsl_ocp.h	2004-06-11 19:22:06.000000000 +0100
@@ -0,0 +1,54 @@
+/*
+ * include/asm-ppc/fsl_ocp.h
+ *
+ * Definitions for the on-chip peripherals on Freescale PPC processors
+ *
+ * Maintainer: Kumar Gala (kumar.gala@freescale.com)
+ *
+ * Copyright 2004 Freescale Semiconductor, Inc
+ *
+ * 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.
+ */
+
+#ifdef __KERNEL__
+#ifndef __ASM_FS_OCP_H__
+#define __ASM_FS_OCP_H__
+
+/* A table of information for supporting the Gianfar Ethernet Controller
+ * This helps identify which enet controller we are dealing with,
+ * and what type of enet controller it is
+ */
+struct ocp_gfar_data {
+	uint interruptTransmit;
+	uint interruptError;
+	uint interruptReceive;
+	uint interruptPHY;
+	uint flags;
+	uint phyid;
+	uint phyregidx;
+	unsigned char mac_addr[6];
+};
+
+/* Flags in the flags field */
+#define GFAR_HAS_COALESCE		0x20
+#define GFAR_HAS_RMON			0x10
+#define GFAR_HAS_MULTI_INTR		0x08
+#define GFAR_FIRM_SET_MACADDR		0x04
+#define GFAR_HAS_PHY_INTR		0x02	/* if not set use a timer */
+#define GFAR_HAS_GIGABIT		0x01
+
+/* Data structure for I2C support.  Just contains a couple flags
+ * to distinguish various I2C implementations*/
+struct ocp_fs_i2c_data {
+	uint flags;
+};
+
+/* Flags for I2C */
+#define FS_I2C_SEPARATE_DFSRR	0x02
+#define FS_I2C_32BIT		0x01
+
+#endif	/* __ASM_FS_OCP_H__ */
+#endif	/* __KERNEL__ */
--- diff/include/asm-ppc/immap_85xx.h	1970-01-01 01:00:00.000000000 +0100
+++ source/include/asm-ppc/immap_85xx.h	2004-06-11 19:22:06.000000000 +0100
@@ -0,0 +1,126 @@
+/*
+ * include/asm-ppc/immap_85xx.h
+ *
+ * MPC85xx Internal Memory Map
+ *
+ * Maintainer: Kumar Gala <kumar.gala@freescale.com>
+ *
+ * Copyright 2004 Freescale Semiconductor, Inc
+ *
+ * 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.
+ *
+ */
+
+#ifdef __KERNEL__
+#ifndef __ASM_IMMAP_85XX_H__
+#define __ASM_IMMAP_85XX_H__
+
+/* Eventually this should define all the IO block registers in 85xx */
+
+/* PCI Registers */
+typedef struct ccsr_pci {
+	uint	cfg_addr;	/* 0x.000 - PCI Configuration Address Register */
+	uint	cfg_data;	/* 0x.004 - PCI Configuration Data Register */
+	uint	int_ack;	/* 0x.008 - PCI Interrupt Acknowledge Register */
+	char	res1[3060];
+	uint	potar0;		/* 0x.c00 - PCI Outbound Transaction Address Register 0 */
+	uint	potear0;	/* 0x.c04 - PCI Outbound Translation Extended Address Register 0 */
+	uint	powbar0;	/* 0x.c08 - PCI Outbound Window Base Address Register 0 */
+	char	res2[4];
+	uint	powar0;		/* 0x.c10 - PCI Outbound Window Attributes Register 0 */
+	char	res3[12];
+	uint	potar1;		/* 0x.c20 - PCI Outbound Transaction Address Register 1 */
+	uint	potear1;	/* 0x.c24 - PCI Outbound Translation Extended Address Register 1 */
+	uint	powbar1;	/* 0x.c28 - PCI Outbound Window Base Address Register 1 */
+	char	res4[4];
+	uint	powar1;		/* 0x.c30 - PCI Outbound Window Attributes Register 1 */
+	char	res5[12];
+	uint	potar2;		/* 0x.c40 - PCI Outbound Transaction Address Register 2 */
+	uint	potear2;	/* 0x.c44 - PCI Outbound Translation Extended Address Register 2 */
+	uint	powbar2;	/* 0x.c48 - PCI Outbound Window Base Address Register 2 */
+	char	res6[4];
+	uint	powar2;		/* 0x.c50 - PCI Outbound Window Attributes Register 2 */
+	char	res7[12];
+	uint	potar3;		/* 0x.c60 - PCI Outbound Transaction Address Register 3 */
+	uint	potear3;	/* 0x.c64 - PCI Outbound Translation Extended Address Register 3 */
+	uint	powbar3;	/* 0x.c68 - PCI Outbound Window Base Address Register 3 */
+	char	res8[4];
+	uint	powar3;		/* 0x.c70 - PCI Outbound Window Attributes Register 3 */
+	char	res9[12];
+	uint	potar4;		/* 0x.c80 - PCI Outbound Transaction Address Register 4 */
+	uint	potear4;	/* 0x.c84 - PCI Outbound Translation Extended Address Register 4 */
+	uint	powbar4;	/* 0x.c88 - PCI Outbound Window Base Address Register 4 */
+	char	res10[4];
+	uint	powar4;		/* 0x.c90 - PCI Outbound Window Attributes Register 4 */
+	char	res11[268];
+	uint	pitar3;		/* 0x.da0 - PCI Inbound Translation Address Register 3  */
+	char	res12[4];
+	uint	piwbar3;	/* 0x.da8 - PCI Inbound Window Base Address Register 3 */
+	uint	piwbear3;	/* 0x.dac - PCI Inbound Window Base Extended Address Register 3 */
+	uint	piwar3;		/* 0x.db0 - PCI Inbound Window Attributes Register 3 */
+	char	res13[12];
+	uint	pitar2;		/* 0x.dc0 - PCI Inbound Translation Address Register 2  */
+	char	res14[4];
+	uint	piwbar2;	/* 0x.dc8 - PCI Inbound Window Base Address Register 2 */
+	uint	piwbear2;	/* 0x.dcc - PCI Inbound Window Base Extended Address Register 2 */
+	uint	piwar2;		/* 0x.dd0 - PCI Inbound Window Attributes Register 2 */
+	char	res15[12];
+	uint	pitar1;		/* 0x.de0 - PCI Inbound Translation Address Register 1  */
+	char	res16[4];
+	uint	piwbar1;	/* 0x.de8 - PCI Inbound Window Base Address Register 1 */
+	char	res17[4];
+	uint	piwar1;		/* 0x.df0 - PCI Inbound Window Attributes Register 1 */
+	char	res18[12];
+	uint	err_dr;		/* 0x.e00 - PCI Error Detect Register */
+	uint	err_cap_dr;	/* 0x.e04 - PCI Error Capture Disable Register */
+	uint	err_en;		/* 0x.e08 - PCI Error Enable Register */
+	uint	err_attrib;	/* 0x.e0c - PCI Error Attributes Capture Register */
+	uint	err_addr;	/* 0x.e10 - PCI Error Address Capture Register */
+	uint	err_ext_addr;	/* 0x.e14 - PCI Error Extended Address Capture Register */
+	uint	err_dl;		/* 0x.e18 - PCI Error Data Low Capture Register */
+	uint	err_dh;		/* 0x.e1c - PCI Error Data High Capture Register */
+	uint	gas_timr;	/* 0x.e20 - PCI Gasket Timer Register */
+	uint	pci_timr;	/* 0x.e24 - PCI Timer Register */
+	char	res19[472];
+} ccsr_pci_t;
+
+/* Global Utility Registers */
+typedef struct ccsr_guts {
+	uint	porpllsr;	/* 0x.0000 - POR PLL Ratio Status Register */
+	uint	porbmsr;	/* 0x.0004 - POR Boot Mode Status Register */
+	uint	porimpscr;	/* 0x.0008 - POR I/O Impedance Status and Control Register */
+	uint	pordevsr;	/* 0x.000c - POR I/O Device Status Register */
+	uint	pordbgmsr;	/* 0x.0010 - POR Debug Mode Status Register */
+	char	res1[12];
+	uint	gpporcr;	/* 0x.0020 - General-Purpose POR Configuration Register */
+	char	res2[12];
+	uint	gpiocr;		/* 0x.0030 - GPIO Control Register */
+	char	res3[12];
+	uint	gpoutdr;	/* 0x.0040 - General-Purpose Output Data Register */
+	char	res4[12];
+	uint	gpindr;		/* 0x.0050 - General-Purpose Input Data Register */
+	char	res5[12];
+	uint	pmuxcr;		/* 0x.0060 - Alternate Function Signal Multiplex Control */
+	char	res6[12];
+	uint	devdisr;	/* 0x.0070 - Device Disable Control */
+	char	res7[12];
+	uint	powmgtcsr;	/* 0x.0080 - Power Management Status and Control Register */
+	char	res8[12];
+	uint	mcpsumr;	/* 0x.0090 - Machine Check Summary Register */
+	char	res9[12];
+	uint	pvr;		/* 0x.00a0 - Processor Version Register */
+	uint	svr;		/* 0x.00a4 - System Version Register */
+	char	res10[3416];
+	uint	clkocr;		/* 0x.0e00 - Clock Out Select Register */
+	char	res11[12];
+	uint	ddrdllcr;	/* 0x.0e10 - DDR DLL Control Register */
+	char	res12[12];
+	uint	lbcdllcr;	/* 0x.0e20 - LBC DLL Control Register */
+	char	res13[61916];
+} ccsr_guts_t;
+
+#endif /* __ASM_IMMAP_85XX_H__ */
+#endif /* __KERNEL__ */
--- diff/include/asm-ppc/mpc85xx.h	1970-01-01 01:00:00.000000000 +0100
+++ source/include/asm-ppc/mpc85xx.h	2004-06-11 19:22:06.000000000 +0100
@@ -0,0 +1,128 @@
+/*
+ * include/asm-ppc/mpc85xx.h
+ *
+ * MPC85xx definitions
+ *
+ * Maintainer: Kumar Gala <kumar.gala@freescale.com>
+ *
+ * Copyright 2004 Freescale Semiconductor, Inc
+ *
+ * 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.
+ */
+
+#ifdef __KERNEL__
+#ifndef __ASM_MPC85xx_H__
+#define __ASM_MPC85xx_H__
+
+#include <linux/config.h>
+#include <asm/mmu.h>
+
+#ifdef CONFIG_85xx
+
+#ifdef CONFIG_MPC8540_ADS
+#include <platforms/85xx/mpc8540_ads.h>
+#endif
+
+#define _IO_BASE        isa_io_base
+#define _ISA_MEM_BASE   isa_mem_base
+#define PCI_DRAM_OFFSET pci_dram_offset
+
+/*
+ * The "residual" board information structure the boot loader passes
+ * into the kernel.
+ */
+extern unsigned char __res[];
+
+/* Internal IRQs on MPC85xx OpenPIC */
+/* Not all of these exist on all MPC85xx implementations */
+
+#ifndef MPC85xx_OPENPIC_IRQ_OFFSET
+#define MPC85xx_OPENPIC_IRQ_OFFSET	64
+#endif
+
+/* The 32 internal sources */
+#define MPC85xx_IRQ_L2CACHE	( 0 + MPC85xx_OPENPIC_IRQ_OFFSET)
+#define MPC85xx_IRQ_ECM		( 1 + MPC85xx_OPENPIC_IRQ_OFFSET)
+#define MPC85xx_IRQ_DDR		( 2 + MPC85xx_OPENPIC_IRQ_OFFSET)
+#define MPC85xx_IRQ_LBIU	( 3 + MPC85xx_OPENPIC_IRQ_OFFSET)
+#define MPC85xx_IRQ_DMA0	( 4 + MPC85xx_OPENPIC_IRQ_OFFSET)
+#define MPC85xx_IRQ_DMA1	( 5 + MPC85xx_OPENPIC_IRQ_OFFSET)
+#define MPC85xx_IRQ_DMA2	( 6 + MPC85xx_OPENPIC_IRQ_OFFSET)
+#define MPC85xx_IRQ_DMA3	( 7 + MPC85xx_OPENPIC_IRQ_OFFSET)
+#define MPC85xx_IRQ_PCI1	( 8 + MPC85xx_OPENPIC_IRQ_OFFSET)
+#define MPC85xx_IRQ_PCI2	( 9 + MPC85xx_OPENPIC_IRQ_OFFSET)
+#define MPC85xx_IRQ_RIO_ERROR	( 9 + MPC85xx_OPENPIC_IRQ_OFFSET)
+#define MPC85xx_IRQ_RIO_BELL	(10 + MPC85xx_OPENPIC_IRQ_OFFSET)
+#define MPC85xx_IRQ_RIO_TX	(11 + MPC85xx_OPENPIC_IRQ_OFFSET)
+#define MPC85xx_IRQ_RIO_RX	(12 + MPC85xx_OPENPIC_IRQ_OFFSET)
+#define MPC85xx_IRQ_TSEC1_TX	(13 + MPC85xx_OPENPIC_IRQ_OFFSET)
+#define MPC85xx_IRQ_TSEC1_RX	(14 + MPC85xx_OPENPIC_IRQ_OFFSET)
+#define MPC85xx_IRQ_TSEC1_ERROR	(18 + MPC85xx_OPENPIC_IRQ_OFFSET)
+#define MPC85xx_IRQ_TSEC2_TX	(19 + MPC85xx_OPENPIC_IRQ_OFFSET)
+#define MPC85xx_IRQ_TSEC2_RX	(20 + MPC85xx_OPENPIC_IRQ_OFFSET)
+#define MPC85xx_IRQ_TSEC2_ERROR	(24 + MPC85xx_OPENPIC_IRQ_OFFSET)
+#define MPC85xx_IRQ_FEC		(25 + MPC85xx_OPENPIC_IRQ_OFFSET)
+#define MPC85xx_IRQ_DUART	(26 + MPC85xx_OPENPIC_IRQ_OFFSET)
+#define MPC85xx_IRQ_IIC1	(27 + MPC85xx_OPENPIC_IRQ_OFFSET)
+#define MPC85xx_IRQ_PERFMON	(28 + MPC85xx_OPENPIC_IRQ_OFFSET)
+#define MPC85xx_IRQ_CPM		(30 + MPC85xx_OPENPIC_IRQ_OFFSET)
+
+/* The 12 external interrupt lines */
+#define MPC85xx_IRQ_EXT0        (32 + MPC85xx_OPENPIC_IRQ_OFFSET)
+#define MPC85xx_IRQ_EXT1        (33 + MPC85xx_OPENPIC_IRQ_OFFSET)
+#define MPC85xx_IRQ_EXT2        (34 + MPC85xx_OPENPIC_IRQ_OFFSET)
+#define MPC85xx_IRQ_EXT3        (35 + MPC85xx_OPENPIC_IRQ_OFFSET)
+#define MPC85xx_IRQ_EXT4        (36 + MPC85xx_OPENPIC_IRQ_OFFSET)
+#define MPC85xx_IRQ_EXT5        (37 + MPC85xx_OPENPIC_IRQ_OFFSET)
+#define MPC85xx_IRQ_EXT6        (38 + MPC85xx_OPENPIC_IRQ_OFFSET)
+#define MPC85xx_IRQ_EXT7        (39 + MPC85xx_OPENPIC_IRQ_OFFSET)
+#define MPC85xx_IRQ_EXT8        (40 + MPC85xx_OPENPIC_IRQ_OFFSET)
+#define MPC85xx_IRQ_EXT9        (41 + MPC85xx_OPENPIC_IRQ_OFFSET)
+#define MPC85xx_IRQ_EXT10       (42 + MPC85xx_OPENPIC_IRQ_OFFSET)
+#define MPC85xx_IRQ_EXT11       (43 + MPC85xx_OPENPIC_IRQ_OFFSET)
+
+/* Offset from CCSRBAR */
+#define MPC85xx_CPM_OFFSET	(0x80000)
+#define MPC85xx_CPM_SIZE	(0x40000)
+#define MPC85xx_DMA_OFFSET	(0x21000)
+#define MPC85xx_DMA_SIZE	(0x01000)
+#define MPC85xx_ENET1_OFFSET	(0x24000)
+#define MPC85xx_ENET1_SIZE	(0x01000)
+#define MPC85xx_ENET2_OFFSET	(0x25000)
+#define MPC85xx_ENET2_SIZE	(0x01000)
+#define MPC85xx_ENET3_OFFSET	(0x26000)
+#define MPC85xx_ENET3_SIZE	(0x01000)
+#define MPC85xx_GUTS_OFFSET	(0xe0000)
+#define MPC85xx_GUTS_SIZE	(0x01000)
+#define MPC85xx_IIC1_OFFSET	(0x03000)
+#define MPC85xx_IIC1_SIZE	(0x01000)
+#define MPC85xx_OPENPIC_OFFSET	(0x40000)
+#define MPC85xx_OPENPIC_SIZE	(0x40000)
+#define MPC85xx_PCI1_OFFSET	(0x08000)
+#define MPC85xx_PCI1_SIZE	(0x01000)
+#define MPC85xx_PCI2_OFFSET	(0x09000)
+#define MPC85xx_PCI2_SIZE	(0x01000)
+#define MPC85xx_PERFMON_OFFSET	(0xe1000)
+#define MPC85xx_PERFMON_SIZE	(0x01000)
+#define MPC85xx_UART0_OFFSET	(0x04500)
+#define MPC85xx_UART0_SIZE	(0x00100)
+#define MPC85xx_UART1_OFFSET	(0x04600)
+#define MPC85xx_UART1_SIZE	(0x00100)
+
+#define MPC85xx_CCSRBAR_SIZE	(1024*1024)
+
+/* Let modules/drivers get at CCSRBAR */
+extern phys_addr_t get_ccsrbar(void);
+
+#ifdef MODULE
+#define CCSRBAR get_ccsrbar()
+#else
+#define CCSRBAR BOARD_CCSRBAR
+#endif
+
+#endif /* CONFIG_85xx */
+#endif /* __ASM_MPC85xx_H__ */
+#endif /* __KERNEL__ */
--- diff/include/asm-ppc/perfctr.h	1970-01-01 01:00:00.000000000 +0100
+++ source/include/asm-ppc/perfctr.h	2004-06-11 19:22:06.000000000 +0100
@@ -0,0 +1,170 @@
+/* $Id: perfctr.h,v 1.6 2004/05/30 14:47:34 mikpe Exp $
+ * PPC32 Performance-Monitoring Counters driver
+ *
+ * Copyright (C) 2004  Mikael Pettersson
+ */
+#ifndef _ASM_PPC_PERFCTR_H
+#define _ASM_PPC_PERFCTR_H
+
+/* perfctr_info.cpu_type values */
+#define PERFCTR_PPC_604		1
+#define PERFCTR_PPC_604e	2
+#define PERFCTR_PPC_750		3
+#define PERFCTR_PPC_7400	4
+#define PERFCTR_PPC_7450	5
+
+struct perfctr_sum_ctrs {
+	unsigned long long tsc;
+	unsigned long long pmc[8];
+};
+
+struct perfctr_cpu_control {
+	unsigned int tsc_on;
+	unsigned int nractrs;		/* # of a-mode counters */
+	unsigned int nrictrs;		/* # of i-mode counters */
+	unsigned int pmc_map[8];
+	unsigned int evntsel[8];	/* one per counter, even on P5 */
+	int ireset[8];			/* [0,0x7fffffff], for i-mode counters */
+	struct {
+		unsigned int mmcr0;	/* sans PMC{1,2}SEL */
+		unsigned int mmcr2;	/* only THRESHMULT */
+		/* IABR/DABR/BAMR not supported */
+	} ppc;
+	unsigned int _reserved1;
+	unsigned int _reserved2;
+	unsigned int _reserved3;
+	unsigned int _reserved4;
+};
+
+struct perfctr_cpu_state {
+	unsigned int cstatus;
+	struct {	/* k1 is opaque in the user ABI */
+		unsigned int id;
+		int isuspend_cpu;
+	} k1;
+	/* The two tsc fields must be inlined. Placing them in a
+	   sub-struct causes unwanted internal padding on x86-64. */
+	unsigned int tsc_start;
+	unsigned long long tsc_sum;
+	struct {
+		unsigned int map;
+		unsigned int start;
+		unsigned long long sum;
+	} pmc[8];	/* the size is not part of the user ABI */
+#ifdef __KERNEL__
+	unsigned int ppc_mmcr[3];
+	struct perfctr_cpu_control control;
+#endif
+};
+
+/* cstatus is a re-encoding of control.tsc_on/nractrs/nrictrs
+   which should have less overhead in most cases */
+/* XXX: ppc driver internally also uses cstatus&(1<<30) */
+
+static inline
+unsigned int perfctr_mk_cstatus(unsigned int tsc_on, unsigned int nractrs,
+				unsigned int nrictrs)
+{
+	return (tsc_on<<31) | (nrictrs<<16) | ((nractrs+nrictrs)<<8) | nractrs;
+}
+
+static inline unsigned int perfctr_cstatus_enabled(unsigned int cstatus)
+{
+	return cstatus;
+}
+
+static inline int perfctr_cstatus_has_tsc(unsigned int cstatus)
+{
+	return (int)cstatus < 0;	/* test and jump on sign */
+}
+
+static inline unsigned int perfctr_cstatus_nractrs(unsigned int cstatus)
+{
+	return cstatus & 0x7F;		/* and with imm8 */
+}
+
+static inline unsigned int perfctr_cstatus_nrctrs(unsigned int cstatus)
+{
+	return (cstatus >> 8) & 0x7F;
+}
+
+static inline unsigned int perfctr_cstatus_has_ictrs(unsigned int cstatus)
+{
+	return cstatus & (0x7F << 16);
+}
+
+/*
+ * 'struct siginfo' support for perfctr overflow signals.
+ * In unbuffered mode, si_code is set to SI_PMC_OVF and a bitmask
+ * describing which perfctrs overflowed is put in si_pmc_ovf_mask.
+ * A bitmask is used since more than one perfctr can have overflowed
+ * by the time the interrupt handler runs.
+ *
+ * glibc's <signal.h> doesn't seem to define __SI_FAULT or __SI_CODE(),
+ * and including <asm/siginfo.h> as well may cause redefinition errors,
+ * so the user and kernel values are different #defines here.
+ */
+#ifdef __KERNEL__
+#define SI_PMC_OVF	(__SI_FAULT|'P')
+#else
+#define SI_PMC_OVF	('P')
+#endif
+#define si_pmc_ovf_mask	_sifields._pad[0] /* XXX: use an unsigned field later */
+
+/* version number for user-visible CPU-specific data */
+#define PERFCTR_CPU_VERSION	0	/* XXX: not yet cast in stone */
+
+#ifdef __KERNEL__
+
+#if defined(CONFIG_PERFCTR)
+
+/* Driver init/exit. */
+extern int perfctr_cpu_init(void);
+extern void perfctr_cpu_exit(void);
+
+/* CPU type name. */
+extern char *perfctr_cpu_name;
+
+/* Hardware reservation. */
+extern const char *perfctr_cpu_reserve(const char *service);
+extern void perfctr_cpu_release(const char *service);
+
+/* PRE: state has no running interrupt-mode counters.
+   Check that the new control data is valid.
+   Update the driver's private control data.
+   Returns a negative error code if the control data is invalid. */
+extern int perfctr_cpu_update_control(struct perfctr_cpu_state *state, int is_global);
+
+/* Read a-mode counters. Subtract from start and accumulate into sums.
+   Must be called with preemption disabled. */
+extern void perfctr_cpu_suspend(struct perfctr_cpu_state *state);
+
+/* Write control registers. Read a-mode counters into start.
+   Must be called with preemption disabled. */
+extern void perfctr_cpu_resume(struct perfctr_cpu_state *state);
+
+/* Perform an efficient combined suspend/resume operation.
+   Must be called with preemption disabled. */
+extern void perfctr_cpu_sample(struct perfctr_cpu_state *state);
+
+/* The type of a perfctr overflow interrupt handler.
+   It will be called in IRQ context, with preemption disabled. */
+typedef void (*perfctr_ihandler_t)(unsigned long pc);
+
+/* XXX: The hardware supports overflow interrupts, but the driver
+   does not yet enable this due to an erratum in 750/7400/7410. */
+//#define PERFCTR_INTERRUPT_SUPPORT 1
+
+#ifdef PERFCTR_INTERRUPT_SUPPORT
+extern void perfctr_cpu_set_ihandler(perfctr_ihandler_t);
+extern void perfctr_cpu_ireload(struct perfctr_cpu_state*);
+extern unsigned int perfctr_cpu_identify_overflow(struct perfctr_cpu_state*);
+#else
+static inline void perfctr_cpu_set_ihandler(perfctr_ihandler_t x) { }
+#endif
+
+#endif	/* CONFIG_PERFCTR */
+
+#endif	/* __KERNEL__ */
+
+#endif	/* _ASM_PPC_PERFCTR_H */
--- diff/include/asm-sh/setup.h	1970-01-01 01:00:00.000000000 +0100
+++ source/include/asm-sh/setup.h	2004-06-11 19:22:06.000000000 +0100
@@ -0,0 +1,8 @@
+#ifdef __KERNEL__
+#ifndef _SH_SETUP_H
+#define _SH_SETUP_H
+
+#define COMMAND_LINE_SIZE 256
+
+#endif /* _SH_SETUP_H */
+#endif /* __KERNEL__ */
--- diff/include/asm-sparc64/lockmeter.h	1970-01-01 01:00:00.000000000 +0100
+++ source/include/asm-sparc64/lockmeter.h	2004-06-11 19:22:06.000000000 +0100
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2000 Anton Blanchard (anton@linuxcare.com)
+ * Copyright (C) 2003 David S. Miller (davem@redhat.com)
+ */
+
+#ifndef _SPARC64_LOCKMETER_H
+#define _SPARC64_LOCKMETER_H
+
+#include <linux/smp.h>
+#include <asm/spinlock.h>
+#include <asm/timer.h>
+#include <asm/timex.h>
+
+/* Actually, this is not the CPU frequency by the system tick
+ * frequency which is good enough for lock metering.
+ */
+#define CPU_CYCLE_FREQUENCY	(timer_tick_offset * HZ)
+#define THIS_CPU_NUMBER		smp_processor_id()
+
+#define PUT_INDEX(lock_ptr,indexv)	(lock_ptr)->index = (indexv)
+#define GET_INDEX(lock_ptr)		(lock_ptr)->index
+
+#define PUT_RWINDEX(rwlock_ptr,indexv) (rwlock_ptr)->index = (indexv)
+#define GET_RWINDEX(rwlock_ptr)        (rwlock_ptr)->index
+#define PUT_RW_CPU(rwlock_ptr,cpuv)    (rwlock_ptr)->cpu = (cpuv)
+#define GET_RW_CPU(rwlock_ptr)         (rwlock_ptr)->cpu
+
+#define RWLOCK_READERS(rwlock_ptr)	rwlock_readers(rwlock_ptr)
+
+extern inline int rwlock_readers(rwlock_t *rwlock_ptr)
+{
+	signed int tmp = rwlock_ptr->lock;
+
+	if (tmp > 0)
+		return tmp;
+	else
+		return 0;
+}
+
+#define RWLOCK_IS_WRITE_LOCKED(rwlock_ptr)	((signed int)((rwlock_ptr)->lock) < 0)
+#define RWLOCK_IS_READ_LOCKED(rwlock_ptr)	((signed int)((rwlock_ptr)->lock) > 0)
+
+#define get_cycles64()	get_cycles()
+
+#endif /* _SPARC64_LOCKMETER_H */
--- diff/include/asm-um/setup.h	1970-01-01 01:00:00.000000000 +0100
+++ source/include/asm-um/setup.h	2004-06-11 19:22:06.000000000 +0100
@@ -0,0 +1,6 @@
+#ifndef SETUP_H_INCLUDED
+#define SETUP_H_INCLUDED
+
+#define COMMAND_LINE_SIZE 512
+
+#endif		/* SETUP_H_INCLUDED */
--- diff/include/asm-v850/setup.h	1970-01-01 01:00:00.000000000 +0100
+++ source/include/asm-v850/setup.h	2004-06-11 19:22:06.000000000 +0100
@@ -0,0 +1,6 @@
+#ifndef _V850_SETUP_H
+#define _V850_SETUP_H
+
+#define COMMAND_LINE_SIZE	512
+
+#endif /* __SETUP_H */
--- diff/include/asm-x86_64/kgdb.h	1970-01-01 01:00:00.000000000 +0100
+++ source/include/asm-x86_64/kgdb.h	2004-06-11 19:22:06.000000000 +0100
@@ -0,0 +1,71 @@
+#ifndef __KGDB
+#define __KGDB
+
+/*
+ * This file should not include ANY others.  This makes it usable
+ * most anywhere without the fear of include order or inclusion.
+ * Make it so!
+ *
+ * This file may be included all the time.  It is only active if
+ * CONFIG_KGDB is defined, otherwise it stubs out all the macros
+ * and entry points.
+ */
+#if defined(CONFIG_KGDB) && !defined(__ASSEMBLY__)
+
+extern void breakpoint(void);
+#define INIT_KGDB_INTS kgdb_enable_ints()
+
+#ifndef BREAKPOINT
+#define BREAKPOINT   asm("   int $3")
+#endif
+
+extern void kgdb_schedule_breakpoint(void);
+extern void kgdb_process_breakpoint(void);
+
+extern int kgdb_tty_hook(void);
+extern int kgdb_eth_hook(void);
+extern int kgdboe;
+
+/*
+ * GDB debug stub (or any debug stub) can point the 'linux_debug_hook'
+ * pointer to its routine and it will be entered as the first thing
+ * when a trap occurs.
+ *
+ * Return values are, at present, undefined.
+ *
+ * The debug hook routine does not necessarily return to its caller.
+ * It has the register image and thus may choose to resume execution
+ * anywhere it pleases.
+ */
+struct pt_regs;
+
+extern int kgdb_handle_exception(int trapno,
+				 int signo, int err_code, struct pt_regs *regs);
+extern int in_kgdb(struct pt_regs *regs);
+
+extern void set_debug_traps(void);
+
+#ifdef CONFIG_KGDB_TS
+void kgdb_tstamp(int line, char *source, int data0, int data1);
+/*
+ * This is the time stamp function.  The macro adds the source info and
+ * does a cast on the data to allow most any 32-bit value.
+ */
+
+#define kgdb_ts(data0,data1) kgdb_tstamp(__LINE__,__FILE__,(int)data0,(int)data1)
+#else
+#define kgdb_ts(data0,data1)
+#endif
+#else				/* CONFIG_KGDB  && ! __ASSEMBLY__ ,stubs follow... */
+#ifndef BREAKPOINT
+#define BREAKPOINT
+#endif
+#define kgdb_ts(data0,data1)
+#define in_kgdb	(0)
+#define kgdb_handle_exception
+#define breakpoint
+#define INIT_KGDB_INTS
+#define kgdb_process_breakpoint() do {} while(0)
+
+#endif
+#endif				/* __KGDB */
--- diff/include/asm-x86_64/kgdb_local.h	1970-01-01 01:00:00.000000000 +0100
+++ source/include/asm-x86_64/kgdb_local.h	2004-06-11 19:22:06.000000000 +0100
@@ -0,0 +1,102 @@
+#ifndef __KGDB_LOCAL
+#define ___KGDB_LOCAL
+#include <linux/config.h>
+#include <linux/types.h>
+#include <linux/serial.h>
+#include <linux/serialP.h>
+#include <linux/spinlock.h>
+#include <asm/processor.h>
+#include <asm/msr.h>
+#include <asm/kgdb.h>
+
+#define PORT 0x3f8
+#ifdef CONFIG_KGDB_PORT
+#undef PORT
+#define PORT CONFIG_KGDB_PORT
+#endif
+#define IRQ 4
+#ifdef CONFIG_KGDB_IRQ
+#undef IRQ
+#define IRQ CONFIG_KGDB_IRQ
+#endif
+#define SB_CLOCK 1843200
+#define SB_BASE (SB_CLOCK/16)
+#define SB_BAUD9600 SB_BASE/9600
+#define SB_BAUD192  SB_BASE/19200
+#define SB_BAUD384  SB_BASE/38400
+#define SB_BAUD576  SB_BASE/57600
+#define SB_BAUD1152 SB_BASE/115200
+#ifdef CONFIG_KGDB_9600BAUD
+#define SB_BAUD SB_BAUD9600
+#endif
+#ifdef CONFIG_KGDB_19200BAUD
+#define SB_BAUD SB_BAUD192
+#endif
+#ifdef CONFIG_KGDB_38400BAUD
+#define SB_BAUD SB_BAUD384
+#endif
+#ifdef CONFIG_KGDB_57600BAUD
+#define SB_BAUD SB_BAUD576
+#endif
+#ifdef CONFIG_KGDB_115200BAUD
+#define SB_BAUD SB_BAUD1152
+#endif
+#ifndef SB_BAUD
+#define SB_BAUD SB_BAUD1152	/* Start with this if not given */
+#endif
+
+#ifndef CONFIG_X86_TSC
+#undef rdtsc
+#define rdtsc(a,b) if (a++ > 10000){a = 0; b++;}
+#undef rdtscll
+#define rdtscll(s) s++
+#endif
+
+#ifdef _raw_read_unlock		/* must use a name that is "define"ed, not an inline */
+#undef spin_lock
+#undef spin_trylock
+#undef spin_unlock
+#define spin_lock	 _raw_spin_lock
+#define spin_trylock	 _raw_spin_trylock
+#define spin_unlock	 _raw_spin_unlock
+#else
+#endif
+#undef spin_unlock_wait
+#define spin_unlock_wait(x)  do { cpu_relax(); barrier();} \
+                                     while(spin_is_locked(x))
+
+#define SB_IER 1
+#define SB_MCR UART_MCR_OUT2 | UART_MCR_DTR | UART_MCR_RTS
+
+#define FLAGS 0
+#define SB_STATE { \
+     magic: SSTATE_MAGIC, \
+     baud_base: SB_BASE,  \
+     port:      PORT,     \
+     irq:       IRQ,      \
+     flags:     FLAGS,    \
+     custom_divisor:SB_BAUD}
+#define SB_INFO  { \
+      magic: SERIAL_MAGIC, \
+      port:  PORT,0,FLAGS, \
+      state: &state,       \
+      tty:   (struct tty_struct *)&state, \
+      IER:   SB_IER,       \
+      MCR:   SB_MCR}
+extern void putDebugChar(int);
+/* RTAI support needs us to really stop/start interrupts */
+
+#define kgdb_sti() __asm__ __volatile__("sti": : :"memory")
+#define kgdb_cli() __asm__ __volatile__("cli": : :"memory")
+#define kgdb_local_save_flags(x) __asm__ __volatile__(\
+                                   "pushfl ; popl %0":"=g" (x): /* no input */)
+#define kgdb_local_irq_restore(x) __asm__ __volatile__(\
+                                   "pushl %0 ; popfl": \
+                                     /* no output */ :"g" (x):"memory", "cc")
+#define kgdb_local_irq_save(x) kgdb_local_save_flags(x); kgdb_cli()
+
+#ifdef CONFIG_SERIAL
+extern void shutdown_for_kgdb(struct async_struct *info);
+#endif
+#define INIT_KDEBUG putDebugChar("+");
+#endif				/* __KGDB_LOCAL */
--- diff/include/asm-x86_64/perfctr.h	1970-01-01 01:00:00.000000000 +0100
+++ source/include/asm-x86_64/perfctr.h	2004-06-11 19:22:06.000000000 +0100
@@ -0,0 +1 @@
+#include <asm-i386/perfctr.h>
--- diff/include/linux/dmi.h	1970-01-01 01:00:00.000000000 +0100
+++ source/include/linux/dmi.h	2004-06-11 19:22:06.000000000 +0100
@@ -0,0 +1,47 @@
+#ifndef __DMI_H__
+#define __DMI_H__
+
+enum dmi_field {
+	DMI_NONE,
+	DMI_BIOS_VENDOR,
+	DMI_BIOS_VERSION,
+	DMI_BIOS_DATE,
+	DMI_SYS_VENDOR,
+	DMI_PRODUCT_NAME,
+	DMI_PRODUCT_VERSION,
+	DMI_BOARD_VENDOR,
+	DMI_BOARD_NAME,
+	DMI_BOARD_VERSION,
+	DMI_STRING_MAX,
+};
+
+/*
+ *	DMI callbacks for problem boards
+ */
+struct dmi_strmatch {
+	u8 slot;
+	char *substr;
+};
+
+struct dmi_system_id {
+	int (*callback)(struct dmi_system_id *);
+	char *ident;
+	struct dmi_strmatch matches[4];
+	void *driver_data;
+};
+
+#define DMI_MATCH(a,b)	{ a, b }
+
+#if defined(CONFIG_X86) && !defined(CONFIG_X86_64)
+
+extern int dmi_check_system(struct dmi_system_id *list);
+extern char * dmi_get_system_info(int field);
+
+#else
+
+static inline int dmi_check_system(struct dmi_system_id *list) { return 0; }
+static inline char * dmi_get_system_info(int field) { return NULL; }
+
+#endif
+
+#endif	/* __DMI_H__ */
--- diff/include/linux/dwarf2-lang.h	1970-01-01 01:00:00.000000000 +0100
+++ source/include/linux/dwarf2-lang.h	2004-06-11 19:22:06.000000000 +0100
@@ -0,0 +1,132 @@
+#ifndef DWARF2_LANG
+#define DWARF2_LANG
+#include <linux/dwarf2.h>
+
+/*
+ * This 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, or (at your option) any later
+ * version.
+ */
+/*
+ * This file defines macros that allow generation of DWARF debug records
+ * for asm files.  This file is platform independent.  Register numbers
+ * (which are about the only thing that is platform dependent) are to be
+ * supplied by a platform defined file.
+ */
+#define DWARF_preamble()	.section	.debug_frame,"",@progbits
+/*
+ * This macro starts a debug frame section.  The debug_frame describes
+ * where to find the registers that the enclosing function saved on
+ * entry.
+ *
+ * ORD is use by the label generator and should be the same as what is
+ * passed to CFI_postamble.
+ *
+ * pc,	pc register gdb ordinal.
+ *
+ * code_align this is the factor used to define locations or regions
+ * where the given definitions apply.  If you use labels to define these
+ * this should be 1.
+ *
+ * data_align this is the factor used to define register offsets.  If
+ * you use struct offset, this should be the size of the register in
+ * bytes or the negative of that.  This is how it is used: you will
+ * define a register as the reference register, say the stack pointer,
+ * then you will say where a register is located relative to this
+ * reference registers value, say 40 for register 3 (the gdb register
+ * number).  The <40> will be multiplied by <data_align> to define the
+ * byte offset of the given register (3, in this example).  So if your
+ * <40> is the byte offset and the reference register points at the
+ * begining, you would want 1 for the data_offset.  If <40> was the 40th
+ * 4-byte element in that structure you would want 4.  And if your
+ * reference register points at the end of the structure you would want
+ * a negative data_align value(and you would have to do other math as
+ * well).
+ */
+
+#define CFI_preamble(ORD, pc, code_align, data_align)	\
+.section	.debug_frame,"",@progbits ;		\
+frame/**/_/**/ORD:						\
+	.long end/**/_/**/ORD-start/**/_/**/ORD;			\
+start/**/_/**/ORD:						\
+	.long	DW_CIE_ID;				\
+	.byte	DW_CIE_VERSION;			\
+	.byte 0	 ;				\
+	.uleb128 code_align;				\
+	.sleb128 data_align;				\
+	.byte pc;
+
+/*
+ * After the above macro and prior to the CFI_postamble, you need to
+ * define the initial state.  This starts with defining the reference
+ * register and, usually the pc.  Here are some helper macros:
+ */
+
+#define CFA_define_reference(reg, offset)	\
+	.byte DW_CFA_def_cfa;			\
+	.uleb128 reg;				\
+	.uleb128 (offset);
+
+#define CFA_define_offset(reg, offset)		\
+	.byte (DW_CFA_offset + reg);		\
+	.uleb128 (offset);
+
+#define CFI_postamble(ORD)			\
+	.align 4;				\
+end/**/_/**/ORD:
+/*
+ * So now your code pushs stuff on the stack, you need a new location
+ * and the rules for what to do.  This starts a running description of
+ * the call frame.  You need to describe what changes with respect to
+ * the call registers as the location of the pc moves through the code.
+ * The following builds an FDE (fram descriptor entry?).  Like the
+ * above, it has a preamble and a postamble.  It also is tied to the CFI
+ * above.
+ * The first entry after the preamble must be the location in the code
+ * that the call frame is being described for.
+ */
+#define FDE_preamble(ORD, fde_no, initial_address, length)	\
+	.long FDE_end/**/_/**/fde_no-FDE_start/**/_/**/fde_no;		\
+FDE_start/**/_/**/fde_no:						\
+	.long frame/**/_/**/ORD;					\
+	.long initial_address;					\
+	.long length;
+
+#define FDE_postamble(fde_no)			\
+	.align 4;				\
+FDE_end/**/_/**/fde_no:
+/*
+ * That done, you can now add registers, subtract registers, move the
+ * reference and even change the reference.  You can also define a new
+ * area of code the info applies to.  For discontinuous bits you should
+ * start a new FDE.  You may have as many as you like.
+ */
+
+/*
+ * To advance the address by <bytes>
+ */
+
+#define FDE_advance(bytes)			\
+	.byte DW_CFA_advance_loc4		\
+	.long bytes
+
+
+
+/*
+ * With the above you can define all the register locations.  But
+ * suppose the reference register moves... Takes the new offset NOT an
+ * increment.  This is how esp is tracked if it is not saved.
+ */
+
+#define CFA_define_cfa_offset(offset) \
+	.byte $DW_CFA_def_cfa_offset; \
+	.uleb128 (offset);
+/*
+ * Or suppose you want to use a different reference register...
+ */
+#define CFA_define_cfa_register(reg)		\
+	.byte DW_CFA_def_cfa_register;		\
+	.uleb128 reg;
+
+#endif
--- diff/include/linux/dwarf2.h	1970-01-01 01:00:00.000000000 +0100
+++ source/include/linux/dwarf2.h	2004-06-11 19:22:06.000000000 +0100
@@ -0,0 +1,738 @@
+/* Declarations and definitions of codes relating to the DWARF2 symbolic
+   debugging information format.
+   Copyright (C) 1992, 1993, 1995, 1996, 1997, 1999, 2000, 2001, 2002
+   Free Software Foundation, Inc.
+
+   Written by Gary Funck (gary@intrepid.com) The Ada Joint Program
+   Office (AJPO), Florida State Unviversity and Silicon Graphics Inc.
+   provided support for this effort -- June 21, 1995.
+
+   Derived from the DWARF 1 implementation written by Ron Guilmette
+   (rfg@netcom.com), November 1990.
+
+   This file is part of GCC.
+
+   GCC 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, or (at your option) any later
+   version.
+
+   GCC 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 GCC; see the file COPYING.  If not, write to the Free
+   Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+   02111-1307, USA.  */
+
+/* This file is derived from the DWARF specification (a public document)
+   Revision 2.0.0 (July 27, 1993) developed by the UNIX International
+   Programming Languages Special Interest Group (UI/PLSIG) and distributed
+   by UNIX International.  Copies of this specification are available from
+   UNIX International, 20 Waterview Boulevard, Parsippany, NJ, 07054.
+
+   This file also now contains definitions from the DWARF 3 specification.  */
+
+/* This file is shared between GCC and GDB, and should not contain
+   prototypes.	*/
+
+#ifndef _ELF_DWARF2_H
+#define _ELF_DWARF2_H
+
+/* Structure found in the .debug_line section.	*/
+#ifndef __ASSEMBLY__
+typedef struct
+{
+  unsigned char li_length	   [4];
+  unsigned char li_version	   [2];
+  unsigned char li_prologue_length [4];
+  unsigned char li_min_insn_length [1];
+  unsigned char li_default_is_stmt [1];
+  unsigned char li_line_base	   [1];
+  unsigned char li_line_range	   [1];
+  unsigned char li_opcode_base	   [1];
+}
+DWARF2_External_LineInfo;
+
+typedef struct
+{
+  unsigned long  li_length;
+  unsigned short li_version;
+  unsigned int	 li_prologue_length;
+  unsigned char  li_min_insn_length;
+  unsigned char  li_default_is_stmt;
+  int		 li_line_base;
+  unsigned char  li_line_range;
+  unsigned char  li_opcode_base;
+}
+DWARF2_Internal_LineInfo;
+
+/* Structure found in .debug_pubnames section.	*/
+typedef struct
+{
+  unsigned char pn_length  [4];
+  unsigned char pn_version [2];
+  unsigned char pn_offset  [4];
+  unsigned char pn_size    [4];
+}
+DWARF2_External_PubNames;
+
+typedef struct
+{
+  unsigned long  pn_length;
+  unsigned short pn_version;
+  unsigned long  pn_offset;
+  unsigned long  pn_size;
+}
+DWARF2_Internal_PubNames;
+
+/* Structure found in .debug_info section.  */
+typedef struct
+{
+  unsigned char  cu_length	  [4];
+  unsigned char  cu_version	  [2];
+  unsigned char  cu_abbrev_offset [4];
+  unsigned char  cu_pointer_size  [1];
+}
+DWARF2_External_CompUnit;
+
+typedef struct
+{
+  unsigned long  cu_length;
+  unsigned short cu_version;
+  unsigned long  cu_abbrev_offset;
+  unsigned char  cu_pointer_size;
+}
+DWARF2_Internal_CompUnit;
+
+typedef struct
+{
+  unsigned char  ar_length	 [4];
+  unsigned char  ar_version	 [2];
+  unsigned char  ar_info_offset  [4];
+  unsigned char  ar_pointer_size [1];
+  unsigned char  ar_segment_size [1];
+}
+DWARF2_External_ARange;
+
+typedef struct
+{
+  unsigned long  ar_length;
+  unsigned short ar_version;
+  unsigned long  ar_info_offset;
+  unsigned char  ar_pointer_size;
+  unsigned char  ar_segment_size;
+}
+DWARF2_Internal_ARange;
+
+#define ENUM(name) enum name {
+#define IF_NOT_ASM(a) a
+#define COMMA ,
+#else
+#define ENUM(name)
+#define IF_NOT_ASM(a)
+#define COMMA
+
+#endif
+
+/* Tag names and codes.  */
+ENUM(dwarf_tag)
+
+    DW_TAG_padding = 0x00 COMMA
+    DW_TAG_array_type = 0x01 COMMA
+    DW_TAG_class_type = 0x02 COMMA
+    DW_TAG_entry_point = 0x03 COMMA
+    DW_TAG_enumeration_type = 0x04 COMMA
+    DW_TAG_formal_parameter = 0x05 COMMA
+    DW_TAG_imported_declaration = 0x08 COMMA
+    DW_TAG_label = 0x0a COMMA
+    DW_TAG_lexical_block = 0x0b COMMA
+    DW_TAG_member = 0x0d COMMA
+    DW_TAG_pointer_type = 0x0f COMMA
+    DW_TAG_reference_type = 0x10 COMMA
+    DW_TAG_compile_unit = 0x11 COMMA
+    DW_TAG_string_type = 0x12 COMMA
+    DW_TAG_structure_type = 0x13 COMMA
+    DW_TAG_subroutine_type = 0x15 COMMA
+    DW_TAG_typedef = 0x16 COMMA
+    DW_TAG_union_type = 0x17 COMMA
+    DW_TAG_unspecified_parameters = 0x18 COMMA
+    DW_TAG_variant = 0x19 COMMA
+    DW_TAG_common_block = 0x1a COMMA
+    DW_TAG_common_inclusion = 0x1b COMMA
+    DW_TAG_inheritance = 0x1c COMMA
+    DW_TAG_inlined_subroutine = 0x1d COMMA
+    DW_TAG_module = 0x1e COMMA
+    DW_TAG_ptr_to_member_type = 0x1f COMMA
+    DW_TAG_set_type = 0x20 COMMA
+    DW_TAG_subrange_type = 0x21 COMMA
+    DW_TAG_with_stmt = 0x22 COMMA
+    DW_TAG_access_declaration = 0x23 COMMA
+    DW_TAG_base_type = 0x24 COMMA
+    DW_TAG_catch_block = 0x25 COMMA
+    DW_TAG_const_type = 0x26 COMMA
+    DW_TAG_constant = 0x27 COMMA
+    DW_TAG_enumerator = 0x28 COMMA
+    DW_TAG_file_type = 0x29 COMMA
+    DW_TAG_friend = 0x2a COMMA
+    DW_TAG_namelist = 0x2b COMMA
+    DW_TAG_namelist_item = 0x2c COMMA
+    DW_TAG_packed_type = 0x2d COMMA
+    DW_TAG_subprogram = 0x2e COMMA
+    DW_TAG_template_type_param = 0x2f COMMA
+    DW_TAG_template_value_param = 0x30 COMMA
+    DW_TAG_thrown_type = 0x31 COMMA
+    DW_TAG_try_block = 0x32 COMMA
+    DW_TAG_variant_part = 0x33 COMMA
+    DW_TAG_variable = 0x34 COMMA
+    DW_TAG_volatile_type = 0x35 COMMA
+    /* DWARF 3.  */
+    DW_TAG_dwarf_procedure = 0x36 COMMA
+    DW_TAG_restrict_type = 0x37 COMMA
+    DW_TAG_interface_type = 0x38 COMMA
+    DW_TAG_namespace = 0x39 COMMA
+    DW_TAG_imported_module = 0x3a COMMA
+    DW_TAG_unspecified_type = 0x3b COMMA
+    DW_TAG_partial_unit = 0x3c COMMA
+    DW_TAG_imported_unit = 0x3d COMMA
+    /* SGI/MIPS Extensions.  */
+    DW_TAG_MIPS_loop = 0x4081 COMMA
+    /* GNU extensions.	*/
+    DW_TAG_format_label = 0x4101 COMMA	/* For FORTRAN 77 and Fortran 90.  */
+    DW_TAG_function_template = 0x4102 COMMA	/* For C++.  */
+    DW_TAG_class_template = 0x4103 COMMA	/* For C++.  */
+    DW_TAG_GNU_BINCL = 0x4104 COMMA
+    DW_TAG_GNU_EINCL = 0x4105 COMMA
+    /* Extensions for UPC.  See: http://upc.gwu.edu/~upc.  */
+    DW_TAG_upc_shared_type = 0x8765 COMMA
+    DW_TAG_upc_strict_type = 0x8766 COMMA
+    DW_TAG_upc_relaxed_type = 0x8767
+IF_NOT_ASM(};)
+
+#define DW_TAG_lo_user	0x4080
+#define DW_TAG_hi_user	0xffff
+
+/* Flag that tells whether entry has a child or not.  */
+#define DW_children_no	 0
+#define	DW_children_yes  1
+
+/* Form names and codes.  */
+ENUM(dwarf_form)
+
+    DW_FORM_addr = 0x01 COMMA
+    DW_FORM_block2 = 0x03 COMMA
+    DW_FORM_block4 = 0x04 COMMA
+    DW_FORM_data2 = 0x05 COMMA
+    DW_FORM_data4 = 0x06 COMMA
+    DW_FORM_data8 = 0x07 COMMA
+    DW_FORM_string = 0x08 COMMA
+    DW_FORM_block = 0x09 COMMA
+    DW_FORM_block1 = 0x0a COMMA
+    DW_FORM_data1 = 0x0b COMMA
+    DW_FORM_flag = 0x0c COMMA
+    DW_FORM_sdata = 0x0d COMMA
+    DW_FORM_strp = 0x0e COMMA
+    DW_FORM_udata = 0x0f COMMA
+    DW_FORM_ref_addr = 0x10 COMMA
+    DW_FORM_ref1 = 0x11 COMMA
+    DW_FORM_ref2 = 0x12 COMMA
+    DW_FORM_ref4 = 0x13 COMMA
+    DW_FORM_ref8 = 0x14 COMMA
+    DW_FORM_ref_udata = 0x15 COMMA
+    DW_FORM_indirect = 0x16
+IF_NOT_ASM(};)
+
+/* Attribute names and codes.  */
+
+ENUM(dwarf_attribute)
+
+    DW_AT_sibling = 0x01 COMMA
+    DW_AT_location = 0x02 COMMA
+    DW_AT_name = 0x03 COMMA
+    DW_AT_ordering = 0x09 COMMA
+    DW_AT_subscr_data = 0x0a COMMA
+    DW_AT_byte_size = 0x0b COMMA
+    DW_AT_bit_offset = 0x0c COMMA
+    DW_AT_bit_size = 0x0d COMMA
+    DW_AT_element_list = 0x0f COMMA
+    DW_AT_stmt_list = 0x10 COMMA
+    DW_AT_low_pc = 0x11 COMMA
+    DW_AT_high_pc = 0x12 COMMA
+    DW_AT_language = 0x13 COMMA
+    DW_AT_member = 0x14 COMMA
+    DW_AT_discr = 0x15 COMMA
+    DW_AT_discr_value = 0x16 COMMA
+    DW_AT_visibility = 0x17 COMMA
+    DW_AT_import = 0x18 COMMA
+    DW_AT_string_length = 0x19 COMMA
+    DW_AT_common_reference = 0x1a COMMA
+    DW_AT_comp_dir = 0x1b COMMA
+    DW_AT_const_value = 0x1c COMMA
+    DW_AT_containing_type = 0x1d COMMA
+    DW_AT_default_value = 0x1e COMMA
+    DW_AT_inline = 0x20 COMMA
+    DW_AT_is_optional = 0x21 COMMA
+    DW_AT_lower_bound = 0x22 COMMA
+    DW_AT_producer = 0x25 COMMA
+    DW_AT_prototyped = 0x27 COMMA
+    DW_AT_return_addr = 0x2a COMMA
+    DW_AT_start_scope = 0x2c COMMA
+    DW_AT_stride_size = 0x2e COMMA
+    DW_AT_upper_bound = 0x2f COMMA
+    DW_AT_abstract_origin = 0x31 COMMA
+    DW_AT_accessibility = 0x32 COMMA
+    DW_AT_address_class = 0x33 COMMA
+    DW_AT_artificial = 0x34 COMMA
+    DW_AT_base_types = 0x35 COMMA
+    DW_AT_calling_convention = 0x36 COMMA
+    DW_AT_count = 0x37 COMMA
+    DW_AT_data_member_location = 0x38 COMMA
+    DW_AT_decl_column = 0x39 COMMA
+    DW_AT_decl_file = 0x3a COMMA
+    DW_AT_decl_line = 0x3b COMMA
+    DW_AT_declaration = 0x3c COMMA
+    DW_AT_discr_list = 0x3d COMMA
+    DW_AT_encoding = 0x3e COMMA
+    DW_AT_external = 0x3f COMMA
+    DW_AT_frame_base = 0x40 COMMA
+    DW_AT_friend = 0x41 COMMA
+    DW_AT_identifier_case = 0x42 COMMA
+    DW_AT_macro_info = 0x43 COMMA
+    DW_AT_namelist_items = 0x44 COMMA
+    DW_AT_priority = 0x45 COMMA
+    DW_AT_segment = 0x46 COMMA
+    DW_AT_specification = 0x47 COMMA
+    DW_AT_static_link = 0x48 COMMA
+    DW_AT_type = 0x49 COMMA
+    DW_AT_use_location = 0x4a COMMA
+    DW_AT_variable_parameter = 0x4b COMMA
+    DW_AT_virtuality = 0x4c COMMA
+    DW_AT_vtable_elem_location = 0x4d COMMA
+    /* DWARF 3 values.	*/
+    DW_AT_allocated	= 0x4e COMMA
+    DW_AT_associated	= 0x4f COMMA
+    DW_AT_data_location = 0x50 COMMA
+    DW_AT_stride	= 0x51 COMMA
+    DW_AT_entry_pc	= 0x52 COMMA
+    DW_AT_use_UTF8	= 0x53 COMMA
+    DW_AT_extension	= 0x54 COMMA
+    DW_AT_ranges	= 0x55 COMMA
+    DW_AT_trampoline	= 0x56 COMMA
+    DW_AT_call_column	= 0x57 COMMA
+    DW_AT_call_file	= 0x58 COMMA
+    DW_AT_call_line	= 0x59 COMMA
+    /* SGI/MIPS extensions.  */
+    DW_AT_MIPS_fde = 0x2001 COMMA
+    DW_AT_MIPS_loop_begin = 0x2002 COMMA
+    DW_AT_MIPS_tail_loop_begin = 0x2003 COMMA
+    DW_AT_MIPS_epilog_begin = 0x2004 COMMA
+    DW_AT_MIPS_loop_unroll_factor = 0x2005 COMMA
+    DW_AT_MIPS_software_pipeline_depth = 0x2006 COMMA
+    DW_AT_MIPS_linkage_name = 0x2007 COMMA
+    DW_AT_MIPS_stride = 0x2008 COMMA
+    DW_AT_MIPS_abstract_name = 0x2009 COMMA
+    DW_AT_MIPS_clone_origin = 0x200a COMMA
+    DW_AT_MIPS_has_inlines = 0x200b COMMA
+    /* GNU extensions.	*/
+    DW_AT_sf_names   = 0x2101 COMMA
+    DW_AT_src_info   = 0x2102 COMMA
+    DW_AT_mac_info   = 0x2103 COMMA
+    DW_AT_src_coords = 0x2104 COMMA
+    DW_AT_body_begin = 0x2105 COMMA
+    DW_AT_body_end   = 0x2106 COMMA
+    DW_AT_GNU_vector = 0x2107 COMMA
+    /* VMS extensions.	*/
+    DW_AT_VMS_rtnbeg_pd_address = 0x2201 COMMA
+    /* UPC extension.  */
+    DW_AT_upc_threads_scaled = 0x3210
+IF_NOT_ASM(};)
+
+#define DW_AT_lo_user	0x2000	/* Implementation-defined range start.	*/
+#define DW_AT_hi_user	0x3ff0	/* Implementation-defined range end.  */
+
+/* Location atom names and codes.  */
+ENUM(dwarf_location_atom)
+
+    DW_OP_addr = 0x03 COMMA
+    DW_OP_deref = 0x06 COMMA
+    DW_OP_const1u = 0x08 COMMA
+    DW_OP_const1s = 0x09 COMMA
+    DW_OP_const2u = 0x0a COMMA
+    DW_OP_const2s = 0x0b COMMA
+    DW_OP_const4u = 0x0c COMMA
+    DW_OP_const4s = 0x0d COMMA
+    DW_OP_const8u = 0x0e COMMA
+    DW_OP_const8s = 0x0f COMMA
+    DW_OP_constu = 0x10 COMMA
+    DW_OP_consts = 0x11 COMMA
+    DW_OP_dup = 0x12 COMMA
+    DW_OP_drop = 0x13 COMMA
+    DW_OP_over = 0x14 COMMA
+    DW_OP_pick = 0x15 COMMA
+    DW_OP_swap = 0x16 COMMA
+    DW_OP_rot = 0x17 COMMA
+    DW_OP_xderef = 0x18 COMMA
+    DW_OP_abs = 0x19 COMMA
+    DW_OP_and = 0x1a COMMA
+    DW_OP_div = 0x1b COMMA
+    DW_OP_minus = 0x1c COMMA
+    DW_OP_mod = 0x1d COMMA
+    DW_OP_mul = 0x1e COMMA
+    DW_OP_neg = 0x1f COMMA
+    DW_OP_not = 0x20 COMMA
+    DW_OP_or = 0x21 COMMA
+    DW_OP_plus = 0x22 COMMA
+    DW_OP_plus_uconst = 0x23 COMMA
+    DW_OP_shl = 0x24 COMMA
+    DW_OP_shr = 0x25 COMMA
+    DW_OP_shra = 0x26 COMMA
+    DW_OP_xor = 0x27 COMMA
+    DW_OP_bra = 0x28 COMMA
+    DW_OP_eq = 0x29 COMMA
+    DW_OP_ge = 0x2a COMMA
+    DW_OP_gt = 0x2b COMMA
+    DW_OP_le = 0x2c COMMA
+    DW_OP_lt = 0x2d COMMA
+    DW_OP_ne = 0x2e COMMA
+    DW_OP_skip = 0x2f COMMA
+    DW_OP_lit0 = 0x30 COMMA
+    DW_OP_lit1 = 0x31 COMMA
+    DW_OP_lit2 = 0x32 COMMA
+    DW_OP_lit3 = 0x33 COMMA
+    DW_OP_lit4 = 0x34 COMMA
+    DW_OP_lit5 = 0x35 COMMA
+    DW_OP_lit6 = 0x36 COMMA
+    DW_OP_lit7 = 0x37 COMMA
+    DW_OP_lit8 = 0x38 COMMA
+    DW_OP_lit9 = 0x39 COMMA
+    DW_OP_lit10 = 0x3a COMMA
+    DW_OP_lit11 = 0x3b COMMA
+    DW_OP_lit12 = 0x3c COMMA
+    DW_OP_lit13 = 0x3d COMMA
+    DW_OP_lit14 = 0x3e COMMA
+    DW_OP_lit15 = 0x3f COMMA
+    DW_OP_lit16 = 0x40 COMMA
+    DW_OP_lit17 = 0x41 COMMA
+    DW_OP_lit18 = 0x42 COMMA
+    DW_OP_lit19 = 0x43 COMMA
+    DW_OP_lit20 = 0x44 COMMA
+    DW_OP_lit21 = 0x45 COMMA
+    DW_OP_lit22 = 0x46 COMMA
+    DW_OP_lit23 = 0x47 COMMA
+    DW_OP_lit24 = 0x48 COMMA
+    DW_OP_lit25 = 0x49 COMMA
+    DW_OP_lit26 = 0x4a COMMA
+    DW_OP_lit27 = 0x4b COMMA
+    DW_OP_lit28 = 0x4c COMMA
+    DW_OP_lit29 = 0x4d COMMA
+    DW_OP_lit30 = 0x4e COMMA
+    DW_OP_lit31 = 0x4f COMMA
+    DW_OP_reg0 = 0x50 COMMA
+    DW_OP_reg1 = 0x51 COMMA
+    DW_OP_reg2 = 0x52 COMMA
+    DW_OP_reg3 = 0x53 COMMA
+    DW_OP_reg4 = 0x54 COMMA
+    DW_OP_reg5 = 0x55 COMMA
+    DW_OP_reg6 = 0x56 COMMA
+    DW_OP_reg7 = 0x57 COMMA
+    DW_OP_reg8 = 0x58 COMMA
+    DW_OP_reg9 = 0x59 COMMA
+    DW_OP_reg10 = 0x5a COMMA
+    DW_OP_reg11 = 0x5b COMMA
+    DW_OP_reg12 = 0x5c COMMA
+    DW_OP_reg13 = 0x5d COMMA
+    DW_OP_reg14 = 0x5e COMMA
+    DW_OP_reg15 = 0x5f COMMA
+    DW_OP_reg16 = 0x60 COMMA
+    DW_OP_reg17 = 0x61 COMMA
+    DW_OP_reg18 = 0x62 COMMA
+    DW_OP_reg19 = 0x63 COMMA
+    DW_OP_reg20 = 0x64 COMMA
+    DW_OP_reg21 = 0x65 COMMA
+    DW_OP_reg22 = 0x66 COMMA
+    DW_OP_reg23 = 0x67 COMMA
+    DW_OP_reg24 = 0x68 COMMA
+    DW_OP_reg25 = 0x69 COMMA
+    DW_OP_reg26 = 0x6a COMMA
+    DW_OP_reg27 = 0x6b COMMA
+    DW_OP_reg28 = 0x6c COMMA
+    DW_OP_reg29 = 0x6d COMMA
+    DW_OP_reg30 = 0x6e COMMA
+    DW_OP_reg31 = 0x6f COMMA
+    DW_OP_breg0 = 0x70 COMMA
+    DW_OP_breg1 = 0x71 COMMA
+    DW_OP_breg2 = 0x72 COMMA
+    DW_OP_breg3 = 0x73 COMMA
+    DW_OP_breg4 = 0x74 COMMA
+    DW_OP_breg5 = 0x75 COMMA
+    DW_OP_breg6 = 0x76 COMMA
+    DW_OP_breg7 = 0x77 COMMA
+    DW_OP_breg8 = 0x78 COMMA
+    DW_OP_breg9 = 0x79 COMMA
+    DW_OP_breg10 = 0x7a COMMA
+    DW_OP_breg11 = 0x7b COMMA
+    DW_OP_breg12 = 0x7c COMMA
+    DW_OP_breg13 = 0x7d COMMA
+    DW_OP_breg14 = 0x7e COMMA
+    DW_OP_breg15 = 0x7f COMMA
+    DW_OP_breg16 = 0x80 COMMA
+    DW_OP_breg17 = 0x81 COMMA
+    DW_OP_breg18 = 0x82 COMMA
+    DW_OP_breg19 = 0x83 COMMA
+    DW_OP_breg20 = 0x84 COMMA
+    DW_OP_breg21 = 0x85 COMMA
+    DW_OP_breg22 = 0x86 COMMA
+    DW_OP_breg23 = 0x87 COMMA
+    DW_OP_breg24 = 0x88 COMMA
+    DW_OP_breg25 = 0x89 COMMA
+    DW_OP_breg26 = 0x8a COMMA
+    DW_OP_breg27 = 0x8b COMMA
+    DW_OP_breg28 = 0x8c COMMA
+    DW_OP_breg29 = 0x8d COMMA
+    DW_OP_breg30 = 0x8e COMMA
+    DW_OP_breg31 = 0x8f COMMA
+    DW_OP_regx = 0x90 COMMA
+    DW_OP_fbreg = 0x91 COMMA
+    DW_OP_bregx = 0x92 COMMA
+    DW_OP_piece = 0x93 COMMA
+    DW_OP_deref_size = 0x94 COMMA
+    DW_OP_xderef_size = 0x95 COMMA
+    DW_OP_nop = 0x96 COMMA
+    /* DWARF 3 extensions.  */
+    DW_OP_push_object_address = 0x97 COMMA
+    DW_OP_call2 = 0x98 COMMA
+    DW_OP_call4 = 0x99 COMMA
+    DW_OP_call_ref = 0x9a COMMA
+    /* GNU extensions.	*/
+    DW_OP_GNU_push_tls_address = 0xe0
+IF_NOT_ASM(};)
+
+#define DW_OP_lo_user	0xe0	/* Implementation-defined range start.	*/
+#define DW_OP_hi_user	0xff	/* Implementation-defined range end.  */
+
+/* Type encodings.  */
+ENUM(dwarf_type)
+
+    DW_ATE_void = 0x0 COMMA
+    DW_ATE_address = 0x1 COMMA
+    DW_ATE_boolean = 0x2 COMMA
+    DW_ATE_complex_float = 0x3 COMMA
+    DW_ATE_float = 0x4 COMMA
+    DW_ATE_signed = 0x5 COMMA
+    DW_ATE_signed_char = 0x6 COMMA
+    DW_ATE_unsigned = 0x7 COMMA
+    DW_ATE_unsigned_char = 0x8 COMMA
+    /* DWARF 3.  */
+    DW_ATE_imaginary_float = 0x9
+IF_NOT_ASM(};)
+
+#define	DW_ATE_lo_user 0x80
+#define	DW_ATE_hi_user 0xff
+
+/* Array ordering names and codes.  */
+ENUM(dwarf_array_dim_ordering)
+
+    DW_ORD_row_major = 0 COMMA
+    DW_ORD_col_major = 1
+IF_NOT_ASM(};)
+
+/* Access attribute.  */
+ENUM(dwarf_access_attribute)
+
+    DW_ACCESS_public = 1 COMMA
+    DW_ACCESS_protected = 2 COMMA
+    DW_ACCESS_private = 3
+IF_NOT_ASM(};)
+
+/* Visibility.	*/
+ENUM(dwarf_visibility_attribute)
+
+    DW_VIS_local = 1 COMMA
+    DW_VIS_exported = 2 COMMA
+    DW_VIS_qualified = 3
+IF_NOT_ASM(};)
+
+/* Virtuality.	*/
+ENUM(dwarf_virtuality_attribute)
+
+    DW_VIRTUALITY_none = 0 COMMA
+    DW_VIRTUALITY_virtual = 1 COMMA
+    DW_VIRTUALITY_pure_virtual = 2
+IF_NOT_ASM(};)
+
+/* Case sensitivity.  */
+ENUM(dwarf_id_case)
+
+    DW_ID_case_sensitive = 0 COMMA
+    DW_ID_up_case = 1 COMMA
+    DW_ID_down_case = 2 COMMA
+    DW_ID_case_insensitive = 3
+IF_NOT_ASM(};)
+
+/* Calling convention.	*/
+ENUM(dwarf_calling_convention)
+
+    DW_CC_normal = 0x1 COMMA
+    DW_CC_program = 0x2 COMMA
+    DW_CC_nocall = 0x3
+IF_NOT_ASM(};)
+
+#define DW_CC_lo_user 0x40
+#define DW_CC_hi_user 0xff
+
+/* Inline attribute.  */
+ENUM(dwarf_inline_attribute)
+
+    DW_INL_not_inlined = 0 COMMA
+    DW_INL_inlined = 1 COMMA
+    DW_INL_declared_not_inlined = 2 COMMA
+    DW_INL_declared_inlined = 3
+IF_NOT_ASM(};)
+
+/* Discriminant lists.	*/
+ENUM(dwarf_discrim_list)
+
+    DW_DSC_label = 0 COMMA
+    DW_DSC_range = 1
+IF_NOT_ASM(};)
+
+/* Line number opcodes.  */
+ENUM(dwarf_line_number_ops)
+
+    DW_LNS_extended_op = 0 COMMA
+    DW_LNS_copy = 1 COMMA
+    DW_LNS_advance_pc = 2 COMMA
+    DW_LNS_advance_line = 3 COMMA
+    DW_LNS_set_file = 4 COMMA
+    DW_LNS_set_column = 5 COMMA
+    DW_LNS_negate_stmt = 6 COMMA
+    DW_LNS_set_basic_block = 7 COMMA
+    DW_LNS_const_add_pc = 8 COMMA
+    DW_LNS_fixed_advance_pc = 9 COMMA
+    /* DWARF 3.  */
+    DW_LNS_set_prologue_end = 10 COMMA
+    DW_LNS_set_epilogue_begin = 11 COMMA
+    DW_LNS_set_isa = 12
+IF_NOT_ASM(};)
+
+/* Line number extended opcodes.  */
+ENUM(dwarf_line_number_x_ops)
+
+    DW_LNE_end_sequence = 1 COMMA
+    DW_LNE_set_address = 2 COMMA
+    DW_LNE_define_file = 3
+IF_NOT_ASM(};)
+
+/* Call frame information.  */
+ENUM(dwarf_call_frame_info)
+
+    DW_CFA_advance_loc = 0x40 COMMA
+    DW_CFA_offset = 0x80 COMMA
+    DW_CFA_restore = 0xc0 COMMA
+    DW_CFA_nop = 0x00 COMMA
+    DW_CFA_set_loc = 0x01 COMMA
+    DW_CFA_advance_loc1 = 0x02 COMMA
+    DW_CFA_advance_loc2 = 0x03 COMMA
+    DW_CFA_advance_loc4 = 0x04 COMMA
+    DW_CFA_offset_extended = 0x05 COMMA
+    DW_CFA_restore_extended = 0x06 COMMA
+    DW_CFA_undefined = 0x07 COMMA
+    DW_CFA_same_value = 0x08 COMMA
+    DW_CFA_register = 0x09 COMMA
+    DW_CFA_remember_state = 0x0a COMMA
+    DW_CFA_restore_state = 0x0b COMMA
+    DW_CFA_def_cfa = 0x0c COMMA
+    DW_CFA_def_cfa_register = 0x0d COMMA
+    DW_CFA_def_cfa_offset = 0x0e COMMA
+
+    /* DWARF 3.  */
+    DW_CFA_def_cfa_expression = 0x0f COMMA
+    DW_CFA_expression = 0x10 COMMA
+    DW_CFA_offset_extended_sf = 0x11 COMMA
+    DW_CFA_def_cfa_sf = 0x12 COMMA
+    DW_CFA_def_cfa_offset_sf = 0x13 COMMA
+
+    /* SGI/MIPS specific.  */
+    DW_CFA_MIPS_advance_loc8 = 0x1d COMMA
+
+    /* GNU extensions.	*/
+    DW_CFA_GNU_window_save = 0x2d COMMA
+    DW_CFA_GNU_args_size = 0x2e COMMA
+    DW_CFA_GNU_negative_offset_extended = 0x2f
+IF_NOT_ASM(};)
+
+#define DW_CIE_ID	  0xffffffff
+#define DW_CIE_VERSION	  1
+
+#define DW_CFA_extended   0
+#define DW_CFA_lo_user	  0x1c
+#define DW_CFA_hi_user	  0x3f
+
+#define DW_CHILDREN_no		     0x00
+#define DW_CHILDREN_yes		     0x01
+
+#define DW_ADDR_none		0
+
+/* Source language names and codes.  */
+ENUM(dwarf_source_language)
+
+    DW_LANG_C89 = 0x0001 COMMA
+    DW_LANG_C = 0x0002 COMMA
+    DW_LANG_Ada83 = 0x0003 COMMA
+    DW_LANG_C_plus_plus = 0x0004 COMMA
+    DW_LANG_Cobol74 = 0x0005 COMMA
+    DW_LANG_Cobol85 = 0x0006 COMMA
+    DW_LANG_Fortran77 = 0x0007 COMMA
+    DW_LANG_Fortran90 = 0x0008 COMMA
+    DW_LANG_Pascal83 = 0x0009 COMMA
+    DW_LANG_Modula2 = 0x000a COMMA
+    DW_LANG_Java = 0x000b COMMA
+    /* DWARF 3.  */
+    DW_LANG_C99 = 0x000c COMMA
+    DW_LANG_Ada95 = 0x000d COMMA
+    DW_LANG_Fortran95 = 0x000e COMMA
+    /* MIPS.  */
+    DW_LANG_Mips_Assembler = 0x8001 COMMA
+    /* UPC.  */
+    DW_LANG_Upc = 0x8765
+IF_NOT_ASM(};)
+
+#define DW_LANG_lo_user 0x8000	/* Implementation-defined range start.	*/
+#define DW_LANG_hi_user 0xffff	/* Implementation-defined range start.	*/
+
+/* Names and codes for macro information.  */
+ENUM(dwarf_macinfo_record_type)
+
+    DW_MACINFO_define = 1 COMMA
+    DW_MACINFO_undef = 2 COMMA
+    DW_MACINFO_start_file = 3 COMMA
+    DW_MACINFO_end_file = 4 COMMA
+    DW_MACINFO_vendor_ext = 255
+IF_NOT_ASM(};)
+
+/* @@@ For use with GNU frame unwind information.  */
+
+#define DW_EH_PE_absptr		0x00
+#define DW_EH_PE_omit		0xff
+
+#define DW_EH_PE_uleb128	0x01
+#define DW_EH_PE_udata2		0x02
+#define DW_EH_PE_udata4		0x03
+#define DW_EH_PE_udata8		0x04
+#define DW_EH_PE_sleb128	0x09
+#define DW_EH_PE_sdata2		0x0A
+#define DW_EH_PE_sdata4		0x0B
+#define DW_EH_PE_sdata8		0x0C
+#define DW_EH_PE_signed		0x08
+
+#define DW_EH_PE_pcrel		0x10
+#define DW_EH_PE_textrel	0x20
+#define DW_EH_PE_datarel	0x30
+#define DW_EH_PE_funcrel	0x40
+#define DW_EH_PE_aligned	0x50
+
+#define DW_EH_PE_indirect	0x80
+
+#endif /* _ELF_DWARF2_H */
--- diff/include/linux/hpet.h	1970-01-01 01:00:00.000000000 +0100
+++ source/include/linux/hpet.h	2004-06-11 19:22:06.000000000 +0100
@@ -0,0 +1,133 @@
+#ifndef	__HPET__
+#define	__HPET__ 1
+
+/*
+ * Offsets into HPET Registers
+ */
+
+struct hpet {
+	u64 hpet_cap;		/* capabilities */
+	u64 res0;		/* reserved */
+	u64 hpet_config;	/* configuration */
+	u64 res1;		/* reserved */
+	u64 hpet_isr;		/* interrupt status reg */
+	u64 res2[25];		/* reserved */
+	union {			/* main counter */
+		u64 _hpet_mc64;
+		u32 _hpet_mc32;
+		unsigned long _hpet_mc;
+	} _u0;
+	u64 res3;		/* reserved */
+	struct hpet_timer {
+		u64 hpet_config;	/* configuration/cap */
+		union {		/* timer compare register */
+			u64 _hpet_hc64;
+			u32 _hpet_hc32;
+			unsigned long _hpet_compare;
+		} _u1;
+		u64 hpet_fsb[2];	/* FSB route */
+	} hpet_timers[1];
+};
+
+#define	hpet_mc		_u0._hpet_mc
+#define	hpet_compare	_u1._hpet_compare
+
+#define	HPET_MAX_TIMERS	(32)
+
+/*
+ * HPET general capabilities register
+ */
+
+#define	HPET_COUNTER_CLK_PERIOD_MASK	(0xffffffff00000000ULL)
+#define	HPET_COUNTER_CLK_PERIOD_SHIFT	(32UL)
+#define	HPET_VENDOR_ID_MASK		(0x00000000ffff0000ULL)
+#define	HPET_VENDOR_ID_SHIFT		(16ULL)
+#define	HPET_LEG_RT_CAP_MASK		(0x8000)
+#define	HPET_COUNTER_SIZE_MASK		(0x2000)
+#define	HPET_NUM_TIM_CAP_MASK		(0x1f00)
+#define	HPET_NUM_TIM_CAP_SHIFT		(8ULL)
+
+/*
+ * HPET general configuration register
+ */
+
+#define	HPET_LEG_RT_CNF_MASK		(2UL)
+#define	HPET_ENABLE_CNF_MASK		(1UL)
+
+/*
+ * HPET interrupt status register
+ */
+
+#define	HPET_ISR_CLEAR(HPET, TIMER)				\
+		(HPET)->hpet_isr |= (1UL << TIMER)
+
+/*
+ * Timer configuration register
+ */
+
+#define	Tn_INT_ROUTE_CAP_MASK		(0xffffffff00000000ULL)
+#define	Tn_INI_ROUTE_CAP_SHIFT		(32UL)
+#define	Tn_FSB_INT_DELCAP_MASK		(0x8000UL)
+#define	Tn_FSB_INT_DELCAP_SHIFT		(15)
+#define	Tn_FSB_EN_CNF_MASK		(0x4000UL)
+#define	Tn_FSB_EN_CNF_SHIFT		(14)
+#define	Tn_INT_ROUTE_CNF_MASK		(0x3e00UL)
+#define	Tn_INT_ROUTE_CNF_SHIFT		(9)
+#define	Tn_32MODE_CNF_MASK		(0x0100UL)
+#define	Tn_VAL_SET_CNF_MASK		(0x0040UL)
+#define	Tn_SIZE_CAP_MASK		(0x0020UL)
+#define	Tn_PER_INT_CAP_MASK		(0x0010UL)
+#define	Tn_TYPE_CNF_MASK		(0x0008UL)
+#define	Tn_INT_ENB_CNF_MASK		(0x0004UL)
+#define	Tn_INT_TYPE_CNF_MASK		(0x0002UL)
+
+/*
+ * Timer FSB Interrupt Route Register
+ */
+
+#define	Tn_FSB_INT_ADDR_MASK		(0xffffffff00000000ULL)
+#define	Tn_FSB_INT_ADDR_SHIFT		(32UL)
+#define	Tn_FSB_INT_VAL_MASK		(0x00000000ffffffffULL)
+
+struct hpet_info {
+	unsigned long hi_ireqfreq;	/* Hz */
+	unsigned long hi_flags;	/* information */
+	unsigned short hi_hpet;
+	unsigned short hi_timer;
+};
+
+#define	HPET_INFO_PERIODIC	0x0001	/* timer is periodic */
+
+#define	HPET_IE_ON	_IO('h', 0x01)	/* interrupt on */
+#define	HPET_IE_OFF	_IO('h', 0x02)	/* interrupt off */
+#define	HPET_INFO	_IOR('h', 0x03, struct hpet_info)
+#define	HPET_EPI	_IO('h', 0x04)	/* enable periodic */
+#define	HPET_DPI	_IO('h', 0x05)	/* disable periodic */
+#define	HPET_IRQFREQ	_IOW('h', 0x6, unsigned long)	/* IRQFREQ usec */
+
+/*
+ * exported interfaces
+ */
+
+struct hpet_task {
+	void (*ht_func) (void *);
+	void *ht_data;
+	void *ht_opaque;
+};
+
+struct hpet_data {
+	unsigned long hd_address;
+	unsigned short hd_nirqs;
+	unsigned short hd_flags;
+	unsigned int hd_state;	/* timer allocated */
+	unsigned int hd_irq[HPET_MAX_TIMERS];
+};
+
+#define	HPET_DATA_PLATFORM	0x0001	/* platform call to hpet_alloc */
+
+int hpet_alloc(struct hpet_data *);
+int hpet_register(struct hpet_task *, int);
+int hpet_unregister(struct hpet_task *);
+int hpet_control(struct hpet_task *, unsigned int, unsigned long);
+
+#endif				/* !__HPET__ */
--- diff/include/linux/lockmeter.h	1970-01-01 01:00:00.000000000 +0100
+++ source/include/linux/lockmeter.h	2004-06-11 19:22:06.000000000 +0100
@@ -0,0 +1,320 @@
+/*
+ *  Copyright (C) 1999-2002 Silicon Graphics, Inc.
+ *
+ *  Written by John Hawkes (hawkes@sgi.com)
+ *  Based on klstat.h by Jack Steiner (steiner@sgi.com)
+ *
+ *  Modified by Ray Bryant (raybry@us.ibm.com) Feb-Apr 2000
+ *  Changes Copyright (C) 2000 IBM, Inc.
+ *  Added save of index in spinlock_t to improve efficiency
+ *  of "hold" time reporting for spinlocks
+ *  Added support for hold time statistics for read and write
+ *  locks.
+ *  Moved machine dependent code to include/asm/lockmeter.h.
+ *
+ */
+
+#ifndef _LINUX_LOCKMETER_H
+#define _LINUX_LOCKMETER_H
+
+
+/*---------------------------------------------------
+ *	architecture-independent lockmeter.h
+ *-------------------------------------------------*/
+
+/*
+ * raybry -- version 2: added efficient hold time statistics
+ *           requires lstat recompile, so flagged as new version
+ * raybry -- version 3: added global reader lock data
+ * hawkes -- version 4: removed some unnecessary fields to simplify mips64 port
+ */
+#define LSTAT_VERSION	5
+
+int	lstat_update(void*, void*, int);
+int	lstat_update_time(void*, void*, int, uint32_t);
+
+/*
+ * Currently, the mips64 and sparc64 kernels talk to a 32-bit lockstat, so we
+ * need to force compatibility in the inter-communication data structure.
+ */
+
+#if defined(CONFIG_MIPS32_COMPAT)
+#define TIME_T		uint32_t
+#elif defined(CONFIG_SPARC) || defined(CONFIG_SPARC64)
+#define TIME_T		uint64_t
+#else
+#define TIME_T		time_t
+#endif
+
+#if defined(__KERNEL__) || (!defined(CONFIG_MIPS32_COMPAT) && !defined(CONFIG_SPARC) && !defined(CONFIG_SPARC64)) || (_MIPS_SZLONG==32)
+#define POINTER		void *
+#else
+#define	POINTER		int64_t
+#endif
+
+/*
+ * Values for the "action" parameter passed to lstat_update.
+ *	ZZZ - do we want a try-success status here???
+ */
+#define LSTAT_ACT_NO_WAIT	0
+#define LSTAT_ACT_SPIN		1
+#define LSTAT_ACT_REJECT	2
+#define LSTAT_ACT_WW_SPIN       3
+#define LSTAT_ACT_SLEPT		4 /* UNUSED */
+
+#define LSTAT_ACT_MAX_VALUES	4 /* NOTE: Increase to 5 if use ACT_SLEPT */
+
+/*
+ * Special values for the low 2 bits of an RA passed to
+ * lstat_update.
+ */
+/* we use these values to figure out what kind of lock data */
+/* is stored in the statistics table entry at index ....... */
+#define LSTAT_RA_SPIN           0  /* spin lock data */
+#define LSTAT_RA_READ           1  /* read lock statistics */
+#define LSTAT_RA_SEMA		2  /* RESERVED */
+#define LSTAT_RA_WRITE          3  /* write lock statistics*/
+
+#define LSTAT_RA(n)	\
+	((void*)( ((unsigned long)__builtin_return_address(0) & ~3) | n) )
+
+/*
+ * Constants used for lock addresses in the lstat_directory
+ * to indicate special values of the lock address.
+ */
+#define	LSTAT_MULTI_LOCK_ADDRESS	NULL
+
+/*
+ * Maximum size of the lockstats tables. Increase this value
+ * if its not big enough. (Nothing bad happens if its not
+ * big enough although some locks will not be monitored.)
+ * We record overflows of this quantity in lstat_control.dir_overflows
+ *
+ * Note:  The max value here must fit into the field set
+ * and obtained by the macro's PUT_INDEX() and GET_INDEX().
+ * This value depends on how many bits are available in the
+ * lock word in the particular machine implementation we are on.
+ */
+#define LSTAT_MAX_STAT_INDEX		2000
+
+/*
+ * Size and mask for the hash table into the directory.
+ */
+#define LSTAT_HASH_TABLE_SIZE		4096		/* must be 2**N */
+#define LSTAT_HASH_TABLE_MASK		(LSTAT_HASH_TABLE_SIZE-1)
+
+#define DIRHASH(ra)      ((unsigned long)(ra)>>2 & LSTAT_HASH_TABLE_MASK)
+
+/*
+ *	This defines an entry in the lockstat directory. It contains
+ *	information about a lock being monitored.
+ *	A directory entry only contains the lock identification -
+ *	counts on usage of the lock are kept elsewhere in a per-cpu
+ *	data structure to minimize cache line pinging.
+ */
+typedef struct {
+	POINTER	caller_ra;		  /* RA of code that set lock */
+	POINTER	lock_ptr;		  /* lock address */
+	ushort	next_stat_index;  /* Used to link multiple locks that have the same hash table value */
+} lstat_directory_entry_t;
+
+/*
+ *	A multi-dimensioned array used to contain counts for lock accesses.
+ *	The array is 3-dimensional:
+ *		- CPU number. Keep from thrashing cache lines between CPUs
+ *		- Directory entry index. Identifies the lock
+ *		- Action. Indicates what kind of contention occurred on an
+ *		  access to the lock.
+ *
+ *	The index of an entry in the directory is the same as the 2nd index
+ *	of the entry in the counts array.
+ */
+/*
+ *  This table contains data for spin_locks, write locks, and read locks
+ *  Not all data is used for all cases.  In particular, the hold time
+ *  information is not stored here for read locks since that is a global
+ *  (e. g. cannot be separated out by return address) quantity.
+ *  See the lstat_read_lock_counts_t structure for the global read lock
+ *  hold time.
+ */
+typedef struct {
+	uint64_t    cum_wait_ticks;	/* sum of wait times               */
+	                                /* for write locks, sum of time a  */
+					/* writer is waiting for a reader  */
+	int64_t	    cum_hold_ticks;	/* cumulative sum of holds         */
+	                                /* not used for read mode locks    */
+					/* must be signed. ............... */
+	uint32_t    max_wait_ticks;	/* max waiting time                */
+	uint32_t    max_hold_ticks;	/* max holding time                */
+	uint64_t    cum_wait_ww_ticks;  /* sum times writer waits on writer*/
+	uint32_t    max_wait_ww_ticks;  /* max wait time writer vs writer  */
+	                                /* prev 2 only used for write locks*/
+	uint32_t    acquire_time;       /* time lock acquired this CPU     */
+	uint32_t    count[LSTAT_ACT_MAX_VALUES];
+} lstat_lock_counts_t;
+
+typedef lstat_lock_counts_t	lstat_cpu_counts_t[LSTAT_MAX_STAT_INDEX];
+
+/*
+ * User request to:
+ *	- turn statistic collection on/off, or to reset
+ */
+#define LSTAT_OFF	 0
+#define LSTAT_ON	 1
+#define LSTAT_RESET      2
+#define LSTAT_RELEASE    3
+
+#define LSTAT_MAX_READ_LOCK_INDEX 1000
+typedef struct {
+	POINTER	    lock_ptr;            /* address of lock for output stats */
+	uint32_t    read_lock_count;
+	int64_t     cum_hold_ticks;       /* sum of read lock hold times over */
+	                                  /* all callers. ....................*/
+	uint32_t    write_index;          /* last write lock hash table index */
+	uint32_t    busy_periods;         /* count of busy periods ended this */
+	uint64_t    start_busy;           /* time this busy period started. ..*/
+	uint64_t    busy_ticks;           /* sum of busy periods this lock. ..*/
+	uint64_t    max_busy;             /* longest busy period for this lock*/
+	uint32_t    max_readers;          /* maximum number of readers ...... */
+#ifdef USER_MODE_TESTING
+	rwlock_t    entry_lock;           /* lock for this read lock entry... */
+	                                  /* avoid having more than one rdr at*/
+	                                  /* needed for user space testing... */
+	                                  /* not needed for kernel 'cause it  */
+					  /* is non-preemptive. ............. */
+#endif
+} lstat_read_lock_counts_t;
+typedef lstat_read_lock_counts_t	lstat_read_lock_cpu_counts_t[LSTAT_MAX_READ_LOCK_INDEX];
+
+#if defined(__KERNEL__) || defined(USER_MODE_TESTING)
+
+#ifndef USER_MODE_TESTING
+#include <asm/lockmeter.h>
+#else
+#include "asm_newlockmeter.h"
+#endif
+
+/*
+ * Size and mask for the hash table into the directory.
+ */
+#define LSTAT_HASH_TABLE_SIZE		4096		/* must be 2**N */
+#define LSTAT_HASH_TABLE_MASK		(LSTAT_HASH_TABLE_SIZE-1)
+
+#define DIRHASH(ra)      ((unsigned long)(ra)>>2 & LSTAT_HASH_TABLE_MASK)
+
+/*
+ * This version eliminates the per processor lock stack.  What we do is to
+ * store the index of the lock hash structure in unused bits in the lock
+ * itself.  Then on unlock we can find the statistics record without doing
+ * any additional hash or lock stack lookup.  This works for spin_locks.
+ * Hold time reporting is now basically as cheap as wait time reporting
+ * so we ignore the difference between LSTAT_ON_HOLD and LSTAT_ON_WAIT
+ * as in version 1.1.* of lockmeter.
+ *
+ * For rw_locks, we store the index of a global reader stats structure in
+ * the lock and the writer index is stored in the latter structure.
+ * For read mode locks we hash at the time of the lock to find an entry
+ * in the directory for reader wait time and the like.
+ * At unlock time for read mode locks, we update just the global structure
+ * so we don't need to know the reader directory index value at unlock time.
+ *
+ */
+
+/*
+ * Protocol to change lstat_control.state
+ *   This is complicated because we don't want the cum_hold_time for
+ * a rw_lock to be decremented in _read_lock_ without making sure it
+ * is incremented in _read_lock_ and vice versa.  So here is the
+ * way we change the state of lstat_control.state:
+ * I.  To Turn Statistics On
+ *     After allocating storage, set lstat_control.state non-zero.
+ * This works because we don't start updating statistics for in use
+ * locks until the reader lock count goes to zero.
+ * II. To Turn Statistics Off:
+ * (0)  Disable interrupts on this CPU
+ * (1)  Seize the lstat_control.directory_lock
+ * (2)  Obtain the current value of lstat_control.next_free_read_lock_index
+ * (3)  Store a zero in lstat_control.state.
+ * (4)  Release the lstat_control.directory_lock
+ * (5)  For each lock in the read lock list up to the saved value
+ *      (well, -1) of the next_free_read_lock_index, do the following:
+ *      (a)  Check validity of the stored lock address
+ *           by making sure that the word at the saved addr
+ *           has an index that matches this entry.  If not
+ *           valid, then skip this entry.
+ *      (b)  If there is a write lock already set on this lock,
+ *           skip to (d) below.
+ *      (c)  Set a non-metered write lock on the lock
+ *      (d)  set the cached INDEX in the lock to zero
+ *      (e)  Release the non-metered write lock.
+ * (6)  Re-enable interrupts
+ *
+ * These rules ensure that a read lock will not have its statistics
+ * partially updated even though the global lock recording state has
+ * changed.  See put_lockmeter_info() for implementation.
+ *
+ * The reason for (b) is that there may be write locks set on the
+ * syscall path to put_lockmeter_info() from user space.  If we do
+ * not do this check, then we can deadlock.  A similar problem would
+ * occur if the lock was read locked by the current CPU.  At the
+ * moment this does not appear to happen.
+ */
+
+/*
+ * Main control structure for lockstat. Used to turn statistics on/off
+ * and to maintain directory info.
+ */
+typedef struct {
+	int				state;
+	spinlock_t		control_lock;		/* used to serialize turning statistics on/off   */
+	spinlock_t		directory_lock;		/* for serialize adding entries to directory     */
+	volatile int	next_free_dir_index;/* next free entry in the directory */
+	/* FIXME not all of these fields are used / needed .............. */
+                /* the following fields represent data since     */
+		/* first "lstat on" or most recent "lstat reset" */
+	TIME_T      first_started_time;     /* time when measurement first enabled */
+	TIME_T      started_time;           /* time when measurement last started  */
+	TIME_T      ending_time;            /* time when measurement last disabled */
+	uint64_t    started_cycles64;       /* cycles when measurement last started          */
+	uint64_t    ending_cycles64;        /* cycles when measurement last disabled         */
+	uint64_t    enabled_cycles64;       /* total cycles with measurement enabled         */
+	int         intervals;              /* number of measurement intervals recorded      */
+	                                    /* i. e. number of times did lstat on;lstat off  */
+	lstat_directory_entry_t	*dir;		/* directory */
+	int         dir_overflow;           /* count of times ran out of space in directory  */
+	int         rwlock_overflow;        /* count of times we couldn't allocate a rw block*/
+	ushort		*hashtab;		 	    /* hash table for quick dir scans */
+	lstat_cpu_counts_t	*counts[NR_CPUS];	 /* Array of pointers to per-cpu stats */
+    int         next_free_read_lock_index;   /* next rwlock reader (global) stats block  */
+    lstat_read_lock_cpu_counts_t *read_lock_counts[NR_CPUS]; /* per cpu read lock stats  */
+} lstat_control_t;
+
+#endif	/* defined(__KERNEL__) || defined(USER_MODE_TESTING) */
+
+typedef struct {
+	short		lstat_version;		/* version of the data */
+	short		state;			/* the current state is returned */
+	int		maxcpus;		/* Number of cpus present */
+	int		next_free_dir_index;	/* index of the next free directory entry */
+	TIME_T          first_started_time;	/* when measurement enabled for first time */
+	TIME_T          started_time;		/* time in secs since 1969 when stats last turned on  */
+	TIME_T		ending_time;		/* time in secs since 1969 when stats last turned off */
+	uint32_t	cycleval;		/* cycles per second */
+#ifdef notyet
+	void		*kernel_magic_addr;	/* address of kernel_magic */
+	void		*kernel_end_addr;	/* contents of kernel magic (points to "end") */
+#endif
+	int              next_free_read_lock_index; /* index of next (global) read lock stats struct */
+	uint64_t         started_cycles64;	/* cycles when measurement last started        */
+	uint64_t         ending_cycles64;	/* cycles when stats last turned off           */
+	uint64_t         enabled_cycles64;	/* total cycles with measurement enabled       */
+	int              intervals;		/* number of measurement intervals recorded      */
+						/* i.e. number of times we did lstat on;lstat off*/
+	int              dir_overflow;		/* number of times we wanted more space in directory */
+	int              rwlock_overflow;	/* # of times we wanted more space in read_locks_count */
+	struct new_utsname   uts;		/* info about machine where stats are measured */
+						/* -T option of lockstat allows data to be     */
+						/* moved to another machine. ................. */
+} lstat_user_request_t;
+
+#endif /* _LINUX_LOCKMETER_H */
--- diff/include/linux/perfctr.h	1970-01-01 01:00:00.000000000 +0100
+++ source/include/linux/perfctr.h	2004-06-11 19:22:06.000000000 +0100
@@ -0,0 +1,158 @@
+/* $Id: perfctr.h,v 1.78 2004/05/31 20:45:51 mikpe Exp $
+ * Performance-Monitoring Counters driver
+ *
+ * Copyright (C) 1999-2004  Mikael Pettersson
+ */
+#ifndef _LINUX_PERFCTR_H
+#define _LINUX_PERFCTR_H
+
+#ifdef CONFIG_PERFCTR	/* don't break archs without <asm/perfctr.h> */
+
+#include <asm/perfctr.h>
+
+struct perfctr_info {
+	unsigned int abi_version;
+	char driver_version[32];
+	unsigned int cpu_type;
+	unsigned int cpu_features;
+	unsigned int cpu_khz;
+	unsigned int tsc_to_cpu_mult;
+	unsigned int _reserved2;
+	unsigned int _reserved3;
+	unsigned int _reserved4;
+};
+
+struct perfctr_cpu_mask {
+	unsigned int nrwords;
+	unsigned int mask[1];	/* actually 'nrwords' */
+};
+
+/* abi_version values: Lower 16 bits contain the CPU data version, upper
+   16 bits contain the API version. Each half has a major version in its
+   upper 8 bits, and a minor version in its lower 8 bits. */
+#define PERFCTR_API_VERSION	0x0600	/* 6.0 */
+#define PERFCTR_ABI_VERSION	((PERFCTR_API_VERSION<<16)|PERFCTR_CPU_VERSION)
+
+/* cpu_features flag bits */
+#define PERFCTR_FEATURE_RDPMC	0x01
+#define PERFCTR_FEATURE_RDTSC	0x02
+#define PERFCTR_FEATURE_PCINT	0x04
+
+/* user's view of mmap:ed virtual perfctr */
+struct vperfctr_state {
+	struct perfctr_cpu_state cpu_state;
+};
+
+/* virtual perfctr control object */
+struct vperfctr_control {
+	int si_signo;
+	struct perfctr_cpu_control cpu_control;
+	unsigned int preserve;
+	unsigned int _reserved1;
+	unsigned int _reserved2;
+	unsigned int _reserved3;
+	unsigned int _reserved4;
+};
+
+#else
+struct perfctr_info;
+struct perfctr_cpu_mask;
+struct perfctr_sum_ctrs;
+struct vperfctr_control;
+#endif	/* CONFIG_PERFCTR */
+
+#ifdef __KERNEL__
+
+/*
+ * The perfctr system calls.
+ */
+asmlinkage long sys_perfctr_info(struct perfctr_info*, struct perfctr_cpu_mask*, struct perfctr_cpu_mask*);
+asmlinkage long sys_vperfctr_open(int tid, int creat);
+asmlinkage long sys_vperfctr_control(int fd, const struct vperfctr_control*);
+asmlinkage long sys_vperfctr_unlink(int fd);
+asmlinkage long sys_vperfctr_iresume(int fd);
+asmlinkage long sys_vperfctr_read(int fd,
+				  struct perfctr_sum_ctrs*,
+				  struct vperfctr_control*);
+
+extern struct perfctr_info perfctr_info;
+
+#ifdef CONFIG_PERFCTR_VIRTUAL
+
+/*
+ * Virtual per-process performance-monitoring counters.
+ */
+struct vperfctr;	/* opaque */
+
+/* process management operations */
+extern struct vperfctr *__vperfctr_copy(struct vperfctr*);
+extern void __vperfctr_exit(struct vperfctr*);
+extern void __vperfctr_suspend(struct vperfctr*);
+extern void __vperfctr_resume(struct vperfctr*);
+extern void __vperfctr_sample(struct vperfctr*);
+extern void __vperfctr_set_cpus_allowed(struct task_struct*, struct vperfctr*, cpumask_t);
+
+static inline void perfctr_copy_thread(struct thread_struct *thread)
+{
+	thread->perfctr = NULL;
+}
+
+static inline void perfctr_exit_thread(struct thread_struct *thread)
+{
+	struct vperfctr *perfctr;
+	perfctr = thread->perfctr;
+	if (perfctr)
+		__vperfctr_exit(perfctr);
+}
+
+static inline void perfctr_suspend_thread(struct thread_struct *prev)
+{
+	struct vperfctr *perfctr;
+	perfctr = prev->perfctr;
+	if (perfctr)
+		__vperfctr_suspend(perfctr);
+}
+
+static inline void perfctr_resume_thread(struct thread_struct *next)
+{
+	struct vperfctr *perfctr;
+	perfctr = next->perfctr;
+	if (perfctr)
+		__vperfctr_resume(perfctr);
+}
+
+static inline void perfctr_sample_thread(struct thread_struct *thread)
+{
+	struct vperfctr *perfctr;
+	perfctr = thread->perfctr;
+	if (perfctr)
+		__vperfctr_sample(perfctr);
+}
+
+static inline void perfctr_set_cpus_allowed(struct task_struct *p, cpumask_t new_mask)
+{
+#ifdef PERFCTR_CPUS_FORBIDDEN_MASK_NEEDED
+	struct vperfctr *perfctr;
+
+	task_lock(p);
+	perfctr = p->thread.perfctr;
+	if (perfctr)
+		__vperfctr_set_cpus_allowed(p, perfctr, new_mask);
+	task_unlock(p);
+#endif
+}
+
+#else	/* !CONFIG_PERFCTR_VIRTUAL */
+
+static inline void perfctr_copy_thread(struct thread_struct *t) { }
+static inline void perfctr_exit_thread(struct thread_struct *t) { }
+static inline void perfctr_suspend_thread(struct thread_struct *t) { }
+static inline void perfctr_resume_thread(struct thread_struct *t) { }
+static inline void perfctr_sample_thread(struct thread_struct *t) { }
+static inline void perfctr_set_cpus_allowed(struct task_struct *p, cpumask_t m) { }
+
+#endif	/* CONFIG_PERFCTR_VIRTUAL */
+
+#endif	/* __KERNEL__ */
+
+#endif	/* _LINUX_PERFCTR_H */
--- diff/include/scsi/scsi_dbg.h	1970-01-01 01:00:00.000000000 +0100
+++ source/include/scsi/scsi_dbg.h	2004-06-11 19:22:07.000000000 +0100
@@ -0,0 +1,18 @@
+#ifndef _SCSI_SCSI_DBG_H
+#define _SCSI_SCSI_DBG_H
+
+struct scsi_cmnd;
+struct scsi_request;
+
+extern void scsi_print_command(struct scsi_cmnd *);
+extern void __scsi_print_command(unsigned char *);
+extern void scsi_print_sense(const char *, struct scsi_cmnd *);
+extern void scsi_print_req_sense(const char *, struct scsi_request *);
+extern void scsi_print_driverbyte(int);
+extern void scsi_print_hostbyte(int);
+extern void scsi_print_status(unsigned char);
+extern int scsi_print_msg(const unsigned char *);
+extern const char *scsi_sense_key_string(unsigned char);
+extern const char *scsi_extd_sense_format(unsigned char, unsigned char);
+
+#endif /* _SCSI_SCSI_DBG_H */
--- diff/kernel/lockmeter.c	1970-01-01 01:00:00.000000000 +0100
+++ source/kernel/lockmeter.c	2004-06-11 19:22:07.000000000 +0100
@@ -0,0 +1,1178 @@
+/*
+ *  Copyright (C) 1999,2000 Silicon Graphics, Inc.
+ *
+ *  Written by John Hawkes (hawkes@sgi.com)
+ *  Based on klstat.c by Jack Steiner (steiner@sgi.com)
+ *
+ *  Modified by Ray Bryant (raybry@us.ibm.com)
+ *  Changes Copyright (C) 2000 IBM, Inc.
+ *  Added save of index in spinlock_t to improve efficiency
+ *  of "hold" time reporting for spinlocks
+ *  Added support for hold time statistics for read and write
+ *  locks.
+ */
+
+#include <linux/config.h>
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/slab.h>
+#include <linux/sched.h>
+#include <linux/smp.h>
+#include <linux/threads.h>
+#include <linux/version.h>
+#include <linux/vmalloc.h>
+#include <linux/spinlock.h>
+#include <linux/utsname.h>
+#include <linux/module.h>
+#include <asm/system.h>
+#include <asm/uaccess.h>
+
+#include <linux/lockmeter.h>
+
+#define ASSERT(cond)
+#define bzero(loc,size)		memset(loc,0,size)
+
+/*<---------------------------------------------------*/
+/*              lockmeter.c                           */
+/*>---------------------------------------------------*/
+
+static lstat_control_t lstat_control __cacheline_aligned =
+	{ LSTAT_OFF, SPIN_LOCK_UNLOCKED, SPIN_LOCK_UNLOCKED,
+	  19 * 0, NR_CPUS * 0, 0, NR_CPUS * 0 };
+
+static ushort lstat_make_dir_entry(void *, void *);
+
+/*
+ * lstat_lookup
+ *
+ * Given a RA, locate the directory entry for the lock.
+ */
+static ushort
+lstat_lookup(void *lock_ptr, void *caller_ra)
+{
+	ushort index;
+	lstat_directory_entry_t *dirp;
+
+	dirp = lstat_control.dir;
+
+	index = lstat_control.hashtab[DIRHASH(caller_ra)];
+	while (dirp[index].caller_ra != caller_ra) {
+		if (index == 0) {
+			return lstat_make_dir_entry(lock_ptr, caller_ra);
+		}
+		index = dirp[index].next_stat_index;
+	}
+
+	if (dirp[index].lock_ptr != NULL && dirp[index].lock_ptr != lock_ptr) {
+		dirp[index].lock_ptr = NULL;
+	}
+
+	return index;
+}
+
+/*
+ * lstat_make_dir_entry
+ * Called to add a new lock to the lock directory.
+ */
+static ushort
+lstat_make_dir_entry(void *lock_ptr, void *caller_ra)
+{
+	lstat_directory_entry_t *dirp;
+	ushort index, hindex;
+	unsigned long flags;
+
+	/* lock the table without recursively reentering this metering code */
+	local_irq_save(flags);
+	_raw_spin_lock(&lstat_control.directory_lock);
+
+	hindex = DIRHASH(caller_ra);
+	index = lstat_control.hashtab[hindex];
+	dirp = lstat_control.dir;
+	while (index && dirp[index].caller_ra != caller_ra)
+		index = dirp[index].next_stat_index;
+
+	if (index == 0) {
+		if (lstat_control.next_free_dir_index < LSTAT_MAX_STAT_INDEX) {
+			index = lstat_control.next_free_dir_index++;
+			lstat_control.dir[index].caller_ra = caller_ra;
+			lstat_control.dir[index].lock_ptr = lock_ptr;
+			lstat_control.dir[index].next_stat_index =
+				lstat_control.hashtab[hindex];
+			lstat_control.hashtab[hindex] = index;
+		} else {
+			lstat_control.dir_overflow++;
+		}
+	}
+	_raw_spin_unlock(&lstat_control.directory_lock);
+	local_irq_restore(flags);
+	return index;
+}
+
+int
+lstat_update(void *lock_ptr, void *caller_ra, int action)
+{
+	int index;
+	int cpu;
+
+	ASSERT(action < LSTAT_ACT_MAX_VALUES);
+
+	if (lstat_control.state == LSTAT_OFF)
+		return 0;
+
+	index = lstat_lookup(lock_ptr, caller_ra);
+	cpu = THIS_CPU_NUMBER;
+	(*lstat_control.counts[cpu])[index].count[action]++;
+	(*lstat_control.counts[cpu])[index].acquire_time = get_cycles();
+
+	return index;
+}
+
+int
+lstat_update_time(void *lock_ptr, void *caller_ra, int action, uint32_t ticks)
+{
+	ushort index;
+	int cpu;
+
+	ASSERT(action < LSTAT_ACT_MAX_VALUES);
+
+	if (lstat_control.state == LSTAT_OFF)
+		return 0;
+
+	index = lstat_lookup(lock_ptr, caller_ra);
+	cpu = THIS_CPU_NUMBER;
+	(*lstat_control.counts[cpu])[index].count[action]++;
+	(*lstat_control.counts[cpu])[index].cum_wait_ticks += (uint64_t) ticks;
+	if ((*lstat_control.counts[cpu])[index].max_wait_ticks < ticks)
+		(*lstat_control.counts[cpu])[index].max_wait_ticks = ticks;
+
+	(*lstat_control.counts[cpu])[index].acquire_time = get_cycles();
+
+	return index;
+}
+
+void
+_metered_spin_lock(spinlock_t * lock_ptr)
+{
+	if (lstat_control.state == LSTAT_OFF) {
+		_raw_spin_lock(lock_ptr);	/* do the real lock */
+		PUT_INDEX(lock_ptr, 0);	/* clean index in case lockmetering  */
+		/* gets turned on before unlock */
+	} else {
+		void *this_pc = LSTAT_RA(LSTAT_RA_SPIN);
+		int index;
+
+		if (_raw_spin_trylock(lock_ptr)) {
+			index = lstat_update(lock_ptr, this_pc,
+						LSTAT_ACT_NO_WAIT);
+		} else {
+			uint32_t start_cycles = get_cycles();
+			_raw_spin_lock(lock_ptr);	/* do the real lock */
+			index = lstat_update_time(lock_ptr, this_pc,
+				LSTAT_ACT_SPIN, get_cycles() - start_cycles);
+		}
+		/* save the index in the lock itself for use in spin unlock */
+		PUT_INDEX(lock_ptr, index);
+	}
+}
+
+int
+_metered_spin_trylock(spinlock_t * lock_ptr)
+{
+	if (lstat_control.state == LSTAT_OFF) {
+		return _raw_spin_trylock(lock_ptr);
+	} else {
+		int retval;
+		void *this_pc = LSTAT_RA(LSTAT_RA_SPIN);
+
+		if ((retval = _raw_spin_trylock(lock_ptr))) {
+			int index = lstat_update(lock_ptr, this_pc,
+						LSTAT_ACT_NO_WAIT);
+			/*
+			 * save the index in the lock itself for use in spin
+			 * unlock
+			 */
+			PUT_INDEX(lock_ptr, index);
+		} else {
+			lstat_update(lock_ptr, this_pc, LSTAT_ACT_REJECT);
+		}
+
+		return retval;
+	}
+}
+
+void
+_metered_spin_unlock(spinlock_t * lock_ptr)
+{
+	int index = -1;
+
+	if (lstat_control.state != LSTAT_OFF) {
+		index = GET_INDEX(lock_ptr);
+		/*
+		 * If statistics were turned off when we set the lock,
+		 * then the index can be zero.  If that is the case,
+		 * then collect no stats on this call.
+		 */
+		if (index > 0) {
+			uint32_t hold_time;
+			int cpu = THIS_CPU_NUMBER;
+			hold_time = get_cycles() -
+			 (*lstat_control.counts[cpu])[index].acquire_time;
+			(*lstat_control.counts[cpu])[index].cum_hold_ticks +=
+				(uint64_t) hold_time;
+			if ((*lstat_control.counts[cpu])[index].max_hold_ticks <
+			    hold_time)
+				(*lstat_control.counts[cpu])[index].
+				    max_hold_ticks = hold_time;
+		}
+	}
+
+	/* make sure we don't have a stale index value saved */
+	PUT_INDEX(lock_ptr, 0);
+	_raw_spin_unlock(lock_ptr);	/* do the real unlock */
+}
+
+/*
+ * allocate the next global read lock structure and store its index
+ * in the rwlock at "lock_ptr".
+ */
+uint32_t
+alloc_rwlock_struct(rwlock_t * rwlock_ptr)
+{
+	int index;
+	unsigned long flags;
+	int cpu = THIS_CPU_NUMBER;
+
+	/* If we've already overflowed, then do a quick exit */
+	if (lstat_control.next_free_read_lock_index >
+			LSTAT_MAX_READ_LOCK_INDEX) {
+		lstat_control.rwlock_overflow++;
+		return 0;
+	}
+
+	local_irq_save(flags);
+	_raw_spin_lock(&lstat_control.directory_lock);
+
+	/* It is possible this changed while we were waiting for the directory_lock */
+	if (lstat_control.state == LSTAT_OFF) {
+		index = 0;
+		goto unlock;
+	}
+
+	/* It is possible someone else got here first and set the index */
+	if ((index = GET_RWINDEX(rwlock_ptr)) == 0) {
+		/*
+		 * we can't turn on read stats for this lock while there are
+		 * readers (this would mess up the running hold time sum at
+		 * unlock time)
+		 */
+		if (RWLOCK_READERS(rwlock_ptr) != 0) {
+			index = 0;
+			goto unlock;
+		}
+
+		/*
+		 * if stats are turned on after being off, we may need to
+		 * return an old index from when the statistics were on last
+		 * time.
+		 */
+		for (index = 1; index < lstat_control.next_free_read_lock_index;
+				index++)
+			if ((*lstat_control.read_lock_counts[cpu])[index].
+					lock_ptr == rwlock_ptr)
+				goto put_index_and_unlock;
+
+		/* allocate the next global read lock structure */
+		if (lstat_control.next_free_read_lock_index >=
+		    LSTAT_MAX_READ_LOCK_INDEX) {
+			lstat_control.rwlock_overflow++;
+			index = 0;
+			goto unlock;
+		}
+		index = lstat_control.next_free_read_lock_index++;
+
+		/*
+		 * initialize the global read stats data structure for each
+		 * cpu
+		 */
+		for (cpu = 0; cpu < num_online_cpus(); cpu++) {
+			(*lstat_control.read_lock_counts[cpu])[index].lock_ptr =
+				rwlock_ptr;
+		}
+put_index_and_unlock:
+		/* store the index for the read lock structure into the lock */
+		PUT_RWINDEX(rwlock_ptr, index);
+	}
+
+unlock:
+	_raw_spin_unlock(&lstat_control.directory_lock);
+	local_irq_restore(flags);
+	return index;
+}
+
+void
+_metered_read_lock(rwlock_t * rwlock_ptr)
+{
+	void *this_pc;
+	uint32_t start_cycles;
+	int index;
+	int cpu;
+	unsigned long flags;
+	int readers_before, readers_after;
+	uint64_t cycles64;
+
+	if (lstat_control.state == LSTAT_OFF) {
+		_raw_read_lock(rwlock_ptr);
+		/* clean index in case lockmetering turns on before an unlock */
+		PUT_RWINDEX(rwlock_ptr, 0);
+		return;
+	}
+
+	this_pc = LSTAT_RA(LSTAT_RA_READ);
+	cpu = THIS_CPU_NUMBER;
+	index = GET_RWINDEX(rwlock_ptr);
+
+	/* allocate the global stats entry for this lock, if needed */
+	if (index == 0)
+		index = alloc_rwlock_struct(rwlock_ptr);
+
+	readers_before = RWLOCK_READERS(rwlock_ptr);
+	if (_raw_read_trylock(rwlock_ptr)) {
+		/*
+		 * We have decremented the lock to count a new reader,
+		 * and have confirmed that no writer has it locked.
+		 */
+		/* update statistics if enabled */
+		if (index > 0) {
+			local_irq_save(flags);
+			lstat_update((void *) rwlock_ptr, this_pc,
+					LSTAT_ACT_NO_WAIT);
+			/* preserve value of TSC so cum_hold_ticks and start_busy use same value */
+			cycles64 = get_cycles64();
+			(*lstat_control.read_lock_counts[cpu])[index].
+				cum_hold_ticks -= cycles64;
+
+			/* record time and cpu of start of busy period */
+			/* this is not perfect (some race conditions are possible) */
+			if (readers_before == 0) {
+				(*lstat_control.read_lock_counts[cpu])[index].
+					start_busy = cycles64;
+				PUT_RW_CPU(rwlock_ptr, cpu);
+			}
+			readers_after = RWLOCK_READERS(rwlock_ptr);
+			if (readers_after >
+				(*lstat_control.read_lock_counts[cpu])[index].
+					max_readers)
+				(*lstat_control.read_lock_counts[cpu])[index].
+					max_readers = readers_after;
+			local_irq_restore(flags);
+		}
+
+		return;
+	}
+	/* If we get here, then we could not quickly grab the read lock */
+
+	start_cycles = get_cycles();	/* start counting the wait time */
+
+	/* Now spin until read_lock is successful */
+	_raw_read_lock(rwlock_ptr);
+
+	lstat_update_time((void *) rwlock_ptr, this_pc, LSTAT_ACT_SPIN,
+			  get_cycles() - start_cycles);
+
+	/* update statistics if they are enabled for this lock */
+	if (index > 0) {
+		local_irq_save(flags);
+		cycles64 = get_cycles64();
+		(*lstat_control.read_lock_counts[cpu])[index].cum_hold_ticks -=
+				cycles64;
+
+		/* this is not perfect (some race conditions are possible) */
+		if (readers_before == 0) {
+			(*lstat_control.read_lock_counts[cpu])[index].
+				start_busy = cycles64;
+			PUT_RW_CPU(rwlock_ptr, cpu);
+		}
+		readers_after = RWLOCK_READERS(rwlock_ptr);
+		if (readers_after >
+		    (*lstat_control.read_lock_counts[cpu])[index].max_readers)
+			(*lstat_control.read_lock_counts[cpu])[index].
+				max_readers = readers_after;
+		local_irq_restore(flags);
+	}
+}
+
+void
+_metered_read_unlock(rwlock_t * rwlock_ptr)
+{
+	int index;
+	int cpu;
+	unsigned long flags;
+	uint64_t busy_length;
+	uint64_t cycles64;
+
+	if (lstat_control.state == LSTAT_OFF) {
+		_raw_read_unlock(rwlock_ptr);
+		return;
+	}
+
+	index = GET_RWINDEX(rwlock_ptr);
+	cpu = THIS_CPU_NUMBER;
+
+	if (index > 0) {
+		local_irq_save(flags);
+		/*
+		 * preserve value of TSC so cum_hold_ticks and busy_ticks are
+		 * consistent.
+		 */
+		cycles64 = get_cycles64();
+		(*lstat_control.read_lock_counts[cpu])[index].cum_hold_ticks +=
+			cycles64;
+		(*lstat_control.read_lock_counts[cpu])[index].read_lock_count++;
+
+		/*
+		 * once again, this is not perfect (some race conditions are
+		 * possible)
+		 */
+		if (RWLOCK_READERS(rwlock_ptr) == 1) {
+			int cpu1 = GET_RW_CPU(rwlock_ptr);
+			uint64_t last_start_busy =
+				(*lstat_control.read_lock_counts[cpu1])[index].
+					start_busy;
+			(*lstat_control.read_lock_counts[cpu])[index].
+				busy_periods++;
+			if (cycles64 > last_start_busy) {
+				busy_length = cycles64 - last_start_busy;
+				(*lstat_control.read_lock_counts[cpu])[index].
+					busy_ticks += busy_length;
+				if (busy_length >
+					(*lstat_control.
+						read_lock_counts[cpu])[index].
+							max_busy)
+					(*lstat_control.
+					 read_lock_counts[cpu])[index].
+						max_busy = busy_length;
+			}
+		}
+		local_irq_restore(flags);
+	}
+	_raw_read_unlock(rwlock_ptr);
+}
+
+void
+_metered_write_lock(rwlock_t * rwlock_ptr)
+{
+	uint32_t start_cycles;
+	void *this_pc;
+	uint32_t spin_ticks = 0; /* in anticipation of a potential wait */
+	int index;
+	int write_index = 0;
+	int cpu;
+	enum {
+		writer_writer_conflict,
+		writer_reader_conflict
+	} why_wait = writer_writer_conflict;
+
+	if (lstat_control.state == LSTAT_OFF) {
+		_raw_write_lock(rwlock_ptr);
+		/* clean index in case lockmetering turns on before an unlock */
+		PUT_RWINDEX(rwlock_ptr, 0);
+		return;
+	}
+
+	this_pc = LSTAT_RA(LSTAT_RA_WRITE);
+	cpu = THIS_CPU_NUMBER;
+	index = GET_RWINDEX(rwlock_ptr);
+
+	/* allocate the global stats entry for this lock, if needed */
+	if (index == 0) {
+		index = alloc_rwlock_struct(rwlock_ptr);
+	}
+
+	if (_raw_write_trylock(rwlock_ptr)) {
+		/* We acquired the lock on the first try */
+		write_index = lstat_update((void *) rwlock_ptr, this_pc,
+					LSTAT_ACT_NO_WAIT);
+		/* save the write_index for use in unlock if stats enabled */
+		if (index > 0)
+			(*lstat_control.read_lock_counts[cpu])[index].
+				write_index = write_index;
+		return;
+	}
+
+	/* If we get here, then we could not quickly grab the write lock */
+	start_cycles = get_cycles();	/* start counting the wait time */
+
+	why_wait = RWLOCK_READERS(rwlock_ptr) ?
+			writer_reader_conflict : writer_writer_conflict;
+
+	/* Now set the lock and wait for conflicts to disappear */
+	_raw_write_lock(rwlock_ptr);
+
+	spin_ticks = get_cycles() - start_cycles;
+
+	/* update stats -- if enabled */
+	if (index > 0 && spin_ticks) {
+		if (why_wait == writer_reader_conflict) {
+			/* waited due to a reader holding the lock */
+			write_index = lstat_update_time((void *)rwlock_ptr,
+					this_pc, LSTAT_ACT_SPIN, spin_ticks);
+		} else {
+			/*
+			 * waited due to another writer holding the lock
+			 */
+			write_index = lstat_update_time((void *)rwlock_ptr,
+				this_pc, LSTAT_ACT_WW_SPIN, spin_ticks);
+			(*lstat_control.counts[cpu])[write_index].
+				cum_wait_ww_ticks += spin_ticks;
+			if (spin_ticks >
+				(*lstat_control.counts[cpu])[write_index].
+					max_wait_ww_ticks) {
+				(*lstat_control.counts[cpu])[write_index].
+					max_wait_ww_ticks = spin_ticks;
+			}
+		}
+
+		/* save the directory index for use on write_unlock */
+		(*lstat_control.read_lock_counts[cpu])[index].
+			write_index = write_index;
+	}
+}
+
+void
+_metered_write_unlock(rwlock_t * rwlock_ptr)
+{
+	int index;
+	int cpu;
+	int write_index;
+	uint32_t hold_time;
+
+	if (lstat_control.state == LSTAT_OFF) {
+		_raw_write_unlock(rwlock_ptr);
+		return;
+	}
+
+	cpu = THIS_CPU_NUMBER;
+	index = GET_RWINDEX(rwlock_ptr);
+
+	/* update statistics if stats enabled for this lock */
+	if (index > 0) {
+		write_index =
+		    (*lstat_control.read_lock_counts[cpu])[index].write_index;
+
+		hold_time = get_cycles() -
+			(*lstat_control.counts[cpu])[write_index].acquire_time;
+		(*lstat_control.counts[cpu])[write_index].cum_hold_ticks +=
+			(uint64_t) hold_time;
+		if ((*lstat_control.counts[cpu])[write_index].max_hold_ticks <
+				hold_time)
+			(*lstat_control.counts[cpu])[write_index].
+				max_hold_ticks = hold_time;
+	}
+	_raw_write_unlock(rwlock_ptr);
+}
+
+int
+_metered_write_trylock(rwlock_t * rwlock_ptr)
+{
+	int retval;
+	void *this_pc = LSTAT_RA(LSTAT_RA_WRITE);
+
+	if ((retval = _raw_write_trylock(rwlock_ptr))) {
+		lstat_update(rwlock_ptr, this_pc, LSTAT_ACT_NO_WAIT);
+	} else {
+		lstat_update(rwlock_ptr, this_pc, LSTAT_ACT_REJECT);
+	}
+
+	return retval;
+}
+
+static void
+init_control_space(void)
+{
+	/* Set all control space pointers to null and indices to "empty" */
+	int cpu;
+
+	/*
+	 * Access CPU_CYCLE_FREQUENCY at the outset, which in some
+	 * architectures may trigger a runtime calculation that uses a
+	 * spinlock.  Let's do this before lockmetering is turned on.
+	 */
+	if (CPU_CYCLE_FREQUENCY == 0)
+		BUG();
+
+	lstat_control.hashtab = NULL;
+	lstat_control.dir = NULL;
+	for (cpu = 0; cpu < NR_CPUS; cpu++) {
+		lstat_control.counts[cpu] = NULL;
+		lstat_control.read_lock_counts[cpu] = NULL;
+	}
+}
+
+static int
+reset_lstat_data(void)
+{
+	int cpu, flags;
+
+	flags = 0;
+	lstat_control.next_free_dir_index = 1;	/* 0 is for overflows */
+	lstat_control.next_free_read_lock_index = 1;
+	lstat_control.dir_overflow = 0;
+	lstat_control.rwlock_overflow = 0;
+
+	lstat_control.started_cycles64 = 0;
+	lstat_control.ending_cycles64 = 0;
+	lstat_control.enabled_cycles64 = 0;
+	lstat_control.first_started_time = 0;
+	lstat_control.started_time = 0;
+	lstat_control.ending_time = 0;
+	lstat_control.intervals = 0;
+
+	/*
+	 * paranoia -- in case someone does a "lockstat reset" before
+	 * "lockstat on"
+	 */
+	if (lstat_control.hashtab) {
+		bzero(lstat_control.hashtab,
+			LSTAT_HASH_TABLE_SIZE * sizeof (short));
+		bzero(lstat_control.dir, LSTAT_MAX_STAT_INDEX *
+				sizeof (lstat_directory_entry_t));
+
+		for (cpu = 0; cpu < num_online_cpus(); cpu++) {
+			bzero(lstat_control.counts[cpu],
+				sizeof (lstat_cpu_counts_t));
+			bzero(lstat_control.read_lock_counts[cpu],
+				sizeof (lstat_read_lock_cpu_counts_t));
+		}
+	}
+#ifdef NOTDEF
+	_raw_spin_unlock(&lstat_control.directory_lock);
+	local_irq_restore(flags);
+#endif
+	return 1;
+}
+
+static void
+release_control_space(void)
+{
+	/*
+	 * Called when either (1) allocation of kmem
+	 * or (2) when user writes LSTAT_RELEASE to /pro/lockmeter.
+	 * Assume that all pointers have been initialized to zero,
+	 * i.e., nonzero pointers are valid addresses.
+	 */
+	int cpu;
+
+	if (lstat_control.hashtab) {
+		kfree(lstat_control.hashtab);
+		lstat_control.hashtab = NULL;
+	}
+
+	if (lstat_control.dir) {
+		vfree(lstat_control.dir);
+		lstat_control.dir = NULL;
+	}
+
+	for (cpu = 0; cpu < NR_CPUS; cpu++) {
+		if (lstat_control.counts[cpu]) {
+			vfree(lstat_control.counts[cpu]);
+			lstat_control.counts[cpu] = NULL;
+		}
+		if (lstat_control.read_lock_counts[cpu]) {
+			kfree(lstat_control.read_lock_counts[cpu]);
+			lstat_control.read_lock_counts[cpu] = NULL;
+		}
+	}
+}
+
+int
+get_lockmeter_info_size(void)
+{
+	return sizeof (lstat_user_request_t)
+		+ num_online_cpus() * sizeof (lstat_cpu_counts_t)
+		+ num_online_cpus() * sizeof (lstat_read_lock_cpu_counts_t)
+		+ (LSTAT_MAX_STAT_INDEX * sizeof (lstat_directory_entry_t));
+}
+
+ssize_t
+get_lockmeter_info(char *buffer, size_t max_len, loff_t * last_index)
+{
+	lstat_user_request_t req;
+	struct timeval tv;
+	ssize_t next_ret_bcount;
+	ssize_t actual_ret_bcount = 0;
+	int cpu;
+
+	*last_index = 0;	/* a one-shot read */
+
+	req.lstat_version = LSTAT_VERSION;
+	req.state = lstat_control.state;
+	req.maxcpus = num_online_cpus();
+	req.cycleval = CPU_CYCLE_FREQUENCY;
+#ifdef notyet
+	req.kernel_magic_addr = (void *) &_etext;
+	req.kernel_end_addr = (void *) &_etext;
+#endif
+	req.uts = system_utsname;
+	req.intervals = lstat_control.intervals;
+
+	req.first_started_time = lstat_control.first_started_time;
+	req.started_time = lstat_control.started_time;
+	req.started_cycles64 = lstat_control.started_cycles64;
+
+	req.next_free_dir_index = lstat_control.next_free_dir_index;
+	req.next_free_read_lock_index = lstat_control.next_free_read_lock_index;
+	req.dir_overflow = lstat_control.dir_overflow;
+	req.rwlock_overflow = lstat_control.rwlock_overflow;
+
+	if (lstat_control.state == LSTAT_OFF) {
+		if (req.intervals == 0) {
+			/* mesasurement is off and no valid data present */
+			next_ret_bcount = sizeof (lstat_user_request_t);
+			req.enabled_cycles64 = 0;
+
+			if ((actual_ret_bcount + next_ret_bcount) > max_len)
+				return actual_ret_bcount;
+
+			copy_to_user(buffer, (void *) &req, next_ret_bcount);
+			actual_ret_bcount += next_ret_bcount;
+			return actual_ret_bcount;
+		} else {
+			/*
+			 * measurement is off but valid data present
+			 * fetch time info from lstat_control
+			 */
+			req.ending_time = lstat_control.ending_time;
+			req.ending_cycles64 = lstat_control.ending_cycles64;
+			req.enabled_cycles64 = lstat_control.enabled_cycles64;
+		}
+	} else {
+		/*
+		 * this must be a read while data active--use current time,
+		 * etc
+		 */
+		do_gettimeofday(&tv);
+		req.ending_time = tv.tv_sec;
+		req.ending_cycles64 = get_cycles64();
+		req.enabled_cycles64 = req.ending_cycles64 -
+			req.started_cycles64 + lstat_control.enabled_cycles64;
+	}
+
+	next_ret_bcount = sizeof (lstat_user_request_t);
+	if ((actual_ret_bcount + next_ret_bcount) > max_len)
+		return actual_ret_bcount;
+
+	copy_to_user(buffer, (void *) &req, next_ret_bcount);
+	actual_ret_bcount += next_ret_bcount;
+
+	if (!lstat_control.counts[0])	/* not initialized? */
+		return actual_ret_bcount;
+
+	next_ret_bcount = sizeof (lstat_cpu_counts_t);
+	for (cpu = 0; cpu < num_online_cpus(); cpu++) {
+		if ((actual_ret_bcount + next_ret_bcount) > max_len)
+			return actual_ret_bcount;	/* leave early */
+		copy_to_user(buffer + actual_ret_bcount,
+				lstat_control.counts[cpu], next_ret_bcount);
+		actual_ret_bcount += next_ret_bcount;
+	}
+
+	next_ret_bcount = LSTAT_MAX_STAT_INDEX *
+			sizeof (lstat_directory_entry_t);
+	if (((actual_ret_bcount + next_ret_bcount) > max_len)
+			|| !lstat_control.dir)
+		return actual_ret_bcount;	/* leave early */
+
+	copy_to_user(buffer + actual_ret_bcount, lstat_control.dir,
+			next_ret_bcount);
+	actual_ret_bcount += next_ret_bcount;
+
+	next_ret_bcount = sizeof (lstat_read_lock_cpu_counts_t);
+	for (cpu = 0; cpu < num_online_cpus(); cpu++) {
+		if (actual_ret_bcount + next_ret_bcount > max_len)
+			return actual_ret_bcount;
+		copy_to_user(buffer + actual_ret_bcount,
+				lstat_control.read_lock_counts[cpu],
+				next_ret_bcount);
+		actual_ret_bcount += next_ret_bcount;
+	}
+
+	return actual_ret_bcount;
+}
+
+/*
+ *  Writing to the /proc lockmeter node enables or disables metering.
+ *  based upon the first byte of the "written" data.
+ *  The following values are defined:
+ *  LSTAT_ON: 1st call: allocates storage, intializes and turns on measurement
+ *            subsequent calls just turn on measurement
+ *  LSTAT_OFF: turns off measurement
+ *  LSTAT_RESET: resets statistics
+ *  LSTAT_RELEASE: releases statistics storage
+ *
+ *  This allows one to accumulate statistics over several lockstat runs:
+ *
+ *  lockstat on
+ *  lockstat off
+ *  ...repeat above as desired...
+ *  lockstat get
+ *  ...now start a new set of measurements...
+ *  lockstat reset
+ *  lockstat on
+ *  ...
+ *
+ */
+ssize_t
+put_lockmeter_info(const char *buffer, size_t len)
+{
+	int error = 0;
+	int dirsize, countsize, read_lock_countsize, hashsize;
+	int cpu;
+	char put_char;
+	int i, read_lock_blocks;
+	unsigned long flags;
+	rwlock_t *lock_ptr;
+	struct timeval tv;
+
+	if (len <= 0)
+		return -EINVAL;
+
+	_raw_spin_lock(&lstat_control.control_lock);
+
+	get_user(put_char, buffer);
+	switch (put_char) {
+
+	case LSTAT_OFF:
+		if (lstat_control.state != LSTAT_OFF) {
+			/*
+			 * To avoid seeing read lock hold times in an
+			 * inconsisent state, we have to follow this protocol
+			 * to turn off statistics
+			 */
+			local_irq_save(flags);
+			/*
+			 * getting this lock will stop any read lock block
+			 * allocations
+			 */
+			_raw_spin_lock(&lstat_control.directory_lock);
+			/*
+			 * keep any more read lock blocks from being
+			 * allocated
+			 */
+			lstat_control.state = LSTAT_OFF;
+			/* record how may read lock blocks there are */
+			read_lock_blocks =
+				lstat_control.next_free_read_lock_index;
+			_raw_spin_unlock(&lstat_control.directory_lock);
+			/* now go through the list of read locks */
+			cpu = THIS_CPU_NUMBER;
+			for (i = 1; i < read_lock_blocks; i++) {
+				lock_ptr =
+				    (*lstat_control.read_lock_counts[cpu])[i].
+				    lock_ptr;
+				/* is this saved lock address still valid? */
+				if (GET_RWINDEX(lock_ptr) == i) {
+					/*
+					 * lock address appears to still be
+					 * valid because we only hold one lock
+					 * at a time, this can't cause a
+					 * deadlock unless this is a lock held
+					 * as part of the current system call
+					 * path. At the moment there
+					 * are no READ mode locks held to get
+					 * here from user space, so we solve
+					 * this by skipping locks held in
+					 * write mode.
+					 */
+					if (RWLOCK_IS_WRITE_LOCKED(lock_ptr)) {
+						PUT_RWINDEX(lock_ptr, 0);
+						continue;
+					}
+					/*
+					 * now we know there are no read
+					 * holders of this lock! stop
+					 * statistics collection for this
+					 * lock
+					 */
+					_raw_write_lock(lock_ptr);
+					PUT_RWINDEX(lock_ptr, 0);
+					_raw_write_unlock(lock_ptr);
+				}
+				/*
+				 * it may still be possible for the hold time
+				 * sum to be negative e.g. if a lock is
+				 * reallocated while "busy" we will have to fix
+				 * this up in the data reduction program.
+				 */
+			}
+			local_irq_restore(flags);
+			lstat_control.intervals++;
+			lstat_control.ending_cycles64 = get_cycles64();
+			lstat_control.enabled_cycles64 +=
+				lstat_control.ending_cycles64 -
+				lstat_control.started_cycles64;
+			do_gettimeofday(&tv);
+			lstat_control.ending_time = tv.tv_sec;
+			/*
+			 * don't deallocate the structures -- we may do a
+			 * lockstat on to add to the data that is already
+			 * there. Use LSTAT_RELEASE to release storage
+			 */
+		} else {
+			error = -EBUSY;	/* already OFF */
+		}
+		break;
+
+	case LSTAT_ON:
+		if (lstat_control.state == LSTAT_OFF) {
+#ifdef DEBUG_LOCKMETER
+			printk("put_lockmeter_info(cpu=%d): LSTAT_ON\n",
+				THIS_CPU_NUMBER);
+#endif
+			lstat_control.next_free_dir_index = 1;	/* 0 is for overflows */
+
+			dirsize = LSTAT_MAX_STAT_INDEX *
+					sizeof (lstat_directory_entry_t);
+			hashsize =
+				(1 + LSTAT_HASH_TABLE_SIZE) * sizeof (ushort);
+			countsize = sizeof (lstat_cpu_counts_t);
+			read_lock_countsize =
+				sizeof (lstat_read_lock_cpu_counts_t);
+#ifdef DEBUG_LOCKMETER
+			printk(" dirsize:%d", dirsize);
+			printk(" hashsize:%d", hashsize);
+			printk(" countsize:%d", countsize);
+			printk(" read_lock_countsize:%d\n",
+				read_lock_countsize);
+#endif
+#ifdef DEBUG_LOCKMETER
+			{
+				int secs;
+				unsigned long cycles;
+				uint64_t cycles64;
+
+				do_gettimeofday(&tv);
+				secs = tv.tv_sec;
+				do {
+					do_gettimeofday(&tv);
+				} while (secs == tv.tv_sec);
+				cycles = get_cycles();
+				cycles64 = get_cycles64();
+				secs = tv.tv_sec;
+				do {
+					do_gettimeofday(&tv);
+				} while (secs == tv.tv_sec);
+				cycles = get_cycles() - cycles;
+				cycles64 = get_cycles64() - cycles;
+				printk("lockmeter: cycleFrequency:%d "
+					"cycles:%d cycles64:%d\n",
+					CPU_CYCLE_FREQUENCY, cycles, cycles64);
+			}
+#endif
+
+			/*
+			 * if this is the first call, allocate storage and
+			 * initialize
+			 */
+			if (!lstat_control.hashtab) {
+
+				spin_lock_init(&lstat_control.directory_lock);
+
+				/* guarantee all pointers at zero */
+				init_control_space();
+
+				lstat_control.hashtab =
+				    kmalloc(hashsize, GFP_KERNEL);
+				if (!lstat_control.hashtab) {
+					error = -ENOSPC;
+#ifdef DEBUG_LOCKMETER
+					printk("!!error kmalloc of hashtab\n");
+#endif
+				}
+				lstat_control.dir = vmalloc(dirsize);
+				if (!lstat_control.dir) {
+					error = -ENOSPC;
+#ifdef DEBUG_LOCKMETER
+					printk("!!error kmalloc of dir\n");
+#endif
+				}
+
+				for (cpu = 0; cpu < num_online_cpus(); cpu++) {
+					lstat_control.counts[cpu] =
+						vmalloc(countsize);
+					if (!lstat_control.counts[cpu]) {
+						error = -ENOSPC;
+#ifdef DEBUG_LOCKMETER
+						printk("!!error vmalloc of "
+							"counts[%d]\n", cpu);
+#endif
+					}
+					lstat_control.read_lock_counts[cpu] =
+						(lstat_read_lock_cpu_counts_t *)
+						kmalloc(read_lock_countsize,
+							GFP_KERNEL);
+					if (!lstat_control.
+							read_lock_counts[cpu]) {
+						error = -ENOSPC;
+#ifdef DEBUG_LOCKMETER
+						printk("!!error kmalloc of "
+						  "read_lock_counts[%d]\n",
+							cpu);
+#endif
+					}
+				}
+			}
+
+			if (error) {
+				/*
+				 * One or more kmalloc failures -- free
+				 * everything
+				 */
+				release_control_space();
+			} else {
+
+				if (!reset_lstat_data()) {
+					error = -EINVAL;
+					break;
+				};
+
+				/*
+				 * record starting and ending times and the
+				 * like
+				 */
+				if (lstat_control.intervals == 0) {
+					do_gettimeofday(&tv);
+					lstat_control.first_started_time =
+						tv.tv_sec;
+				}
+				lstat_control.started_cycles64 = get_cycles64();
+				do_gettimeofday(&tv);
+				lstat_control.started_time = tv.tv_sec;
+
+				lstat_control.state = LSTAT_ON;
+			}
+		} else {
+			error = -EBUSY;	/* already ON */
+		}
+		break;
+
+	case LSTAT_RESET:
+		if (lstat_control.state == LSTAT_OFF) {
+			if (!reset_lstat_data())
+				error = -EINVAL;
+		} else {
+			error = -EBUSY;	/* still on; can't reset */
+		}
+		break;
+
+	case LSTAT_RELEASE:
+		if (lstat_control.state == LSTAT_OFF) {
+			release_control_space();
+			lstat_control.intervals = 0;
+			lstat_control.enabled_cycles64 = 0;
+		} else {
+			error = -EBUSY;
+		}
+		break;
+
+	default:
+		error = -EINVAL;
+	}			/* switch */
+
+	_raw_spin_unlock(&lstat_control.control_lock);
+	return error ? error : len;
+}
+
+#ifdef USER_MODE_TESTING
+/* following used for user mode testing */
+void
+lockmeter_init()
+{
+	int dirsize, hashsize, countsize, read_lock_countsize, cpu;
+
+	printf("lstat_control is at %x size=%d\n", &lstat_control,
+		sizeof (lstat_control));
+	printf("sizeof(spinlock_t)=%d\n", sizeof (spinlock_t));
+	lstat_control.state = LSTAT_ON;
+
+	lstat_control.directory_lock = SPIN_LOCK_UNLOCKED;
+	lstat_control.next_free_dir_index = 1;	/* 0 is for overflows */
+	lstat_control.next_free_read_lock_index = 1;
+
+	dirsize = LSTAT_MAX_STAT_INDEX * sizeof (lstat_directory_entry_t);
+	hashsize = (1 + LSTAT_HASH_TABLE_SIZE) * sizeof (ushort);
+	countsize = sizeof (lstat_cpu_counts_t);
+	read_lock_countsize = sizeof (lstat_read_lock_cpu_counts_t);
+
+	lstat_control.hashtab = (ushort *) malloc(hashsize);
+
+	if (lstat_control.hashtab == 0) {
+		printf("malloc failure for at line %d in lockmeter.c\n",
+			__LINE__);
+		exit(0);
+	}
+
+	lstat_control.dir = (lstat_directory_entry_t *) malloc(dirsize);
+
+	if (lstat_control.dir == 0) {
+		printf("malloc failure for at line %d in lockmeter.c\n", cpu,
+			__LINE__);
+		exit(0);
+	}
+
+	for (cpu = 0; cpu < num_online_cpus(); cpu++) {
+		int j, k;
+		j = (int) (lstat_control.counts[cpu] =
+			   (lstat_cpu_counts_t *) malloc(countsize));
+		k = (int) (lstat_control.read_lock_counts[cpu] =
+			   (lstat_read_lock_cpu_counts_t *)
+			   malloc(read_lock_countsize));
+		if (j * k == 0) {
+			printf("malloc failure for cpu=%d at line %d in "
+				"lockmeter.c\n", cpu, __LINE__);
+			exit(0);
+		}
+	}
+
+	memset(lstat_control.hashtab, 0, hashsize);
+	memset(lstat_control.dir, 0, dirsize);
+
+	for (cpu = 0; cpu < num_online_cpus(); cpu++) {
+		memset(lstat_control.counts[cpu], 0, countsize);
+		memset(lstat_control.read_lock_counts[cpu], 0,
+			read_lock_countsize);
+	}
+}
+
+asm(" \
+.align	4 \
+.globl	__write_lock_failed \
+__write_lock_failed: \
+	" LOCK "addl	$" RW_LOCK_BIAS_STR ",(%eax) \
+1:	cmpl	$" RW_LOCK_BIAS_STR ",(%eax) \
+	jne	1b \
+\
+	" LOCK "subl	$" RW_LOCK_BIAS_STR ",(%eax) \
+	jnz	__write_lock_failed \
+	ret \
+\
+\
+.align	4 \
+.globl	__read_lock_failed \
+__read_lock_failed: \
+	lock ; incl	(%eax) \
+1:	cmpl	$1,(%eax) \
+	js	1b \
+\
+	lock ; decl	(%eax) \
+	js	__read_lock_failed \
+	ret \
+");
+#endif
+
+EXPORT_SYMBOL(_metered_spin_lock);
+EXPORT_SYMBOL(_metered_spin_unlock);
+EXPORT_SYMBOL(_metered_spin_trylock);
+EXPORT_SYMBOL(_metered_read_lock);
+EXPORT_SYMBOL(_metered_read_unlock);
+EXPORT_SYMBOL(_metered_write_lock);
+EXPORT_SYMBOL(_metered_write_unlock);
--- diff/sound/pci/ice1712/vt1720_mobo.c	1970-01-01 01:00:00.000000000 +0100
+++ source/sound/pci/ice1712/vt1720_mobo.c	2004-06-11 19:22:07.000000000 +0100
@@ -0,0 +1,97 @@
+/*
+ *   ALSA driver for VT1720/VT1724 (Envy24PT/Envy24HT)
+ *
+ *   Lowlevel functions for VT1720-based motherboards
+ *
+ *	Copyright (c) 2004 Takashi Iwai <tiwai@suse.de>
+ *
+ *   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
+ *
+ */      
+
+#include <sound/driver.h>
+#include <asm/io.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <sound/core.h>
+
+#include "ice1712.h"
+#include "vt1720_mobo.h"
+
+
+static int __devinit k8x800_init(ice1712_t *ice)
+{
+	ice->vt1720 = 1;
+
+	/* VT1616 codec */
+	ice->num_total_dacs = 6;
+	ice->num_total_adcs = 2;
+
+	/* WM8728 codec */
+	/* FIXME: TODO */
+
+	return 0;
+}
+
+static int __devinit k8x800_add_controls(ice1712_t *ice)
+{
+	/* FIXME: needs some quirks for VT1616? */
+	return 0;
+}
+
+/* EEPROM image */
+
+static unsigned char k8x800_eeprom[] __devinitdata = {
+	0x01,	/* SYSCONF: clock 256, 1ADC, 2DACs */
+	0x02,	/* ACLINK: ACLINK, packed */
+	0x00,	/* I2S: - */
+	0x00,	/* SPDIF: - */
+	0xff,	/* GPIO_DIR */
+	0xff,	/* GPIO_DIR1 */
+	0x00,	/* - */
+	0xff,	/* GPIO_MASK */
+	0xff,	/* GPIO_MASK1 */
+	0x00,	/* - */
+	0x00,	/* GPIO_STATE */
+	0x00,	/* GPIO_STATE1 */
+	0x00,	/* - */
+};
+
+
+/* entry point */
+struct snd_ice1712_card_info snd_vt1720_mobo_cards[] __devinitdata = {
+	{
+		.subvendor = VT1720_SUBDEVICE_K8X800,
+		.name = "Albatron K8X800 Pro II",
+		.model = "k8x800",
+		.chip_init = k8x800_init,
+		.build_controls = k8x800_add_controls,
+		.eeprom_size = sizeof(k8x800_eeprom),
+		.eeprom_data = k8x800_eeprom,
+	},
+	{
+		.subvendor = VT1720_SUBDEVICE_ZNF3_150,
+		.name = "Chaintech ZNF3-150",
+		/* identical with k8x800 */
+		.chip_init = k8x800_init,
+		.build_controls = k8x800_add_controls,
+		.eeprom_size = sizeof(k8x800_eeprom),
+		.eeprom_data = k8x800_eeprom,
+	},
+	{ } /* terminator */
+};
+
--- diff/sound/pci/ice1712/vt1720_mobo.h	1970-01-01 01:00:00.000000000 +0100
+++ source/sound/pci/ice1712/vt1720_mobo.h	2004-06-11 19:22:07.000000000 +0100
@@ -0,0 +1,35 @@
+#ifndef __SOUND_VT1720_MOBO_H
+#define __SOUND_VT1720_MOBO_H
+
+/*
+ *   ALSA driver for VT1720/VT1724 (Envy24PT/Envy24HT)
+ *
+ *   Lowlevel functions for VT1720-based motherboards
+ *
+ *	Copyright (c) 2004 Takashi Iwai <tiwai@suse.de>
+ *
+ *   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
+ *
+ */      
+
+#define VT1720_MOBO_DEVICE_DESC        "{Albatron,K8X800 Pro II},"\
+				       "{Chaintech,ZNF3-150},"
+
+#define VT1720_SUBDEVICE_K8X800		0xf217052c
+#define VT1720_SUBDEVICE_ZNF3_150	0x0f2741f6
+
+extern struct snd_ice1712_card_info  snd_vt1720_mobo_cards[];
+
+#endif /* __SOUND_VT1720_MOBO_H */
--- diff/usb/host/ohci-lh7a404.c	1970-01-01 01:00:00.000000000 +0100
+++ source/usb/host/ohci-lh7a404.c	2004-06-11 19:22:08.000000000 +0100
@@ -0,0 +1,387 @@
+/*
+ * OHCI HCD (Host Controller Driver) for USB.
+ *
+ * (C) Copyright 1999 Roman Weissgaerber <weissg@vienna.at>
+ * (C) Copyright 2000-2002 David Brownell <dbrownell@users.sourceforge.net>
+ * (C) Copyright 2002 Hewlett-Packard Company
+ *
+ * Bus Glue for Sharp LH7A404
+ *
+ * Written by Christopher Hoover <ch@hpl.hp.com>
+ * Based on fragments of previous driver by Rusell King et al.
+ *
+ * Modified for LH7A404 from ohci-sa1111.c
+ *  by Durgesh Pattamatta <pattamattad@sharpsec.com>
+ *
+ * This file is licenced under the GPL.
+ */
+
+#include <asm/hardware.h>
+#include <asm/mach-types.h>
+#include <asm/arch/hardware.h>
+
+
+extern int usb_disabled(void);
+
+/*-------------------------------------------------------------------------*/
+
+static void lh7a404_start_hc(struct platform_device *dev)
+{
+	printk(KERN_DEBUG __FILE__
+	       ": starting LH7A404 OHCI USB Controller\n");
+
+	/*
+	 * Now, carefully enable the USB clock, and take
+	 * the USB host controller out of reset.
+	 */
+	CSC_PWRCNT |= CSC_PWRCNT_USBH_EN; /* Enable clock */
+	udelay(1000);
+	USBH_CMDSTATUS = OHCI_HCR;
+	
+	printk(KERN_DEBUG __FILE__
+		   ": Clock to USB host has been enabled \n");
+}
+
+static void lh7a404_stop_hc(struct platform_device *dev)
+{
+	printk(KERN_DEBUG __FILE__
+	       ": stopping LH7A404 OHCI USB Controller\n");
+
+	CSC_PWRCNT &= ~CSC_PWRCNT_USBH_EN; /* Disable clock */
+}
+
+
+/*-------------------------------------------------------------------------*/
+
+
+static irqreturn_t usb_hcd_lh7a404_hcim_irq (int irq, void *__hcd,
+					     struct pt_regs * r)
+{
+	struct usb_hcd *hcd = __hcd;
+
+	return usb_hcd_irq(irq, hcd, r);
+}
+
+/*-------------------------------------------------------------------------*/
+
+void usb_hcd_lh7a404_remove (struct usb_hcd *, struct platform_device *);
+
+/* configure so an HC device and id are always provided */
+/* always called with process context; sleeping is OK */
+
+
+/**
+ * usb_hcd_lh7a404_probe - initialize LH7A404-based HCDs
+ * Context: !in_interrupt()
+ *
+ * Allocates basic resources for this USB host controller, and
+ * then invokes the start() method for the HCD associated with it
+ * through the hotplug entry's driver_data.
+ *
+ */
+int usb_hcd_lh7a404_probe (const struct hc_driver *driver,
+			  struct usb_hcd **hcd_out,
+			  struct platform_device *dev)
+{
+	int retval;
+	struct usb_hcd *hcd = 0;
+
+	unsigned int *addr = NULL;
+
+	if (!request_mem_region(dev->resource[0].start,
+				dev->resource[0].end
+				- dev->resource[0].start + 1, hcd_name)) {
+		pr_debug("request_mem_region failed");
+		return -EBUSY;
+	}
+	
+	
+	lh7a404_start_hc(dev);
+	
+	addr = ioremap(dev->resource[0].start,
+		       dev->resource[0].end
+		       - dev->resource[0].start + 1);
+	if (!addr) {
+		pr_debug("ioremap failed");
+		retval = -ENOMEM;
+		goto err1;
+	}
+	
+
+	hcd = driver->hcd_alloc ();
+	if (hcd == NULL){
+		pr_debug ("hcd_alloc failed");
+		retval = -ENOMEM;
+		goto err1;
+	}
+
+	if(dev->resource[1].flags != IORESOURCE_IRQ){
+		pr_debug ("resource[1] is not IORESOURCE_IRQ");
+		retval = -ENOMEM;
+		goto err1;
+	}
+
+	hcd->driver = (struct hc_driver *) driver;
+	hcd->description = driver->description;
+	hcd->irq = dev->resource[1].start;
+	hcd->regs = addr;
+	hcd->self.controller = &dev->dev;
+
+	retval = hcd_buffer_create (hcd);
+	if (retval != 0) {
+		pr_debug ("pool alloc fail");
+		goto err1;
+	}
+
+	retval = request_irq (hcd->irq, usb_hcd_lh7a404_hcim_irq, SA_INTERRUPT,
+			      hcd->description, hcd);
+	if (retval != 0) {
+		pr_debug("request_irq failed");
+		retval = -EBUSY;
+		goto err2;
+	}
+
+	pr_debug ("%s (LH7A404) at 0x%p, irq %d",
+	     hcd->description, hcd->regs, hcd->irq);
+
+	usb_bus_init (&hcd->self);
+	hcd->self.op = &usb_hcd_operations;
+	hcd->self.hcpriv = (void *) hcd;
+	hcd->self.bus_name = "lh7a404";
+	hcd->product_desc = "LH7A404 OHCI";
+
+	INIT_LIST_HEAD (&hcd->dev_list);
+
+	usb_register_bus (&hcd->self);
+
+	if ((retval = driver->start (hcd)) < 0)
+	{
+		usb_hcd_lh7a404_remove(hcd, dev);
+		return retval;
+	}
+
+	*hcd_out = hcd;
+	return 0;
+
+ err2:
+	hcd_buffer_destroy (hcd);
+	if (hcd)
+		driver->hcd_free(hcd);
+ err1:
+	lh7a404_stop_hc(dev);
+	release_mem_region(dev->resource[0].start,
+				dev->resource[0].end
+			   - dev->resource[0].start + 1);
+	return retval;
+}
+
+
+/* may be called without controller electrically present */
+/* may be called with controller, bus, and devices active */
+
+/**
+ * usb_hcd_lh7a404_remove - shutdown processing for LH7A404-based HCDs
+ * @dev: USB Host Controller being removed
+ * Context: !in_interrupt()
+ *
+ * Reverses the effect of usb_hcd_lh7a404_probe(), first invoking
+ * the HCD's stop() method.  It is always called from a thread
+ * context, normally "rmmod", "apmd", or something similar.
+ *
+ */
+void usb_hcd_lh7a404_remove (struct usb_hcd *hcd, struct platform_device *dev)
+{
+	struct usb_device	*hub;
+	void *base;
+
+	pr_debug ("remove: %s, state %x", hcd->self.bus_name, hcd->state);
+
+	if (in_interrupt ())
+		BUG ();
+
+	hub = hcd->self.root_hub;
+	hcd->state = USB_STATE_QUIESCING;
+
+	pr_debug ("%s: roothub graceful disconnect", hcd->self.bus_name);
+	usb_disconnect (&hub);
+
+	hcd->driver->stop (hcd);
+	hcd->state = USB_STATE_HALT;
+
+	free_irq (hcd->irq, hcd);
+	hcd_buffer_destroy (hcd);
+
+	usb_deregister_bus (&hcd->self);
+
+	base = hcd->regs;
+	hcd->driver->hcd_free (hcd);
+
+	lh7a404_stop_hc(dev);
+	release_mem_region(dev->resource[0].start,
+			   dev->resource[0].end
+			   - dev->resource[0].start + 1);
+}
+
+/*-------------------------------------------------------------------------*/
+
+static int __devinit
+ohci_lh7a404_start (struct usb_hcd *hcd)
+{
+	struct ohci_hcd	*ohci = hcd_to_ohci (hcd);
+	int		ret;
+
+	ohci_dbg (ohci, "ohci_lh7a404_start, ohci:%p", ohci);
+			
+	ohci->hcca = dma_alloc_coherent (hcd->self.controller,
+			sizeof *ohci->hcca, &ohci->hcca_dma, 0);
+	if (!ohci->hcca)
+		return -ENOMEM;
+
+	ohci_dbg (ohci, "ohci_lh7a404_start, ohci->hcca:%p",
+			ohci->hcca);
+
+	memset (ohci->hcca, 0, sizeof (struct ohci_hcca));
+
+	if ((ret = ohci_mem_init (ohci)) < 0) {
+		ohci_stop (hcd);
+		return ret;
+	}
+	ohci->regs = hcd->regs;
+
+	if (hc_reset (ohci) < 0) {
+		ohci_stop (hcd);
+		return -ENODEV;
+	}
+
+	if (hc_start (ohci) < 0) {
+		err ("can't start %s", ohci->hcd.self.bus_name);
+		ohci_stop (hcd);
+		return -EBUSY;
+	}
+	create_debug_files (ohci);
+
+#ifdef	DEBUG
+	ohci_dump (ohci, 1);
+#endif /*DEBUG*/
+	return 0;
+}
+
+/*-------------------------------------------------------------------------*/
+
+static const struct hc_driver ohci_lh7a404_hc_driver = {
+	.description =		hcd_name,
+
+	/*
+	 * generic hardware linkage
+	 */
+	.irq =			ohci_irq,
+	.flags =		HCD_USB11,
+
+	/*
+	 * basic lifecycle operations
+	 */
+	.start =		ohci_lh7a404_start,
+#ifdef	CONFIG_PM
+	/* suspend:		ohci_lh7a404_suspend,  -- tbd */
+	/* resume:		ohci_lh7a404_resume,   -- tbd */
+#endif /*CONFIG_PM*/
+	.stop =			ohci_stop,
+
+	/*
+	 * memory lifecycle (except per-request)
+	 */
+	.hcd_alloc =		ohci_hcd_alloc,
+	.hcd_free =		ohci_hcd_free,
+
+	/*
+	 * managing i/o requests and associated device resources
+	 */
+	.urb_enqueue =		ohci_urb_enqueue,
+	.urb_dequeue =		ohci_urb_dequeue,
+	.endpoint_disable =	ohci_endpoint_disable,
+
+	/*
+	 * scheduling support
+	 */
+	.get_frame_number =	ohci_get_frame,
+
+	/*
+	 * root hub support
+	 */
+	.hub_status_data =	ohci_hub_status_data,
+	.hub_control =		ohci_hub_control,
+};
+
+/*-------------------------------------------------------------------------*/
+
+static int ohci_hcd_lh7a404_drv_probe(struct device *dev)
+{
+	struct platform_device *pdev = to_platform_device(dev);
+	struct usb_hcd *hcd = NULL;
+	int ret;
+
+	pr_debug ("In ohci_hcd_lh7a404_drv_probe");
+
+	if (usb_disabled())
+		return -ENODEV;
+
+	ret = usb_hcd_lh7a404_probe(&ohci_lh7a404_hc_driver, &hcd, pdev);
+
+	if (ret == 0)
+		dev_set_drvdata(dev, hcd);
+
+	return ret;
+}
+
+static int ohci_hcd_lh7a404_drv_remove(struct device *dev)
+{
+	struct platform_device *pdev = to_platform_device(dev);
+	struct usb_hcd *hcd = dev_get_drvdata(dev);
+
+	usb_hcd_lh7a404_remove(hcd, pdev);
+	dev_set_drvdata(dev, NULL);
+	return 0;
+}
+	/*TBD*/
+/*static int ohci_hcd_lh7a404_drv_suspend(struct device *dev)
+{
+	struct platform_device *pdev = to_platform_device(dev);
+	struct usb_hcd *hcd = dev_get_drvdata(dev);
+
+	return 0;
+}
+static int ohci_hcd_lh7a404_drv_resume(struct device *dev)
+{
+	struct platform_device *pdev = to_platform_device(dev);
+	struct usb_hcd *hcd = dev_get_drvdata(dev);
+
+
+	return 0;
+}
+*/
+
+static struct device_driver ohci_hcd_lh7a404_driver = {
+	.name		= "lh7a404-ohci",
+	.bus		= &platform_bus_type,
+	.probe		= ohci_hcd_lh7a404_drv_probe,
+	.remove		= ohci_hcd_lh7a404_drv_remove,
+	/*.suspend	= ohci_hcd_lh7a404_drv_suspend, */
+	/*.resume	= ohci_hcd_lh7a404_drv_resume, */
+};
+
+static int __init ohci_hcd_lh7a404_init (void)
+{
+	pr_debug (DRIVER_INFO " (LH7A404)");
+	pr_debug ("block sizes: ed %d td %d\n",
+		sizeof (struct ed), sizeof (struct td));
+
+	return driver_register(&ohci_hcd_lh7a404_driver);
+}
+
+static void __exit ohci_hcd_lh7a404_cleanup (void)
+{
+	driver_unregister(&ohci_hcd_lh7a404_driver);
+}
+
+module_init (ohci_hcd_lh7a404_init);
+module_exit (ohci_hcd_lh7a404_cleanup);
--- diff/arch/i386/kernel/std_resources.c	2004-05-19 22:11:00.000000000 +0100
+++ source/arch/i386/kernel/std_resources.c	1970-01-01 01:00:00.000000000 +0100
@@ -1,204 +0,0 @@
-/*
- *  Machine specific resource allocation for generic.
- */
-
-#include <linux/ioport.h>
-#include <asm/io.h>
-#include <asm/std_resources.h>
-
-#define romsignature(x) (*(unsigned short *)(x) == 0xaa55)
-
-static struct resource system_rom_resource = {
-	.name	= "System ROM",
-	.start	= 0xf0000,
-	.end	= 0xfffff,
-	.flags	= IORESOURCE_BUSY | IORESOURCE_READONLY | IORESOURCE_MEM
-};
-
-static struct resource extension_rom_resource = {
-	.name	= "Extension ROM",
-	.start	= 0xe0000,
-	.end	= 0xeffff,
-	.flags	= IORESOURCE_BUSY | IORESOURCE_READONLY | IORESOURCE_MEM
-};
-
-static struct resource adapter_rom_resources[] = { {
-	.name 	= "Adapter ROM",
-	.start	= 0xc8000,
-	.end	= 0,
-	.flags	= IORESOURCE_BUSY | IORESOURCE_READONLY | IORESOURCE_MEM
-}, {
-	.name 	= "Adapter ROM",
-	.start	= 0,
-	.end	= 0,
-	.flags	= IORESOURCE_BUSY | IORESOURCE_READONLY | IORESOURCE_MEM
-}, {
-	.name 	= "Adapter ROM",
-	.start	= 0,
-	.end	= 0,
-	.flags	= IORESOURCE_BUSY | IORESOURCE_READONLY | IORESOURCE_MEM
-}, {
-	.name 	= "Adapter ROM",
-	.start	= 0,
-	.end	= 0,
-	.flags	= IORESOURCE_BUSY | IORESOURCE_READONLY | IORESOURCE_MEM
-}, {
-	.name 	= "Adapter ROM",
-	.start	= 0,
-	.end	= 0,
-	.flags	= IORESOURCE_BUSY | IORESOURCE_READONLY | IORESOURCE_MEM
-}, {
-	.name 	= "Adapter ROM",
-	.start	= 0,
-	.end	= 0,
-	.flags	= IORESOURCE_BUSY | IORESOURCE_READONLY | IORESOURCE_MEM
-} };
-
-#define ADAPTER_ROM_RESOURCES \
-	(sizeof adapter_rom_resources / sizeof adapter_rom_resources[0])
-
-static struct resource video_rom_resource = {
-	.name 	= "Video ROM",
-	.start	= 0xc0000,
-	.end	= 0xc7fff,
-	.flags	= IORESOURCE_BUSY | IORESOURCE_READONLY | IORESOURCE_MEM
-};
-
-static struct resource vram_resource = {
-	.name	= "Video RAM area",
-	.start	= 0xa0000,
-	.end	= 0xbffff,
-	.flags	= IORESOURCE_BUSY | IORESOURCE_MEM
-};
-
-static struct resource standard_io_resources[] = { {
-	.name	= "dma1",
-	.start	= 0x0000,
-	.end	= 0x001f,
-	.flags	= IORESOURCE_BUSY | IORESOURCE_IO
-}, {
-	.name	= "pic1",
-	.start	= 0x0020,
-	.end	= 0x0021,
-	.flags	= IORESOURCE_BUSY | IORESOURCE_IO
-}, {
-	.name	= "timer",
-	.start	= 0x0040,
-	.end	= 0x005f,
-	.flags	= IORESOURCE_BUSY | IORESOURCE_IO
-}, {
-	.name	= "keyboard",
-	.start	= 0x0060,
-	.end	= 0x006f,
-	.flags	= IORESOURCE_BUSY | IORESOURCE_IO
-}, {
-	.name	= "dma page reg",
-	.start	= 0x0080,
-	.end	= 0x008f,
-	.flags	= IORESOURCE_BUSY | IORESOURCE_IO
-}, {
-	.name	= "pic2",
-	.start	= 0x00a0,
-	.end	= 0x00a1,
-	.flags	= IORESOURCE_BUSY | IORESOURCE_IO
-}, {
-	.name	= "dma2",
-	.start	= 0x00c0,
-	.end	= 0x00df,
-	.flags	= IORESOURCE_BUSY | IORESOURCE_IO
-}, {
-	.name	= "fpu",
-	.start	= 0x00f0,
-	.end	= 0x00ff,
-	.flags	= IORESOURCE_BUSY | IORESOURCE_IO
-} };
-
-#define STANDARD_IO_RESOURCES \
-	(sizeof standard_io_resources / sizeof standard_io_resources[0])
-
-static int __init checksum(unsigned char *rom, unsigned long length)
-{
-	unsigned char *p, sum = 0;
-
-	for (p = rom; p < rom + length; p++)
-		sum += *p;
-	return sum == 0;
-}
-
-void __init probe_roms(void)
-{
-	unsigned long start, length, upper;
-	unsigned char *rom;
-	int	      i;
-
-	/* video rom */
-	upper = adapter_rom_resources[0].start;
-	for (start = video_rom_resource.start; start < upper; start += 2048) {
-		rom = isa_bus_to_virt(start);
-		if (!romsignature(rom))
-			continue;
-
-		video_rom_resource.start = start;
-
-		/* 0 < length <= 0x7f * 512, historically */
-		length = rom[2] * 512;
-
-		/* if checksum okay, trust length byte */
-		if (length && checksum(rom, length))
-			video_rom_resource.end = start + length - 1;
-
-		request_resource(&iomem_resource, &video_rom_resource);
-		break;
-	}
-
-	start = (video_rom_resource.end + 1 + 2047) & ~2047UL;
-	if (start < upper)
-		start = upper;
-
-	/* system rom */
-	request_resource(&iomem_resource, &system_rom_resource);
-	upper = system_rom_resource.start;
-
-	/* check for extension rom (ignore length byte!) */
-	rom = isa_bus_to_virt(extension_rom_resource.start);
-	if (romsignature(rom)) {
-		length = extension_rom_resource.end - extension_rom_resource.start + 1;
-		if (checksum(rom, length)) {
-			request_resource(&iomem_resource, &extension_rom_resource);
-			upper = extension_rom_resource.start;
-		}
-	}
-
-	/* check for adapter roms on 2k boundaries */
-	for (i = 0; i < ADAPTER_ROM_RESOURCES && start < upper; start += 2048) {
-		rom = isa_bus_to_virt(start);
-		if (!romsignature(rom))
-			continue;
-
-		/* 0 < length <= 0x7f * 512, historically */
-		length = rom[2] * 512;
-
-		/* but accept any length that fits if checksum okay */
-		if (!length || start + length > upper || !checksum(rom, length))
-			continue;
-
-		adapter_rom_resources[i].start = start;
-		adapter_rom_resources[i].end = start + length - 1;
-		request_resource(&iomem_resource, &adapter_rom_resources[i]);
-
-		start = adapter_rom_resources[i++].end & ~2047UL;
-	}
-}
-
-void __init request_graphics_resource(void)
-{
-	request_resource(&iomem_resource, &vram_resource);
-}
-
-void __init request_standard_io_resources(void)
-{
-	int i;
-
-	for (i = 0; i < STANDARD_IO_RESOURCES; i++)
-		request_resource(&ioport_resource, &standard_io_resources[i]);
-}
--- diff/include/asm-alpha/cpumask.h	2004-05-19 22:12:34.000000000 +0100
+++ source/include/asm-alpha/cpumask.h	1970-01-01 01:00:00.000000000 +0100
@@ -1,6 +0,0 @@
-#ifndef _ASM_ALPHA_CPUMASK_H
-#define _ASM_ALPHA_CPUMASK_H
-
-#include <asm-generic/cpumask.h>
-
-#endif /* _ASM_ALPHA_CPUMASK_H */
--- diff/include/asm-arm/cpumask.h	2004-05-19 22:12:34.000000000 +0100
+++ source/include/asm-arm/cpumask.h	1970-01-01 01:00:00.000000000 +0100
@@ -1,6 +0,0 @@
-#ifndef _ASM_ARM_CPUMASK_H
-#define _ASM_ARM_CPUMASK_H
-
-#include <asm-generic/cpumask.h>
-
-#endif /* _ASM_ARM_CPUMASK_H */
--- diff/include/asm-arm26/cpumask.h	2004-05-19 22:12:38.000000000 +0100
+++ source/include/asm-arm26/cpumask.h	1970-01-01 01:00:00.000000000 +0100
@@ -1,6 +0,0 @@
-#ifndef _ASM_ARM26_CPUMASK_H
-#define _ASM_ARM26_CPUMASK_H
-
-#include <asm-generic/cpumask.h>
-
-#endif /* _ASM_ARM26_CPUMASK_H */
--- diff/include/asm-cris/cpumask.h	2004-05-19 22:12:38.000000000 +0100
+++ source/include/asm-cris/cpumask.h	1970-01-01 01:00:00.000000000 +0100
@@ -1,6 +0,0 @@
-#ifndef _ASM_CRIS_CPUMASK_H
-#define _ASM_CRIS_CPUMASK_H
-
-#include <asm-generic/cpumask.h>
-
-#endif /* _ASM_CRIS_CPUMASK_H */
--- diff/include/asm-generic/cpumask.h	2004-05-19 22:12:39.000000000 +0100
+++ source/include/asm-generic/cpumask.h	1970-01-01 01:00:00.000000000 +0100
@@ -1,40 +0,0 @@
-#ifndef __ASM_GENERIC_CPUMASK_H
-#define __ASM_GENERIC_CPUMASK_H
-
-#include <linux/config.h>
-#include <linux/kernel.h>
-#include <linux/threads.h>
-#include <linux/types.h>
-#include <linux/bitmap.h>
-
-#if NR_CPUS > BITS_PER_LONG && NR_CPUS != 1
-#define CPU_ARRAY_SIZE		BITS_TO_LONGS(NR_CPUS)
-
-struct cpumask
-{
-	unsigned long mask[CPU_ARRAY_SIZE];
-};
-
-typedef struct cpumask cpumask_t;
-
-#else
-typedef unsigned long cpumask_t;
-#endif
-
-#ifdef CONFIG_SMP
-#if NR_CPUS > BITS_PER_LONG
-#include <asm-generic/cpumask_array.h>
-#else
-#include <asm-generic/cpumask_arith.h>
-#endif
-#else
-#include <asm-generic/cpumask_up.h>
-#endif
-
-#if NR_CPUS <= 4*BITS_PER_LONG
-#include <asm-generic/cpumask_const_value.h>
-#else
-#include <asm-generic/cpumask_const_reference.h>
-#endif
-
-#endif /* __ASM_GENERIC_CPUMASK_H */
--- diff/include/asm-generic/cpumask_arith.h	2004-05-19 22:12:39.000000000 +0100
+++ source/include/asm-generic/cpumask_arith.h	1970-01-01 01:00:00.000000000 +0100
@@ -1,49 +0,0 @@
-#ifndef __ASM_GENERIC_CPUMASK_ARITH_H
-#define __ASM_GENERIC_CPUMASK_ARITH_H
-
-/*
- * Arithmetic type -based cpu bitmaps. A single unsigned long is used
- * to contain the whole cpu bitmap.
- */
-
-#define cpu_set(cpu, map)		set_bit(cpu, &(map))
-#define cpu_clear(cpu, map)		clear_bit(cpu, &(map))
-#define cpu_isset(cpu, map)		test_bit(cpu, &(map))
-#define cpu_test_and_set(cpu, map)	test_and_set_bit(cpu, &(map))
-
-#define cpus_and(dst,src1,src2)		do { dst = (src1) & (src2); } while (0)
-#define cpus_or(dst,src1,src2)		do { dst = (src1) | (src2); } while (0)
-#define cpus_clear(map)			do { map = 0; } while (0)
-#define cpus_complement(map)		do { map = ~(map); } while (0)
-#define cpus_equal(map1, map2)		((map1) == (map2))
-#define cpus_empty(map)			((map) == 0)
-#define cpus_addr(map)			(&(map))
-
-#if BITS_PER_LONG == 32
-#define cpus_weight(map)		hweight32(map)
-#elif BITS_PER_LONG == 64
-#define cpus_weight(map)		hweight64(map)
-#endif
-
-#define cpus_shift_right(dst, src, n)	do { dst = (src) >> (n); } while (0)
-#define cpus_shift_left(dst, src, n)	do { dst = (src) << (n); } while (0)
-
-#define any_online_cpu(map)			\
-({						\
-	cpumask_t __tmp__;			\
-	cpus_and(__tmp__, map, cpu_online_map);	\
-	__tmp__ ? first_cpu(__tmp__) : NR_CPUS;	\
-})
-
-#define CPU_MASK_ALL	(~((cpumask_t)0) >> (8*sizeof(cpumask_t) - NR_CPUS))
-#define CPU_MASK_NONE	((cpumask_t)0)
-
-/* only ever use this for things that are _never_ used on large boxen */
-#define cpus_coerce(map)		((unsigned long)(map))
-#define cpus_promote(map)		({ map; })
-#define cpumask_of_cpu(cpu)		({ ((cpumask_t)1) << (cpu); })
-
-#define first_cpu(map)			find_first_bit(&(map), NR_CPUS)
-#define next_cpu(cpu, map)		find_next_bit(&(map), NR_CPUS, cpu + 1)
-
-#endif /* __ASM_GENERIC_CPUMASK_ARITH_H */
--- diff/include/asm-generic/cpumask_array.h	2004-05-19 22:12:39.000000000 +0100
+++ source/include/asm-generic/cpumask_array.h	1970-01-01 01:00:00.000000000 +0100
@@ -1,54 +0,0 @@
-#ifndef __ASM_GENERIC_CPUMASK_ARRAY_H
-#define __ASM_GENERIC_CPUMASK_ARRAY_H
-
-/*
- * Array-based cpu bitmaps. An array of unsigned longs is used to contain
- * the bitmap, and then contained in a structure so it may be passed by
- * value.
- */
-
-#define CPU_ARRAY_SIZE		BITS_TO_LONGS(NR_CPUS)
-
-#define cpu_set(cpu, map)		set_bit(cpu, (map).mask)
-#define cpu_clear(cpu, map)		clear_bit(cpu, (map).mask)
-#define cpu_isset(cpu, map)		test_bit(cpu, (map).mask)
-#define cpu_test_and_set(cpu, map)	test_and_set_bit(cpu, (map).mask)
-
-#define cpus_and(dst,src1,src2)	bitmap_and((dst).mask,(src1).mask, (src2).mask, NR_CPUS)
-#define cpus_or(dst,src1,src2)	bitmap_or((dst).mask, (src1).mask, (src2).mask, NR_CPUS)
-#define cpus_clear(map)		bitmap_zero((map).mask, NR_CPUS)
-#define cpus_complement(map)	bitmap_complement((map).mask, NR_CPUS)
-#define cpus_equal(map1, map2)	bitmap_equal((map1).mask, (map2).mask, NR_CPUS)
-#define cpus_empty(map)		bitmap_empty(map.mask, NR_CPUS)
-#define cpus_addr(map)		((map).mask)
-#define cpus_weight(map)		bitmap_weight((map).mask, NR_CPUS)
-#define cpus_shift_right(d, s, n)	bitmap_shift_right((d).mask, (s).mask, n, NR_CPUS)
-#define cpus_shift_left(d, s, n)	bitmap_shift_left((d).mask, (s).mask, n, NR_CPUS)
-#define first_cpu(map)		find_first_bit((map).mask, NR_CPUS)
-#define next_cpu(cpu, map)	find_next_bit((map).mask, NR_CPUS, cpu + 1)
-
-/* only ever use this for things that are _never_ used on large boxen */
-#define cpus_coerce(map)	((map).mask[0])
-#define cpus_promote(map)	({ cpumask_t __cpu_mask = CPU_MASK_NONE;\
-					__cpu_mask.mask[0] = map;	\
-					__cpu_mask;			\
-				})
-#define cpumask_of_cpu(cpu)	({ cpumask_t __cpu_mask = CPU_MASK_NONE;\
-					cpu_set(cpu, __cpu_mask);	\
-					__cpu_mask;			\
-				})
-#define any_online_cpu(map)			\
-({						\
-	cpumask_t __tmp__;			\
-	cpus_and(__tmp__, map, cpu_online_map);	\
-	find_first_bit(__tmp__.mask, NR_CPUS);	\
-})
-
-
-/*
- * um, these need to be usable as static initializers
- */
-#define CPU_MASK_ALL	((cpumask_t) { {[0 ... CPU_ARRAY_SIZE-1] = ~0UL} })
-#define CPU_MASK_NONE	((cpumask_t) { {[0 ... CPU_ARRAY_SIZE-1] =  0UL} })
-
-#endif /* __ASM_GENERIC_CPUMASK_ARRAY_H */
--- diff/include/asm-generic/cpumask_const_reference.h	2004-05-19 22:12:39.000000000 +0100
+++ source/include/asm-generic/cpumask_const_reference.h	1970-01-01 01:00:00.000000000 +0100
@@ -1,29 +0,0 @@
-#ifndef __ASM_GENERIC_CPUMASK_CONST_REFERENCE_H
-#define __ASM_GENERIC_CPUMASK_CONST_REFERENCE_H
-
-struct cpumask_ref {
-	const cpumask_t *val;
-};
-
-typedef const struct cpumask_ref cpumask_const_t;
-
-#define mk_cpumask_const(map)		((cpumask_const_t){ &(map) })
-#define cpu_isset_const(cpu, map)	cpu_isset(cpu, *(map).val)
-
-#define cpus_and_const(dst,src1,src2)	cpus_and(dst,*(src1).val,*(src2).val)
-#define cpus_or_const(dst,src1,src2)	cpus_or(dst,*(src1).val,*(src2).val)
-
-#define cpus_equal_const(map1, map2)	cpus_equal(*(map1).val, *(map2).val)
-
-#define cpus_copy_const(map1, map2)	bitmap_copy((map1).mask, (map2).val->mask, NR_CPUS)
-
-#define cpus_empty_const(map)		cpus_empty(*(map).val)
-#define cpus_weight_const(map)		cpus_weight(*(map).val)
-#define first_cpu_const(map)		first_cpu(*(map).val)
-#define next_cpu_const(cpu, map)	next_cpu(cpu, *(map).val)
-
-/* only ever use this for things that are _never_ used on large boxen */
-#define cpus_coerce_const(map)		cpus_coerce(*(map).val)
-#define any_online_cpu_const(map)	any_online_cpu(*(map).val)
-
-#endif /* __ASM_GENERIC_CPUMASK_CONST_REFERENCE_H */
--- diff/include/asm-generic/cpumask_const_value.h	2004-05-19 22:12:39.000000000 +0100
+++ source/include/asm-generic/cpumask_const_value.h	1970-01-01 01:00:00.000000000 +0100
@@ -1,21 +0,0 @@
-#ifndef __ASM_GENERIC_CPUMASK_CONST_VALUE_H
-#define __ASM_GENERIC_CPUMASK_CONST_VALUE_H
-
-typedef const cpumask_t cpumask_const_t;
-
-#define mk_cpumask_const(map)		(map)
-#define cpu_isset_const(cpu, map)	cpu_isset(cpu, map)
-#define cpus_and_const(dst,src1,src2)	cpus_and(dst, src1, src2)
-#define cpus_or_const(dst,src1,src2)	cpus_or(dst, src1, src2)
-#define cpus_equal_const(map1, map2)	cpus_equal(map1, map2)
-#define cpus_empty_const(map)		cpus_empty(map)
-#define cpus_copy_const(map1, map2)	do { map1 = (cpumask_t)map2; } while (0)
-#define cpus_weight_const(map)		cpus_weight(map)
-#define first_cpu_const(map)		first_cpu(map)
-#define next_cpu_const(cpu, map)	next_cpu(cpu, map)
-
-/* only ever use this for things that are _never_ used on large boxen */
-#define cpus_coerce_const(map)		cpus_coerce(map)
-#define any_online_cpu_const(map)	any_online_cpu(map)
-
-#endif /* __ASM_GENERIC_CPUMASK_CONST_VALUE_H */
--- diff/include/asm-generic/cpumask_up.h	2004-05-19 22:12:39.000000000 +0100
+++ source/include/asm-generic/cpumask_up.h	1970-01-01 01:00:00.000000000 +0100
@@ -1,59 +0,0 @@
-#ifndef __ASM_GENERIC_CPUMASK_UP_H
-#define __ASM_GENERIC_CPUMASK_UP_H
-
-#define cpus_coerce(map)	(map)
-
-#define cpu_set(cpu, map)		do { (void)(cpu); cpus_coerce(map) = 1UL; } while (0)
-#define cpu_clear(cpu, map)		do { (void)(cpu); cpus_coerce(map) = 0UL; } while (0)
-#define cpu_isset(cpu, map)		((void)(cpu), cpus_coerce(map) != 0UL)
-#define cpu_test_and_set(cpu, map)	((void)(cpu), test_and_set_bit(0, &(map)))
-
-#define cpus_and(dst, src1, src2)					\
-	do {								\
-		if (cpus_coerce(src1) && cpus_coerce(src2))		\
-			cpus_coerce(dst) = 1UL;				\
-		else							\
-			cpus_coerce(dst) = 0UL;				\
-	} while (0)
-
-#define cpus_or(dst, src1, src2)					\
-	do {								\
-		if (cpus_coerce(src1) || cpus_coerce(src2))		\
-			cpus_coerce(dst) = 1UL;				\
-		else							\
-			cpus_coerce(dst) = 0UL;				\
-	} while (0)
-
-#define cpus_clear(map)			do { cpus_coerce(map) = 0UL; } while (0)
-
-#define cpus_complement(map)						\
-	do {								\
-		cpus_coerce(map) = !cpus_coerce(map);			\
-	} while (0)
-
-#define cpus_equal(map1, map2)		(cpus_coerce(map1) == cpus_coerce(map2))
-#define cpus_empty(map)			(cpus_coerce(map) == 0UL)
-#define cpus_addr(map)			(&(map))
-#define cpus_weight(map)		(cpus_coerce(map) ? 1UL : 0UL)
-#define cpus_shift_right(d, s, n)	do { cpus_coerce(d) = 0UL; } while (0)
-#define cpus_shift_left(d, s, n)	do { cpus_coerce(d) = 0UL; } while (0)
-#define first_cpu(map)			(cpus_coerce(map) ? 0 : 1)
-#define next_cpu(cpu, map)		1
-
-/* only ever use this for things that are _never_ used on large boxen */
-#define cpus_promote(map)						\
-	({								\
-		cpumask_t __tmp__;					\
-		cpus_coerce(__tmp__) = map;				\
-		__tmp__;						\
-	})
-#define cpumask_of_cpu(cpu)		((void)(cpu), cpus_promote(1))
-#define any_online_cpu(map)		(cpus_coerce(map) ? 0 : 1)
-
-/*
- * um, these need to be usable as static initializers
- */
-#define CPU_MASK_ALL	1UL
-#define CPU_MASK_NONE	0UL
-
-#endif /* __ASM_GENERIC_CPUMASK_UP_H */
--- diff/include/asm-h8300/cpumask.h	2004-05-19 22:12:39.000000000 +0100
+++ source/include/asm-h8300/cpumask.h	1970-01-01 01:00:00.000000000 +0100
@@ -1,6 +0,0 @@
-#ifndef _ASM_H8300_CPUMASK_H
-#define _ASM_H8300_CPUMASK_H
-
-#include <asm-generic/cpumask.h>
-
-#endif /* _ASM_H8300_CPUMASK_H */
--- diff/include/asm-i386/cpumask.h	2004-05-19 22:12:40.000000000 +0100
+++ source/include/asm-i386/cpumask.h	1970-01-01 01:00:00.000000000 +0100
@@ -1,6 +0,0 @@
-#ifndef _ASM_I386_CPUMASK_H
-#define _ASM_I386_CPUMASK_H
-
-#include <asm-generic/cpumask.h>
-
-#endif /* _ASM_I386_CPUMASK_H */
--- diff/include/asm-i386/std_resources.h	2004-05-19 22:12:40.000000000 +0100
+++ source/include/asm-i386/std_resources.h	1970-01-01 01:00:00.000000000 +0100
@@ -1,14 +0,0 @@
-/*
- * include/asm-i386/std_resources.h
- */
-
-#ifndef __ASM_I386_STD_RESOURCES_H
-#define __ASM_I386_STD_RESOURCES_H
-
-#include <linux/init.h>
-
-void probe_roms(void) __init;
-void request_graphics_resource(void) __init;
-void request_standard_io_resources(void) __init;
-
-#endif
--- diff/include/asm-ia64/cpumask.h	2004-05-19 22:12:41.000000000 +0100
+++ source/include/asm-ia64/cpumask.h	1970-01-01 01:00:00.000000000 +0100
@@ -1,6 +0,0 @@
-#ifndef _ASM_IA64_CPUMASK_H
-#define _ASM_IA64_CPUMASK_H
-
-#include <asm-generic/cpumask.h>
-
-#endif /* _ASM_IA64_CPUMASK_H */
--- diff/include/asm-m68k/cpumask.h	2004-05-19 22:12:44.000000000 +0100
+++ source/include/asm-m68k/cpumask.h	1970-01-01 01:00:00.000000000 +0100
@@ -1,6 +0,0 @@
-#ifndef _ASM_M68K_CPUMASK_H
-#define _ASM_M68K_CPUMASK_H
-
-#include <asm-generic/cpumask.h>
-
-#endif /* _ASM_M68K_CPUMASK_H */
--- diff/include/asm-m68knommu/cpumask.h	2004-05-19 22:12:45.000000000 +0100
+++ source/include/asm-m68knommu/cpumask.h	1970-01-01 01:00:00.000000000 +0100
@@ -1,6 +0,0 @@
-#ifndef _ASM_M68KNOMMU_CPUMASK_H
-#define _ASM_M68KNOMMU_CPUMASK_H
-
-#include <asm-generic/cpumask.h>
-
-#endif /* _ASM_M68KNOMMU_CPUMASK_H */
--- diff/include/asm-mips/cpumask.h	2004-05-19 22:12:45.000000000 +0100
+++ source/include/asm-mips/cpumask.h	1970-01-01 01:00:00.000000000 +0100
@@ -1,6 +0,0 @@
-#ifndef _ASM_MIPS_CPUMASK_H
-#define _ASM_MIPS_CPUMASK_H
-
-#include <asm-generic/cpumask.h>
-
-#endif /* _ASM_MIPS_CPUMASK_H */
--- diff/include/asm-parisc/cpumask.h	2004-05-19 22:12:48.000000000 +0100
+++ source/include/asm-parisc/cpumask.h	1970-01-01 01:00:00.000000000 +0100
@@ -1,6 +0,0 @@
-#ifndef _ASM_PARISC_CPUMASK_H
-#define _ASM_PARISC_CPUMASK_H
-
-#include <asm-generic/cpumask.h>
-
-#endif /* _ASM_PARISC_CPUMASK_H */
--- diff/include/asm-ppc/cpumask.h	2004-05-19 22:12:49.000000000 +0100
+++ source/include/asm-ppc/cpumask.h	1970-01-01 01:00:00.000000000 +0100
@@ -1,6 +0,0 @@
-#ifndef _ASM_PPC_CPUMASK_H
-#define _ASM_PPC_CPUMASK_H
-
-#include <asm-generic/cpumask.h>
-
-#endif /* _ASM_PPC_CPUMASK_H */
--- diff/include/asm-ppc64/cpumask.h	2004-05-19 22:12:51.000000000 +0100
+++ source/include/asm-ppc64/cpumask.h	1970-01-01 01:00:00.000000000 +0100
@@ -1,6 +0,0 @@
-#ifndef _ASM_PPC64_CPUMASK_H
-#define _ASM_PPC64_CPUMASK_H
-
-#include <asm-generic/cpumask.h>
-
-#endif /* _ASM_PPC64_CPUMASK_H */
--- diff/include/asm-s390/cpumask.h	2004-05-19 22:12:52.000000000 +0100
+++ source/include/asm-s390/cpumask.h	1970-01-01 01:00:00.000000000 +0100
@@ -1,6 +0,0 @@
-#ifndef _ASM_S390_CPUMASK_H
-#define _ASM_S390_CPUMASK_H
-
-#include <asm-generic/cpumask.h>
-
-#endif /* _ASM_S390_CPUMASK_H */
--- diff/include/asm-sh/cpumask.h	2004-05-19 22:12:53.000000000 +0100
+++ source/include/asm-sh/cpumask.h	1970-01-01 01:00:00.000000000 +0100
@@ -1,6 +0,0 @@
-#ifndef _ASM_SH_CPUMASK_H
-#define _ASM_SH_CPUMASK_H
-
-#include <asm-generic/cpumask.h>
-
-#endif /* _ASM_SH_CPUMASK_H */
--- diff/include/asm-sparc/cpumask.h	2004-05-19 22:12:55.000000000 +0100
+++ source/include/asm-sparc/cpumask.h	1970-01-01 01:00:00.000000000 +0100
@@ -1,6 +0,0 @@
-#ifndef _ASM_SPARC_CPUMASK_H
-#define _ASM_SPARC_CPUMASK_H
-
-#include <asm-generic/cpumask.h>
-
-#endif /* _ASM_SPARC_CPUMASK_H */
--- diff/include/asm-sparc64/cpumask.h	2004-05-19 22:12:56.000000000 +0100
+++ source/include/asm-sparc64/cpumask.h	1970-01-01 01:00:00.000000000 +0100
@@ -1,6 +0,0 @@
-#ifndef _ASM_SPARC64_CPUMASK_H
-#define _ASM_SPARC64_CPUMASK_H
-
-#include <asm-generic/cpumask.h>
-
-#endif /* _ASM_SPARC64_CPUMASK_H */
--- diff/include/asm-um/cpumask.h	2004-05-19 22:12:57.000000000 +0100
+++ source/include/asm-um/cpumask.h	1970-01-01 01:00:00.000000000 +0100
@@ -1,6 +0,0 @@
-#ifndef _ASM_UM_CPUMASK_H
-#define _ASM_UM_CPUMASK_H
-
-#include <asm-generic/cpumask.h>
-
-#endif /* _ASM_UM_CPUMASK_H */
--- diff/include/asm-v850/cpumask.h	2004-05-19 22:12:57.000000000 +0100
+++ source/include/asm-v850/cpumask.h	1970-01-01 01:00:00.000000000 +0100
@@ -1,6 +0,0 @@
-#ifndef _ASM_V850_CPUMASK_H
-#define _ASM_V850_CPUMASK_H
-
-#include <asm-generic/cpumask.h>
-
-#endif /* _ASM_V850_CPUMASK_H */
--- diff/include/asm-x86_64/cpumask.h	2004-05-19 22:12:57.000000000 +0100
+++ source/include/asm-x86_64/cpumask.h	1970-01-01 01:00:00.000000000 +0100
@@ -1,6 +0,0 @@
-#ifndef _ASM_X86_64_CPUMASK_H
-#define _ASM_X86_64_CPUMASK_H
-
-#include <asm-generic/cpumask.h>
-
-#endif /* _ASM_X86_64_CPUMASK_H */
