## Automatically generated incremental diff
## From:   linux-2.4.6-pre5
## To:     linux-2.4.6-pre6
## Robot:  $Id: make-incremental-diff,v 1.8 2001/12/04 06:05:04 hpa Exp $

diff -urN linux-2.4.6-pre5/CREDITS linux/CREDITS
--- linux-2.4.6-pre5/CREDITS	Mon Dec  3 22:49:00 2001
+++ linux/CREDITS	Mon Dec  3 22:49:10 2001
@@ -454,6 +454,11 @@
 E: xavyer@ix.netcom.com
 D: USB Serial Empeg Empeg-car Mark I/II Driver
 
+N: Matthias Bruestle
+E: m@mbsks.franken.de
+D: REINER SCT cyberJack pinpad/e-com USB chipcard reader driver
+S: Germany
+
 N: Ray Burr
 E: ryb@nightmare.com
 D: Original author of Amiga FFS filesystem
@@ -1136,13 +1141,11 @@
 S: USA
 
 N: Benjamin Herrenschmidt
-E: bh40@calva.net
+E: benh@kernel.crashing.org
 E: benh@mipsys.com
-D: PowerMac booter (BootX)
-D: Additional PowerBook support
-D: Apple "Core99" machines support (ibook,g4,...)
-S: 22, rue des Marguettes
-S: 75012 Paris
+D: Various parts of PPC & PowerMac
+S: 122, boulevard Baille
+S: 13005 Marseille
 S: France
 
 N: Sebastian Hetze
@@ -1755,6 +1758,8 @@
 
 N: Paul Mackerras
 E: paulus@samba.org
+D: PPP driver
+D: Linux for PowerPC
 D: Linux port for PCI Power Macintosh
 
 N: Pat Mackinlay
@@ -2894,6 +2899,14 @@
 S: X/OS Experts in Open Systems BV
 S: Kruislaan 419
 S: 1098 VA Amsterdam 
+S: The Netherlands
+
+N: Jeroen Vreeken
+E: pe1rxq@amsat.org
+W: http://www.chello.nl/~j.vreeken/
+D: SE401 usb webcam driver
+S: Maastrichterweg 63
+S: 5554 GG Valkenswaard
 S: The Netherlands
 
 N: Peter Shaobo Wang
diff -urN linux-2.4.6-pre5/Documentation/Changes linux/Documentation/Changes
--- linux-2.4.6-pre5/Documentation/Changes	Mon Dec  3 22:49:00 2001
+++ linux/Documentation/Changes	Mon Dec  3 22:49:10 2001
@@ -347,7 +347,7 @@
 
 PPP
 ---
-o  <ftp://ftp.samba.org/ppp/ppp-2.4.0.tar.gz>
+o  <ftp://ftp.samba.org/pub/ppp/ppp-2.4.0.tar.gz>
 
 Isdn4k-utils
 ------------
diff -urN linux-2.4.6-pre5/Documentation/Configure.help linux/Documentation/Configure.help
--- linux-2.4.6-pre5/Documentation/Configure.help	Mon Dec  3 22:49:01 2001
+++ linux/Documentation/Configure.help	Mon Dec  3 22:49:10 2001
@@ -11243,6 +11243,29 @@
   The module will be called mct_u232.o.  If you want to compile it as
   a module, say M here and read Documentation/modules.txt.
 
+USB Prolific 2303 Single Port Serial Driver
+CONFIG_USB_SERIAL_PL2303
+  Say Y here if you want to use the PL2303 USB Serial single port
+  adapter from Prolific.
+
+  This code is also available as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want).
+  The module will be called pl2303.o.  If you want to compile it as
+  a module, say M here and read Documentation/modules.txt.
+
+USB REINER SCT cyberJack pinpad/e-com chipcard reader
+CONFIG_USB_SERIAL_CYBERJACK
+  Say Y here if you want to use a cyberJack pinpad/e-com USB chipcard
+  reader. This is an interface to ISO 7816 compatible contactbased
+  chipcards, e.g. GSM SIMs.
+ 
+  This code is also available as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want).
+  The module will be called cyberjack.o. If you want to compile it as
+  a module, say M here and read Documentation/modules.txt.
+ 
+  If unsure, say N.
+
 USB Edgeport Serial Driver
 CONFIG_USB_SERIAL_EDGEPORT
   Say Y here if you want to use any of the following devices from
@@ -11347,6 +11370,22 @@
   The module will be called pwc.o. If you want to compile it as a
   module, say M here and read Documentation/modules.txt.
 
+
+USB SE401 Camera support
+CONFIG_USB_SE401
+  Say Y here if you want to connect this type of camera to your
+  computer's USB port. See Documentation/usb/se401.txt for more
+  information and for a list of supported cameras.
+  
+  This driver uses the Video For Linux API. You must say Y or M to
+  "Video For Linux" (under Multimedia Devices) to use this driver.
+  Information on this API and pointers to "v4l" programs may be found
+  on the WWW at http://roadrunner.swansea.uk.linux.org/v4l.shtml .
+
+  This code is also available as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want).
+  The module will be called se401.o. If you want to compile it as a
+  module, say M here and read Documentation/modules.txt.
 
 USB ADMtek Pegasus-based ethernet device support
 CONFIG_USB_PEGASUS
diff -urN linux-2.4.6-pre5/Documentation/java.txt linux/Documentation/java.txt
--- linux-2.4.6-pre5/Documentation/java.txt	Thu Jul  1 10:47:08 1999
+++ linux/Documentation/java.txt	Mon Dec  3 22:49:10 2001
@@ -1,4 +1,4 @@
-               Java(tm) Binary Kernel Support for Linux v1.02
+               Java(tm) Binary Kernel Support for Linux v1.03
                ----------------------------------------------
 
 Linux beats them ALL! While all other OS's are TALKING about direct
@@ -30,6 +30,8 @@
    (you should really have read binfmt_misc.txt now):
    support for Java applications:
      ':Java:M::\xca\xfe\xba\xbe::/usr/local/bin/javawrapper:'
+   support for executable Jar files:
+     ':ExecutableJAR:E::jar::/usr/local/bin/jarwrapper:'
    support for Java Applets:
      ':Applet:E::html::/usr/bin/appletviewer:'
    or the following, if you want to be more selective:
@@ -343,7 +345,15 @@
 ====================== Cut here ===================
 
 
-Now simply chmod +x the .class and/or .html files you want to execute.
+====================== Cut here ===================
+#!/bin/bash
+# /usr/local/java/bin/jarwrapper - the wrapper for binfmt_misc/jar
+
+java -jar $1
+====================== Cut here ===================
+
+
+Now simply chmod +x the .class, .jar and/or .html files you want to execute.
 To add a Java program to your path best put a symbolic link to the main
 .class file into /usr/bin (or another place you like) omitting the .class
 extension. The directory containing the original .class file will be
@@ -369,6 +379,11 @@
 	./HelloWorld.class
 
 
+To execute Java Jar files, simple chmod the *.jar files to include
+the execution bit, then just do
+       ./Application.jar
+
+
 To execute Java Applets, simple chmod the *.html files to include
 the execution bit, then just do
 	./Applet.html
@@ -376,5 +391,6 @@
 
 originally by Brian A. Lantz, brian@lantz.com
 heavily edited for binfmt_misc by Richard Günther
-new scripts by Colin J. Watson <cjw44@cam.ac.uk>.
+new scripts by Colin J. Watson <cjw44@cam.ac.uk>
+added executable Jar file support by Kurt Huwig <kurt@iku-netz.de>
 
diff -urN linux-2.4.6-pre5/Documentation/usb/se401.txt linux/Documentation/usb/se401.txt
--- linux-2.4.6-pre5/Documentation/usb/se401.txt	Wed Dec 31 16:00:00 1969
+++ linux/Documentation/usb/se401.txt	Mon Dec  3 22:49:10 2001
@@ -0,0 +1,54 @@
+Linux driver for SE401 based USB cameras
+
+Copyright, 2001, Jeroen Vreeken
+
+
+INTRODUCTION:
+
+The SE401 chip is the used in low-cost usb webcams.
+It is produced by Endpoints Inc. (www.endpoints.com).
+It interfaces directly to a cmos image sensor and USB. The only other major
+part in a se401 based camera is a dram chip.
+
+The following cameras are known to work with this driver:
+
+Aox se401 (non-branded) cameras
+Philips PVCV665 USB VGA webcam 'Vesta Fun'
+Kensington VideoCAM PC Camera Model 67014
+Kensington VideoCAM PC Camera Model 67015
+Kensington VideoCAM PC Camera Model 67016
+Kensington VideoCAM PC Camera Model 67017
+
+
+WHAT YOU NEED:
+
+-	USB support
+-	VIDEO4LINUX support
+
+More information about USB support for linux can be found at:
+http://www.linux-usb.org
+
+
+MODULE OPTIONS:
+
+When the driver is compiled as a module you can also use the 'flickerless'
+option. With it exposure is limited to values that do not interfere with the
+net frequency. Valid options for this option are 0, 50 and 60. (0=disable,
+50=50hz, 60=60hz)
+
+
+KNOWN PROBLEMS:
+
+The driver works fine with the usb-ohci and uhci host controller drivers,
+the default settings also work with usb-uhci. But sending more then one bulk
+transfer at a time with usb-uhci doesn't work yet.
+Users of usb-ohci and uhci can safely enlarge SE401_NUMSBUF in se401.h in
+order to increase the throughput (and thus framerate).
+
+
+HELP:
+
+The latest info on this driver can be found at:
+http://www.chello.nl/~j.vreeken/se401/
+And questions to me can be send to:
+pe1rxq@amsat.org
diff -urN linux-2.4.6-pre5/Documentation/usb/usb-serial.txt linux/Documentation/usb/usb-serial.txt
--- linux-2.4.6-pre5/Documentation/usb/usb-serial.txt	Mon Mar 19 17:21:54 2001
+++ linux/Documentation/usb/usb-serial.txt	Mon Dec  3 22:49:10 2001
@@ -245,6 +245,17 @@
        Edgeport/16 Dual
 
 
+REINER SCT cyberJack pinpad/e-com USB chipcard reader
+   
+  Interface to ISO 7816 compatible contactbased chipcards, e.g. GSM SIMs.
+  
+Current status:
+  This is the kernel part of the driver for this USB card reader.
+  There is also a user part for a CT-API driver available. A site
+  for downloading is TBA. For now, you can request it from the
+  maintainer (linux-usb@sii.li).
+
+
 Generic Serial driver
 
   If your device is not one of the above listed devices, compatible with
diff -urN linux-2.4.6-pre5/MAINTAINERS linux/MAINTAINERS
--- linux-2.4.6-pre5/MAINTAINERS	Mon Dec  3 22:49:01 2001
+++ linux/MAINTAINERS	Mon Dec  3 22:49:10 2001
@@ -784,15 +784,21 @@
 L:	linux-x25@vger.kernel.org
 S:	Maintained
 
+LINUX FOR IBM pSERIES (RS/6000)
+P:	Paul Mackerras
+M:	paulus@au.ibm.com
+W:	http://www.ibm.com/linux/ltc/projects/ppc
+S:	Supported
+
 LINUX FOR POWERPC
-P:	Cort Dougan
-M:	cort@fsmlabs.com
+P:	Paul Mackerras
+M:	paulus@samba.org
 W:	http://www.fsmlabs.com/linuxppcbk.html
-S:	Maintained
+S:	Supported
 
 LINUX FOR POWER MACINTOSH
-P:	Paul Mackerras
-M:	paulus@samba.org
+P:	Benjamin Herrenschmidt
+M:	benh@kernel.crashing.org
 W:	http://www.linuxppc.org/
 L:	linuxppc-dev@lists.linuxppc.org
 S:	Maintained
@@ -1461,6 +1467,12 @@
 L:	linux-usb-users@lists.sourceforge.net
 L:	linux-usb-devel@lists.sourceforge.net
 S:	Maintained
+
+USB SERIAL CYBERJACK PINPAD/E-COM DRIVER
+M:  linux-usb@sii.li
+L:  linux-usb-users@lists.sourceforge.net
+L:  linux-usb-devel@lists.sourceforge.net
+S:  Supported
 
 USB MASS STORAGE DRIVER
 P:	Matthew Dharm
diff -urN linux-2.4.6-pre5/Makefile linux/Makefile
--- linux-2.4.6-pre5/Makefile	Mon Dec  3 22:49:01 2001
+++ linux/Makefile	Mon Dec  3 22:49:10 2001
@@ -1,7 +1,7 @@
 VERSION = 2
 PATCHLEVEL = 4
 SUBLEVEL = 6
-EXTRAVERSION =-pre5
+EXTRAVERSION =-pre6
 
 KERNELRELEASE=$(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION)
 
@@ -128,6 +128,7 @@
 DRIVERS-m :=
 DRIVERS-  :=
 
+DRIVERS-$(CONFIG_ACPI) += drivers/acpi/acpi.o
 DRIVERS-$(CONFIG_PARPORT) += drivers/parport/driver.o
 DRIVERS-y += drivers/char/char.o \
 	drivers/block/block.o \
@@ -177,7 +178,6 @@
 DRIVERS-$(CONFIG_IRDA) += drivers/net/irda/irda.o
 DRIVERS-$(CONFIG_I2C) += drivers/i2c/i2c.o
 DRIVERS-$(CONFIG_PHONE) += drivers/telephony/telephony.o
-DRIVERS-$(CONFIG_ACPI) += drivers/acpi/acpi.o
 DRIVERS-$(CONFIG_MD) += drivers/md/mddev.o
 DRIVERS-$(CONFIG_BLUEZ) += drivers/bluetooth/bluetooth.o
 
diff -urN linux-2.4.6-pre5/arch/alpha/kernel/sys_alcor.c linux/arch/alpha/kernel/sys_alcor.c
--- linux-2.4.6-pre5/arch/alpha/kernel/sys_alcor.c	Fri Oct 27 10:55:01 2000
+++ linux/arch/alpha/kernel/sys_alcor.c	Mon Dec  3 22:49:10 2001
@@ -15,6 +15,7 @@
 #include <linux/sched.h>
 #include <linux/pci.h>
 #include <linux/init.h>
+#include <linux/reboot.h>
 
 #include <asm/ptrace.h>
 #include <asm/system.h>
@@ -219,11 +220,21 @@
 static void
 alcor_kill_arch(int mode)
 {
-	/* Who said DEC engineer's have no sense of humor? ;-)  */
-	if (alpha_using_srm) {
-		*(vuip) GRU_RESET = 0x0000dead;
-		mb();
+	switch(mode) {
+	case LINUX_REBOOT_CMD_RESTART:
+		/* Who said DEC engineer's have no sense of humor? ;-)  */
+		if (alpha_using_srm) {
+			*(vuip) GRU_RESET = 0x0000dead;
+			mb();
+		}
+		break;
+	case LINUX_REBOOT_CMD_HALT:
+		break;
+	case LINUX_REBOOT_CMD_POWER_OFF:
+		break;
 	}
+
+	halt();
 }
 
 
diff -urN linux-2.4.6-pre5/arch/arm/Makefile linux/arch/arm/Makefile
--- linux-2.4.6-pre5/arch/arm/Makefile	Thu Apr 12 12:20:31 2001
+++ linux/arch/arm/Makefile	Mon Dec  3 22:49:10 2001
@@ -26,7 +26,7 @@
 apcs-$(CONFIG_CPU_26)		:=-mcpu=arm3 -Os
 
 arch-y				:=
-arch-$(CONFIG_CPU_32v3)		:=-march=armv3m
+arch-$(CONFIG_CPU_32v3)		:=-march=armv3
 arch-$(CONFIG_CPU_32v4)		:=-march=armv4
 arch-$(CONFIG_CPU_32v5)		:=-march=armv5
 
@@ -123,6 +123,10 @@
 MACHINE		 = clps711x
 endif
 
+ifeq ($(CONFIG_ARCH_ANAKIN),y)
+MACHINE		 = anakin
+endif
+
 export	LIBGCC MACHINE PROCESSOR TEXTADDR GZFLAGS
 
 # Only set INCDIR if its not already defined above
@@ -156,7 +160,7 @@
 LIBS		:= arch/arm/fastfpe/fast-math-emu.o $(LIBS)
 endif
 
-ifeq ($(CONFIG_ARCH_CLPS7500),y)
+ifeq ($(findstring y,$(CONFIG_ARCH_CLPS7500) $(CONFIG_ARCH_L7200)),y)
 SUBDIRS		+= drivers/acorn/char
 DRIVERS		+= drivers/acorn/char/acorn-char.o
 endif
@@ -237,8 +241,8 @@
 	@( \
 	CFG=$(@:_config=); \
 	if [ -f arch/arm/def-configs/$$CFG ]; then \
-	  $(RM) arch/arm/defconfig; \
-	  cp arch/arm/def-configs/$$CFG arch/arm/defconfig; \
+	  [ -f .config ] && $(MV) .config .config.old; \
+	  cp arch/arm/def-configs/$$CFG .config; \
 	  echo "*** Default configuration for $$CFG installed"; \
 	  echo "*** Next, you may run 'make oldconfig'"; \
 	else \
diff -urN linux-2.4.6-pre5/arch/arm/boot/Makefile linux/arch/arm/boot/Makefile
--- linux-2.4.6-pre5/arch/arm/boot/Makefile	Thu Apr 12 12:03:50 2001
+++ linux/arch/arm/boot/Makefile	Mon Dec  3 22:49:10 2001
@@ -90,9 +90,17 @@
 ifeq ($(CONFIG_SA1100_GRAPHICSCLIENT),y)
   ZTEXTADDR	 = 0xC0200000
 endif
+ifeq ($(CONFIG_SA1100_YOPY),y)
+  ZTEXTADDR      = 0x00080000
+  ZBSSADDR       = 0xc0200000
+endif
 ifeq ($(CONFIG_SA1111),y)
   ZRELADDR	 = 0xc0208000
 endif
+endif
+
+ifeq ($(CONFIG_ARCH_ANAKIN),y)
+ZTEXTADDR	 = 0x20008000
 endif
 
 #
diff -urN linux-2.4.6-pre5/arch/arm/boot/compressed/Makefile linux/arch/arm/boot/compressed/Makefile
--- linux-2.4.6-pre5/arch/arm/boot/compressed/Makefile	Thu Apr 12 12:03:50 2001
+++ linux/arch/arm/boot/compressed/Makefile	Mon Dec  3 22:49:10 2001
@@ -30,7 +30,7 @@
 endif
 
 ifeq ($(CONFIG_ARCH_INTEGRATOR),y)
-OBJS		+= head-netwinder.o
+OBJS		+= head-integrator.o
 endif
 
 ifeq ($(CONFIG_ARCH_FTVPCI),y)
diff -urN linux-2.4.6-pre5/arch/arm/boot/compressed/head-integrator.S linux/arch/arm/boot/compressed/head-integrator.S
--- linux-2.4.6-pre5/arch/arm/boot/compressed/head-integrator.S	Wed Dec 31 16:00:00 1969
+++ linux/arch/arm/boot/compressed/head-integrator.S	Mon Dec  3 22:49:10 2001
@@ -0,0 +1,4 @@
+#include <asm/mach-types.h>
+
+		.section	".start", #alloc, #execinstr
+		mov	r7, #MACH_TYPE_INTEGRATOR
diff -urN linux-2.4.6-pre5/arch/arm/boot/compressed/head.S linux/arch/arm/boot/compressed/head.S
--- linux-2.4.6-pre5/arch/arm/boot/compressed/head.S	Thu Apr 12 12:03:50 2001
+++ linux/arch/arm/boot/compressed/head.S	Mon Dec  3 22:49:10 2001
@@ -12,7 +12,39 @@
 
 /*
  * Debugging stuff
+ *
+ * Note that these macros must not contain any code which is not
+ * 100% relocatable.  Any attempt to do so will result in a crash.
+ * Please select one of the following when turning on debugging.
  */
+#ifdef DEBUG
+#if 0 /* DC21285-type */
+		.macro	loadsp,	rb
+		mov	\rb, #0x7c000000
+		.endm
+		.macro	writeb,	rb
+		strb	\rb, [r3, #0x3f8]
+		.endm
+#elif 0 /* RiscPC-type */
+		.macro	loadsp,	rb
+		mov	\rb, #0x03000000
+		orr	\rb, \rb, #0x00010000
+		.endm
+		.macro	writeb,	rb
+		strb	\rb, [r3, #0x3f8 << 2]
+		.endm
+#elif 0 /* integrator-type */
+		.macro	loadsp, rb
+		mov	\rb, #0x16000000
+		.endm
+		.macro	writeb, rb
+		strb	\rb, [r3, #0]
+		.endm
+#else
+#error no serial architecture defined
+#endif
+#endif
+
 		.macro	kputc,val
 		mov	r0, \val
 		bl	putc
@@ -27,53 +59,31 @@
 		.macro	debug_reloc_start
 #ifdef DEBUG
 		kputc	#'\n'
-		kphex	r6, 8
+		kphex	r6, 8		/* processor id */
 		kputc	#':'
-		kphex	r5, 8
+		kphex	r7, 8		/* architecture id */
+		kputc	#':'
+		mrc	p15, 0, r0, c1, c0
+		kphex	r0, 8		/* control reg
+		kputc	#'\n'
+		kphex	r5, 8		/* decompressed kernel start */
 		kputc	#'-'
-		kphex	r8, 8
+		kphex	r8, 8		/* decompressed kernel end  */
 		kputc	#'>'
-		kphex	r4, 8
+		kphex	r4, 8		/* kernel execution address */
 		kputc	#'\n'
 #endif
 		.endm
 
 		.macro	debug_reloc_end
 #ifdef DEBUG
-		mov	r8, r0
-		kphex	r5, 8
-		kputc	#'-'
-		kphex	r8, 8
+		kphex	r5, 8		/* end of kernel */
 		kputc	#'\n'
 		mov	r0, r4
-		bl	memdump
+		bl	memdump		/* dump 256 bytes at start of kernel */
 #endif
 		.endm
 
-/*
- * Note that these macros must not contain any code which is not
- * 100% relocatable.  Any attempt to do so will result in a crash.
- */
-#if 0
-		.macro	loadsp,	rb
-		mov	\rb, #0x7c000000
-		.endm
-
-		.macro	writeb,	rb
-		strb	\rb, [r3, #0x3f8]
-		.endm
-#else
-		.macro	loadsp,	rb
-		mov	\rb, #0x03000000
-		orr	\rb, \rb, #0x00010000
-		.endm
-
-		.macro	writeb,	rb
-		strb	\rb, [r3, #0x3f8 << 2]
-		.endm
-#endif
-
-
 		.section ".start", #alloc, #execinstr
 /*
  * sort out different calling conventions
@@ -91,14 +101,18 @@
 		.word	_edata			@ zImage end address
 1:		mov	r7, r1			@ save architecture ID
 		mov	r8, #0			@ save r0
-#ifdef CONFIG_ANGELBOOT
+
 		/*
 		 * Booting from Angel - need to enter SVC mode and disable
-		 * FIQs/IRQs (numeric definitions from angel arm.h source)
+		 * FIQs/IRQs (numeric definitions from angel arm.h source).
+		 * We only do this if we were in user mode on entry.
 		 */
+		mrs	r0, cpsr		@ get current mode
+		tst	r0, #3			@ not user?
+		bne	not_angel
 		mov	r0, #0x17		@ angel_SWIreason_EnterSVC
 		swi	0x123456		@ angel_SWI_ARM
-		mrs	r0, cpsr		@ turn off interrupts to
+not_angel:	mrs	r0, cpsr		@ turn off interrupts to
 		orr	r0, r0, #0xc0		@ prevent angel from running
 		msr	cpsr_c, r0
 
@@ -106,7 +120,7 @@
 		 * Note that some cache flushing and other stuff may
 		 * be needed here - is there an Angel SWI call for this?
 		 */
-#endif
+
 		/*
 		 * some architecture specific code can be inserted
 		 * by the linker here, but it should preserve r7 and r8.
@@ -300,30 +314,46 @@
 		.size	proc_sa1110_type, . - proc_sa1110_type
 
 /*
- * Turn off StrongARM cache and MMU.  It is safe to
- * leave the I-cache on.
+ * Turn off the Cache and MMU.  ARMv3 does not support
+ * reading the control register, but ARMv4 does.
  *
- * On entry,
- *  r6 = processor ID
- * On exit,
- *  r0, r1 corrupted
- * This routine must preserve:
- *  r4, r6, r7
+ * On entry,  r6 = processor ID
+ * On exit,   r0, r1 corrupted
+ * This routine must preserve: r4, r6, r7
  */
 		.align	5
-cache_off:	ldr	r1, proc_sa110_type
-		eor	r1, r1, r6
-		movs	r1, r1, lsr #5		@ catch SA110 and SA1100
-		beq	1f
-		ldr	r1, proc_sa1110_type
-		eor	r1, r1, r6
-		movs	r1, r1, lsr #4
-		movne	pc, lr
-1:
+cache_off:
+#ifdef CONFIG_CPU_ARM610
+		eor	r1, r6, #0x41000000
+		eor	r1, r1, #0x00560000
+		bic	r1, r1, #0x0000001f
+		teq	r1, #0x00000600
+		mov	r0, #0x00000060		@ ARM6 control reg.
+		beq	__armv3_cache_off
+#endif
+#ifdef CONFIG_CPU_ARM710
+		eor	r1, r6, #0x41000000
+		bic	r1, r1, #0x00070000
+		bic	r1, r1, #0x000000ff
+		teq	r1, #0x00007000		@ ARM7
+		teqne	r1, #0x00007100		@ ARM710
+		mov	r0, #0x00000070		@ ARM7 control reg.
+		beq	__armv3_cache_off
+#endif
 		mrc	p15, 0, r0, c1, c0
 		bic	r0, r0, #0x000d
-		mcr	p15, 0, r0, c1, c0
-		mov	pc, lr		
+		mcr	p15, 0, r0, c1, c0	@ turn MMU and cache off
+		mov	r0, #0
+		mcr	p15, 0, r0, c7, c7	@ invalidate whole cache v4
+		mcr	p15, 0, r0, c8, c7	@ invalidate whole TLB v4
+		mov	pc, lr
+
+__armv3_cache_off:
+		mcr	p15, 0, r0, c1, c0	@ turn MMU and cache off
+		mov	r0, #0
+		mcr	p15, 0, r0, c7, c0	@ invalidate whole cache v3
+		mcr	p15, 0, r0, c5, c0	@ invalidate whole TLB v3
+		mov	pc, lr
 
 /*
  * Clean and flush the cache to maintain consistency.
@@ -401,13 +431,10 @@
 
 memdump:	mov	r12, r0
 		mov	r10, lr
-		mov	r1, #8
-		bl	phex
-		mov	r0, #'\n'
-		bl	putc
 		mov	r11, #0
 2:		mov	r0, r11, lsl #2
-		mov	r1, #4
+		add	r0, r0, r12
+		mov	r1, #8
 		bl	phex
 		mov	r0, #':'
 		bl	putc
diff -urN linux-2.4.6-pre5/arch/arm/boot/compressed/setup-sa1100.S linux/arch/arm/boot/compressed/setup-sa1100.S
--- linux-2.4.6-pre5/arch/arm/boot/compressed/setup-sa1100.S	Thu Apr 12 12:03:50 2001
+++ linux/arch/arm/boot/compressed/setup-sa1100.S	Mon Dec  3 22:49:10 2001
@@ -16,16 +16,16 @@
 		.text
 
 GPIO_BASE:	.long	0x90040000
-#define GPLR	0x00
-#define GPDR	0x04
-#define GPSR	0x08
-#define GAFR	0x1c
+#define GPLR		0x00
+#define GPDR		0x04
+#define GPSR		0x08
+#define GAFR		0x1c
 
 PPC_BASE:	.long	0x90060000
-#define PPAR	0x08
+#define PPAR		0x08
 
 IC_BASE:	.long	0x90050000
-#define ICMR	0x04
+#define ICMR		0x04
 
 UART1_BASE:	.long	0x80010000
 UART3_BASE:	.long	0x80050000
@@ -95,7 +95,11 @@
 		@ Initialize UART (if bootloader has not done it yet)...
 		teq	r3, #MACH_TYPE_BRUTUS
 		teqne	r3, #MACH_TYPE_ASSABET
+		teqne   r3, #MACH_TYPE_ITSY
+		teqne   r3, #MACH_TYPE_OMNIMETER
+		teqne   r3, #MACH_TYPE_JORNADA720
 		teqne	r3, #MACH_TYPE_GRAPHICSCLIENT
+		teqne	r3, #MACH_TYPE_FLEXANET
 		bne	skip_uart
 
 		@ UART3 if Assabet is used with Neponset
diff -urN linux-2.4.6-pre5/arch/arm/kernel/calls.S linux/arch/arm/kernel/calls.S
--- linux-2.4.6-pre5/arch/arm/kernel/calls.S	Mon Sep 18 15:15:24 2000
+++ linux/arch/arm/kernel/calls.S	Mon Dec  3 22:49:10 2001
@@ -13,6 +13,7 @@
 #define NR_syscalls 256
 #else
 
+__syscall_start:
 /* 0 */		.long	SYMBOL_NAME(sys_ni_syscall)
 		.long	SYMBOL_NAME(sys_exit)
 		.long	SYMBOL_NAME(sys_fork_wrapper)
@@ -176,7 +177,7 @@
 /* 160 */	.long	SYMBOL_NAME(sys_sched_get_priority_min)
 		.long	SYMBOL_NAME(sys_sched_rr_get_interval)
 		.long	SYMBOL_NAME(sys_nanosleep)
-		.long	SYMBOL_NAME(sys_mremap)
+		.long	SYMBOL_NAME(sys_arm_mremap)
 		.long	SYMBOL_NAME(sys_setresuid16)
 /* 165 */	.long	SYMBOL_NAME(sys_getresuid16)
 		.long	SYMBOL_NAME(sys_ni_syscall)
@@ -231,8 +232,13 @@
 /* 215 */	.long	SYMBOL_NAME(sys_setfsuid)
 		.long	SYMBOL_NAME(sys_setfsgid)
 		.long	SYMBOL_NAME(sys_getdents64)
+		.long	SYMBOL_NAME(sys_pivot_root)
+		.long	SYMBOL_NAME(sys_mincore)
+/* 220 */	.long	SYMBOL_NAME(sys_madvise)
+		.long	SYMBOL_NAME(sys_fcntl64)
+__syscall_end:
 
-		.rept	NR_syscalls-217
+		.rept	NR_syscalls - (__syscall_end - __syscall_start) / 4
 			.long	SYMBOL_NAME(sys_ni_syscall)
 		.endr
 #endif
diff -urN linux-2.4.6-pre5/arch/arm/kernel/ecard.c linux/arch/arm/kernel/ecard.c
--- linux-2.4.6-pre5/arch/arm/kernel/ecard.c	Thu Apr 12 12:20:31 2001
+++ linux/arch/arm/kernel/ecard.c	Mon Dec  3 22:49:10 2001
@@ -1,7 +1,7 @@
 /*
  *  linux/arch/arm/kernel/ecard.c
  *
- *  Copyright 1995-1998 Russell King
+ *  Copyright 1995-2001 Russell King
  *
  * 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
@@ -26,7 +26,6 @@
  *  17-Apr-1999	RMK	Support for EASI Type C cycles.
  */
 #define ECARD_C
-#define __KERNEL_SYSCALLS__
 
 #include <linux/config.h>
 #include <linux/module.h>
@@ -34,6 +33,7 @@
 #include <linux/types.h>
 #include <linux/sched.h>
 #include <linux/interrupt.h>
+#include <linux/reboot.h>
 #include <linux/mm.h>
 #include <linux/slab.h>
 #include <linux/proc_fs.h>
@@ -382,12 +382,12 @@
  * We ignore all calls, unless it is a SYS_RESTART call - power down/halts
  * will be followed by a SYS_RESTART if ctrl-alt-del is pressed again.
  */
-static void ecard_reboot(struct notifier_block *me, unsigned long val, void *v)
+static int ecard_reboot(struct notifier_block *me, unsigned long val, void *v)
 {
 	struct ecard_request req;
 
 	if (val != SYS_RESTART)
-		return;
+		return 0;
 
 	/*
 	 * Disable the expansion card interrupt
@@ -414,6 +414,7 @@
 	have_expmask = ~0;
 	__raw_writeb(have_expmask, EXPMASK_ENABLE);
 #endif
+	return 0;
 }
 
 static struct notifier_block ecard_reboot_notifier = {
diff -urN linux-2.4.6-pre5/arch/arm/kernel/entry-armv.S linux/arch/arm/kernel/entry-armv.S
--- linux-2.4.6-pre5/arch/arm/kernel/entry-armv.S	Thu Apr 12 12:20:31 2001
+++ linux/arch/arm/kernel/entry-armv.S	Mon Dec  3 22:49:10 2001
@@ -1179,7 +1179,6 @@
 		stmfd	sp!, {r4 - r6, lr}
 
 		adr	r1, .LCvectors			@ set up the vectors
-		mov	r0, #0
 		ldmia	r1, {r1, r2, r3, r4, r5, r6, ip, lr}
 		stmia	r0, {r1, r2, r3, r4, r5, r6, ip, lr}
 
diff -urN linux-2.4.6-pre5/arch/arm/kernel/fiq.c linux/arch/arm/kernel/fiq.c
--- linux-2.4.6-pre5/arch/arm/kernel/fiq.c	Thu Apr 12 12:20:31 2001
+++ linux/arch/arm/kernel/fiq.c	Mon Dec  3 22:49:10 2001
@@ -48,7 +48,7 @@
 #include <asm/system.h>
 #include <asm/uaccess.h>
 
-#define FIQ_VECTOR 0x1c
+#define FIQ_VECTOR (vectors_base() + 0x1c)
 
 static unsigned long no_fiq_insn;
 
diff -urN linux-2.4.6-pre5/arch/arm/kernel/sys_arm.c linux/arch/arm/kernel/sys_arm.c
--- linux-2.4.6-pre5/arch/arm/kernel/sys_arm.c	Mon Mar 19 12:35:10 2001
+++ linux/arch/arm/kernel/sys_arm.c	Mon Dec  3 22:49:10 2001
@@ -55,10 +55,19 @@
 	unsigned long prot, unsigned long flags,
 	unsigned long fd, unsigned long pgoff)
 {
-	int error = -EBADF;
+	int error = -EINVAL;
 	struct file * file = NULL;
 
 	flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE);
+
+	/*
+	 * If we are doing a fixed mapping, and address < PAGE_SIZE,
+	 * then deny it.
+	 */
+	if (flags & MAP_FIXED && addr < PAGE_SIZE && vectors_base() == 0)
+		goto out;
+
+	error = -EBADF;
 	if (!(flags & MAP_ANONYMOUS)) {
 		file = fget(fd);
 		if (!file)
@@ -99,6 +108,29 @@
 	error = do_mmap2(a.addr, a.len, a.prot, a.flags, a.fd, a.offset >> PAGE_SHIFT);
 out:
 	return error;
+}
+
+asmlinkage unsigned long
+sys_arm_mremap(unsigned long addr, unsigned long old_len,
+	       unsigned long new_len, unsigned long flags,
+	       unsigned long new_addr)
+{
+	unsigned long ret = -EINVAL;
+
+	/*
+	 * If we are doing a fixed mapping, and address < PAGE_SIZE,
+	 * then deny it.
+	 */
+	if (flags & MREMAP_FIXED && new_addr < PAGE_SIZE &&
+	    vectors_base() == 0)
+		goto out;
+
+	down_write(&current->mm->mmap_sem);
+	ret = do_mremap(addr, old_len, new_len, flags, new_addr);
+	up_write(&current->mm->mmap_sem);
+
+out:
+	return ret;
 }
 
 /*
diff -urN linux-2.4.6-pre5/arch/arm/kernel/traps.c linux/arch/arm/kernel/traps.c
--- linux-2.4.6-pre5/arch/arm/kernel/traps.c	Thu Feb  8 16:32:44 2001
+++ linux/arch/arm/kernel/traps.c	Mon Dec  3 22:49:10 2001
@@ -20,6 +20,7 @@
 #include <linux/mm.h>
 #include <linux/spinlock.h>
 #include <linux/ptrace.h>
+#include <linux/elf.h>
 #include <linux/init.h>
 
 #include <asm/atomic.h>
@@ -27,6 +28,7 @@
 #include <asm/pgtable.h>
 #include <asm/system.h>
 #include <asm/uaccess.h>
+#include <asm/unistd.h>
 
 #include "ptrace.h"
 
@@ -143,12 +145,24 @@
 		c_backtrace(fp, processor_mode(regs));
 }
 
+/*
+ * This is called from SysRq-T (show_task) to display the current
+ * call trace for each process.  Very useful.
+ */
+void show_trace_task(struct task_struct *tsk)
+{
+	if (tsk != current) {
+		unsigned int fp = tsk->thread.save->fp;
+		c_backtrace(fp, 0x10);
+	}
+}
+
 spinlock_t die_lock = SPIN_LOCK_UNLOCKED;
 
 /*
  * This function is protected against re-entrancy.
  */
-void die(const char *str, struct pt_regs *regs, int err)
+NORET_TYPE void die(const char *str, struct pt_regs *regs, int err)
 {
 	struct task_struct *tsk = current;
 
@@ -173,9 +187,9 @@
 		fs = get_fs();
 		set_fs(KERNEL_DS);
 
-		dump_instr(regs);
 		dump_stack(tsk, (unsigned long)(regs + 1));
 		dump_backtrace(regs, tsk);
+		dump_instr(regs);
 
 		set_fs(fs);
 	}
@@ -448,9 +462,12 @@
 
 void __init trap_init(void)
 {
-	extern void __trap_init(void);
+	extern void __trap_init(void *);
 
-	__trap_init();
+	__trap_init((void *)vectors_base());
+	if (vectors_base() != 0)
+		printk("Relocating machine vectors to 0x%08x\n",
+			vectors_base());
 #ifdef CONFIG_CPU_32
 	modify_domain(DOMAIN_USER, DOMAIN_CLIENT);
 #endif
diff -urN linux-2.4.6-pre5/arch/arm/mach-ebsa110/arch.c linux/arch/arm/mach-ebsa110/arch.c
--- linux-2.4.6-pre5/arch/arm/mach-ebsa110/arch.c	Thu Apr 12 12:20:31 2001
+++ linux/arch/arm/mach-ebsa110/arch.c	Mon Dec  3 22:49:10 2001
@@ -1,10 +1,7 @@
 /*
  *  linux/arch/arm/mach-ebsa110/arch.c
  *
- *  Architecture specific fixups.  This is where any
- *  parameters in the params struct are fixed up, or
- *  any additional architecture specific information
- *  is pulled from the params struct.
+ *  Architecture specific fixups.
  */
 #include <linux/tty.h>
 #include <linux/delay.h>
diff -urN linux-2.4.6-pre5/arch/arm/mach-ebsa110/hardware.h linux/arch/arm/mach-ebsa110/hardware.h
--- linux-2.4.6-pre5/arch/arm/mach-ebsa110/hardware.h	Wed Dec 31 16:00:00 1969
+++ linux/arch/arm/mach-ebsa110/hardware.h	Mon Dec  3 22:49:10 2001
@@ -0,0 +1,16 @@
+/*
+ *  linux/arch/arm/mach-ebsa110/hardware.h
+ *
+ *  Copyright (C) 2001 Russell King
+ *
+ *  Local hardware definitions.
+ */
+#ifndef HARDWARE_H
+#define HARDWARE_H
+
+#define IRQ_MASK		0xfe000000	/* read */
+#define IRQ_MSET		0xfe000000	/* write */
+#define IRQ_STAT		0xff000000	/* read */
+#define IRQ_MCLR		0xff000000	/* write */
+
+#endif
diff -urN linux-2.4.6-pre5/arch/arm/mach-ebsa110/io.c linux/arch/arm/mach-ebsa110/io.c
--- linux-2.4.6-pre5/arch/arm/mach-ebsa110/io.c	Sun May 20 12:11:38 2001
+++ linux/arch/arm/mach-ebsa110/io.c	Mon Dec  3 22:49:10 2001
@@ -188,6 +188,7 @@
 u32 __inl(int port)
 {
 	BUG();
+	return 0;
 }
 
 EXPORT_SYMBOL(__inb);
diff -urN linux-2.4.6-pre5/arch/arm/mm/consistent.c linux/arch/arm/mm/consistent.c
--- linux-2.4.6-pre5/arch/arm/mm/consistent.c	Thu Apr 12 12:20:31 2001
+++ linux/arch/arm/mm/consistent.c	Mon Dec  3 22:49:10 2001
@@ -67,18 +67,21 @@
 #endif
 
 	/*
-	 * free wasted pages.  We skip the first page since
-	 * we know that it will have count = 1 and won't
-	 * require freeing.
+	 * free wasted pages.  We skip the first page since we know
+	 * that it will have count = 1 and won't require freeing.
+	 * We also mark the pages in use as reserved so that
+	 * remap_page_range works.
 	 */
 	page = virt_to_page(virt);
 	free = page + (size >> PAGE_SHIFT);
 	end  = page + (1 << order);
 
-	while (++page < end) {
+	for (; page < end; page++) {
 		set_page_count(page, 1);
 		if (page >= free)
 			__free_page(page);
+		else
+			SetPageReserved(page);
 	}
 	return ret;
 
@@ -108,10 +111,26 @@
  * free a page as defined by the above mapping.  We expressly forbid
  * calling this from interrupt context.
  */
-void consistent_free(void *vaddr)
+void consistent_free(void *vaddr, size_t size, dma_addr_t handle)
 {
+	struct page *page, *end;
+	void *virt;
+
 	if (in_interrupt())
 		BUG();
+
+	virt = bus_to_virt(handle);
+
+	/*
+	 * More messing around with the MM internals.  This is
+	 * sick, but then so is remap_page_range().
+	 */
+	size = PAGE_ALIGN(size);
+	page = virt_to_page(virt);
+	end = page + (size >> PAGE_SHIFT);
+
+	for (; page < end; page++)
+		ClearPageReserved(page);
 
 	__iounmap(vaddr);
 }
diff -urN linux-2.4.6-pre5/arch/arm/mm/fault-armv.c linux/arch/arm/mm/fault-armv.c
--- linux-2.4.6-pre5/arch/arm/mm/fault-armv.c	Wed May 16 15:25:16 2001
+++ linux/arch/arm/mm/fault-armv.c	Mon Dec  3 22:49:10 2001
@@ -24,6 +24,7 @@
 
 #include <asm/system.h>
 #include <asm/uaccess.h>
+#include <asm/pgalloc.h>
 #include <asm/pgtable.h>
 #include <asm/unaligned.h>
 
@@ -45,9 +46,8 @@
  *
  * Speed optimisations and better fault handling by Russell King.
  *
- * NOTE!!! This is not portable onto the ARM6/ARM7 processors yet.  Also,
- * it seems to give a severe performance impact (1 abort/ms - NW runs at
- * ARM6 speeds) with GCC 2.7.2.2 - needs checking with a later GCC/EGCS.
+ * *** NOTE ***
+ * This code is not portable to processors with late data abort handling.
  */
 #define CODING_BITS(i)	(i & 0x0e000000)
 
@@ -57,6 +57,8 @@
 #define LDST_W_BIT(i)	(i & (1 << 21))		/* Writeback		*/
 #define LDST_L_BIT(i)	(i & (1 << 20))		/* Load			*/
 
+#define LDST_P_EQ_U(i)	((((i) ^ ((i) >> 1)) & (1 << 23)) == 0)
+
 #define LDSTH_I_BIT(i)	(i & (1 << 22))		/* half-word immed	*/
 #define LDM_S_BIT(i)	(i & (1 << 22))		/* write CPSR from SPSR	*/
 
@@ -336,29 +338,48 @@
 	return TYPE_FAULT;
 }
 
+/*
+ * LDM/STM alignment handler.
+ *
+ * There are 4 variants of this instruction:
+ *
+ * B = rn pointer before instruction, A = rn pointer after instruction
+ *              ------ increasing address ----->
+ *	        |    | r0 | r1 | ... | rx |    |
+ * PU = 01             B                    A
+ * PU = 11        B                    A
+ * PU = 00        A                    B
+ * PU = 10             A                    B
+ */
 static int
 do_alignment_ldmstm(unsigned long addr, unsigned long instr, struct pt_regs *regs)
 {
 	unsigned int rd, rn, correction, nr_regs, regbits;
-	unsigned long eaddr;
-
-	correction = 4; /* sometimes 8 on ARMv3 */
-	regs->ARM_pc += correction;
-
-	rd = RD_BITS(instr);
-	rn = RN_BITS(instr);
-	eaddr = regs->uregs[rn];
+	unsigned long eaddr, newaddr;
 
 	if (LDM_S_BIT(instr))
 		goto bad;
 
+	correction = 4; /* processor implementation defined */
+	regs->ARM_pc += correction;
+
 	ai_multi += 1;
 
+	/* count the number of registers in the mask to be transferred */
 	for (regbits = REGMASK_BITS(instr), nr_regs = 0; regbits; regbits >>= 1)
 		nr_regs += 4;
 
+	rn = RN_BITS(instr);
+	newaddr = eaddr = regs->uregs[rn];
+
 	if (!LDST_U_BIT(instr))
-		eaddr -= nr_regs;
+		nr_regs = -nr_regs;
+	newaddr += nr_regs;
+	if (!LDST_U_BIT(instr))
+		eaddr = newaddr;
+
+	if (LDST_P_EQ_U(instr))	/* U = P */
+		eaddr += 4;
 
 	/*
 	 * This is a "hint" - we already have eaddr worked out by the
@@ -369,34 +390,23 @@
 			"addr = %08lx, eaddr = %08lx\n",
 			 instruction_pointer(regs), instr, addr, eaddr);
 
-	if ((LDST_U_BIT(instr) == 0 && LDST_P_BIT(instr) == 0) ||
-	    (LDST_U_BIT(instr)      && LDST_P_BIT(instr)))
-		eaddr += 4;
-
 	for (regbits = REGMASK_BITS(instr), rd = 0; regbits; regbits >>= 1, rd += 1)
 		if (regbits & 1) {
-			if (LDST_L_BIT(instr)) {
+			if (LDST_L_BIT(instr))
 				get32_unaligned_check(regs->uregs[rd], eaddr);
-				if (rd == 15)
-					correction = 0;
-			} else
+			else
 				put32_unaligned_check(regs->uregs[rd], eaddr);
 			eaddr += 4;
 		}
 
-	if (LDST_W_BIT(instr)) {
-		if (LDST_P_BIT(instr) && !LDST_U_BIT(instr))
-			eaddr -= nr_regs;
-		else if (LDST_P_BIT(instr))
-			eaddr -= 4;
-		else if (!LDST_U_BIT(instr))
-			eaddr -= 4 + nr_regs;
-		regs->uregs[rn] = eaddr;
-	}
-	regs->ARM_pc -= correction;
+	if (LDST_W_BIT(instr))
+		regs->uregs[rn] = newaddr;
+	if (!LDST_L_BIT(instr) || !(REGMASK_BITS(instr) & (1 << 15)))
+		regs->ARM_pc -= correction;
 	return TYPE_DONE;
 
 fault:
+	regs->ARM_pc -= correction;
 	return TYPE_FAULT;
 
 bad:
diff -urN linux-2.4.6-pre5/arch/arm/mm/mm-armv.c linux/arch/arm/mm/mm-armv.c
--- linux-2.4.6-pre5/arch/arm/mm/mm-armv.c	Thu Apr 12 12:20:31 2001
+++ linux/arch/arm/mm/mm-armv.c	Mon Dec  3 22:49:10 2001
@@ -79,37 +79,40 @@
 
 	memzero(new_pgd, FIRST_KERNEL_PGD_NR * sizeof(pgd_t));
 
-	/*
-	 * This lock is here just to satisfy pmd_alloc and pte_lock
-	 */
-	spin_lock(&mm->page_table_lock);
+	init_pgd = pgd_offset_k(0);
 
-	/*
-	 * On ARM, first page must always be allocated since it contains
-	 * the machine vectors.
-	 */
-	new_pmd = pmd_alloc(mm, new_pgd, 0);
-	if (!new_pmd)
-		goto no_pmd;
-
-	new_pte = pte_alloc(mm, new_pmd, 0);
-	if (!new_pte)
-		goto no_pte;
+	if (vectors_base() == 0) {
+		init_pmd = pmd_offset(init_pgd, 0);
+		init_pte = pte_offset(init_pmd, 0);
+
+		/*
+		 * This lock is here just to satisfy pmd_alloc and pte_lock
+		 */
+		spin_lock(&mm->page_table_lock);
+
+		/*
+		 * On ARM, first page must always be allocated since it
+		 * contains the machine vectors.
+		 */
+		new_pmd = pmd_alloc(mm, new_pgd, 0);
+		if (!new_pmd)
+			goto no_pmd;
+
+		new_pte = pte_alloc(mm, new_pmd, 0);
+		if (!new_pte)
+			goto no_pte;
 
-	init_pgd = pgd_offset_k(0);
-	init_pmd = pmd_offset(init_pgd, 0);
-	init_pte = pte_offset(init_pmd, 0);
+		set_pte(new_pte, *init_pte);
 
-	set_pte(new_pte, *init_pte);
+		spin_unlock(&mm->page_table_lock);
+	}
 
 	/*
 	 * Copy over the kernel and IO PGD entries
 	 */
-	memcpy(new_pgd  + FIRST_KERNEL_PGD_NR, init_pgd + FIRST_KERNEL_PGD_NR,
+	memcpy(new_pgd + FIRST_KERNEL_PGD_NR, init_pgd + FIRST_KERNEL_PGD_NR,
 		       (PTRS_PER_PGD - FIRST_KERNEL_PGD_NR) * sizeof(pgd_t));
 
-	spin_unlock(&mm->page_table_lock);
-
 	/*
 	 * FIXME: this should not be necessary
 	 */
@@ -134,25 +137,26 @@
 
 void free_pgd_slow(pgd_t *pgd)
 {
-	if (pgd) { /* can pgd be NULL? */
-		pmd_t *pmd;
-		pte_t *pte;
-
-		/* pgd is always present and good */
-		pmd = (pmd_t *)pgd;
-		if (pmd_none(*pmd))
-			goto free;
-		if (pmd_bad(*pmd)) {
-			pmd_ERROR(*pmd);
-			pmd_clear(pmd);
-			goto free;
-		}
+	pmd_t *pmd;
+	pte_t *pte;
 
-		pte = pte_offset(pmd, 0);
+	if (!pgd)
+		return;
+
+	/* pgd is always present and good */
+	pmd = (pmd_t *)pgd;
+	if (pmd_none(*pmd))
+		goto free;
+	if (pmd_bad(*pmd)) {
+		pmd_ERROR(*pmd);
 		pmd_clear(pmd);
-		pte_free(pte);
-		pmd_free(pmd);
+		goto free;
 	}
+
+	pte = pte_offset(pmd, 0);
+	pmd_clear(pmd);
+	pte_free(pte);
+	pmd_free(pmd);
 free:
 	free_pages((unsigned long) pgd, 2);
 }
@@ -296,17 +300,6 @@
 
 	init_maps = p = alloc_bootmem_low_pages(PAGE_SIZE);
 
-	p->physical   = virt_to_phys(init_maps);
-	p->virtual    = 0;
-	p->length     = PAGE_SIZE;
-	p->domain     = DOMAIN_USER;
-	p->prot_read  = 0;
-	p->prot_write = 0;
-	p->cacheable  = 1;
-	p->bufferable = 0;
-
-	p ++;
-
 	for (i = 0; i < mi->nr_banks; i++) {
 		if (mi->bank[i].size == 0)
 			continue;
@@ -350,16 +343,9 @@
 #endif
 
 	/*
-	 * We may have a mapping in virtual address 0.
-	 * Clear it out.
-	 */
-	clear_mapping(0);
-
-	/*
 	 * Go through the initial mappings, but clear out any
 	 * pgdir entries that are not in the description.
 	 */
-	i = 0;
 	q = init_maps;
 	do {
 		if (address < q->virtual || q == p) {
@@ -374,6 +360,21 @@
 			q ++;
 		}
 	} while (address != 0);
+
+	/*
+	 * Create a mapping for the machine vectors at virtual address 0
+	 * or 0xffff0000.  We should always try the high mapping.
+	 */
+	init_maps->physical   = virt_to_phys(init_maps);
+	init_maps->virtual    = vectors_base();
+	init_maps->length     = PAGE_SIZE;
+	init_maps->domain     = DOMAIN_USER;
+	init_maps->prot_read  = 0;
+	init_maps->prot_write = 0;
+	init_maps->cacheable  = 1;
+	init_maps->bufferable = 0;
+
+	create_mapping(init_maps);
 
 	flush_cache_all();
 }
diff -urN linux-2.4.6-pre5/arch/arm/mm/mm-l7200.c linux/arch/arm/mm/mm-l7200.c
--- linux-2.4.6-pre5/arch/arm/mm/mm-l7200.c	Thu Apr 12 12:20:31 2001
+++ linux/arch/arm/mm/mm-l7200.c	Mon Dec  3 22:49:10 2001
@@ -10,7 +10,6 @@
 #include <asm/hardware.h>
 #include <asm/page.h>
 #include <asm/proc/domain.h>
-#include <asm/setup.h>
 
 #include <asm/mach/map.h>
 
diff -urN linux-2.4.6-pre5/arch/arm/tools/Makefile linux/arch/arm/tools/Makefile
--- linux-2.4.6-pre5/arch/arm/tools/Makefile	Tue Mar  6 19:44:35 2001
+++ linux/arch/arm/tools/Makefile	Mon Dec  3 22:49:10 2001
@@ -16,7 +16,7 @@
 
 $(TOPDIR)/include/asm-arm/constants.h: constants-hdr getconstants.c
 	$(CC) $(CFLAGS) -S -o - getconstants.c | \
-	 sed 's/^\(#define .* \)#\(.*\)/\1\2/;/^#define/!d' | \
+	 sed 's/^\(#define .* \)[#$$]\(.*\)/\1\2/;/^#define/!d' | \
 	 cat constants-hdr - > $@.tmp
 	cmp $@.tmp $@ >/dev/null 2>&1 || mv $@.tmp $@; $(RM) $@.tmp
 
diff -urN linux-2.4.6-pre5/arch/arm/tools/getconstants.c linux/arch/arm/tools/getconstants.c
--- linux-2.4.6-pre5/arch/arm/tools/getconstants.c	Wed Apr 11 19:02:27 2001
+++ linux/arch/arm/tools/getconstants.c	Mon Dec  3 22:49:10 2001
@@ -60,7 +60,5 @@
 
 DEFN("PAGE_SZ",			PAGE_SIZE);
 
-DEFN("KSWI_BASE",		0x900000);
-DEFN("KSWI_SYS_BASE",		0x9f0000);
 DEFN("SYS_ERROR0",		0x9f0000);
 }
diff -urN linux-2.4.6-pre5/arch/arm/tools/mach-types linux/arch/arm/tools/mach-types
--- linux-2.4.6-pre5/arch/arm/tools/mach-types	Wed Apr 11 19:02:27 2001
+++ linux/arch/arm/tools/mach-types	Mon Dec  3 22:49:10 2001
@@ -6,7 +6,7 @@
 # To add an entry into this database, please see Documentation/arm/README,
 # or contact rmk@arm.linux.org.uk
 #
-# Last update: Sat Apr 7 09:45:09 2001
+# Last update: Sun Jun 17 00:53:17 2001
 #
 # machine_is_xxx	CONFIG_xxxx		MACH_TYPE_xxx		number
 #
@@ -63,7 +63,7 @@
 citygo			SA1100_CITYGO		CITYGO			51
 pfs168			SA1100_PFS168		PFS168			52
 spot			SA1100_SPOT		SPOT			53
-flexanet		ARCH_FLEXANET		FLEXANET		54
+flexanet		SA1100_FLEXANET		FLEXANET		54
 webpal			ARCH_WEBPAL		WEBPAL			55
 linpda			SA1100_LINPDA		LINPDA			56
 anakin			ARCH_ANAKIN		ANAKIN			57
@@ -77,6 +77,26 @@
 xfile			SA1100_XFILE		XFILE			65
 accelent_ep9312		ARCH_ACCELENT_EP9312	ACCELENT_EP9312		66
 ic200			ARCH_IC200		IC200			67
+creditlart		SA1100_CREDITLART	CREDITLART		68
+htm			SA1100_HTM		HTM			69
+iq80310			ARCH_IQ80310		IQ80310			70
+freebot			SA1100_FREEBOT		FREEBOT			71
+entel			ARCH_ENTEL		ENTEL			72
+enp3510			ARCH_ENP3510		ENP3510			73
+trizeps			SA1100_TRIZEPS		TRIZEPS			74
+nesa			SA1100_NESA		NESA			75
+venus			ARCH_VENUS		VENUS			76
+tardis			ARCH_TARDIS		TARDIS			77
+mercury			ARCH_MERCURY		MERCURY			78
+empeg			SA1100_EMPEG		EMPEG			79
+adi_eb			ARCH_I80200FCC		I80200FCC		80
+itt_cpb			SA1100_ITT_CPB		ITT_CPB			81
+sa1110_svc		ARCH_SA1110_SVC		SA1110_SVC		82
+alpha2			SA1100_ALPHA2		ALPHA2			84
+alpha1			SA1100_ALPHA1		ALPHA1			85
+netarm			ARCH_NETARM		NETARM			86
+simpad			SA1100_SIMPAD		SIMPAD			87
+pda1			ARCH_PDA1		PDA1			88
+lubbock			ARCH_LUBBOCK		LUBBOCK			89
 
 # The following are unallocated
-empeg			SA1100_EMPEG		EMPEG
diff -urN linux-2.4.6-pre5/arch/i386/defconfig linux/arch/i386/defconfig
--- linux-2.4.6-pre5/arch/i386/defconfig	Mon Dec  3 22:49:01 2001
+++ linux/arch/i386/defconfig	Mon Dec  3 22:49:10 2001
@@ -103,64 +103,6 @@
 # CONFIG_MTD is not set
 
 #
-# RAM/ROM/Flash chip drivers
-#
-# CONFIG_MTD_CFI is not set
-# CONFIG_MTD_CFI_INTELEXT is not set
-# CONFIG_MTD_CFI_AMDSTD is not set
-# CONFIG_MTD_AMDSTD is not set
-# CONFIG_MTD_SHARP is not set
-# CONFIG_MTD_RAM is not set
-# CONFIG_MTD_ROM is not set
-# CONFIG_MTD_JEDEC is not set
-
-#
-# Mapping drivers for chip access
-#
-# CONFIG_MTD_PHYSMAP is not set
-# CONFIG_MTD_SUN_UFLASH is not set
-# CONFIG_MTD_NORA is not set
-# CONFIG_MTD_PNC2000 is not set
-# CONFIG_MTD_RPXLITE is not set
-# CONFIG_MTD_SC520CDP is not set
-# CONFIG_MTD_NETSC520 is not set
-# CONFIG_MTD_SBC_GXX is not set
-# CONFIG_MTD_ELAN_104NC is not set
-# CONFIG_MTD_SA1100 is not set
-# CONFIG_MTD_SA1100_REDBOOT_PARTITIONS is not set
-# CONFIG_MTD_SA1100_BOOTLDR_PARTITIONS is not set
-# CONFIG_MTD_DC21285 is not set
-# CONFIG_MTD_IQ80310 is not set
-# CONFIG_MTD_DBOX2 is not set
-# CONFIG_MTD_CSTM_MIPS_IXX is not set
-# CONFIG_MTD_CFI_FLAGADM is not set
-# CONFIG_MTD_MIXMEM is not set
-# CONFIG_MTD_OCTAGON is not set
-# CONFIG_MTD_VMAX is not set
-# CONFIG_MTD_OCELOT is not set
-
-#
-# Self-contained MTD device drivers
-#
-# CONFIG_MTD_PMC551 is not set
-# CONFIG_MTD_SLRAM is not set
-# CONFIG_MTD_MTDRAM is not set
-
-#
-# Disk-On-Chip Device Drivers
-#
-# CONFIG_MTD_DOC1000 is not set
-# CONFIG_MTD_DOC2000 is not set
-# CONFIG_MTD_DOC2001 is not set
-# CONFIG_MTD_DOCPROBE is not set
-
-#
-# NAND Flash Device Drivers
-#
-# CONFIG_MTD_NAND is not set
-# CONFIG_MTD_NAND_SPIA is not set
-
-#
 # Parallel port support
 #
 # CONFIG_PARPORT is not set
@@ -421,6 +363,13 @@
 # Ethernet (10 or 100Mbit)
 #
 CONFIG_NET_ETHERNET=y
+# CONFIG_ARM_AM79C961A is not set
+# CONFIG_SUNLANCE is not set
+# CONFIG_HAPPYMEAL is not set
+# CONFIG_SUNBMAC is not set
+# CONFIG_SUNQE is not set
+# CONFIG_SUNLANCE is not set
+# CONFIG_SUNGEM is not set
 # CONFIG_NET_VENDOR_3COM is not set
 # CONFIG_LANCE is not set
 # CONFIG_NET_VENDOR_SMC is not set
@@ -439,7 +388,6 @@
 # CONFIG_DGRS is not set
 # CONFIG_DM9102 is not set
 CONFIG_EEPRO100=y
-# CONFIG_EEPRO100_PM is not set
 # CONFIG_LNE390 is not set
 # CONFIG_FEALNX is not set
 # CONFIG_NATSEMI is not set
@@ -456,16 +404,18 @@
 # CONFIG_TLAN is not set
 # CONFIG_VIA_RHINE is not set
 # CONFIG_WINBOND_840 is not set
-# CONFIG_HAPPYMEAL is not set
 # CONFIG_NET_POCKET is not set
 
 #
 # Ethernet (1000 Mbit)
 #
 # CONFIG_ACENIC is not set
+# CONFIG_MYRI_SBUS is not set
 # CONFIG_HAMACHI is not set
+# CONFIG_YELLOWFIN is not set
 # CONFIG_SK98LIN is not set
 # CONFIG_FDDI is not set
+# CONFIG_PLIP is not set
 # CONFIG_PPP is not set
 # CONFIG_SLIP is not set
 
@@ -761,6 +711,7 @@
 # CONFIG_USB_IBMCAM is not set
 # CONFIG_USB_OV511 is not set
 # CONFIG_USB_PWC is not set
+# CONFIG_USB_SE401 is not set
 # CONFIG_USB_DSBR is not set
 # CONFIG_USB_DABUSB is not set
 
@@ -769,6 +720,7 @@
 #
 # CONFIG_USB_PLUSB is not set
 # CONFIG_USB_PEGASUS is not set
+# CONFIG_USB_CATC is not set
 # CONFIG_USB_NET1080 is not set
 
 #
diff -urN linux-2.4.6-pre5/arch/i386/kernel/bluesmoke.c linux/arch/i386/kernel/bluesmoke.c
--- linux-2.4.6-pre5/arch/i386/kernel/bluesmoke.c	Mon May 21 12:34:50 2001
+++ linux/arch/i386/kernel/bluesmoke.c	Mon Dec  3 22:49:10 2001
@@ -182,7 +182,7 @@
  *	Set up machine check reporting on the Winchip C6 series
  */
  
-static void winchip_mcheck_init(struct cpuinfo_x86 *c)
+static void __init winchip_mcheck_init(struct cpuinfo_x86 *c)
 {
 	u32 lo, hi;
 	/* Not supported on C3 */
@@ -207,8 +207,14 @@
  *	This has to be run for each processor
  */
 
+
+static int mce_disabled = 0;
+
 void __init mcheck_init(struct cpuinfo_x86 *c)
 {
+	if(mce_disabled)
+		return;
+		
 	switch(c->x86_vendor)
 	{
 		case X86_VENDOR_AMD:
@@ -226,3 +232,9 @@
 			break;
 	}
 }
+
+static void __init mcheck_disable(char *str, int *unused)
+{
+	mce_disabled = 1;
+}
+__setup("nomce", mcheck_disable);
diff -urN linux-2.4.6-pre5/arch/sh/config.in linux/arch/sh/config.in
--- linux-2.4.6-pre5/arch/sh/config.in	Tue Apr 17 17:19:25 2001
+++ linux/arch/sh/config.in	Mon Dec  3 22:49:10 2001
@@ -29,7 +29,9 @@
 choice 'SuperH system type'					\
 	"Generic		CONFIG_SH_GENERIC		\
 	 SolutionEngine		CONFIG_SH_SOLUTION_ENGINE	\
-	 Overdrive		CONFIG_SH_OVERDRIVE		\
+	 SolutionEngine7751	CONFIG_SH_7751_SOLUTION_ENGINE	\
+	 STB1_Harp		CONFIG_SH_STB1_HARP		\
+	 STB1_Overdrive		CONFIG_SH_STB1_OVERDRIVE	\
 	 HP620			CONFIG_SH_HP620			\
 	 HP680			CONFIG_SH_HP680			\
 	 HP690			CONFIG_SH_HP690			\
@@ -37,9 +39,17 @@
 	 DMIDA			CONFIG_SH_DMIDA    		\
 	 EC3104			CONFIG_SH_EC3104		\
 	 Dreamcast		CONFIG_SH_DREAMCAST		\
+	 CAT68701		CONFIG_SH_CAT68701		\
+	 BigSur			CONFIG_SH_BIGSUR		\
+	 SH2000			CONFIG_SH_SH2000		\
 	 BareCPU		CONFIG_SH_UNKNOWN" Generic
 
-define_bool CONFIG_SH_RTC y
+# The SH7750 RTC module is disabled in the Dreamcast
+if [ "$CONFIG_SH_DREAMCAST" = "y" ]; then
+   define_bool CONFIG_SH_RTC n
+else
+   define_bool CONFIG_SH_RTC y
+fi
 
 if [ "$CONFIG_SH_HP620" = "y" -o "$CONFIG_SH_HP680" = "y" -o \
      "$CONFIG_SH_HP690" = "y" ]; then
@@ -50,7 +60,9 @@
    "SH7707 CONFIG_CPU_SUBTYPE_SH7707 \
     SH7708 CONFIG_CPU_SUBTYPE_SH7708 \
     SH7709 CONFIG_CPU_SUBTYPE_SH7709 \
-    SH7750 CONFIG_CPU_SUBTYPE_SH7750" SH7708
+    SH7750 CONFIG_CPU_SUBTYPE_SH7750 \
+    SH7751 CONFIG_CPU_SUBTYPE_SH7751 \
+    ST40STB1 CONFIG_CPU_SUBTYPE_ST40STB1" SH7708
 if [ "$CONFIG_CPU_SUBTYPE_SH7707" = "y" ]; then
    define_bool CONFIG_CPU_SH3 y
    define_bool CONFIG_CPU_SH4 n
@@ -67,12 +79,30 @@
    define_bool CONFIG_CPU_SH3 n
    define_bool CONFIG_CPU_SH4 y
 fi
+if [ "$CONFIG_CPU_SUBTYPE_SH7751" = "y" ]; then
+   define_bool CONFIG_CPU_SH3 n
+   define_bool CONFIG_CPU_SH4 y
+fi
+if [ "$CONFIG_CPU_SUBTYPE_ST40STB1" = "y" ]; then
+   define_bool CONFIG_CPU_SH3 n
+   define_bool CONFIG_CPU_SH4 y
+fi
 bool 'Little Endian' CONFIG_CPU_LITTLE_ENDIAN
 if [ "$CONFIG_SH_SOLUTION_ENGINE" = "y" -o "$CONFIG_SH_HP600" = "y" -o \
-     "$CONFIG_SH_OVERDRIVE" = "y" ]; then
+     "$CONFIG_SH_BIGSUR" = "y" -o "$CONFIG_SH_7751_SOLUTION_ENGINE" = "y" -o \
+     "$CONFIG_SH_DREAMCAST" = "y" -o "$CONFIG_SH_SH2000" = "y" ]; then
   define_hex CONFIG_MEMORY_START 0c000000
 else
-  hex 'Physical memory start address' CONFIG_MEMORY_START 08000000
+  if [ "$CONFIG_CPU_SUBTYPE_ST40STB1" = "y" ]; then
+    bool 'Memory on LMI' CONFIG_ST40_LMI_MEMORY
+    if [ "$CONFIG_ST40_LMI_MEMORY" = "y" ] ; then
+      define_hex CONFIG_MEMORY_START 08000000
+    else
+      hex 'EMI physical memory start address' CONFIG_MEMORY_START 08000000
+    fi
+  else
+    hex 'Physical memory start address' CONFIG_MEMORY_START 08000000
+  fi
 fi
 endmenu
 
@@ -89,7 +119,8 @@
 
 bool 'Networking support' CONFIG_NET
 
-if [ "$CONFIG_SH_GENERIC" = "y" -o "$CONFIG_SH_SOLUTION_ENGINE" = "y" -o "$CONFIG_SH_UNKNOWN" = "y" ]; then
+if [ "$CONFIG_SH_GENERIC" = "y" -o "$CONFIG_SH_SOLUTION_ENGINE" = "y" -o \
+     "$CONFIG_SH_UNKNOWN" = "y" -o "$CONFIG_SH_CAT68701" = "y" ]; then
   bool 'Compact Flash Enabler support' CONFIG_CF_ENABLER
 fi
 
@@ -101,6 +132,7 @@
 
 bool 'Hitachi HD64465 companion chip support' CONFIG_HD64465
 if [ "$CONFIG_HD64465" = "y" ]; then
+   hex 'HD64465 start address' CONFIG_HD64465_IOBASE b0000000
    int 'HD64465 IRQ' CONFIG_HD64465_IRQ 5
 fi
 
@@ -197,6 +229,10 @@
 #
 source drivers/input/Config.in
 
+if [ "$CONFIG_SH_DREAMCAST" = "y" ]; then
+source drivers/maple/Config.in
+fi
+
 mainmenu_option next_comment
 comment 'Character devices'
 
@@ -217,10 +253,29 @@
 fi
 
 if [ "$CONFIG_SH_GENERIC" = "y" -o \
-     "$CONFIG_SH_OVERDRIVE" = "y" -o "$CONFIG_SH_SOLUTION_ENGINE" = "y" ]; then
+     "$CONFIG_SH_CAT68701" = "y" -o \
+     "$CONFIG_SH_STB1_HARP" = "y" -o \
+     "$CONFIG_SH_STB1_OVERDRIVE" = "y" -o \
+     "$CONFIG_SH_BIGSUR" = "y" -o \
+     "$CONFIG_SH_7751_SOLUTION_ENGINE" = "y" -o \
+     "$CONFIG_SH_SOLUTION_ENGINE" = "y" ]; then
   bool 'Heartbeat LED' CONFIG_HEARTBEAT
 fi
 
+if [ "$CONFIG_SH_DREAMCAST" = "y" -a "$CONFIG_MAPLE" != "n" ]; then
+   mainmenu_option next_comment
+   comment 'Maple Bus input peripherals'
+   if [ "$CONFIG_INPUT" != "n" ]; then
+      dep_tristate '  Maple Bus keyboard support' CONFIG_MAPLE_KEYBOARD $CONFIG_INPUT
+      dep_tristate '  Maple Bus mouse support' CONFIG_MAPLE_MOUSE $CONFIG_INPUT
+   else
+      comment 'Input core support is required for Maple input peripherals'
+   fi
+   endmenu
+fi
+
+source drivers/char/joystick/Config.in
+
 if [ "$CONFIG_PARPORT" != "n" ]; then
    dep_tristate 'Parallel printer support' CONFIG_PRINTER $CONFIG_PARPORT
    if [ "$CONFIG_PRINTER" != "n" ]; then
@@ -228,13 +283,16 @@
    fi
    dep_tristate 'Support for user-space parallel port device drivers' CONFIG_PPDEV $CONFIG_PARPORT
 fi
-endmenu
-
+bool 'PS/2 mouse (aka "auxiliary device") support' CONFIG_PSMOUSE
+tristate 'Enhanced Real Time Clock Support' CONFIG_RTC
 if [ "$CONFIG_HOTPLUG" = "y" -a "$CONFIG_PCMCIA" != "n" ]; then
    source drivers/char/pcmcia/Config.in
 fi
+endmenu
 
 source fs/Config.in
+
+source drivers/media/Config.in
 
 if [ "$CONFIG_VT" = "y" ]; then
    mainmenu_option next_comment
diff -urN linux-2.4.6-pre5/arch/sh/kernel/Makefile linux/arch/sh/kernel/Makefile
--- linux-2.4.6-pre5/arch/sh/kernel/Makefile	Wed Apr 11 21:24:52 2001
+++ linux/arch/sh/kernel/Makefile	Mon Dec  3 22:49:10 2001
@@ -24,8 +24,15 @@
 obj-$(CONFIG_SH_STANDARD_BIOS)	+= sh_bios.o
 
 ifeq ($(CONFIG_PCI),y)
-obj-y				+= pci-sh.o 
+ifeq ($(CONFIG_SH_DREAMCAST),y)
+obj-y 				+= pci-dc.o
+else
+obj-y                           += pci-dma.o 
 obj-$(CONFIG_CPU_SUBTYPE_ST40STB1)+= pci_st40.o
+obj-$(CONFIG_CPU_SUBTYPE_SH7751)+= pci-sh7751.o 
+obj-$(CONFIG_SH_BIGSUR)+= pci-bigsur.o
+obj-$(CONFIG_SH_7751_SOLUTION_ENGINE)+= pci-7751se.o
+endif
 endif
 
 obj-$(CONFIG_SH_HP600)		+= mach_hp600.o
@@ -33,6 +40,15 @@
 
 obj-$(CONFIG_SH_SOLUTION_ENGINE)+= mach_se.o setup_se.o io_se.o led_se.o
 machine-specific-objs		+= mach_se.o setup_se.o io_se.o led_se.o
+
+obj-$(CONFIG_SH_7751_SOLUTION_ENGINE)+= mach_se.o setup_se.o io_se.o led_se.o pci-7751se.o
+machine-specific-objs           += mach_se.o setup_se.o io_se.o led_se.o pci-7751se.o
+
+obj-$(CONFIG_SH_BIGSUR)		+= mach_bigsur.o setup_bigsur.o io_bigsur.o led_bigsur.o
+machine-specific-objs		+= mach_bigsur.o setup_bigsur.o io_bigsur.o led_bigsur.o
+
+obj-$(CONFIG_SH_SH2000)		+= setup_sh2000.o io_sh2000.o
+machine-specific-objs		+= setup_sh2000.o io_sh2000.o
 
 obj-$(CONFIG_SH_CAT68701) 	+= mach_cat68701.o io_cat68701.o
 machine-specific-objs		+= mach_cat68701.o io_cat68701.o
diff -urN linux-2.4.6-pre5/arch/sh/kernel/entry.S linux/arch/sh/kernel/entry.S
--- linux-2.4.6-pre5/arch/sh/kernel/entry.S	Wed Apr 11 21:24:52 2001
+++ linux/arch/sh/kernel/entry.S	Mon Dec  3 22:49:10 2001
@@ -489,8 +489,9 @@
 __syscall_ret_trace:
 	.long	syscall_ret_trace
 __syscall_ret:
-	.long	SYMBOL_NAME(syscall_ret)
-
+	.long	syscall_ret
+__INV_IMASK:
+	.long	0xffffff0f	! ~(IMASK)
 
 
 	.align	2
@@ -502,30 +503,16 @@
 	.align	2
 1:	.long	SYMBOL_NAME(schedule)
 
-ENTRY(ret_from_irq)
-	mov	#OFF_SR, r0
-	mov.l	@(r0,r15), r0	! get status register
-	shll	r0
-	shll	r0		! kernel space?
-	bt	restore_all	! Yes, it's from kernel, go back soon
-	!
-	STI()
-	bra	ret_with_reschedule
-	 nop
-
-ENTRY(ret_from_exception)
+ret_from_irq:
+ret_from_exception:
 	mov	#OFF_SR, r0
 	mov.l	@(r0,r15), r0	! get status register
 	shll	r0
 	shll	r0		! kernel space?
 	bt	restore_all	! Yes, it's from kernel, go back soon
 	!
-	STI()
 	bra	ret_from_syscall
 	 nop
-	.align	2
-__INV_IMASK:
-	.long	0xffffff0f	! ~(IMASK)
 
 	.align 2
 #ifdef COMPAT_OLD_SYSCALL_ABI
@@ -538,16 +525,11 @@
 	/* fall through */
 
 ENTRY(ret_from_syscall)
-	mov.l	__irq_stat, r0	! softirq_active
-	mov.l	@r0, r1
-	mov.l	@(4,r0), r2	! softirq_mask
-	tst	r2, r1
-	bt	ret_with_reschedule
-handle_softirq:
-	mov.l	__do_softirq, r0
-	jsr	@r0
-	 nop
-ret_with_reschedule:
+	/* CLI */
+	stc	sr, r0
+	or	#0xf0, r0
+	ldc	r0, sr
+	!
 	stc	k_current, r1
 	mov.l	@(need_resched,r1), r0
 	tst	r0, r0
@@ -567,8 +549,6 @@
 	.long	SYMBOL_NAME(do_signal)
 __irq_stat:
 	.long	SYMBOL_NAME(irq_stat)
-__do_softirq:
-	.long	SYMBOL_NAME(do_softirq)
 
 	.align 2
 restore_all:
@@ -707,7 +687,7 @@
 	bra	handle_exception
 	 mov.l	@k2, k2
 	.align	2
-2:	.long	SYMBOL_NAME(ret_from_exception)
+2:	.long	ret_from_exception
 1:	.long	EXPEVT
 !
 !
@@ -728,8 +708,8 @@
 	.align	2
 1:	.long	EXPEVT
 2:	.long	INTEVT
-3:	.long	SYMBOL_NAME(ret_from_irq)
-4:	.long	SYMBOL_NAME(ret_from_exception)
+3:	.long	ret_from_irq
+4:	.long	ret_from_exception
 
 !
 !
@@ -941,24 +921,143 @@
 	.long   SYMBOL_NAME(do_IRQ)	! 63      pcc1i
 #endif
 #elif defined(__SH4__)
-	.long	SYMBOL_NAME(do_IRQ)	! Hitachi UDI
-	.long	SYMBOL_NAME(do_IRQ)	! GPIO
-	.long	SYMBOL_NAME(do_IRQ)	! DMAC dmte0
-	.long	SYMBOL_NAME(do_IRQ)	!      dmte1
-	.long	SYMBOL_NAME(do_IRQ)	!      dmte2
-	.long	SYMBOL_NAME(do_IRQ)	!      dmte3
-	.long	SYMBOL_NAME(do_IRQ)	!      dmae
-	.long	SYMBOL_NAME(do_IRQ)
-	.long	SYMBOL_NAME(do_IRQ)	! SCIF eri
-	.long	SYMBOL_NAME(do_IRQ)	!      rxi
-	.long	SYMBOL_NAME(do_IRQ)	!      bri
-	.long	SYMBOL_NAME(do_IRQ)	!      txi
+	.long	SYMBOL_NAME(do_IRQ)	! 32 Hitachi UDI
+	.long	SYMBOL_NAME(do_IRQ)	! 33 GPIO
+	.long	SYMBOL_NAME(do_IRQ)	! 34 DMAC dmte0
+	.long	SYMBOL_NAME(do_IRQ)	! 35      dmte1
+	.long	SYMBOL_NAME(do_IRQ)	! 36      dmte2
+	.long	SYMBOL_NAME(do_IRQ)	! 37      dmte3
+	.long	SYMBOL_NAME(do_IRQ)	! 38      dmae
+	.long	error			! 39
+	.long	SYMBOL_NAME(do_IRQ)	! 40 SCIF eri
+	.long	SYMBOL_NAME(do_IRQ)	! 41      rxi
+	.long	SYMBOL_NAME(do_IRQ)	! 42      bri
+	.long	SYMBOL_NAME(do_IRQ)	! 43      txi
+	.long	error			! 44
+	.long	error			! 45
+	.long	error			! 46
+	.long	error			! 47
+	.long	SYMBOL_NAME(do_fpu_state_restore)	! 48
+	.long	SYMBOL_NAME(do_fpu_state_restore)	! 49
+#endif
+#if defined(CONFIG_CPU_SUBTYPE_SH7751)
+	.long	error
+	.long	error
+	.long	error
+	.long	error
+	.long	error
+	.long	error
+	.long	error
+	.long	error
+	.long	error
+	.long	error
 	.long	error
 	.long	error
 	.long	error
 	.long	error
-	.long	SYMBOL_NAME(do_fpu_state_restore)
-	.long	SYMBOL_NAME(do_fpu_state_restore)
+	.long	SYMBOL_NAME(do_IRQ)	! PCI serr
+	.long	SYMBOL_NAME(do_IRQ)	!     dma3
+	.long	SYMBOL_NAME(do_IRQ)	!     dma2
+	.long	SYMBOL_NAME(do_IRQ)	!     dma1
+	.long	SYMBOL_NAME(do_IRQ)	!     dma0
+	.long	SYMBOL_NAME(do_IRQ)	!     pwon
+	.long	SYMBOL_NAME(do_IRQ)	!     pwdwn
+	.long	SYMBOL_NAME(do_IRQ)	!     err
+#elif defined(CONFIG_CPU_SUBTYPE_ST40STB1)
+	.long	error			!  50 0x840
+	.long	error			!  51 0x860
+	.long	error			!  52 0x880
+	.long	error			!  53 0x8a0
+	.long	error			!  54 0x8c0
+	.long	error			!  55 0x8e0
+	.long	error			!  56 0x900
+	.long	error			!  57 0x920
+	.long	error			!  58 0x940
+	.long	error			!  59 0x960
+	.long	error			!  60 0x980
+	.long	error			!  61 0x9a0
+	.long	error			!  62 0x9c0
+	.long	error			!  63 0x9e0
+	.long	SYMBOL_NAME(do_IRQ)	!  64 0xa00 PCI serr
+	.long	SYMBOL_NAME(do_IRQ)	!  65 0xa20     err
+	.long	SYMBOL_NAME(do_IRQ)	!  66 0xa40     ad
+	.long	SYMBOL_NAME(do_IRQ)	!  67 0xa60     pwr_dwn
+	.long	error			!  68 0xa80
+	.long	error			!  69 0xaa0
+	.long	error			!  70 0xac0
+	.long	error			!  71 0xae0
+	.long	SYMBOL_NAME(do_IRQ)	!  72 0xb00 DMA INT0
+	.long	SYMBOL_NAME(do_IRQ)	!  73 0xb20     INT1
+	.long	SYMBOL_NAME(do_IRQ)	!  74 0xb40     INT2
+	.long	SYMBOL_NAME(do_IRQ)	!  75 0xb60     INT3
+	.long	SYMBOL_NAME(do_IRQ)	!  76 0xb80     INT4
+	.long	error			!  77 0xba0
+	.long	SYMBOL_NAME(do_IRQ)	!  78 0xbc0 DMA ERR
+	.long	error			!  79 0xbe0
+	.long	SYMBOL_NAME(do_IRQ)	!  80 0xc00 PIO0
+	.long	SYMBOL_NAME(do_IRQ)	!  81 0xc20 PIO1
+	.long	SYMBOL_NAME(do_IRQ)	!  82 0xc40 PIO2
+	.long	error			!  83 0xc60
+	.long	error			!  84 0xc80
+	.long	error			!  85 0xca0
+	.long	error			!  86 0xcc0
+	.long	error			!  87 0xce0
+	.long	error			!  88 0xd00
+	.long	error			!  89 0xd20
+	.long	error			!  90 0xd40
+	.long	error			!  91 0xd60
+	.long	error			!  92 0xd80
+	.long	error			!  93 0xda0
+	.long	error			!  94 0xdc0
+	.long	error			!  95 0xde0
+	.long	error			!  96 0xe00
+	.long	error			!  97 0xe20
+	.long	error			!  98 0xe40
+	.long	error			!  99 0xe60
+	.long	error			! 100 0xe80
+	.long	error			! 101 0xea0
+	.long	error			! 102 0xec0
+	.long	error			! 103 0xee0
+	.long	error			! 104 0xf00
+	.long	error			! 105 0xf20
+	.long	error			! 106 0xf40
+	.long	error			! 107 0xf60
+	.long	error			! 108 0xf80
+	.long	error			! 109 0xfa0
+	.long	error			! 110 0xfc0
+	.long	error			! 111 0xfe0
+	.long	SYMBOL_NAME(do_IRQ)	! 112 0x1000 Mailbox
+	.long	error			! 113 0x1020
+	.long	error			! 114 0x1040
+	.long	error			! 115 0x1060
+	.long	error			! 116 0x1080
+	.long	error			! 117 0x10a0
+	.long	error			! 118 0x10c0
+	.long	error			! 119 0x10e0
+	.long	error			! 120 0x1100
+	.long	error			! 121 0x1120
+	.long	error			! 122 0x1140
+	.long	error			! 123 0x1160
+	.long	error			! 124 0x1180
+	.long	error			! 125 0x11a0
+	.long	error			! 126 0x11c0
+	.long	error			! 127 0x11e0
+	.long	error			! 128 0x1200
+	.long	error			! 129 0x1220
+	.long	error			! 130 0x1240
+	.long	error			! 131 0x1260
+	.long	error			! 132 0x1280
+	.long	error			! 133 0x12a0
+	.long	error			! 134 0x12c0
+	.long	error			! 135 0x12e0
+	.long	error			! 136 0x1300
+	.long	error			! 137 0x1320
+	.long	error			! 138 0x1340
+	.long	error			! 139 0x1360
+	.long	SYMBOL_NAME(do_IRQ)	! 140 0x1380 EMPI INV_ADDR
+	.long	error			! 141 0x13a0
+	.long	error			! 142 0x13c0
+	.long	error			! 143 0x13e0
 #endif
 
 ENTRY(sys_call_table)
diff -urN linux-2.4.6-pre5/arch/sh/kernel/hd64465_gpio.c linux/arch/sh/kernel/hd64465_gpio.c
--- linux-2.4.6-pre5/arch/sh/kernel/hd64465_gpio.c	Sun May 20 12:11:38 2001
+++ linux/arch/sh/kernel/hd64465_gpio.c	Mon Dec  3 22:49:10 2001
@@ -1,5 +1,5 @@
 /*
- * $Id: hd64465_gpio.c,v 1.1 2001/01/02 15:35:22 mjd Exp $
+ * $Id: hd64465_gpio.c,v 1.2 2001/05/24 00:13:47 gniibe Exp $
  * by Greg Banks <gbanks@pocketpenguins.com>
  * (c) 2000 PocketPenguins Inc
  *
diff -urN linux-2.4.6-pre5/arch/sh/kernel/io_bigsur.c linux/arch/sh/kernel/io_bigsur.c
--- linux-2.4.6-pre5/arch/sh/kernel/io_bigsur.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/sh/kernel/io_bigsur.c	Mon Dec  3 22:49:10 2001
@@ -0,0 +1,249 @@
+/*
+ * include/asm-sh/io_bigsur.c
+ *
+ * By Dustin McIntire (dustin@sensoria.com) (c)2001
+ * Derived from io_hd64465.h, which bore the message:
+ * By Greg Banks <gbanks@pocketpenguins.com>
+ * (c) 2000 PocketPenguins Inc. 
+ * and from io_hd64461.h, which bore the message:
+ * Copyright 2000 Stuart Menefy (stuart.menefy@st.com)
+ *
+ * May be copied or modified under the terms of the GNU General Public
+ * License.  See linux/COPYING for more information.
+ *
+ * IO functions for a Hitachi Big Sur Evaluation Board.
+ */
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <asm/machvec.h>
+#include <asm/io.h>
+#include <asm/bigsur.h>
+
+//#define BIGSUR_DEBUG 2
+#undef BIGSUR_DEBUG
+
+#ifdef BIGSUR_DEBUG
+#define DPRINTK(args...)	printk(args)
+#define DIPRINTK(n, args...)	if (BIGSUR_DEBUG>(n)) printk(args)
+#else
+#define DPRINTK(args...)
+#define DIPRINTK(n, args...)
+#endif
+
+
+/* Low iomap maps port 0-1K to addresses in 8byte chunks */
+#define BIGSUR_IOMAP_LO_THRESH 0x400
+#define BIGSUR_IOMAP_LO_SHIFT	3
+#define BIGSUR_IOMAP_LO_MASK	((1<<BIGSUR_IOMAP_LO_SHIFT)-1)
+#define BIGSUR_IOMAP_LO_NMAP	(BIGSUR_IOMAP_LO_THRESH>>BIGSUR_IOMAP_LO_SHIFT)
+static u32 bigsur_iomap_lo[BIGSUR_IOMAP_LO_NMAP];
+static u8 bigsur_iomap_lo_shift[BIGSUR_IOMAP_LO_NMAP];
+
+/* High iomap maps port 1K-64K to addresses in 1K chunks */
+#define BIGSUR_IOMAP_HI_THRESH 0x10000
+#define BIGSUR_IOMAP_HI_SHIFT	10
+#define BIGSUR_IOMAP_HI_MASK	((1<<BIGSUR_IOMAP_HI_SHIFT)-1)
+#define BIGSUR_IOMAP_HI_NMAP	(BIGSUR_IOMAP_HI_THRESH>>BIGSUR_IOMAP_HI_SHIFT)
+static u32 bigsur_iomap_hi[BIGSUR_IOMAP_HI_NMAP];
+static u8 bigsur_iomap_hi_shift[BIGSUR_IOMAP_HI_NMAP];
+
+#ifndef MAX
+#define MAX(a,b)    ((a)>(b)?(a):(b))
+#endif
+
+#define PORT2ADDR(x) (sh_mv.mv_isa_port2addr(x))
+
+void bigsur_port_map(u32 baseport, u32 nports, u32 addr, u8 shift)
+{
+    u32 port, endport = baseport + nports;
+
+    DPRINTK("bigsur_port_map(base=0x%0x, n=0x%0x, addr=0x%08x)\n",
+	    baseport, nports, addr);
+	    
+	for (port = baseport ;
+	     port < endport && port < BIGSUR_IOMAP_LO_THRESH ;
+	     port += (1<<BIGSUR_IOMAP_LO_SHIFT)) {
+	    	DPRINTK("    maplo[0x%x] = 0x%08x\n", port, addr);
+    	    bigsur_iomap_lo[port>>BIGSUR_IOMAP_LO_SHIFT] = addr;
+    	    bigsur_iomap_lo_shift[port>>BIGSUR_IOMAP_LO_SHIFT] = shift;
+	    	addr += (1<<(BIGSUR_IOMAP_LO_SHIFT));
+	}
+
+	for (port = MAX(baseport, BIGSUR_IOMAP_LO_THRESH) ;
+	     port < endport && port < BIGSUR_IOMAP_HI_THRESH ;
+	     port += (1<<BIGSUR_IOMAP_HI_SHIFT)) {
+	    	DPRINTK("    maphi[0x%x] = 0x%08x\n", port, addr);
+    	    bigsur_iomap_hi[port>>BIGSUR_IOMAP_HI_SHIFT] = addr;
+    	    bigsur_iomap_hi_shift[port>>BIGSUR_IOMAP_HI_SHIFT] = shift;
+	    	addr += (1<<(BIGSUR_IOMAP_HI_SHIFT));
+	}
+}
+EXPORT_SYMBOL(bigsur_port_map);
+
+void bigsur_port_unmap(u32 baseport, u32 nports)
+{
+    u32 port, endport = baseport + nports;
+	
+    DPRINTK("bigsur_port_unmap(base=0x%0x, n=0x%0x)\n", baseport, nports);
+
+	for (port = baseport ;
+	     port < endport && port < BIGSUR_IOMAP_LO_THRESH ;
+	     port += (1<<BIGSUR_IOMAP_LO_SHIFT)) {
+    	    bigsur_iomap_lo[port>>BIGSUR_IOMAP_LO_SHIFT] = 0;
+	}
+
+	for (port = MAX(baseport, BIGSUR_IOMAP_LO_THRESH) ;
+	     port < endport && port < BIGSUR_IOMAP_HI_THRESH ;
+	     port += (1<<BIGSUR_IOMAP_HI_SHIFT)) {
+    	    bigsur_iomap_hi[port>>BIGSUR_IOMAP_HI_SHIFT] = 0;
+	}
+}
+EXPORT_SYMBOL(bigsur_port_unmap);
+
+unsigned long bigsur_isa_port2addr(unsigned long port)
+{
+    unsigned long addr = 0;
+	unsigned char shift;
+
+	/* Physical address not in P0, do nothing */
+	if (PXSEG(port)) addr = port;
+	/* physical address in P0, map to P2 */
+	else if (port >= 0x30000)
+	    addr = P2SEGADDR(port);
+	/* Big Sur I/O + HD64465 registers 0x10000-0x30000 */
+	else if (port >= BIGSUR_IOMAP_HI_THRESH)
+	    addr = BIGSUR_INTERNAL_BASE + (port - BIGSUR_IOMAP_HI_THRESH);
+	/* Handle remapping of high IO/PCI IO ports */
+	else if (port >= BIGSUR_IOMAP_LO_THRESH) {
+	    addr = bigsur_iomap_hi[port >> BIGSUR_IOMAP_HI_SHIFT];
+	    shift = bigsur_iomap_hi_shift[port >> BIGSUR_IOMAP_HI_SHIFT];
+	    if (addr != 0)
+		    addr += (port & BIGSUR_IOMAP_HI_MASK) << shift;
+	}
+	/* Handle remapping of low IO ports */
+	else {
+	    addr = bigsur_iomap_lo[port >> BIGSUR_IOMAP_LO_SHIFT];
+	    shift = bigsur_iomap_lo_shift[port >> BIGSUR_IOMAP_LO_SHIFT];
+	    if (addr != 0)
+	    	addr += (port & BIGSUR_IOMAP_LO_MASK) << shift;
+	}
+
+    DIPRINTK(2, "PORT2ADDR(0x%08lx) = 0x%08lx\n", port, addr);
+
+	return addr;
+}
+
+static inline void delay(void)
+{
+	ctrl_inw(0xa0000000);
+}
+
+unsigned char bigsur_inb(unsigned long port)
+{
+	unsigned long addr = PORT2ADDR(port);
+	unsigned long b = (addr == 0 ? 0 : *(volatile unsigned char*)addr);
+
+	DIPRINTK(0, "inb(%08lx) = %02x\n", addr, (unsigned)b);
+	return b;
+}
+
+unsigned char bigsur_inb_p(unsigned long port)
+{
+    unsigned long v;
+	unsigned long addr = PORT2ADDR(port);
+
+	v = (addr == 0 ? 0 : *(volatile unsigned char*)addr);
+	delay();
+	DIPRINTK(0, "inb_p(%08lx) = %02x\n", addr, (unsigned)v);
+	return v;
+}
+
+unsigned short bigsur_inw(unsigned long port)
+{
+    unsigned long addr = PORT2ADDR(port);
+	unsigned long b = (addr == 0 ? 0 : *(volatile unsigned short*)addr);
+	DIPRINTK(0, "inw(%08lx) = %04lx\n", addr, b);
+	return b;
+}
+
+unsigned int bigsur_inl(unsigned long port)
+{
+    unsigned long addr = PORT2ADDR(port);
+	unsigned int b = (addr == 0 ? 0 : *(volatile unsigned long*)addr);
+	DIPRINTK(0, "inl(%08lx) = %08x\n", addr, b);
+	return b;
+}
+
+void bigsur_insb(unsigned long port, void *buffer, unsigned long count)
+{
+	unsigned char *buf=buffer;
+	while(count--) *buf++=inb(port);
+}
+
+void bigsur_insw(unsigned long port, void *buffer, unsigned long count)
+{
+	unsigned short *buf=buffer;
+	while(count--) *buf++=inw(port);
+}
+
+void bigsur_insl(unsigned long port, void *buffer, unsigned long count)
+{
+	unsigned long *buf=buffer;
+	while(count--) *buf++=inl(port);
+}
+
+void bigsur_outb(unsigned char b, unsigned long port)
+{
+	unsigned long addr = PORT2ADDR(port);
+
+	DIPRINTK(0, "outb(%02x, %08lx)\n", (unsigned)b, addr);
+	if (addr != 0)
+	    *(volatile unsigned char*)addr = b;
+}
+
+void bigsur_outb_p(unsigned char b, unsigned long port)
+{
+	unsigned long addr = PORT2ADDR(port);
+
+	DIPRINTK(0, "outb_p(%02x, %08lx)\n", (unsigned)b, addr);
+    if (addr != 0)
+	    *(volatile unsigned char*)addr = b;
+	delay();
+}
+
+void bigsur_outw(unsigned short b, unsigned long port)
+{
+	unsigned long addr = PORT2ADDR(port);
+	DIPRINTK(0, "outw(%04x, %08lx)\n", (unsigned)b, addr);
+	if (addr != 0)
+	    *(volatile unsigned short*)addr = b;
+}
+
+void bigsur_outl(unsigned int b, unsigned long port)
+{
+	unsigned long addr = PORT2ADDR(port);
+	DIPRINTK(0, "outl(%08x, %08lx)\n", b, addr);
+	if (addr != 0)
+            *(volatile unsigned long*)addr = b;
+}
+
+void bigsur_outsb(unsigned long port, const void *buffer, unsigned long count)
+{
+	const unsigned char *buf=buffer;
+	while(count--) outb(*buf++, port);
+}
+
+void bigsur_outsw(unsigned long port, const void *buffer, unsigned long count)
+{
+	const unsigned short *buf=buffer;
+	while(count--) outw(*buf++, port);
+}
+
+void bigsur_outsl(unsigned long port, const void *buffer, unsigned long count)
+{
+	const unsigned long *buf=buffer;
+	while(count--) outl(*buf++, port);
+}
+
diff -urN linux-2.4.6-pre5/arch/sh/kernel/io_dc.c linux/arch/sh/kernel/io_dc.c
--- linux-2.4.6-pre5/arch/sh/kernel/io_dc.c	Sun May 20 12:11:38 2001
+++ linux/arch/sh/kernel/io_dc.c	Mon Dec  3 22:49:10 2001
@@ -1,5 +1,5 @@
 /*
- *	$Id: io_dc.c,v 1.1 2001/04/01 15:02:00 yaegashi Exp $
+ *	$Id: io_dc.c,v 1.2 2001/05/24 00:13:47 gniibe Exp $
  *	I/O routines for SEGA Dreamcast
  */
 
diff -urN linux-2.4.6-pre5/arch/sh/kernel/io_hd64465.c linux/arch/sh/kernel/io_hd64465.c
--- linux-2.4.6-pre5/arch/sh/kernel/io_hd64465.c	Wed Apr 11 21:24:52 2001
+++ linux/arch/sh/kernel/io_hd64465.c	Mon Dec  3 22:49:10 2001
@@ -1,5 +1,5 @@
 /*
- * $Id: io_hd64465.c,v 1.6 2001/02/15 09:13:51 dave_mckay Exp $
+ * $Id: io_hd64465.c,v 1.7 2001/05/09 07:39:36 gniibe Exp $
  * by Greg Banks <gbanks@pocketpenguins.com>
  * (c) 2000 PocketPenguins Inc
  *
@@ -52,6 +52,8 @@
 #define MAX(a,b)    ((a)>(b)?(a):(b))
 #endif
 
+#define PORT2ADDR(x) (sh_mv.mv_isa_port2addr(x))
+
 void hd64465_port_map(unsigned short baseport, unsigned int nports,
 		      unsigned long addr, unsigned char shift)
 {
@@ -101,7 +103,7 @@
 }
 EXPORT_SYMBOL(hd64465_port_unmap);
 
-static /*__inline__*/ unsigned long PORT2ADDR(unsigned long port)
+unsigned long hd64465_isa_port2addr(unsigned long port)
 {
     	unsigned long addr = 0;
 	unsigned char shift;
diff -urN linux-2.4.6-pre5/arch/sh/kernel/io_sh2000.c linux/arch/sh/kernel/io_sh2000.c
--- linux-2.4.6-pre5/arch/sh/kernel/io_sh2000.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/sh/kernel/io_sh2000.c	Mon Dec  3 22:49:10 2001
@@ -0,0 +1,19 @@
+/*
+ * I/O routine for SH-2000
+ */
+#include <linux/config.h>
+#include <asm/io.h>
+#include <asm/machvec.h>
+
+#define IDE_OFFSET    0xb6200000
+#define NIC_OFFSET    0xb6000000
+#define EXTBUS_OFFSET 0xba000000
+
+unsigned long sh2000_isa_port2addr(unsigned long offset)
+{
+	if((offset & ~7) == 0x1f0 || offset == 0x3f6)
+		return IDE_OFFSET + offset;
+	else if((offset & ~0x1f) == 0x300)
+		return NIC_OFFSET + offset;
+	return EXTBUS_OFFSET + offset;
+}
diff -urN linux-2.4.6-pre5/arch/sh/kernel/irq.c linux/arch/sh/kernel/irq.c
--- linux-2.4.6-pre5/arch/sh/kernel/irq.c	Fri Feb  9 11:29:44 2001
+++ linux/arch/sh/kernel/irq.c	Mon Dec  3 22:49:10 2001
@@ -38,12 +38,6 @@
 #include <linux/irq.h>
 
 /*
- * Micro-access to controllers is serialized over the whole
- * system. We never hold this lock when we call the actual
- * IRQ handler.
- */
-spinlock_t irq_controller_lock = SPIN_LOCK_UNLOCKED;
-/*
  * Controller mappings for all interrupt sources:
  */
 irq_desc_t irq_desc[NR_IRQS] __cacheline_aligned =
@@ -160,14 +154,15 @@
  */
 void disable_irq_nosync(unsigned int irq)
 {
+	irq_desc_t *desc = irq_desc + irq;
 	unsigned long flags;
 
-	spin_lock_irqsave(&irq_controller_lock, flags);
-	if (!irq_desc[irq].depth++) {
-		irq_desc[irq].status |= IRQ_DISABLED;
-		irq_desc[irq].handler->disable(irq);
+	spin_lock_irqsave(&desc->lock, flags);
+	if (!desc->depth++) {
+		desc->status |= IRQ_DISABLED;
+		desc->handler->disable(irq);
 	}
-	spin_unlock_irqrestore(&irq_controller_lock, flags);
+	spin_unlock_irqrestore(&desc->lock, flags);
 }
 
 /*
@@ -187,28 +182,29 @@
 
 void enable_irq(unsigned int irq)
 {
+	irq_desc_t *desc = irq_desc + irq;
 	unsigned long flags;
 
-	spin_lock_irqsave(&irq_controller_lock, flags);
-	switch (irq_desc[irq].depth) {
+	spin_lock_irqsave(&desc->lock, flags);
+	switch (desc->depth) {
 	case 1: {
-		unsigned int status = irq_desc[irq].status & ~IRQ_DISABLED;
-		irq_desc[irq].status = status;
+		unsigned int status = desc->status & ~IRQ_DISABLED;
+		desc->status = status;
 		if ((status & (IRQ_PENDING | IRQ_REPLAY)) == IRQ_PENDING) {
-			irq_desc[irq].status = status | IRQ_REPLAY;
-			hw_resend_irq(irq_desc[irq].handler,irq);
+			desc->status = status | IRQ_REPLAY;
+			hw_resend_irq(desc->handler,irq);
 		}
-		irq_desc[irq].handler->enable(irq);
+		desc->handler->enable(irq);
 		/* fall-through */
 	}
 	default:
-		irq_desc[irq].depth--;
+		desc->depth--;
 		break;
 	case 0:
 		printk("enable_irq() unbalanced from %p\n",
 		       __builtin_return_address(0));
 	}
-	spin_unlock_irqrestore(&irq_controller_lock, flags);
+	spin_unlock_irqrestore(&desc->lock, flags);
 }
 
 /*
@@ -245,7 +241,7 @@
 
 	kstat.irqs[cpu][irq]++;
 	desc = irq_desc + irq;
-	spin_lock(&irq_controller_lock);
+	spin_lock(&desc->lock);
 	desc->handler->ack(irq);
 	/*
 	   REPLAY is when Linux resends an IRQ that was dropped earlier
@@ -265,7 +261,6 @@
 		status |= IRQ_INPROGRESS; /* we are handling it */
 	}
 	desc->status = status;
-	spin_unlock(&irq_controller_lock);
 
 	/*
 	 * If there is no IRQ handler or it was disabled, exit early.
@@ -274,7 +269,7 @@
 	   will take care of it.
 	 */
 	if (!action)
-		return 1;
+		goto out;
 
 	/*
 	 * Edge triggered interrupts need to remember
@@ -287,23 +282,24 @@
 	 * SMP environment.
 	 */
 	for (;;) {
+		spin_unlock(&desc->lock);
 		handle_IRQ_event(irq, &regs, action);
-		spin_lock(&irq_controller_lock);
+		spin_lock(&desc->lock);
 
 		if (!(desc->status & IRQ_PENDING))
 			break;
 		desc->status &= ~IRQ_PENDING;
-		spin_unlock(&irq_controller_lock);
 	}
 	desc->status &= ~IRQ_INPROGRESS;
-	if (!(desc->status & IRQ_DISABLED))
-		desc->handler->end(irq);
-	spin_unlock(&irq_controller_lock);
+out:
+	/*
+	 * The ->end() handler has to deal with interrupts which got
+	 * disabled while the handler was running.
+	 */
+	desc->handler->end(irq);
+	spin_unlock(&desc->lock);
 
-#if 0
-	__sti();
-#endif
-	if (softirq_active(cpu)&softirq_mask(cpu))
+	if (softirq_pending(cpu))
 		do_softirq();
 	return 1;
 }
@@ -342,14 +338,16 @@
 
 void free_irq(unsigned int irq, void *dev_id)
 {
+	irq_desc_t *desc;
 	struct irqaction **p;
 	unsigned long flags;
 
 	if (irq >= ACTUAL_NR_IRQS)
 		return;
 
-	spin_lock_irqsave(&irq_controller_lock,flags);
-	p = &irq_desc[irq].action;
+	desc = irq_desc + irq;
+	spin_lock_irqsave(&desc->lock,flags);
+	p = &desc->action;
 	for (;;) {
 		struct irqaction * action = *p;
 		if (action) {
@@ -360,20 +358,22 @@
 
 			/* Found it - now remove it from the list of entries */
 			*pp = action->next;
-			if (!irq_desc[irq].action) {
-				irq_desc[irq].status |= IRQ_DISABLED;
-				irq_desc[irq].handler->shutdown(irq);
+			if (!desc->action) {
+				desc->status |= IRQ_DISABLED;
+				desc->handler->shutdown(irq);
 			}
-			spin_unlock_irqrestore(&irq_controller_lock,flags);
+			spin_unlock_irqrestore(&desc->lock,flags);
 			kfree(action);
 			return;
 		}
 		printk("Trying to free free IRQ%d\n",irq);
-		spin_unlock_irqrestore(&irq_controller_lock,flags);
+		spin_unlock_irqrestore(&desc->lock,flags);
 		return;
 	}
 }
 
+static DECLARE_MUTEX(probe_sem);
+
 /*
  * IRQ autodetection code..
  *
@@ -385,21 +385,44 @@
 unsigned long probe_irq_on(void)
 {
 	unsigned int i;
-	unsigned long delay;
+	irq_desc_t *desc;
 	unsigned long val;
+	unsigned long delay;
+
+	down(&probe_sem);
+	/* 
+	 * something may have generated an irq long ago and we want to
+	 * flush such a longstanding irq before considering it as spurious. 
+	 */
+	for (i = NR_IRQS-1; i > 0; i--) {
+		desc = irq_desc + i;
+
+		spin_lock_irq(&desc->lock);
+		if (!desc->action)
+		  desc->handler->startup(i);
+		spin_unlock_irq(&desc->lock);
+	}
+
+	/* Wait for longstanding interrupts to trigger. */
+	for (delay = jiffies + HZ/50; time_after(delay, jiffies); )
+		/* about 20ms delay */ synchronize_irq();
 
 	/*
-	 * first, enable any unassigned irqs
+	 * enable any unassigned irqs
+	 * (we must startup again here because if a longstanding irq
+	 * happened in the previous stage, it may have masked itself)
 	 */
-	spin_lock_irq(&irq_controller_lock);
 	for (i = NR_IRQS-1; i > 0; i--) {
-		if (!irq_desc[i].action) {
-			irq_desc[i].status |= IRQ_AUTODETECT | IRQ_WAITING;
-			if (irq_desc[i].handler->startup(i))
-				irq_desc[i].status |= IRQ_PENDING;
+		desc = irq_desc + i;
+
+		spin_lock_irq(&desc->lock);
+		if (!desc->action) {
+			desc->status |= IRQ_AUTODETECT | IRQ_WAITING;
+			if (desc->handler->startup(i))
+				desc->status |= IRQ_PENDING;
 		}
+		spin_unlock_irq(&desc->lock);
 	}
-	spin_unlock_irq(&irq_controller_lock);
 
 	/*
 	 * Wait for spurious interrupts to trigger
@@ -411,23 +434,25 @@
 	 * Now filter out any obviously spurious interrupts
 	 */
 	val = 0;
-	spin_lock_irq(&irq_controller_lock);
 	for (i=0; i<NR_IRQS; i++) {
-		unsigned int status = irq_desc[i].status;
+		desc = irq_desc + i;
+		unsigned int status;
 
-		if (!(status & IRQ_AUTODETECT))
-			continue;
+		spin_lock_irq(&desc->lock);
+		status = desc->status;
 
-		/* It triggered already - consider it spurious. */
-		if (!(status & IRQ_WAITING)) {
-			irq_desc[i].status = status & ~IRQ_AUTODETECT;
-			irq_desc[i].handler->shutdown(i);
+		if (status & IRQ_AUTODETECT) {
+			/* It triggered already - consider it spurious. */
+			if (!(status & IRQ_WAITING)) {
+				desc->status = status & ~IRQ_AUTODETECT;
+				desc->handler->shutdown(i);
+			} else
+				if (i < 32)
+					val |= 1 << i;
 		}
-
-		if (i < 32)
-			val |= 1 << i;
+		spin_unlock_irq(&desc->lock);
 	}
-	spin_unlock_irq(&irq_controller_lock);
+	spin_unlock_irq(&desc->lock);
 
 	return val;
 }
@@ -438,22 +463,25 @@
 
 	nr_irqs = 0;
 	irq_found = 0;
-	spin_lock_irq(&irq_controller_lock);
 	for (i=0; i<NR_IRQS; i++) {
-		unsigned int status = irq_desc[i].status;
+		irq_desc_t *desc = irq_desc + i;
+		unsigned int status;
 
-		if (!(status & IRQ_AUTODETECT))
-			continue;
+		spin_lock_irq(&desc->lock);
+		status = desc->status;
 
-		if (!(status & IRQ_WAITING)) {
-			if (!nr_irqs)
-				irq_found = i;
-			nr_irqs++;
+		if (status & IRQ_AUTODETECT) {
+			if (!(status & IRQ_WAITING)) {
+				if (!nr_irqs)
+					irq_found = i;
+				nr_irqs++;
+			}
+			desc->status = status & ~IRQ_AUTODETECT;
+			desc->handler->shutdown(i);
 		}
-		irq_desc[i].status = status & ~IRQ_AUTODETECT;
-		irq_desc[i].handler->shutdown(i);
+		spin_unlock_irq(&desc->lock);
 	}
-	spin_unlock_irq(&irq_controller_lock);
+	up(&probe_sem);
 
 	if (nr_irqs > 1)
 		irq_found = -irq_found;
@@ -465,6 +493,7 @@
 	int shared = 0;
 	struct irqaction *old, **p;
 	unsigned long flags;
+	irq_desc_t *desc = irq_desc + irq;
 
 	/*
 	 * Some drivers like serial.c use request_irq() heavily,
@@ -486,12 +515,12 @@
 	/*
 	 * The following block of code has to be executed atomically
 	 */
-	spin_lock_irqsave(&irq_controller_lock,flags);
-	p = &irq_desc[irq].action;
+	spin_lock_irqsave(&desc->lock,flags);
+	p = &desc->action;
 	if ((old = *p) != NULL) {
 		/* Can't share interrupts unless both agree to */
 		if (!(old->flags & new->flags & SA_SHIRQ)) {
-			spin_unlock_irqrestore(&irq_controller_lock,flags);
+			spin_unlock_irqrestore(&desc->lock,flags);
 			return -EBUSY;
 		}
 
@@ -506,11 +535,11 @@
 	*p = new;
 
 	if (!shared) {
-		irq_desc[irq].depth = 0;
-		irq_desc[irq].status &= ~IRQ_DISABLED;
-		irq_desc[irq].handler->startup(irq);
+		desc->depth = 0;
+		desc->status &= ~IRQ_DISABLED;
+		desc->handler->startup(irq);
 	}
-	spin_unlock_irqrestore(&irq_controller_lock,flags);
+	spin_unlock_irqrestore(&desc->lock,flags);
 	return 0;
 }
 
diff -urN linux-2.4.6-pre5/arch/sh/kernel/irq_intc2.c linux/arch/sh/kernel/irq_intc2.c
--- linux-2.4.6-pre5/arch/sh/kernel/irq_intc2.c	Sun May 20 12:11:38 2001
+++ linux/arch/sh/kernel/irq_intc2.c	Mon Dec  3 22:49:10 2001
@@ -45,7 +45,7 @@
 }
 
 static struct hw_interrupt_type intc2_irq_type = {
-	"INTC2-based-IRQ",
+	"INTC2-IRQ",
 	startup_intc2_irq,
 	shutdown_intc2_irq,
 	enable_intc2_irq,
diff -urN linux-2.4.6-pre5/arch/sh/kernel/irq_ipr.c linux/arch/sh/kernel/irq_ipr.c
--- linux-2.4.6-pre5/arch/sh/kernel/irq_ipr.c	Wed Apr 11 21:24:52 2001
+++ linux/arch/sh/kernel/irq_ipr.c	Mon Dec  3 22:49:10 2001
@@ -46,7 +46,7 @@
 }
 
 static struct hw_interrupt_type ipr_irq_type = {
-	"IPR-based-IRQ",
+	"IPR-IRQ",
 	startup_ipr_irq,
 	shutdown_ipr_irq,
 	enable_ipr_irq,
@@ -189,7 +189,9 @@
 
 void __init init_IRQ(void)
 {
+#if defined(CONFIG_CPU_SUBTYPE_SH7707) || defined(CONFIG_CPU_SUBTYPE_SH7709)
 	int i;
+#endif
 
 	make_ipr_irq(TIMER_IRQ, TIMER_IPR_ADDR, TIMER_IPR_POS, TIMER_PRIORITY);
 	make_ipr_irq(RTC_IRQ, RTC_IPR_ADDR, RTC_IPR_POS, RTC_PRIORITY);
@@ -226,27 +228,6 @@
 	 * Initialize the Interrupt Controller (INTC)
 	 * registers to their power on values
 	 */ 
-#if 0
-	/*
-	 * XXX: I think that this is the job of boot loader. -- gniibe
-	 *
-	 * When Takeshi released new boot loader following setting
-	 * will be removed shortly.
-	 */
-	ctrl_outb(0, INTC_IRR0);
-	ctrl_outb(0, INTC_IRR1);
-	ctrl_outb(0, INTC_IRR2);
-
-	ctrl_outw(0, INTC_ICR0);
-	ctrl_outw(0, INTC_ICR1);/* Really? 0x4000?*/
-	ctrl_outw(0, INTC_ICR2);
-	ctrl_outw(0, INTC_INTER);
-	ctrl_outw(0, INTC_IPRA);
-	ctrl_outw(0, INTC_IPRB);
-	ctrl_outw(0, INTC_IPRC);
-	ctrl_outw(0, INTC_IPRD);
-	ctrl_outw(0, INTC_IPRE);
-#endif
 
 	/*
 	 * Enable external irq (INTC IRQ mode).
diff -urN linux-2.4.6-pre5/arch/sh/kernel/led_bigsur.c linux/arch/sh/kernel/led_bigsur.c
--- linux-2.4.6-pre5/arch/sh/kernel/led_bigsur.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/sh/kernel/led_bigsur.c	Mon Dec  3 22:49:10 2001
@@ -0,0 +1,55 @@
+/*
+ * linux/arch/sh/kernel/led_bigsur.c
+ *
+ * By Dustin McIntire (dustin@sensoria.com) (c)2001
+ * Derived from led_se.c and led.c, which bore the message:
+ * Copyright (C) 2000 Stuart Menefy <stuart.menefy@st.com>
+ *
+ * May be copied or modified under the terms of the GNU General Public
+ * License.  See linux/COPYING for more information.
+ *
+ * This file contains Big Sur specific LED code.
+ */
+
+#include <linux/config.h>
+#include <asm/io.h>
+#include <asm/bigsur.h>
+
+static void mach_led(int position, int value)
+{
+	int word;
+	
+	word = bigsur_inl(BIGSUR_CSLR);
+	if (value) {
+		bigsur_outl(word & ~BIGSUR_LED, BIGSUR_CSLR);
+	} else {
+		bigsur_outl(word | BIGSUR_LED, BIGSUR_CSLR);
+	}
+}
+
+#ifdef CONFIG_HEARTBEAT
+
+#include <linux/sched.h>
+
+/* Cycle the LED on/off */
+void heartbeat_bigsur(void)
+{
+	static unsigned cnt = 0, period = 0, dist = 0;
+
+	if (cnt == 0 || cnt == dist)
+		mach_led( -1, 1);
+	else if (cnt == 7 || cnt == dist+7)
+		mach_led( -1, 0);
+
+	if (++cnt > period) {
+		cnt = 0;
+		/* The hyperbolic function below modifies the heartbeat period
+		 * length in dependency of the current (5min) load. It goes
+		 * through the points f(0)=126, f(1)=86, f(5)=51,
+		 * f(inf)->30. */
+		period = ((672<<FSHIFT)/(5*avenrun[0]+(7<<FSHIFT))) + 30;
+		dist = period / 4;
+	}
+}
+#endif /* CONFIG_HEARTBEAT */
+
diff -urN linux-2.4.6-pre5/arch/sh/kernel/mach_bigsur.c linux/arch/sh/kernel/mach_bigsur.c
--- linux-2.4.6-pre5/arch/sh/kernel/mach_bigsur.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/sh/kernel/mach_bigsur.c	Mon Dec  3 22:49:10 2001
@@ -0,0 +1,77 @@
+/*
+ * linux/arch/sh/kernel/mach_bigsur.c
+ *
+ * By Dustin McIntire (dustin@sensoria.com) (c)2001
+ * Derived from mach_se.h, which bore the message:
+ * Copyright (C) 2000 Stuart Menefy (stuart.menefy@st.com)
+ *
+ * May be copied or modified under the terms of the GNU General Public
+ * License.  See linux/COPYING for more information.
+ *
+ * Machine vector for the Hitachi Big Sur Evaluation Board
+ */
+
+#include <linux/config.h>
+#include <linux/init.h>
+
+#include <asm/machvec.h>
+#include <asm/rtc.h>
+#include <asm/machvec_init.h>
+#include <asm/io.h>
+#include <asm/io_bigsur.h>
+#include <asm/irq.h>
+
+/*
+ * The Machine Vector
+ */
+extern void heartbeat_bigsur(void);
+extern void setup_bigsur(void);
+extern void init_bigsur_IRQ(void);
+
+struct sh_machine_vector mv_bigsur __initmv = {
+	mv_name:		"Big Sur",
+	mv_nr_irqs:		NR_IRQS,     // Defined in <asm/irq.h>
+	mv_inb:			bigsur_inb,
+	mv_inw:			bigsur_inw,
+	mv_inl:			bigsur_inl,
+	mv_outb:		bigsur_outb,
+	mv_outw:		bigsur_outw,
+	mv_outl:		bigsur_outl,
+
+	mv_inb_p:		bigsur_inb_p,
+	mv_inw_p:		bigsur_inw,
+	mv_inl_p:		bigsur_inl,
+	mv_outb_p:		bigsur_outb_p,
+	mv_outw_p:		bigsur_outw,
+	mv_outl_p:		bigsur_outl,
+
+	mv_insb:		bigsur_insb,
+	mv_insw:		bigsur_insw,
+	mv_insl:		bigsur_insl,
+	mv_outsb:		bigsur_outsb,
+	mv_outsw:		bigsur_outsw,
+	mv_outsl:		bigsur_outsl,
+
+	mv_readb:		generic_readb,
+	mv_readw:		generic_readw,
+	mv_readl:		generic_readl,
+	mv_writeb:		generic_writeb,
+	mv_writew:		generic_writew,
+	mv_writel:		generic_writel,
+
+	mv_ioremap:		generic_ioremap,
+	mv_iounmap:		generic_iounmap,
+
+	mv_isa_port2addr:	bigsur_isa_port2addr,
+	mv_irq_demux:       bigsur_irq_demux,
+
+	mv_init_arch:		setup_bigsur,
+	mv_init_irq:		init_bigsur_IRQ,
+#ifdef CONFIG_HEARTBEAT
+	mv_heartbeat:		heartbeat_bigsur,
+#endif
+	mv_rtc_gettimeofday:	sh_rtc_gettimeofday,
+	mv_rtc_settimeofday:	sh_rtc_settimeofday,
+
+};
+ALIAS_MV(bigsur)
diff -urN linux-2.4.6-pre5/arch/sh/kernel/mach_dc.c linux/arch/sh/kernel/mach_dc.c
--- linux-2.4.6-pre5/arch/sh/kernel/mach_dc.c	Sun May 20 12:11:38 2001
+++ linux/arch/sh/kernel/mach_dc.c	Mon Dec  3 22:49:10 2001
@@ -1,5 +1,5 @@
 /*
- *	$Id: mach_dc.c,v 1.1 2001/04/01 15:02:00 yaegashi Exp $
+ *	$Id: mach_dc.c,v 1.4 2001/05/24 05:09:16 mrbrown Exp $
  *	SEGA Dreamcast machine vector
  */
 
@@ -23,7 +23,7 @@
 struct sh_machine_vector mv_dreamcast __initmv = {
 	mv_name:		"dreamcast",
 
-	mv_nr_irqs:		48,
+	mv_nr_irqs:		NR_IRQS,
 
 	mv_inb:			generic_inb,
 	mv_inw:			generic_inw,
@@ -57,11 +57,9 @@
 	mv_iounmap:		generic_iounmap,
 
 	mv_init_arch:		setup_dreamcast,
-#ifdef CONFIG_PCI
-	mv_init_pci:		dreamcast_pcibios_init,
-#endif
 	mv_isa_port2addr:	dreamcast_isa_port2addr,
+	mv_irq_demux:		systemasic_irq_demux,
 
-	mv_hw_dreamcast:		1,
+	mv_hw_dreamcast:	1,
 };
 ALIAS_MV(dreamcast)
diff -urN linux-2.4.6-pre5/arch/sh/kernel/pci-7751se.c linux/arch/sh/kernel/pci-7751se.c
--- linux-2.4.6-pre5/arch/sh/kernel/pci-7751se.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/sh/kernel/pci-7751se.c	Mon Dec  3 22:49:10 2001
@@ -0,0 +1,102 @@
+/*
+ * linux/arch/sh/kernel/pci-7751se.c
+ *
+ * Author:  Ian DaSilva (idasilva@mvista.com)
+ *
+ * Highly leveraged from pci-bigsur.c, written by Dustin McIntire.
+ *
+ * May be copied or modified under the terms of the GNU General Public
+ * License.  See linux/COPYING for more information.
+ *
+ * PCI initialization for the Hitachi SH7751 Solution Engine board (MS7751SE01)
+ */
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/pci.h>
+
+#include <asm/io.h>
+#include <asm/pci-sh7751.h>
+
+#define PCIMCR_MRSET_OFF	0xBFFFFFFF
+#define PCIMCR_RFSH_OFF		0xFFFFFFFB
+
+/*
+ * Only long word accesses of the PCIC's internal local registers and the
+ * configuration registers from the CPU is supported.
+ */
+#define PCIC_WRITE(x,v) writel((v), PCI_REG(x))
+#define PCIC_READ(x) readl(PCI_REG(x))
+
+/*
+ * Description:  This function sets up and initializes the pcic, sets
+ * up the BARS, maps the DRAM into the address space etc, etc.
+ */
+int __init pcibios_init_platform(void)
+{
+   unsigned long data;
+   unsigned long bcr1, wcr1, wcr2, wcr3, mcr;
+   unsigned short bcr2;
+
+   //
+   // Initialize the slave bus controller on the pcic.  The values used
+   // here should not be hardcoded, but they should be taken from the bsc
+   // on the processor, to make this function as generic as possible.
+   // (i.e. Another sbc may usr different SDRAM timing settings -- in order
+   // for the pcic to work, its settings need to be exactly the same.)
+   //
+   bcr1 = (*(volatile unsigned long*)(SH7751_BCR1));
+   bcr2 = (*(volatile unsigned short*)(SH7751_BCR2));
+   wcr1 = (*(volatile unsigned long*)(SH7751_WCR1));
+   wcr2 = (*(volatile unsigned long*)(SH7751_WCR2));
+   wcr3 = (*(volatile unsigned long*)(SH7751_WCR3));
+   mcr = (*(volatile unsigned long*)(SH7751_MCR));
+
+   bcr1 = bcr1 | 0x00080000;  /* Enable Bit 19, BREQEN */
+   (*(volatile unsigned long*)(SH7751_BCR1)) = bcr1;   
+
+   bcr1 = bcr1 | 0x40080000;  /* Enable Bit 19 BREQEN, set PCIC to slave */
+   PCIC_WRITE(SH7751_PCIBCR1, bcr1);	 /* PCIC BCR1 */
+   PCIC_WRITE(SH7751_PCIBCR2, bcr2);     /* PCIC BCR2 */
+   PCIC_WRITE(SH7751_PCIWCR1, wcr1);     /* PCIC WCR1 */
+   PCIC_WRITE(SH7751_PCIWCR2, wcr2);     /* PCIC WCR2 */
+   PCIC_WRITE(SH7751_PCIWCR3, wcr3);     /* PCIC WCR3 */
+   mcr = (mcr & PCIMCR_MRSET_OFF) & PCIMCR_RFSH_OFF;
+   PCIC_WRITE(SH7751_PCIMCR, mcr);      /* PCIC MCR */
+
+   PCIC_WRITE(SH7751_PCIINTM, 0x0000c3ff);
+   PCIC_WRITE(SH7751_PCIAINTM, 0x0000980f);
+   PCIC_WRITE(SH7751_PCICONF1, 0xF39000C7);  /* FB9000C7 */
+   PCIC_WRITE(SH7751_PCICONF2, 0x00000000);  /* PCI Class code & Revision ID */
+   PCIC_WRITE(SH7751_PCICONF4, 0xab000001);  /* PCI I/O */
+   PCIC_WRITE(SH7751_PCICONF5, 0x0c000000);  /* PCI MEM0 old val: 0xb0000000 */
+   PCIC_WRITE(SH7751_PCICONF6, 0xd0000000);  /* PCI MEM1 */
+   PCIC_WRITE(SH7751_PCICONF11, 0x35051054); /* PCI Sub system ID & Sub system vendor ID */
+   PCIC_WRITE(SH7751_PCILSR0, 0x03f00000);   /* PCI MEM0 */
+   PCIC_WRITE(SH7751_PCILSR1, 0x00000000);   /* PCI MEM1 */
+   PCIC_WRITE(SH7751_PCILAR0, 0x0c000000);   /* MEM0 */
+   PCIC_WRITE(SH7751_PCILAR1, 0x00000000);   /* MEM1 */
+
+   PCIC_WRITE(SH7751_PCICR, 0xa5000001);
+
+   printk("SH7751 PCI: Finished initialization of the PCI controller\n");
+
+   return 1;
+}
+
+int __init pcibios_map_platform_irq(u8 slot, u8 pin)
+{
+        switch (slot) {
+        case 0: return 13;
+        case 1: return 13; 	/* AMD Ethernet controller */
+        case 2: return -1;
+        case 3: return -1;
+        case 4: return -1;
+        default:
+                printk("PCI: Bad IRQ mapping request for slot %d\n", slot);
+                return -1;
+        }
+}
diff -urN linux-2.4.6-pre5/arch/sh/kernel/pci-bigsur.c linux/arch/sh/kernel/pci-bigsur.c
--- linux-2.4.6-pre5/arch/sh/kernel/pci-bigsur.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/sh/kernel/pci-bigsur.c	Mon Dec  3 22:49:10 2001
@@ -0,0 +1,163 @@
+/*
+ * linux/arch/sh/kernel/pci-bigsur.c
+ *
+ * By Dustin McIntire (dustin@sensoria.com) (c)2001
+
+ * May be copied or modified under the terms of the GNU General Public
+ * License.  See linux/COPYING for more information.
+ *
+ * PCI initialization for the Hitachi Big Sur Evaluation Board
+ */
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/pci.h>
+
+#include <asm/io.h>
+#include <asm/pci-sh7751.h>
+#include <asm/bigsur.h>
+
+#define PCI_REG(reg)        (SH7751_PCIREG_BASE+reg)
+
+/*
+ * Initialize the Big Sur PCI interface 
+ * Setup hardware to be Central Funtion
+ * Copy the BSR regs to the PCI interface
+ * Setup PCI windows into local RAM
+ */
+int __init pcibios_init_platform(void) {
+	u32 reg;
+	u32 word;
+
+	PCIDBG(1,"PCI: bigsur_pci_init called\n");
+	/* Set the BCR's to enable PCI access */
+	reg = inl(SH7751_BCR1);
+	reg |= 0x80000;
+	outl(reg, SH7751_BCR1);
+	
+	/* Setup the host hardware */
+	if(inl(PCI_REG(SH7751_PCICONF0)) !=
+	   (u32)((SH7751_DEVICE_ID <<16) | (SH7751_VENDOR_ID))) {
+	   printk("PCI: Unkown PCI host bridge.\n");
+	   return 0;
+	}  
+	printk("PCI: SH7751 PCI host bridge found.\n");
+	
+	/* Turn the clocks back on (not done in reset)*/
+	outl(0, PCI_REG(SH7751_PCICLKR));
+	/* Clear Powerdown IRQ's (not done in reset) */
+	word = SH7751_PCIPINT_D3 | SH7751_PCIPINT_D0;
+	outl(word, PCI_REG(SH7751_PCICLKR));
+
+	/* toggle PCI reset pin */
+	word = SH7751_PCICR_PREFIX | SH7751_PCICR_PRST;
+	outl(word,PCI_REG(SH7751_PCICR));    
+	/* Wait for a long time... not 1 sec. but long enough */
+	mdelay(100);
+	word = SH7751_PCICR_PREFIX;
+	outl(word,PCI_REG(SH7751_PCICR)); 
+	
+    /* set the command/status bits to:
+     * Wait Cycle Control + Parity Enable + Bus Master +
+     * Mem space enable
+     */
+    word = SH7751_PCICONF1_WCC | SH7751_PCICONF1_PER | 
+           SH7751_PCICONF1_BUM | SH7751_PCICONF1_MES;
+	outl(word, PCI_REG(SH7751_PCICONF1));
+
+	/* define this host as the host bridge */
+	word = SH7751_PCI_HOST_BRIDGE << 24;
+	outl(word, PCI_REG(SH7751_PCICONF2));
+
+	/* Set IO and Mem windows to local address 
+	 * Make PCI and local address the same for easy 1 to 1 mapping 
+	 * Window0 = BIGSUR_LSR0_SIZE @ non-cached CS3 base = SDRAM
+	 * Window1 = BIGSUR_LSR1_SIZE @ cached CS3 base = SDRAM 
+	 */
+	word = BIGSUR_LSR0_SIZE - 1;
+	outl(word, PCI_REG(SH7751_PCILSR0));
+	word = BIGSUR_LSR1_SIZE - 1;
+	outl(word, PCI_REG(SH7751_PCILSR1));
+	/* Set the values on window 0 PCI config registers */
+	word = P2SEGADDR(SH7751_CS3_BASE_ADDR);
+	outl(word, PCI_REG(SH7751_PCILAR0));
+	outl(word, PCI_REG(SH7751_PCICONF5));
+	/* Set the values on window 1 PCI config registers */
+	word =  PHYSADDR(SH7751_CS3_BASE_ADDR);
+	outl(word, PCI_REG(SH7751_PCILAR1));
+	outl(word, PCI_REG(SH7751_PCICONF6));
+
+	/* Set the local 16MB PCI memory space window to 
+	 * the lowest PCI mapped address
+	 */
+	word = PCIBIOS_MIN_MEM & SH7751_PCIMBR_MASK;
+	PCIDBG(2,"PCI: Setting upper bits of Memory window to 0x%x\n", word);
+	outl(word , PCI_REG(SH7751_PCIMBR));
+
+	/* Map IO space into PCI IO window
+	 * The IO window is 64K-PCIBIOS_MIN_IO in size
+	 * IO addresses will be translated to the 
+	 * PCI IO window base address
+	 */
+	PCIDBG(3,"PCI: Mapping IO address 0x%x - 0x%x to base 0x%x\n", PCIBIOS_MIN_IO,
+	    (64*1024), SH7751_PCI_IO_BASE+PCIBIOS_MIN_IO);
+	bigsur_port_map(PCIBIOS_MIN_IO, (64*1024), SH7751_PCI_IO_BASE+PCIBIOS_MIN_IO,0);
+	    
+	/* Make sure the MSB's of IO window are set to access PCI space correctly */
+	word = PCIBIOS_MIN_IO & SH7751_PCIIOBR_MASK;
+	PCIDBG(2,"PCI: Setting upper bits of IO window to 0x%x\n", word);
+	outl(word, PCI_REG(SH7751_PCIIOBR));
+	
+	/* Set PCI WCRx, BCRx's, copy from BSC locations */
+	word = inl(SH7751_BCR1);
+	/* check BCR for SDRAM in area 3 */
+	if(((word >> 3) & 1) == 0) {
+		printk("PCI: Area 3 is not configured for SDRAM. BCR1=0x%x\n", word);
+		return 0;
+	}
+	outl(word, PCI_REG(SH7751_PCIBCR1));
+	word = (u16)inw(SH7751_BCR2);
+	/* check BCR2 for 32bit SDRAM interface*/
+	if(((word >> 6) & 0x3) != 0x3) {
+		printk("PCI: Area 3 is not 32 bit SDRAM. BCR2=0x%x\n", word);
+		return 0;
+	}
+	outl(word, PCI_REG(SH7751_PCIBCR2));
+	/* configure the wait control registers */
+	word = inl(SH7751_WCR1);
+	outl(word, PCI_REG(SH7751_PCIWCR1));
+	word = inl(SH7751_WCR2);
+	outl(word, PCI_REG(SH7751_PCIWCR2));
+	word = inl(SH7751_WCR3);
+	outl(word, PCI_REG(SH7751_PCIWCR3));
+	word = inl(SH7751_MCR);
+	outl(word, PCI_REG(SH7751_PCIMCR));
+
+	/* NOTE: I'm ignoring the PCI error IRQs for now..
+	 * TODO: add support for the internal error interrupts and
+	 * DMA interrupts...
+	 */
+	 
+	/* SH7751 init done, set central function init complete */
+	word = SH7751_PCICR_PREFIX | SH7751_PCICR_CFIN;
+	outl(word,PCI_REG(SH7751_PCICR)); 
+	PCIDBG(2,"PCI: bigsur_pci_init finished\n");
+
+	return 1;
+}
+
+int pcibios_map_platform_irq(u8 slot, u8 pin)
+{
+    /* The Big Sur can be used in a CPCI chassis, but the SH7751 PCI interface is on the
+     * wrong end of the board so that it can also support a V320 CPI interface chip...
+     * Therefor the IRQ mapping is somewhat use dependent... I'l assume a linear map for
+     * now, i.e. INTA=slot0,pin0... INTD=slot3,pin0...
+     */ 
+    int irq = (slot + pin-1)%4 + BIGSUR_SH7751_PCI_IRQ_BASE;
+    PCIDBG(2,"PCI: Mapping Big Sur IRQ for slot %d, pin %c to irq %d\n", slot, pin-1+'A', irq);
+    return irq;
+     
+}
diff -urN linux-2.4.6-pre5/arch/sh/kernel/pci-dc.c linux/arch/sh/kernel/pci-dc.c
--- linux-2.4.6-pre5/arch/sh/kernel/pci-dc.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/sh/kernel/pci-dc.c	Mon Dec  3 22:49:10 2001
@@ -0,0 +1,276 @@
+/*
+ $	$Id: pci-dc.c,v 1.2 2001/05/24 05:09:16 mrbrown Exp $
+ *	Dreamcast PCI: Supports SEGA Broadband Adaptor only.
+ */
+
+#include <linux/config.h>
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/param.h>
+#include <linux/interrupt.h>
+#include <linux/init.h>
+#include <linux/irq.h>
+#include <linux/pci.h>
+
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/dc_sysasic.h>
+
+#define	GAPSPCI_REGS		0x01001400
+#define GAPSPCI_DMA_BASE	0x01840000
+#define GAPSPCI_DMA_SIZE	32768
+#define GAPSPCI_BBA_CONFIG	0x01001600
+
+#define	GAPSPCI_IRQ		HW_EVENT_EXTERNAL
+
+static int gapspci_dma_used;
+
+static struct pci_bus *pci_root_bus;
+
+struct pci_fixup pcibios_fixups[] = {
+	{0, 0, 0, NULL}
+};
+
+#define BBA_SELECTED(dev) (dev->bus->number==0 && dev->devfn==0)
+
+static int gapspci_read_config_byte(struct pci_dev *dev, int where,
+                                    u8 * val)
+{
+	if (BBA_SELECTED(dev))
+		*val = inb(GAPSPCI_BBA_CONFIG+where);
+	else
+                *val = 0xff;
+
+	return PCIBIOS_SUCCESSFUL;
+}
+
+static int gapspci_read_config_word(struct pci_dev *dev, int where,
+                                    u16 * val)
+{
+        if (BBA_SELECTED(dev))
+		*val = inw(GAPSPCI_BBA_CONFIG+where);
+	else
+                *val = 0xffff;
+
+        return PCIBIOS_SUCCESSFUL;
+}
+
+static int gapspci_read_config_dword(struct pci_dev *dev, int where,
+                                     u32 * val)
+{
+        if (BBA_SELECTED(dev))
+		*val = inl(GAPSPCI_BBA_CONFIG+where);
+	else
+                *val = 0xffffffff;
+
+        return PCIBIOS_SUCCESSFUL;
+}
+
+static int gapspci_write_config_byte(struct pci_dev *dev, int where,
+                                     u8 val)
+{
+        if (BBA_SELECTED(dev))
+		outb(val, GAPSPCI_BBA_CONFIG+where);
+
+        return PCIBIOS_SUCCESSFUL;
+}
+
+
+static int gapspci_write_config_word(struct pci_dev *dev, int where,
+                                     u16 val)
+{
+        if (BBA_SELECTED(dev))
+		outw(val, GAPSPCI_BBA_CONFIG+where);
+
+        return PCIBIOS_SUCCESSFUL;
+}
+
+static int gapspci_write_config_dword(struct pci_dev *dev, int where,
+                                      u32 val)
+{
+        if (BBA_SELECTED(dev))
+		outl(val, GAPSPCI_BBA_CONFIG+where);
+
+        return PCIBIOS_SUCCESSFUL;
+}
+
+static struct pci_ops pci_config_ops = {
+        gapspci_read_config_byte,
+        gapspci_read_config_word,
+        gapspci_read_config_dword,
+        gapspci_write_config_byte,
+        gapspci_write_config_word,
+        gapspci_write_config_dword
+};
+
+
+void pcibios_align_resource(void *data, struct resource *res,
+			    unsigned long size)
+{
+}
+
+
+void __init pcibios_update_irq(struct pci_dev *dev, int irq)
+{
+}
+
+
+void __init pcibios_update_resource(struct pci_dev *dev, struct resource *root,
+			     struct resource *res, int resource)
+{
+}
+
+
+void pcibios_set_master(struct pci_dev *dev)
+{
+	/* No special bus mastering setup handling */
+}
+
+
+int pcibios_enable_device(struct pci_dev *dev)
+{
+
+	u16 cmd, old_cmd;
+	int idx;
+	struct resource *r;
+
+	pci_read_config_word(dev, PCI_COMMAND, &cmd);
+	old_cmd = cmd;
+	for (idx = 0; idx < 6; idx++) {
+		r = dev->resource + idx;
+		if (!r->start && r->end) {
+			printk(KERN_ERR
+			       "PCI: Device %s not available because"
+			       " of resource collisions\n",
+			       dev->slot_name);
+			return -EINVAL;
+		}
+		if (r->flags & IORESOURCE_IO)
+			cmd |= PCI_COMMAND_IO;
+		if (r->flags & IORESOURCE_MEM)
+			cmd |= PCI_COMMAND_MEMORY;
+	}
+	if (cmd != old_cmd) {
+		printk("PCI: enabling device %s (%04x -> %04x)\n",
+		       dev->slot_name, old_cmd, cmd);
+		pci_write_config_word(dev, PCI_COMMAND, cmd);
+	}
+	return 0;
+
+}
+
+
+void *pci_alloc_consistent(struct pci_dev *hwdev, size_t size,
+			   dma_addr_t * dma_handle)
+{
+	unsigned long buf;
+
+	if (gapspci_dma_used+size > GAPSPCI_DMA_SIZE)
+		return NULL;
+
+	buf = GAPSPCI_DMA_BASE+gapspci_dma_used;
+
+	gapspci_dma_used = PAGE_ALIGN(gapspci_dma_used+size);
+	
+	printk("pci_alloc_consistent: %ld bytes at 0x%p\n", size, buf);
+
+	*dma_handle = (dma_addr_t)buf;
+
+	return (void *)P2SEGADDR(buf);
+}
+
+
+void pci_free_consistent(struct pci_dev *hwdev, size_t size,
+			 void *vaddr, dma_addr_t dma_handle)
+{
+	/* XXX */
+}
+
+
+void __init pcibios_fixup_pbus_ranges(struct pci_bus *bus, struct pbus_set_ranges_data *ranges)
+{
+}                                                                                
+
+void __init pcibios_fixup_bus(struct pci_bus *bus)
+{
+	struct list_head *ln;
+	struct pci_dev *dev;
+
+	for (ln=bus->devices.next; ln != &bus->devices; ln=ln->next) {
+		dev = pci_dev_b(ln);
+		if (!BBA_SELECTED(dev)) continue;
+
+		printk("PCI: MMIO fixup to %s\n", dev->name);
+		dev->resource[1].start=0x01001700;
+		dev->resource[1].end=0x010017ff;
+	}
+}
+
+
+static u8 __init no_swizzle(struct pci_dev *dev, u8 * pin)
+{
+	return PCI_SLOT(dev->devfn);
+}
+
+
+static int __init map_dc_irq(struct pci_dev *dev, u8 slot, u8 pin)
+{
+	return GAPSPCI_IRQ;
+}
+
+
+void __init pcibios_init(void)
+{
+	pci_root_bus = pci_scan_bus(0, &pci_config_ops, NULL);
+	/* pci_assign_unassigned_resources(); */
+	pci_fixup_irqs(no_swizzle, map_dc_irq);
+}
+
+
+/* Haven't done anything here as yet */
+char * __init pcibios_setup(char *str)
+{
+	return str;
+}
+
+
+int __init gapspci_init(void)
+{
+	int i;
+	char idbuf[16];
+
+	for(i=0; i<16; i++)
+		idbuf[i]=inb(GAPSPCI_REGS+i);
+
+	if(strncmp(idbuf, "GAPSPCI_BRIDGE_2", 16))
+		return -1;
+
+	outl(0x5a14a501, GAPSPCI_REGS+0x18);
+
+	for(i=0; i<1000000; i++);
+
+	if(inl(GAPSPCI_REGS+0x18)!=1)
+		return -1;
+
+	outl(0x01000000, GAPSPCI_REGS+0x20);
+	outl(0x01000000, GAPSPCI_REGS+0x24);
+
+	outl(GAPSPCI_DMA_BASE, GAPSPCI_REGS+0x28);
+	outl(GAPSPCI_DMA_BASE+GAPSPCI_DMA_SIZE, GAPSPCI_REGS+0x2c);
+
+	outl(1, GAPSPCI_REGS+0x14);
+	outl(1, GAPSPCI_REGS+0x34);
+
+	gapspci_dma_used=0;
+
+	/* Setting Broadband Adapter */
+	outw(0xf900, GAPSPCI_BBA_CONFIG+0x06);
+	outl(0x00000000, GAPSPCI_BBA_CONFIG+0x30);
+	outb(0x00, GAPSPCI_BBA_CONFIG+0x3c);
+	outb(0xf0, GAPSPCI_BBA_CONFIG+0x0d);
+	outw(0x0006, GAPSPCI_BBA_CONFIG+0x04);
+	outl(0x00002001, GAPSPCI_BBA_CONFIG+0x10);
+	outl(0x01000000, GAPSPCI_BBA_CONFIG+0x14);
+
+	return 0;
+}
diff -urN linux-2.4.6-pre5/arch/sh/kernel/pci-dma.c linux/arch/sh/kernel/pci-dma.c
--- linux-2.4.6-pre5/arch/sh/kernel/pci-dma.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/sh/kernel/pci-dma.c	Mon Dec  3 22:49:10 2001
@@ -0,0 +1,42 @@
+/* 
+ * Copyright (C) 2001 David J. Mckay (david.mckay@st.com)
+ *
+ * May be copied or modified under the terms of the GNU General Public
+ * License.  See linux/COPYING for more information.                            
+ *
+ * Dynamic DMA mapping support.
+ */
+
+#include <linux/types.h>
+#include <linux/mm.h>
+#include <linux/string.h>
+#include <linux/pci.h>
+#include <asm/io.h>
+#include <asm/addrspace.h>
+
+
+void *pci_alloc_consistent(struct pci_dev *hwdev, size_t size,
+			   dma_addr_t * dma_handle)
+{
+	void *ret;
+	int gfp = GFP_ATOMIC;
+
+	ret = (void *) __get_free_pages(gfp, get_order(size));
+
+	if (ret != NULL) {
+	        /* Is it neccessary to do the memset? */
+		memset(ret, 0, size);
+		*dma_handle = virt_to_bus(ret);
+	}
+	/* We must flush the cache before we pass it on to the device */
+	flush_cache_all();
+	return  P2SEGADDR(ret);
+}
+
+void pci_free_consistent(struct pci_dev *hwdev, size_t size,
+			 void *vaddr, dma_addr_t dma_handle)
+{
+        unsigned long p1addr=P1SEGADDR((unsigned long)vaddr);
+
+	free_pages(p1addr, get_order(size));
+}
diff -urN linux-2.4.6-pre5/arch/sh/kernel/pci-sh.c linux/arch/sh/kernel/pci-sh.c
--- linux-2.4.6-pre5/arch/sh/kernel/pci-sh.c	Wed Aug  9 13:59:04 2000
+++ linux/arch/sh/kernel/pci-sh.c	Wed Dec 31 16:00:00 1969
@@ -1,25 +0,0 @@
-#include <linux/types.h>
-#include <linux/kernel.h>
-#include <linux/pci.h>
-#include <linux/init.h>
-#include <linux/ioport.h>
-#include <linux/errno.h>
-#include <asm/machvec.h>
-
-void __init pcibios_init(void)
-{
-	if (sh_mv.mv_init_pci != NULL) {
-		sh_mv.mv_init_pci();
-	}
-}
-
-/* Haven't done anything here as yet */
-char * __init pcibios_setup(char *str)
-{
-	return str;
-}
-
-/* We don't have anything here to fixup */
-struct pci_fixup pcibios_fixups[] = {
-	{0, 0, 0, NULL}
-};
diff -urN linux-2.4.6-pre5/arch/sh/kernel/pci-sh7751.c linux/arch/sh/kernel/pci-sh7751.c
--- linux-2.4.6-pre5/arch/sh/kernel/pci-sh7751.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/sh/kernel/pci-sh7751.c	Mon Dec  3 22:49:10 2001
@@ -0,0 +1,674 @@
+/*
+ *	Low-Level PCI Support for the SH7751
+ *
+ *  Dustin McIntire (dustin@sensoria.com)
+ *	Derived from arch/i386/kernel/pci-*.c which bore the message:
+ *	(c) 1999--2000 Martin Mares <mj@suse.cz>
+ *	
+ *  May be copied or modified under the terms of the GNU General Public
+ *  License.  See linux/COPYING for more information.
+ *
+*/
+
+#include <linux/config.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/pci.h>
+#include <linux/sched.h>
+#include <linux/ioport.h>
+#include <linux/errno.h>
+#include <linux/irq.h>
+
+#include <asm/segment.h>
+#include <asm/machvec.h>
+#include <asm/io.h>
+#include <asm/pci-sh7751.h>
+
+struct pci_ops *pci_check_direct(void);
+void pcibios_resource_survey(void);
+static u8 pcibios_swizzle(struct pci_dev *dev, u8 *pin);
+static int pcibios_lookup_irq(struct pci_dev *dev, u8 slot, u8 pin);
+
+unsigned int pci_probe = PCI_PROBE_BIOS | PCI_PROBE_CONF1;
+int pcibios_last_bus = -1;
+struct pci_bus *pci_root_bus;
+struct pci_ops *pci_root_ops;
+
+/*
+ * Direct access to PCI hardware...
+ */
+
+#ifdef CONFIG_PCI_DIRECT
+
+
+#define CONFIG_CMD(dev, where) (0x80000000 | (dev->bus->number << 16) | (dev->devfn << 8) | (where & ~3))
+
+#define PCI_REG(reg) (SH7751_PCIREG_BASE+reg)
+
+/*
+ * Functions for accessing PCI configuration space with type 1 accesses
+ */
+static int pci_conf1_read_config_byte(struct pci_dev *dev, int where, u8 *value)
+{
+	u32 word;
+	unsigned long flags;
+
+    /* PCIPDR may only be accessed as 32 bit words, 
+     * so we must do byte alignment by hand 
+     */
+	__save_and_cli(flags);
+	outl(CONFIG_CMD(dev,where), PCI_REG(SH7751_PCIPAR));
+	word = inl(PCI_REG(SH7751_PCIPDR));
+	__restore_flags(flags);
+	switch (where & 0x3) {
+	    case 3:
+		    *value = (u8)(word >> 24);
+			break;
+		case 2:
+		    *value = (u8)(word >> 16);
+			break;
+		case 1:
+		    *value = (u8)(word >> 8);
+			break;
+		default:
+		    *value = (u8)word;
+			break;
+    }
+	PCIDBG(4,"pci_conf1_read_config_byte@0x%08x=0x%x\n",
+	     CONFIG_CMD(dev,where),*value);
+	return PCIBIOS_SUCCESSFUL;
+}
+
+static int pci_conf1_read_config_word(struct pci_dev *dev, int where, u16 *value)
+{
+	u32 word;
+	unsigned long flags;
+
+    /* PCIPDR may only be accessed as 32 bit words, 
+     * so we must do word alignment by hand 
+     */
+	__save_and_cli(flags);
+	outl(CONFIG_CMD(dev,where), PCI_REG(SH7751_PCIPAR));
+	word = inl(PCI_REG(SH7751_PCIPDR));
+	__restore_flags(flags);
+	switch (where & 0x3) {
+	    case 3:
+		    // This should never happen...
+			printk(KERN_ERR "PCI BIOS: read_config_word: Illegal u16 alignment");
+	        return PCIBIOS_BAD_REGISTER_NUMBER;
+		case 2:
+		    *value = (u16)(word >> 16);
+			break;
+		case 1:
+		    *value = (u16)(word >> 8);
+			break;
+		default:
+		    *value = (u16)word;
+			break;
+    }
+	PCIDBG(4,"pci_conf1_read_config_word@0x%08x=0x%x\n",
+	     CONFIG_CMD(dev,where),*value);
+	return PCIBIOS_SUCCESSFUL;
+}
+
+static int pci_conf1_read_config_dword(struct pci_dev *dev, int where, u32 *value)
+{
+	unsigned long flags;
+	
+	__save_and_cli(flags);
+	outl(CONFIG_CMD(dev,where), PCI_REG(SH7751_PCIPAR));
+	*value = inl(PCI_REG(SH7751_PCIPDR));
+	__restore_flags(flags);
+	PCIDBG(4,"pci_conf1_read_config_dword@0x%08x=0x%x\n",
+	     CONFIG_CMD(dev,where),*value);
+	return PCIBIOS_SUCCESSFUL;    
+}
+
+static int pci_conf1_write_config_byte(struct pci_dev *dev, int where, u8 value)
+{
+	u32 word;
+	u32 shift = (where & 3) * 8;
+	u32 mask = ((1 << 8) - 1) << shift;  // create the byte mask
+	unsigned long flags;
+
+    /* Since SH7751 only does 32bit access we'll have to do a
+     * read,mask,write operation
+     */ 
+	__save_and_cli(flags);
+	outl(CONFIG_CMD(dev,where), PCI_REG(SH7751_PCIPAR));
+	word = inl(PCI_REG(SH7751_PCIPDR)) ;
+	word &= ~mask;
+	word |= value << shift;
+ 
+	outl(word, PCI_REG(SH7751_PCIPDR));
+	__restore_flags(flags);
+	PCIDBG(4,"pci_conf1_write_config_byte@0x%08x=0x%x\n",
+	     CONFIG_CMD(dev,where),word);
+	return PCIBIOS_SUCCESSFUL;
+}
+
+static int pci_conf1_write_config_word(struct pci_dev *dev, int where, u16 value)
+{
+	u32 word;
+	u32 shift = (where & 3) * 8;
+	u32 mask = ((1 << 16) - 1) << shift;  // create the word mask
+	unsigned long flags;
+
+    /* Since SH7751 only does 32bit access we'll have to do a
+     * read,mask,write operation.  We'll allow an odd byte offset,
+	 * though it should be illegal.
+     */ 
+	if (shift == 24)
+	    return PCIBIOS_BAD_REGISTER_NUMBER;
+	__save_and_cli(flags);
+	outl(CONFIG_CMD(dev,where), PCI_REG(SH7751_PCIPAR));
+	word = inl(PCI_REG(SH7751_PCIPDR)) ;
+	word &= ~mask;
+	word |= value << shift;
+ 
+	outl(value, PCI_REG(SH7751_PCIPDR));
+	__restore_flags(flags);
+	PCIDBG(4,"pci_conf1_write_config_word@0x%08x=0x%x\n",
+	     CONFIG_CMD(dev,where),word);
+	return PCIBIOS_SUCCESSFUL;
+}
+
+static int pci_conf1_write_config_dword(struct pci_dev *dev, int where, u32 value)
+{
+	unsigned long flags;
+
+	__save_and_cli(flags);
+	outl(CONFIG_CMD(dev,where), PCI_REG(SH7751_PCIPAR));
+	outl(value, PCI_REG(SH7751_PCIPDR));
+	__restore_flags(flags);
+	PCIDBG(4,"pci_conf1_write_config_dword@0x%08x=0x%x\n",
+	     CONFIG_CMD(dev,where),value);
+	return PCIBIOS_SUCCESSFUL;
+}
+
+#undef CONFIG_CMD
+
+static struct pci_ops pci_direct_conf1 = {
+	pci_conf1_read_config_byte,
+	pci_conf1_read_config_word,
+	pci_conf1_read_config_dword,
+	pci_conf1_write_config_byte,
+	pci_conf1_write_config_word,
+	pci_conf1_write_config_dword
+};
+
+struct pci_ops * __init pci_check_direct(void)
+{
+	unsigned int tmp, id;
+
+	/* check for SH7751 hardware */
+	id = (SH7751_DEVICE_ID << 16) | SH7751_VENDOR_ID;
+	if(inl(SH7751_PCIREG_BASE+SH7751_PCICONF0) != id) {
+		PCIDBG(2,"PCI: This is not an SH7751\n");
+		return NULL;
+	}
+	/*
+	 * Check if configuration works.
+	 */
+	if (pci_probe & PCI_PROBE_CONF1) {
+		tmp = inl (PCI_REG(SH7751_PCIPAR));
+		outl (0x80000000, PCI_REG(SH7751_PCIPAR));
+		if (inl (PCI_REG(SH7751_PCIPAR)) == 0x80000000) {
+			outl (tmp, PCI_REG(SH7751_PCIPAR));
+			printk(KERN_INFO "PCI: Using configuration type 1\n");
+			request_region(PCI_REG(SH7751_PCIPAR), 8, "PCI conf1");
+			return &pci_direct_conf1;
+		}
+		outl (tmp, PCI_REG(SH7751_PCIPAR));
+	}
+
+	PCIDBG(2,"PCI: pci_check_direct failed\n");
+	return NULL;
+}
+
+#endif
+
+/*
+ * BIOS32 and PCI BIOS handling.
+ * 
+ * The BIOS version of the pci functions is not yet implemented but it is left
+ * in for completeness.  Currently an error will be genereated at compile time. 
+ */
+ 
+#ifdef CONFIG_PCI_BIOS
+
+#error PCI BIOS is not yet supported on SH7751
+
+#endif /* CONFIG_PCI_BIOS */
+
+/***************************************************************************************/
+
+/*
+ *  Handle bus scanning and fixups ....
+ */
+
+
+/*
+ * Discover remaining PCI buses in case there are peer host bridges.
+ * We use the number of last PCI bus provided by the PCI BIOS.
+ */
+static void __init pcibios_fixup_peer_bridges(void)
+{
+	int n;
+	struct pci_bus bus;
+	struct pci_dev dev;
+	u16 l;
+
+	if (pcibios_last_bus <= 0 || pcibios_last_bus >= 0xff)
+		return;
+	PCIDBG(2,"PCI: Peer bridge fixup\n");
+	for (n=0; n <= pcibios_last_bus; n++) {
+		if (pci_bus_exists(&pci_root_buses, n))
+			continue;
+		bus.number = n;
+		bus.ops = pci_root_ops;
+		dev.bus = &bus;
+		for(dev.devfn=0; dev.devfn<256; dev.devfn += 8)
+			if (!pci_read_config_word(&dev, PCI_VENDOR_ID, &l) &&
+			    l != 0x0000 && l != 0xffff) {
+				PCIDBG(3,"Found device at %02x:%02x [%04x]\n", n, dev.devfn, l);
+				printk(KERN_INFO "PCI: Discovered peer bus %02x\n", n);
+				pci_scan_bus(n, pci_root_ops, NULL);
+				break;
+			}
+	}
+}
+
+
+static void __init pci_fixup_ide_bases(struct pci_dev *d)
+{
+	int i;
+
+	/*
+	 * PCI IDE controllers use non-standard I/O port decoding, respect it.
+	 */
+	if ((d->class >> 8) != PCI_CLASS_STORAGE_IDE)
+		return;
+	PCIDBG(3,"PCI: IDE base address fixup for %s\n", d->slot_name);
+	for(i=0; i<4; i++) {
+		struct resource *r = &d->resource[i];
+		if ((r->start & ~0x80) == 0x374) {
+			r->start |= 2;
+			r->end = r->start;
+		}
+	}
+}
+
+
+/* Add future fixups here... */
+struct pci_fixup pcibios_fixups[] = {
+	{ PCI_FIXUP_HEADER,	PCI_ANY_ID,	PCI_ANY_ID,	pci_fixup_ide_bases },
+	{ 0 }
+};
+
+void __init pcibios_fixup_pbus_ranges(struct pci_bus *b,
+		struct pbus_set_ranges_data *range)
+{
+	/* No fixups needed */
+}
+
+/*
+ *  Called after each bus is probed, but before its children
+ *  are examined.
+ */
+
+void __init pcibios_fixup_bus(struct pci_bus *b)
+{
+	pci_read_bridge_bases(b);
+}
+
+/*
+ * Initialization. Try all known PCI access methods. Note that we support
+ * using both PCI BIOS and direct access: in such cases, we use I/O ports
+ * to access config space.
+ * 
+ * Note that the platform specific initialization (BSC registers, and memory
+ * space mapping) will be called via the machine vectors (sh_mv.mv_pci_init()) if it
+ * exitst and via the platform defined function pcibios_init_platform().  
+ * See pci_bigsur.c for implementation;
+ * 
+ * The BIOS version of the pci functions is not yet implemented but it is left
+ * in for completeness.  Currently an error will be genereated at compile time. 
+ */
+
+void __init pcibios_init(void)
+{
+	struct pci_ops *bios = NULL;
+	struct pci_ops *dir = NULL;
+
+	PCIDBG(1,"PCI: Starting intialization.\n");
+#ifdef CONFIG_PCI_BIOS
+	if ((pci_probe & PCI_PROBE_BIOS) && ((bios = pci_find_bios()))) {
+		pci_probe |= PCI_BIOS_SORT;
+		pci_bios_present = 1;
+	}
+#endif
+#ifdef CONFIG_PCI_DIRECT
+	if (pci_probe & PCI_PROBE_CONF1 )
+		dir = pci_check_direct();
+#endif
+	if (dir) {
+		pci_root_ops = dir;
+	    if(!pcibios_init_platform())
+			PCIDBG(1,"PCI: Initialization failed\n");
+	    if (sh_mv.mv_init_pci != NULL)
+            sh_mv.mv_init_pci();
+	}
+	else if (bios)
+		pci_root_ops = bios;
+	else {
+		PCIDBG(1,"PCI: No PCI bus detected\n");
+		return;
+	}
+
+	PCIDBG(1,"PCI: Probing PCI hardware\n");
+	pci_root_bus = pci_scan_bus(0, pci_root_ops, NULL);
+	//pci_assign_unassigned_resources();
+	pci_fixup_irqs(pcibios_swizzle, pcibios_lookup_irq);
+	pcibios_fixup_peer_bridges();
+	pcibios_resource_survey();
+
+#ifdef CONFIG_PCI_BIOS
+	if ((pci_probe & PCI_BIOS_SORT) && !(pci_probe & PCI_NO_SORT))
+		pcibios_sort();
+#endif
+}
+
+char * __init pcibios_setup(char *str)
+{
+	if (!strcmp(str, "off")) {
+		pci_probe = 0;
+		return NULL;
+	}
+#ifdef CONFIG_PCI_BIOS
+	else if (!strcmp(str, "bios")) {
+		pci_probe = PCI_PROBE_BIOS;
+		return NULL;
+	} else if (!strcmp(str, "nobios")) {
+		pci_probe &= ~PCI_PROBE_BIOS;
+		return NULL;
+	} else if (!strcmp(str, "nosort")) {
+		pci_probe |= PCI_NO_SORT;
+		return NULL;
+	} else if (!strcmp(str, "biosirq")) {
+		pci_probe |= PCI_BIOS_IRQ_SCAN;
+		return NULL;
+	}
+#endif
+#ifdef CONFIG_PCI_DIRECT
+	else if (!strcmp(str, "conf1")) {
+		pci_probe = PCI_PROBE_CONF1 | PCI_NO_CHECKS;
+		return NULL;
+	}
+#endif
+	else if (!strcmp(str, "rom")) {
+		pci_probe |= PCI_ASSIGN_ROMS;
+		return NULL;
+	} else if (!strncmp(str, "lastbus=", 8)) {
+		pcibios_last_bus = simple_strtol(str+8, NULL, 0);
+		return NULL;
+	}
+	return str;
+}
+
+void
+pcibios_update_resource(struct pci_dev *dev, struct resource *root,
+			struct resource *res, int resource)
+{
+	u32 new, check;
+	int reg;
+
+	new = res->start | (res->flags & PCI_REGION_FLAG_MASK);
+	if (resource < 6) {
+		reg = PCI_BASE_ADDRESS_0 + 4*resource;
+	} else if (resource == PCI_ROM_RESOURCE) {
+		res->flags |= PCI_ROM_ADDRESS_ENABLE;
+		new |= PCI_ROM_ADDRESS_ENABLE;
+		reg = dev->rom_base_reg;
+	} else {
+		/* Somebody might have asked allocation of a non-standard resource */
+		return;
+	}
+	
+	pci_write_config_dword(dev, reg, new);
+	pci_read_config_dword(dev, reg, &check);
+	if ((new ^ check) & ((new & PCI_BASE_ADDRESS_SPACE_IO) ? PCI_BASE_ADDRESS_IO_MASK : PCI_BASE_ADDRESS_MEM_MASK)) {
+		printk(KERN_ERR "PCI: Error while updating region "
+		       "%s/%d (%08x != %08x)\n", dev->slot_name, resource,
+		       new, check);
+	}
+}
+
+/*
+ * We need to avoid collisions with `mirrored' VGA ports
+ * and other strange ISA hardware, so we always want the
+ * addresses to be allocated in the 0x000-0x0ff region
+ * modulo 0x400.
+ */
+void
+pcibios_align_resource(void *data, struct resource *res, unsigned long size)
+{
+	if (res->flags & IORESOURCE_IO) {
+		unsigned long start = res->start;
+
+		if (start & 0x300) {
+			start = (start + 0x3ff) & ~0x3ff;
+			res->start = start;
+		}
+	}
+}
+
+
+/*
+ *    Allocate the bridge and device resources
+ */
+
+static void __init pcibios_allocate_bus_resources(struct list_head *bus_list)
+{
+	struct list_head *ln;
+	struct pci_bus *bus;
+	struct pci_dev *dev;
+	int idx;
+	struct resource *r, *pr;
+	
+	PCIDBG(2,"PCI: pcibios_allocate_bus_reasources called\n" );
+	/* Depth-First Search on bus tree */
+	for (ln=bus_list->next; ln != bus_list; ln=ln->next) {
+		bus = pci_bus_b(ln);
+		if ((dev = bus->self)) {
+			for (idx = PCI_BRIDGE_RESOURCES; idx < PCI_NUM_RESOURCES; idx++) {
+				r = &dev->resource[idx];
+				if (!r->start)
+					continue;
+				pr = pci_find_parent_resource(dev, r);
+				if (!pr || request_resource(pr, r) < 0)
+					printk(KERN_ERR "PCI: Cannot allocate resource region %d of bridge %s\n", idx, dev->slot_name);
+			}
+		}
+		pcibios_allocate_bus_resources(&bus->children);
+	}
+}
+
+static void __init pcibios_allocate_resources(int pass)
+{
+	struct pci_dev *dev;
+	int idx, disabled;
+	u16 command;
+	struct resource *r, *pr;
+
+	PCIDBG(2,"PCI: pcibios_allocate_resources pass %d called\n", pass);
+	pci_for_each_dev(dev) {
+		pci_read_config_word(dev, PCI_COMMAND, &command);
+		for(idx = 0; idx < 6; idx++) {
+			r = &dev->resource[idx];
+			if (r->parent)		/* Already allocated */
+				continue;
+			if (!r->start)		/* Address not assigned at all */
+				continue;
+			if (r->flags & IORESOURCE_IO)
+				disabled = !(command & PCI_COMMAND_IO);
+			else
+				disabled = !(command & PCI_COMMAND_MEMORY);
+			if (pass == disabled) {
+				PCIDBG(3,"PCI: Resource %08lx-%08lx (f=%lx, d=%d, p=%d)\n",
+				    r->start, r->end, r->flags, disabled, pass);
+				pr = pci_find_parent_resource(dev, r);
+				if (!pr || request_resource(pr, r) < 0) {
+					printk(KERN_ERR "PCI: Cannot allocate resource region %d of device %s\n", idx, dev->slot_name);
+					/* We'll assign a new address later */
+					r->end -= r->start;
+					r->start = 0;
+				}
+			}
+		}
+		if (!pass) {
+			r = &dev->resource[PCI_ROM_RESOURCE];
+			if (r->flags & PCI_ROM_ADDRESS_ENABLE) {
+				/* Turn the ROM off, leave the resource region, but keep it unregistered. */
+				u32 reg;
+				PCIDBG(3,"PCI: Switching off ROM of %s\n", dev->slot_name);
+				r->flags &= ~PCI_ROM_ADDRESS_ENABLE;
+				pci_read_config_dword(dev, dev->rom_base_reg, &reg);
+				pci_write_config_dword(dev, dev->rom_base_reg, reg & ~PCI_ROM_ADDRESS_ENABLE);
+			}
+		}
+	}
+}
+
+static void __init pcibios_assign_resources(void)
+{
+	struct pci_dev *dev;
+	int idx;
+	struct resource *r;
+
+	PCIDBG(2,"PCI: pcibios_assign_resources called\n");
+	pci_for_each_dev(dev) {
+		int class = dev->class >> 8;
+
+		/* Don't touch classless devices and host bridges */
+		if (!class || class == PCI_CLASS_BRIDGE_HOST)
+			continue;
+
+		for(idx=0; idx<6; idx++) {
+			r = &dev->resource[idx];
+
+			/*
+			 *  Don't touch IDE controllers and I/O ports of video cards!
+			 */
+			if ((class == PCI_CLASS_STORAGE_IDE && idx < 4) ||
+			    (class == PCI_CLASS_DISPLAY_VGA && (r->flags & IORESOURCE_IO)))
+				continue;
+
+			/*
+			 *  We shall assign a new address to this resource, either because
+			 *  the BIOS forgot to do so or because we have decided the old
+			 *  address was unusable for some reason.
+			 */
+			if (!r->start && r->end)
+				pci_assign_resource(dev, idx);
+		}
+
+		if (pci_probe & PCI_ASSIGN_ROMS) {
+			r = &dev->resource[PCI_ROM_RESOURCE];
+			r->end -= r->start;
+			r->start = 0;
+			if (r->end)
+				pci_assign_resource(dev, PCI_ROM_RESOURCE);
+		}
+	}
+}
+
+void __init pcibios_resource_survey(void)
+{
+	PCIDBG(1,"PCI: Allocating resources\n");
+	pcibios_allocate_bus_resources(&pci_root_buses);
+	pcibios_allocate_resources(0);
+	pcibios_allocate_resources(1);
+	pcibios_assign_resources();
+}
+
+int pcibios_enable_device(struct pci_dev *dev)
+{
+	u16 cmd, old_cmd;
+	int idx;
+	struct resource *r;
+
+	pci_read_config_word(dev, PCI_COMMAND, &cmd);
+	old_cmd = cmd;
+	for(idx=0; idx<6; idx++) {
+		r = &dev->resource[idx];
+		if (!r->start && r->end) {
+			printk(KERN_ERR "PCI: Device %s not available because of resource collisions\n", dev->slot_name);
+			return -EINVAL;
+		}
+		if (r->flags & IORESOURCE_IO)
+			cmd |= PCI_COMMAND_IO;
+		if (r->flags & IORESOURCE_MEM)
+			cmd |= PCI_COMMAND_MEMORY;
+	}
+	if (dev->resource[PCI_ROM_RESOURCE].start)
+		cmd |= PCI_COMMAND_MEMORY;
+	if (cmd != old_cmd) {
+		printk(KERN_INFO "PCI: Enabling device %s (%04x -> %04x)\n", dev->name, old_cmd, cmd);
+		pci_write_config_word(dev, PCI_COMMAND, cmd);
+	}
+	return 0;
+}
+
+/*
+ *  If we set up a device for bus mastering, we need to check and set
+ *  the latency timer as it may not be properly set.
+ */
+unsigned int pcibios_max_latency = 255;
+
+void pcibios_set_master(struct pci_dev *dev)
+{
+	u8 lat;
+	pci_read_config_byte(dev, PCI_LATENCY_TIMER, &lat);
+	if (lat < 16)
+		lat = (64 <= pcibios_max_latency) ? 64 : pcibios_max_latency;
+	else if (lat > pcibios_max_latency)
+		lat = pcibios_max_latency;
+	else
+		return;
+	printk(KERN_INFO "PCI: Setting latency timer of device %s to %d\n", dev->name, lat);
+	pci_write_config_byte(dev, PCI_LATENCY_TIMER, lat);
+}
+
+/***************************************************************************************/
+/* 
+ * 	IRQ functions 
+ */
+static u8 __init pcibios_swizzle(struct pci_dev *dev, u8 *pin)
+{
+	/* no swizzling */
+	return PCI_SLOT(dev->devfn);
+}
+
+static int pcibios_lookup_irq(struct pci_dev *dev, u8 slot, u8 pin)
+{
+	int irq = -1;
+
+	/* now lookup the actual IRQ on a platform specific basis (pci-'platform'.c) */
+	irq = pcibios_map_platform_irq(slot,pin);
+	if( irq < 0 ) {
+	    PCIDBG(3,"PCI: Error mapping IRQ on device %s\n", dev->name);
+		return irq;
+	}
+	
+	PCIDBG(2,"Setting IRQ for slot %s to %d\n", dev->slot_name, irq);
+
+	return irq;
+}
+
+void __init pcibios_update_irq(struct pci_dev *dev, int irq)
+{
+	PCIDBG(3,"PCI: Update IRQ for %s on irq %d\n", dev->name, irq);
+	pci_write_config_byte(dev, PCI_INTERRUPT_LINE, irq);
+}
diff -urN linux-2.4.6-pre5/arch/sh/kernel/pci_st40.c linux/arch/sh/kernel/pci_st40.c
--- linux-2.4.6-pre5/arch/sh/kernel/pci_st40.c	Wed Apr 11 21:24:52 2001
+++ linux/arch/sh/kernel/pci_st40.c	Mon Dec  3 22:49:10 2001
@@ -141,6 +141,31 @@
 	return tmp;
 }
 
+static void __init pci_fixup_ide_bases(struct pci_dev *d)
+{
+	int i;
+
+	/*
+	 * PCI IDE controllers use non-standard I/O port decoding, respect it.
+	 */
+	if ((d->class >> 8) != PCI_CLASS_STORAGE_IDE)
+		return;
+	printk("PCI: IDE base address fixup for %s\n", d->slot_name);
+	for(i=0; i<4; i++) {
+		struct resource *r = &d->resource[i];
+		if ((r->start & ~0x80) == 0x374) {
+			r->start |= 2;
+			r->end = r->start;
+		}
+	}
+}
+
+
+/* Add future fixups here... */
+struct pci_fixup pcibios_fixups[] = {
+	{ PCI_FIXUP_HEADER,	PCI_ANY_ID,	PCI_ANY_ID,	pci_fixup_ide_bases },
+	{ 0 }
+};
 
 int __init st40pci_init(unsigned memStart, unsigned memSize)
 {
@@ -234,6 +259,11 @@
 	return 1;
 }
 
+char * __init pcibios_setup(char *str)
+{
+	return str;
+}
+
 
 #define SET_CONFIG_BITS(bus,devfn,where)\
   (((bus) << 16) | ((devfn) << 8) | ((where) & ~3) | (bus!=0))
@@ -390,10 +420,14 @@
 	ranges->mem_end -= bus->resource[1]->start;
 }
 
-void __init st40_pcibios_init(void)
+void __init pcibios_init(void)
 {
 	extern unsigned long memory_start, memory_end;
 
+	if (sh_mv.mv_init_pci != NULL) {
+		sh_mv.mv_init_pci();
+	}
+
 	/* The pci subsytem needs to know where memory is and how much 
 	 * of it there is. I've simply made these globals. A better mechanism
 	 * is probably needed.
@@ -491,4 +525,24 @@
 {
 	printk("PCI: Assigning IRQ %02d to %s\n", irq, dev->name);
 	pci_write_config_byte(dev, PCI_INTERRUPT_LINE, irq);
+}
+
+/*
+ *  If we set up a device for bus mastering, we need to check the latency
+ *  timer as certain crappy BIOSes forget to set it properly.
+ */
+unsigned int pcibios_max_latency = 255;
+
+void pcibios_set_master(struct pci_dev *dev)
+{
+	u8 lat;
+	pci_read_config_byte(dev, PCI_LATENCY_TIMER, &lat);
+	if (lat < 16)
+		lat = (64 <= pcibios_max_latency) ? 64 : pcibios_max_latency;
+	else if (lat > pcibios_max_latency)
+		lat = pcibios_max_latency;
+	else
+		return;
+	printk("PCI: Setting latency timer of device %s to %d\n", dev->slot_name, lat);
+	pci_write_config_byte(dev, PCI_LATENCY_TIMER, lat);
 }
diff -urN linux-2.4.6-pre5/arch/sh/kernel/rtc.c linux/arch/sh/kernel/rtc.c
--- linux-2.4.6-pre5/arch/sh/kernel/rtc.c	Thu May 24 15:14:08 2001
+++ linux/arch/sh/kernel/rtc.c	Mon Dec  3 22:49:10 2001
@@ -13,62 +13,6 @@
 #include <asm/io.h>
 #include <asm/rtc.h>
 
-/* RCR1 Bits */
-#define RCR1_CF		0x80	/* Carry Flag             */
-#define RCR1_CIE	0x10	/* Carry Interrupt Enable */
-#define RCR1_AIE	0x08	/* Alarm Interrupt Enable */
-#define RCR1_AF		0x01	/* Alarm Flag             */
-
-/* RCR2 Bits */
-#define RCR2_PEF	0x80	/* PEriodic interrupt Flag */
-#define RCR2_PESMASK	0x70	/* Periodic interrupt Set  */
-#define RCR2_RTCEN	0x08	/* ENable RTC              */
-#define RCR2_ADJ	0x04	/* ADJustment (30-second)  */
-#define RCR2_RESET	0x02	/* Reset bit               */
-#define RCR2_START	0x01	/* Start bit               */
-
-#if defined(__sh3__)
-/* SH-3 RTC */
-#define R64CNT  	0xfffffec0
-#define RSECCNT 	0xfffffec2
-#define RMINCNT 	0xfffffec4
-#define RHRCNT  	0xfffffec6
-#define RWKCNT  	0xfffffec8
-#define RDAYCNT 	0xfffffeca
-#define RMONCNT 	0xfffffecc
-#define RYRCNT  	0xfffffece
-#define RSECAR  	0xfffffed0
-#define RMINAR  	0xfffffed2
-#define RHRAR   	0xfffffed4
-#define RWKAR   	0xfffffed6
-#define RDAYAR  	0xfffffed8
-#define RMONAR  	0xfffffeda
-#define RCR1    	0xfffffedc
-#define RCR2    	0xfffffede
-
-#define RTC_BIT_INVERTED	0	/* No bug on SH7708, SH7709A */
-#elif defined(__SH4__)
-/* SH-4 RTC */
-#define R64CNT  	0xffc80000
-#define RSECCNT 	0xffc80004
-#define RMINCNT 	0xffc80008
-#define RHRCNT  	0xffc8000c
-#define RWKCNT  	0xffc80010
-#define RDAYCNT 	0xffc80014
-#define RMONCNT 	0xffc80018
-#define RYRCNT  	0xffc8001c  /* 16bit */
-#define RSECAR  	0xffc80020
-#define RMINAR  	0xffc80024
-#define RHRAR   	0xffc80028
-#define RWKAR   	0xffc8002c
-#define RDAYAR  	0xffc80030
-#define RMONAR  	0xffc80034
-#define RCR1    	0xffc80038
-#define RCR2    	0xffc8003c
-
-#define RTC_BIT_INVERTED	0x40	/* bug on SH7750, SH7750S */
-#endif
-
 #ifndef BCD_TO_BIN
 #define BCD_TO_BIN(val) ((val)=((val)&15) + ((val)>>4)*10)
 #endif
diff -urN linux-2.4.6-pre5/arch/sh/kernel/setup.c linux/arch/sh/kernel/setup.c
--- linux-2.4.6-pre5/arch/sh/kernel/setup.c	Fri Apr 27 14:10:32 2001
+++ linux/arch/sh/kernel/setup.c	Mon Dec  3 22:49:10 2001
@@ -521,6 +521,9 @@
 	
 	PRINT_CLOCK("CPU", boot_cpu_data.cpu_clock);
 	PRINT_CLOCK("Bus", boot_cpu_data.bus_clock);
+#ifdef CONFIG_CPU_SUBTYPE_ST40STB1
+	PRINT_CLOCK("Memory", boot_cpu_data.memory_clock);
+#endif
 	PRINT_CLOCK("Peripheral module", boot_cpu_data.module_clock);
 
 	return p - buffer;
diff -urN linux-2.4.6-pre5/arch/sh/kernel/setup_bigsur.c linux/arch/sh/kernel/setup_bigsur.c
--- linux-2.4.6-pre5/arch/sh/kernel/setup_bigsur.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/sh/kernel/setup_bigsur.c	Mon Dec  3 22:49:10 2001
@@ -0,0 +1,381 @@
+/*
+ *
+ * By Dustin McIntire (dustin@sensoria.com) (c)2001
+ * 
+ * Setup and IRQ handling code for the HD64465 companion chip.
+ * by Greg Banks <gbanks@pocketpenguins.com>
+ * Copyright (c) 2000 PocketPenguins Inc
+ *
+ * Derived from setup_hd64465.c which bore the message:
+ * Greg Banks <gbanks@pocketpenguins.com>
+ * Copyright (c) 2000 PocketPenguins Inc and
+ * Copyright (C) 2000 YAEGASHI Takeshi
+ * and setup_cqreek.c which bore message:
+ * Copyright (C) 2000  Niibe Yutaka
+ * 
+ * May be copied or modified under the terms of the GNU General Public
+ * License.  See linux/COPYING for more information.
+ *
+ * Setup and IRQ functions for a Hitachi Big Sur Evaluation Board.
+ * 
+ */
+
+#include <linux/config.h>
+#include <linux/sched.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/param.h>
+#include <linux/ioport.h>
+#include <linux/interrupt.h>
+#include <linux/init.h>
+#include <linux/irq.h>
+
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/bitops.h>
+
+#include <asm/io_bigsur.h>
+#include <asm/hd64465.h>
+#include <asm/bigsur.h>
+
+//#define BIGSUR_DEBUG 3
+#undef BIGSUR_DEBUG
+
+#ifdef BIGSUR_DEBUG
+#define DPRINTK(args...)	printk(args)
+#define DIPRINTK(n, args...)	if (BIGSUR_DEBUG>(n)) printk(args)
+#else
+#define DPRINTK(args...)
+#define DIPRINTK(n, args...)
+#endif /* BIGSUR_DEBUG */
+
+#ifdef CONFIG_HD64465
+extern int hd64465_irq_demux(int irq);
+#endif /* CONFIG_HD64465 */
+
+
+/*===========================================================*/
+//		Big Sur CPLD IRQ Routines	
+/*===========================================================*/
+
+/* Level 1 IRQ routines */
+static void disable_bigsur_l1irq(unsigned int irq)
+{
+	unsigned long flags;
+	unsigned char mask;
+	unsigned int mask_port = ((irq - BIGSUR_IRQ_LOW)/8) ? BIGSUR_IRLMR1 : BIGSUR_IRLMR0;
+	unsigned char bit =  (1 << ((irq - MGATE_IRQ_LOW)%8) );
+
+	if(irq >= BIGSUR_IRQ_LOW && irq < BIGSUR_IRQ_HIGH) {	
+   		DPRINTK("Disable L1 IRQ %d\n", irq);
+   		DIPRINTK(2,"disable_bigsur_l1irq: IMR=0x%08x mask=0x%x\n", 
+   			mask_port, bit);
+		save_and_cli(flags);
+
+		/* Disable IRQ - set mask bit */
+		mask = inb(mask_port) | bit;
+		outb(mask, mask_port);
+		restore_flags(flags);
+		return;
+	}
+   	DPRINTK("disable_bigsur_l1irq: Invalid IRQ %d\n", irq);	
+}
+
+static void enable_bigsur_l1irq(unsigned int irq)
+{
+	unsigned long flags;
+	unsigned char mask;
+	unsigned int mask_port = ((irq - BIGSUR_IRQ_LOW)/8) ? BIGSUR_IRLMR1 : BIGSUR_IRLMR0;
+	unsigned char bit =  (1 << ((irq - MGATE_IRQ_LOW)%8) );
+
+	if(irq >= BIGSUR_IRQ_LOW && irq < BIGSUR_IRQ_HIGH) {	
+	   	DPRINTK("Enable L1 IRQ %d\n", irq);
+   		DIPRINTK(2,"enable_bigsur_l1irq: IMR=0x%08x mask=0x%x\n", 
+   			mask_port, bit);
+		save_and_cli(flags);
+		/* Enable L1 IRQ - clear mask bit */
+		mask = inb(mask_port) & ~bit;
+		outb(mask, mask_port);
+		restore_flags(flags);
+		return;
+	}
+   	DPRINTK("enable_bigsur_l1irq: Invalid IRQ %d\n", irq);	
+}
+
+
+/* Level 2 irq masks and registers for L2 decoding */
+/* Level2 bitmasks for each level 1 IRQ */
+const u32 bigsur_l2irq_mask[] = 
+    {0x40,0x80,0x08,0x01,0x01,0x3C,0x3E,0xFF,0x40,0x80,0x06,0x03};
+/* Level2 to ISR[n] map for each level 1 IRQ */
+const u32 bigsur_l2irq_reg[]  = 
+    {   2,   2,   3,   3,   1,   2,   1,   0,   1,   1,   3,   2};
+/* Level2 to Level 1 IRQ map */
+const u32 bigsur_l2_l1_map[]  = 
+    {7,7,7,7,7,7,7,7, 4,6,6,6,6,6,8,9, 11,11,5,5,5,5,0,1, 3,10,10,2,-1,-1,-1,-1};
+/* IRQ inactive level (high or low) */
+const u32 bigsur_l2_inactv_state[]  =   {0x00, 0xBE, 0xFC, 0xF7};
+ 
+/* CPLD external status and mask registers base and offsets */
+static const u32 isr_base = BIGSUR_IRQ0;
+static const u32 isr_offset = BIGSUR_IRQ0 - BIGSUR_IRQ1;
+static const u32 imr_base = BIGSUR_IMR0;
+static const u32 imr_offset = BIGSUR_IMR0 - BIGSUR_IMR1;
+
+#define REG_NUM(irq)  ((irq-BIGSUR_2NDLVL_IRQ_LOW)/8 )
+
+/* Level 2 IRQ routines */
+static void disable_bigsur_l2irq(unsigned int irq)
+{
+	unsigned long flags;
+	unsigned char mask;
+	unsigned char bit = 1 << ((irq-BIGSUR_2NDLVL_IRQ_LOW)%8);
+	unsigned int mask_port = imr_base - REG_NUM(irq)*imr_offset;
+
+    if(irq >= BIGSUR_2NDLVL_IRQ_LOW && irq < BIGSUR_2NDLVL_IRQ_HIGH) {
+   		DPRINTK("Disable L2 IRQ %d\n", irq);
+   		DIPRINTK(2,"disable_bigsur_l2irq: IMR=0x%08x mask=0x%x\n", 
+   			mask_port, bit);
+		save_and_cli(flags);
+
+		/* Disable L2 IRQ - set mask bit */
+		mask = inb(mask_port) | bit;
+		outb(mask, mask_port);
+		restore_flags(flags);
+		return;
+	}
+ 	DPRINTK("disable_bigsur_l2irq: Invalid IRQ %d\n", irq);	
+}
+
+static void enable_bigsur_l2irq(unsigned int irq)
+{
+	unsigned long flags;
+	unsigned char mask;
+	unsigned char bit = 1 << ((irq-BIGSUR_2NDLVL_IRQ_LOW)%8);
+	unsigned int mask_port = imr_base - REG_NUM(irq)*imr_offset;
+
+    if(irq >= BIGSUR_2NDLVL_IRQ_LOW && irq < BIGSUR_2NDLVL_IRQ_HIGH) {
+   		DPRINTK("Enable L2 IRQ %d\n", irq);
+   		DIPRINTK(2,"enable_bigsur_l2irq: IMR=0x%08x mask=0x%x\n", 
+   			mask_port, bit);
+		save_and_cli(flags);
+
+		/* Enable L2 IRQ - clear mask bit */
+		mask = inb(mask_port) & ~bit;
+		outb(mask, mask_port);
+		restore_flags(flags);
+		return;
+	}
+   	DPRINTK("enable_bigsur_l2irq: Invalid IRQ %d\n", irq);
+}
+
+static void mask_and_ack_bigsur(unsigned int irq)
+{
+   	DPRINTK("mask_and_ack_bigsur IRQ %d\n", irq);
+	if(irq >= BIGSUR_IRQ_LOW && irq < BIGSUR_IRQ_HIGH)	
+		disable_bigsur_l1irq(irq);
+	else
+		disable_bigsur_l2irq(irq);
+}
+
+static void end_bigsur_irq(unsigned int irq)
+{
+   	DPRINTK("end_bigsur_irq IRQ %d\n", irq);
+	if(irq >= BIGSUR_IRQ_LOW && irq < BIGSUR_IRQ_HIGH)	
+		enable_bigsur_l1irq(irq);
+	else
+		enable_bigsur_l2irq(irq);
+}
+
+static unsigned int startup_bigsur_irq(unsigned int irq)
+{ 
+	u8 mask;
+	u32 reg;
+
+   	DPRINTK("startup_bigsur_irq IRQ %d\n", irq);
+
+	if(irq >= BIGSUR_IRQ_LOW && irq < BIGSUR_IRQ_HIGH) {
+		/* Enable the L1 IRQ */	
+		enable_bigsur_l1irq(irq);
+		/* Enable all L2 IRQs in this L1 IRQ */
+		mask = ~(bigsur_l2irq_mask[irq-BIGSUR_IRQ_LOW]);
+		reg = imr_base - bigsur_l2irq_reg[irq-BIGSUR_IRQ_LOW] * imr_offset;
+		mask &= inb(reg);
+		outb(mask,reg); 
+   		DIPRINTK(2,"startup_bigsur_irq: IMR=0x%08x mask=0x%x\n",reg,inb(reg));
+	}
+	else {
+		/* Enable the L2 IRQ - clear mask bit */
+		enable_bigsur_l2irq(irq);
+		/* Enable the L1 bit masking this L2 IRQ */
+		enable_bigsur_l1irq(bigsur_l2_l1_map[irq-BIGSUR_2NDLVL_IRQ_LOW]);
+   		DIPRINTK(2,"startup_bigsur_irq: L1=%d L2=%d\n",
+   			bigsur_l2_l1_map[irq-BIGSUR_2NDLVL_IRQ_LOW],irq);
+	}
+	return 0;
+}
+
+static void shutdown_bigsur_irq(unsigned int irq)
+{
+   	DPRINTK("shutdown_bigsur_irq IRQ %d\n", irq);
+	if(irq >= BIGSUR_IRQ_LOW && irq < BIGSUR_IRQ_HIGH)	
+		disable_bigsur_l1irq(irq);
+	else
+		disable_bigsur_l2irq(irq);
+}
+
+/* Define the IRQ structures for the L1 and L2 IRQ types */
+static struct hw_interrupt_type bigsur_l1irq_type = {
+	"BigSur-CPLD-Level1-IRQ",
+	startup_bigsur_irq,
+	shutdown_bigsur_irq,
+	enable_bigsur_l1irq,
+	disable_bigsur_l1irq,
+	mask_and_ack_bigsur,
+	end_bigsur_irq
+};
+
+static struct hw_interrupt_type bigsur_l2irq_type = {
+	"BigSur-CPLD-Level2-IRQ",
+	startup_bigsur_irq,
+	shutdown_bigsur_irq,
+	enable_bigsur_l2irq,
+	disable_bigsur_l2irq,
+	mask_and_ack_bigsur,
+	end_bigsur_irq
+};
+
+
+static void make_bigsur_l1isr(unsigned int irq) {
+
+	/* sanity check first */
+	if(irq >= BIGSUR_IRQ_LOW && irq < BIGSUR_IRQ_HIGH) {	
+		/* save the handler in the main description table */
+		irq_desc[irq].handler = &bigsur_l1irq_type;
+		irq_desc[irq].status = IRQ_DISABLED;
+		irq_desc[irq].action = 0;
+		irq_desc[irq].depth = 1;
+
+		disable_bigsur_l1irq(irq);
+		return;
+	}
+   	DPRINTK("make_bigsur_l1isr: bad irq, %d\n", irq);
+	return;
+} 
+
+static void make_bigsur_l2isr(unsigned int irq) {
+
+	/* sanity check first */
+	if(irq >= BIGSUR_2NDLVL_IRQ_LOW && irq < BIGSUR_2NDLVL_IRQ_HIGH) {	
+		/* save the handler in the main description table */
+		irq_desc[irq].handler = &bigsur_l2irq_type;
+		irq_desc[irq].status = IRQ_DISABLED;
+		irq_desc[irq].action = 0;
+		irq_desc[irq].depth = 1;
+
+		disable_bigsur_l2irq(irq);
+		return;
+	}
+   	DPRINTK("make_bigsur_l2isr: bad irq, %d\n", irq);
+	return;
+} 
+
+/* The IRQ's will be decoded as follows: 
+ * If a level 2 handler exists and there is an unmasked active
+ * IRQ, the 2nd level handler will be called.
+ * If a level 2 handler does not exist for the active IRQ
+ * the 1st level handler will be called.
+ */ 
+
+int bigsur_irq_demux(int irq)
+{
+	int dmux_irq = irq;
+	u8 mask, actv_irqs;
+	u32 reg_num;
+
+   	DIPRINTK(3,"bigsur_irq_demux, irq=%d\n", irq);
+   	/* decode the 1st level IRQ */
+	if(irq >= BIGSUR_IRQ_LOW && irq < BIGSUR_IRQ_HIGH) {
+		/* Get corresponding L2 ISR bitmask and ISR number */
+		mask = bigsur_l2irq_mask[irq-BIGSUR_IRQ_LOW];
+		reg_num = bigsur_l2irq_reg[irq-BIGSUR_IRQ_LOW];
+		/* find the active IRQ's (XOR with inactive level)*/
+		actv_irqs = inb(isr_base-reg_num*isr_offset) ^ 
+					bigsur_l2_inactv_state[reg_num];
+		/* decode active IRQ's */
+		actv_irqs = actv_irqs & mask & ~(inb(imr_base-reg_num*imr_offset));
+		/* if NEZ then we have an active L2 IRQ */
+		if(actv_irqs) dmux_irq = ffz(~actv_irqs) + reg_num*8+BIGSUR_2NDLVL_IRQ_LOW;	
+   		/* if no 2nd level IRQ action, but has 1st level, use 1st level handler */
+		if(!irq_desc[dmux_irq].action && irq_desc[irq].action) 
+			dmux_irq = irq;
+   		DIPRINTK(1,"bigsur_irq_demux: irq=%d dmux_irq=%d mask=0x%04x reg=%d\n", 
+   			irq, dmux_irq, mask, reg_num);
+	}
+#ifdef CONFIG_HD64465
+	dmux_irq = hd64465_irq_demux(dmux_irq);
+#endif /* CONFIG_HD64465 */
+   	DIPRINTK(3,"bigsur_irq_demux, demux_irq=%d\n", dmux_irq);
+		
+	return dmux_irq;
+}
+
+/*===========================================================*/
+//		Big Sur Init Routines	
+/*===========================================================*/
+void __init init_bigsur_IRQ(void)
+{
+	int i;
+
+	if (!MACH_BIGSUR) return;
+
+	/* Create ISR's for Big Sur CPLD IRQ's */
+	/*==============================================================*/
+	for(i=BIGSUR_IRQ_LOW;i<BIGSUR_IRQ_HIGH;i++) 
+	 	make_bigsur_l1isr(i);
+
+	printk(KERN_INFO "Big Sur CPLD L1 interrupts %d to %d.\n",
+		BIGSUR_IRQ_LOW,BIGSUR_IRQ_HIGH);
+
+	for(i=BIGSUR_2NDLVL_IRQ_LOW;i<BIGSUR_2NDLVL_IRQ_HIGH;i++) 
+ 		make_bigsur_l2isr(i);
+
+	printk(KERN_INFO "Big Sur CPLD L2 interrupts %d to %d.\n",
+		BIGSUR_2NDLVL_IRQ_LOW,BIGSUR_2NDLVL_IRQ_HIGH);
+
+}
+
+int __init setup_bigsur(void)
+{
+	static int done = 0; /* run this only once */
+
+	if (!MACH_BIGSUR || done) return 0;
+	done = 1;
+
+	/* Mask all 2nd level IRQ's */
+	outb(-1,BIGSUR_IMR0);
+	outb(-1,BIGSUR_IMR1);
+	outb(-1,BIGSUR_IMR2);
+	outb(-1,BIGSUR_IMR3);
+
+	/* Mask 1st level interrupts */
+	outb(-1,BIGSUR_IRLMR0);
+	outb(-1,BIGSUR_IRLMR1);
+
+#if defined (CONFIG_HD64465) && defined (CONFIG_SERIAL) 
+	/* remap IO ports for first ISA serial port to HD64465 UART */
+	bigsur_port_map(0x3f8, 8, CONFIG_HD64465_IOBASE + 0x8000, 1);
+#endif /* CONFIG_HD64465 && CONFIG_SERIAL */
+	/* TODO: setup IDE registers */
+	bigsur_port_map(BIGSUR_IDECTL_IOPORT, 2, BIGSUR_ICTL, 8);
+	/* Setup the Ethernet port to BIGSUR_ETHER_IOPORT */
+	bigsur_port_map(BIGSUR_ETHER_IOPORT, 16, BIGSUR_ETHR+BIGSUR_ETHER_IOPORT, 0);
+	/* set page to 1 */
+	outw(1, BIGSUR_ETHR+0xe);
+	/* set the IO port to BIGSUR_ETHER_IOPORT */
+	outw(BIGSUR_ETHER_IOPORT<<3, BIGSUR_ETHR+0x2);
+
+    return 0;
+}
+
+module_init(setup_bigsur);
diff -urN linux-2.4.6-pre5/arch/sh/kernel/setup_dc.c linux/arch/sh/kernel/setup_dc.c
--- linux-2.4.6-pre5/arch/sh/kernel/setup_dc.c	Sun May 20 12:11:38 2001
+++ linux/arch/sh/kernel/setup_dc.c	Mon Dec  3 22:49:10 2001
@@ -1,5 +1,15 @@
-/*
- *	$Id: setup_dc.c,v 1.1 2001/04/01 15:02:00 yaegashi Exp $
+/* arch/sh/kernel/setup_dc.c
+ *
+ * Hardware support for the Sega Dreamcast.
+ *
+ * Copyright (c) 2001 M. R. Brown <mrbrown@linuxdc.org>
+ *
+ * This file is part of the LinuxDC project (www.linuxdc.org)
+ *
+ * Released under the terms of the GNU GPL v2.0.
+ * 
+ * This file originally bore the message:
+ *	$Id: setup_dc.c,v 1.5 2001/05/24 05:09:16 mrbrown Exp $
  *	SEGA Dreamcast support
  */
 
@@ -9,105 +19,167 @@
 #include <linux/interrupt.h>
 #include <linux/init.h>
 #include <linux/irq.h>
-#include <linux/pci.h>
 
 #include <asm/io.h>
 #include <asm/irq.h>
+#include <asm/dc_sysasic.h>
 
-#define	GAPSPCI_REGS		0x01001400
-#define GAPSPCI_DMA_BASE	0x01840000
-#define GAPSPCI_DMA_SIZE	32768
-#define GAPSPCI_BBA_CONFIG	0x01001600
+int __init gapspci_init(void);
 
-#define	GAPSPCI_IRQ		11
-#define	GAPSPCI_INTC		0x005f6924
+#define DPRINTK(fmt, args...) printk(KERN_DEBUG "%s: " fmt, __FUNCTION__ , ## args)
 
-static int gapspci_dma_used;
+/* Dreamcast System ASIC Hardware Events -
+ 
+   The Dreamcast's System ASIC (located on the PowerVR2 chip) is responsible
+   for receiving hardware events from system peripherals and triggering an
+   SH7750 IRQ.  Hardware events can trigger IRQs 13, 11, or 9 depending on
+   which bits are set in the Event Mask Registers (EMRs).  When a hardware
+   event is triggered, it's corresponding bit in the Event Status Registers
+   (ESRs) is set, and that bit should be rewritten to the ESR to acknowledge
+   that event.
 
-static struct pci_bus *pci_root_bus;
+   There are three 32-bit ESRs located at 0xa05f8900 - 0xa05f6908.  Event
+   types can be found in include/asm-sh/dc_sysasic.h.  There are three groups
+   of EMRs that parallel the ESRs.  Each EMR group corresponds to an IRQ, so
+   0xa05f6910 - 0xa05f6918 triggers IRQ 13, 0xa05f6920 - 0xa05f6928 triggers
+   IRQ 11, and 0xa05f6930 - 0xa05f6938 triggers IRQ 9.
 
-static void disable_gapspci_irq(unsigned int irq)
-{
-	unsigned long flags;
-	unsigned long intc;
+   In the kernel, these events are mapped to virtual IRQs so that drivers can
+   respond to them as they would a normal interrupt.  In order to keep this
+   mapping simple, the events are mapped as:
 
-	save_and_cli(flags);
-	intc = inl(GAPSPCI_INTC);
-	intc &= ~(1<<3);
-	outl(intc, GAPSPCI_INTC);
-	restore_flags(flags);
-}
+   6900/6910 - Events  0-31, IRQ 13
+   6904/6924 - Events 32-63, IRQ 11
+   6908/6938 - Events 64-95, IRQ  9
 
+*/
 
-static void enable_gapspci_irq(unsigned int irq)
-{
-	unsigned long flags;
-	unsigned long intc;
+#define ESR_BASE 0x005f6900    /* Base event status register */
+#define EMR_BASE 0x005f6910    /* Base event mask register */
 
-	save_and_cli(flags);
-	intc = inl(GAPSPCI_INTC);
-	intc |= (1<<3);
-	outl(intc, GAPSPCI_INTC);
-	restore_flags(flags);
-}
+/* Helps us determine the EMR group that this event belongs to: 0 = 0x6910,
+   1 = 0x6920, 2 = 0x6930; also determine the event offset */
+#define LEVEL(event) (((event) - HW_EVENT_IRQ_BASE) / 32)
+
+/* Return the hardware event's bit positon within the EMR/ESR */
+#define EVENT_BIT(event) (((event) - HW_EVENT_IRQ_BASE) & 31)
 
+/* For each of these *_irq routines, the IRQ passed in is the virtual IRQ
+   (logically mapped to the corresponding bit for the hardware event). */
 
-static void mask_and_ack_gapspci_irq(unsigned int irq)
+/* Disable the hardware event by masking its bit in its EMR */
+static inline void disable_systemasic_irq(unsigned int irq)
 {
-	unsigned long flags;
-	unsigned long intc;
+	__u32 emr = EMR_BASE + (LEVEL(irq) << 4) + (LEVEL(irq) << 2);
+	__u32 mask;
+	mask = inl(emr);
+	mask &= ~(1 << EVENT_BIT(irq));
+	outl(mask, emr);
+}
 
-	save_and_cli(flags);
-	intc = inl(GAPSPCI_INTC);
-	intc &= ~(1<<3);
-	outl(intc, GAPSPCI_INTC);
-	restore_flags(flags);
+/* Enable the hardware event by setting its bit in its EMR */
+static inline void enable_systemasic_irq(unsigned int irq)
+{
+	__u32 emr = EMR_BASE + (LEVEL(irq) << 4) + (LEVEL(irq) << 2);
+	__u32 mask;
+	mask = inl(emr);
+	mask |= (1 << EVENT_BIT(irq));
+	outl(mask, emr);
 }
 
+/* Acknowledge a hardware event by writing its bit back to its ESR */
+static void ack_systemasic_irq(unsigned int irq)
+{
+	__u32 esr = ESR_BASE + (LEVEL(irq) << 2);
+	disable_systemasic_irq(irq);
+	outl((1 << EVENT_BIT(irq)), esr);
+}
 
-static void end_gapspci_irq(unsigned int irq)
+/* After a IRQ has been ack'd and responded to, it needs to be renabled */
+static void end_systemasic_irq(unsigned int irq)
 {
-	enable_gapspci_irq(irq);
+	enable_systemasic_irq(irq);
 }
 
+static unsigned int startup_systemasic_irq(unsigned int irq)
+{
+	enable_systemasic_irq(irq);
 
-static unsigned int startup_gapspci_irq(unsigned int irq)
-{ 
-	enable_gapspci_irq(irq);
 	return 0;
 }
 
-
-static void shutdown_gapspci_irq(unsigned int irq)
+static void shutdown_systemasic_irq(unsigned int irq)
 {
-	disable_gapspci_irq(irq);
+	disable_systemasic_irq(irq);
 }
 
-
-static struct hw_interrupt_type gapspci_irq_type = {
-	"GAPSPCI-IRQ",
-	startup_gapspci_irq,
-	shutdown_gapspci_irq,
-	enable_gapspci_irq,
-	disable_gapspci_irq,
-	mask_and_ack_gapspci_irq,
-	end_gapspci_irq
+static struct hw_interrupt_type systemasic_int = {
+	typename:       "System ASIC",
+	startup:        startup_systemasic_irq,
+	shutdown:       shutdown_systemasic_irq,
+	enable:         enable_systemasic_irq,
+	disable:        disable_systemasic_irq,
+	ack:            ack_systemasic_irq,
+	end:            end_systemasic_irq,
 };
 
-
-static u8 __init no_swizzle(struct pci_dev *dev, u8 * pin)
+/*
+ * Map the hardware event indicated by the processor IRQ to a virtual IRQ.
+ */
+int systemasic_irq_demux(int irq)
 {
-	return PCI_SLOT(dev->devfn);
-}
+	__u32 emr, esr, status, level;
+	__u32 j, bit;
 
-static int __init map_od_irq(struct pci_dev *dev, u8 slot, u8 pin)
-{
-	return GAPSPCI_IRQ;
+	switch (irq) {
+		case 13:
+			level = 0;
+			break;
+		case 11:
+			level = 1;
+			break;
+		case  9:
+			level = 2;
+			break;
+		default:
+			return irq;
+	}
+	emr = EMR_BASE + (level << 4) + (level << 2);
+	esr = ESR_BASE + (level << 2);
+
+	/* Mask the ESR to filter any spurious, unwanted interrtupts */
+	status = inl(esr);
+	status &= inl(emr);
+
+	/* Now scan and find the first set bit as the event to map */
+	for (bit = 1, j = 0; j < 32; bit <<= 1, j++) {
+		if (status & bit) {
+			irq = HW_EVENT_IRQ_BASE + j + (level << 5);
+			return irq;
+		}
+	}
+
+	/* Not reached */
+	return irq;
 }
 
 int __init setup_dreamcast(void)
 {
+	int i;
+
+	/* Mask all hardware events */
+	/* XXX */
+
+	/* Acknowledge any previous events */
+	/* XXX */
+
+	/* Assign all virtual IRQs to the System ASIC int. handler */
+	for (i = HW_EVENT_IRQ_BASE; i < HW_EVENT_IRQ_MAX; i++)
+		irq_desc[i].handler = &systemasic_int;
+
+#ifdef CONFIG_PCI
 	gapspci_init();
+#endif
 
 	printk(KERN_INFO "SEGA Dreamcast support.\n");
 #if 0
@@ -128,232 +200,5 @@
  *	PCR: 0x0000
  */
 #endif
-	return 0;
-}
-
-
-/*
- *	Dreamcast PCI: Supports SEGA Broadband Adaptor only.
- */
-
-#define BBA_SELECTED(dev) (dev->bus->number==0 && dev->devfn==0)
-
-static int gapspci_read_config_byte(struct pci_dev *dev, int where,
-                                    u8 * val)
-{
-	if (BBA_SELECTED(dev))
-		*val = inb(GAPSPCI_BBA_CONFIG+where);
-	else
-                *val = 0xff;
-
-	return PCIBIOS_SUCCESSFUL;
-}
-
-static int gapspci_read_config_word(struct pci_dev *dev, int where,
-                                    u16 * val)
-{
-        if (BBA_SELECTED(dev))
-		*val = inw(GAPSPCI_BBA_CONFIG+where);
-	else
-                *val = 0xffff;
-
-        return PCIBIOS_SUCCESSFUL;
-}
-
-static int gapspci_read_config_dword(struct pci_dev *dev, int where,
-                                     u32 * val)
-{
-        if (BBA_SELECTED(dev))
-		*val = inl(GAPSPCI_BBA_CONFIG+where);
-	else
-                *val = 0xffffffff;
-
-        return PCIBIOS_SUCCESSFUL;
-}
-
-static int gapspci_write_config_byte(struct pci_dev *dev, int where,
-                                     u8 val)
-{
-        if (BBA_SELECTED(dev))
-		outb(val, GAPSPCI_BBA_CONFIG+where);
-
-        return PCIBIOS_SUCCESSFUL;
-}
-
-
-static int gapspci_write_config_word(struct pci_dev *dev, int where,
-                                     u16 val)
-{
-        if (BBA_SELECTED(dev))
-		outw(val, GAPSPCI_BBA_CONFIG+where);
-
-        return PCIBIOS_SUCCESSFUL;
-}
-
-static int gapspci_write_config_dword(struct pci_dev *dev, int where,
-                                      u32 val)
-{
-        if (BBA_SELECTED(dev))
-		outl(val, GAPSPCI_BBA_CONFIG+where);
-
-        return PCIBIOS_SUCCESSFUL;
-}
-
-static struct pci_ops pci_config_ops = {
-        gapspci_read_config_byte,
-        gapspci_read_config_word,
-        gapspci_read_config_dword,
-        gapspci_write_config_byte,
-        gapspci_write_config_word,
-        gapspci_write_config_dword
-};
-
-
-void pcibios_align_resource(void *data, struct resource *res,
-			    unsigned long size)
-{
-}
-
-
-void __init pcibios_update_irq(struct pci_dev *dev, int irq)
-{
-}
-
-
-void __init pcibios_update_resource(struct pci_dev *dev, struct resource *root,
-			     struct resource *res, int resource)
-{
-}
-
-
-int pcibios_enable_device(struct pci_dev *dev)
-{
-
-	u16 cmd, old_cmd;
-	int idx;
-	struct resource *r;
-
-	pci_read_config_word(dev, PCI_COMMAND, &cmd);
-	old_cmd = cmd;
-	for (idx = 0; idx < 6; idx++) {
-		r = dev->resource + idx;
-		if (!r->start && r->end) {
-			printk(KERN_ERR
-			       "PCI: Device %s not available because"
-			       " of resource collisions\n",
-			       dev->slot_name);
-			return -EINVAL;
-		}
-		if (r->flags & IORESOURCE_IO)
-			cmd |= PCI_COMMAND_IO;
-		if (r->flags & IORESOURCE_MEM)
-			cmd |= PCI_COMMAND_MEMORY;
-	}
-	if (cmd != old_cmd) {
-		printk("PCI: enabling device %s (%04x -> %04x)\n",
-		       dev->slot_name, old_cmd, cmd);
-		pci_write_config_word(dev, PCI_COMMAND, cmd);
-	}
-	return 0;
-
-}
-
-
-void *pci_alloc_consistent(struct pci_dev *hwdev, size_t size,
-			   dma_addr_t * dma_handle)
-{
-	unsigned long buf;
-
-	if (gapspci_dma_used+size > GAPSPCI_DMA_SIZE)
-		return NULL;
-
-	buf = GAPSPCI_DMA_BASE+gapspci_dma_used;
-
-	gapspci_dma_used = PAGE_ALIGN(gapspci_dma_used+size);
-	
-	printk("pci_alloc_consistent: %d bytes at 0x%08x\n", size, buf);
-
-	*dma_handle = (dma_addr_t)buf;
-
-	return (void *)P2SEGADDR(buf);
-}
-
-
-void pci_free_consistent(struct pci_dev *hwdev, size_t size,
-			 void *vaddr, dma_addr_t dma_handle)
-{
-}
-
-
-void __init
-pcibios_fixup_pbus_ranges(struct pci_bus *bus, struct pbus_set_ranges_data *ranges)
-{
-}                                                                                
-
-void __init pcibios_fixup_bus(struct pci_bus *bus)
-{
-	struct list_head *ln;
-	struct pci_dev *dev;
-
-	for (ln=bus->devices.next; ln != &bus->devices; ln=ln->next) {
-		dev = pci_dev_b(ln);
-		if (!BBA_SELECTED(dev)) continue;
-
-		printk("PCI: MMIO fixup to %s\n", dev->name);
-		dev->resource[1].start=0x01001700;
-		dev->resource[1].end=0x010017ff;
-	}
-}
-
-
-void __init dreamcast_pcibios_init(void)
-{
-	pci_root_bus = pci_scan_bus(0, &pci_config_ops, NULL);
-	/* pci_assign_unassigned_resources(); */
-	pci_fixup_irqs(no_swizzle, map_od_irq);
-}
-
-
-static __init int gapspci_init(void)
-{
-	int i;
-	char idbuf[16];
-
-	for(i=0; i<16; i++)
-		idbuf[i]=inb(GAPSPCI_REGS+i);
-
-	if(strncmp(idbuf, "GAPSPCI_BRIDGE_2", 16))
-		return -1;
-
-	outl(0x5a14a501, GAPSPCI_REGS+0x18);
-
-	for(i=0; i<1000000; i++);
-
-	if(inl(GAPSPCI_REGS+0x18)!=1)
-		return -1;
-
-	outl(0x01000000, GAPSPCI_REGS+0x20);
-	outl(0x01000000, GAPSPCI_REGS+0x24);
-
-	outl(GAPSPCI_DMA_BASE, GAPSPCI_REGS+0x28);
-	outl(GAPSPCI_DMA_BASE+GAPSPCI_DMA_SIZE, GAPSPCI_REGS+0x2c);
-
-	outl(1, GAPSPCI_REGS+0x14);
-	outl(1, GAPSPCI_REGS+0x34);
-
-	gapspci_dma_used=0;
-
-	/*  */
-	irq_desc[GAPSPCI_IRQ].handler = &gapspci_irq_type;
-
-	/* Setting Broadband Adapter */
-	outw(0xf900, GAPSPCI_BBA_CONFIG+0x06);
-	outl(0x00000000, GAPSPCI_BBA_CONFIG+0x30);
-	outb(0x00, GAPSPCI_BBA_CONFIG+0x3c);
-	outb(0xf0, GAPSPCI_BBA_CONFIG+0x0d);
-	outw(0x0006, GAPSPCI_BBA_CONFIG+0x04);
-	outl(0x00002001, GAPSPCI_BBA_CONFIG+0x10);
-	outl(0x01000000, GAPSPCI_BBA_CONFIG+0x14);
-
 	return 0;
 }
diff -urN linux-2.4.6-pre5/arch/sh/kernel/setup_od.c linux/arch/sh/kernel/setup_od.c
--- linux-2.4.6-pre5/arch/sh/kernel/setup_od.c	Mon Jun 19 17:59:37 2000
+++ linux/arch/sh/kernel/setup_od.c	Wed Dec 31 16:00:00 1969
@@ -1,35 +0,0 @@
-/* $Id: setup_od.c,v 1.1 2000/06/14 09:35:59 stuart_menefy Exp $
- *
- * arch/sh/kernel/setup_od.c
- *
- * Copyright (C) 2000  Stuart Menefy
- *
- * STMicroelectronics Overdrive Support.
- *
- */
-
-#include <linux/config.h>
-#include <linux/kernel.h>
-#include <linux/init.h>
-
-/*
- * Initialize the board
- */
-int __init setup_od(void)
-{
-	/* Enable RS232 receive buffers */
-	volatile int* p = (volatile int*)0xa3000000;
-
-#if defined(CONFIG_SH_ORION)
-	*p=1;
-#elif defined(CONFIG_SH_OVERDRIVE)
-	*p=0x1e;
-#else
-#error Illegal configuration
-#endif
-
-	printk(KERN_INFO "STMicroelectronics Overdrive Setup...done\n");
-	return 0;
-}
-
-module_init(setup_od);
diff -urN linux-2.4.6-pre5/arch/sh/kernel/setup_sh2000.c linux/arch/sh/kernel/setup_sh2000.c
--- linux-2.4.6-pre5/arch/sh/kernel/setup_sh2000.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/sh/kernel/setup_sh2000.c	Mon Dec  3 22:49:10 2001
@@ -0,0 +1,95 @@
+/*
+ * linux/arch/sh/kernel/setup_sh2000.c
+ *
+ * Copyright (C) 2001  SUGIOKA Tochinobu
+ *
+ * SH-2000 Support.
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/init.h>
+#include <linux/irq.h>
+
+#include <asm/io.h>
+#include <asm/io_generic.h>
+#include <asm/machvec.h>
+#include <asm/machvec_init.h>
+#include <asm/rtc.h>
+
+#define CF_CIS_BASE	0xb4200000
+
+#define PORT_PECR	0xa4000108
+#define PORT_PHCR	0xa400010E
+#define	PORT_ICR1	0xa4000010
+#define	PORT_IRR0	0xa4000004
+
+/*
+ * Initialize the board
+ */
+int __init setup_sh2000(void)
+{
+	/* XXX: RTC setting comes here */
+
+	/* These should be done by BIOS/IPL ... */
+	/* Enable nCE2A, nCE2B output */
+	ctrl_outw(ctrl_inw(PORT_PECR) & ~0xf00, PORT_PECR);
+	/* Enable the Compact Flash card, and set the level interrupt */
+	ctrl_outw(0x0042, CF_CIS_BASE+0x0200);
+	/* Enable interrupt */
+	ctrl_outw(ctrl_inw(PORT_PHCR) & ~0x03f3, PORT_PHCR);
+	ctrl_outw(1, PORT_ICR1);
+	ctrl_outw(ctrl_inw(PORT_IRR0) & ~0xff3f, PORT_IRR0);
+	printk(KERN_INFO "SH-2000 Setup...done\n");
+	return 0;
+}
+/*
+ * The Machine Vector
+ */
+
+struct sh_machine_vector mv_sh2000 __initmv = {
+	mv_name:		"sh2000",
+
+	mv_nr_irqs:		80,
+
+	mv_inb:			generic_inb,
+	mv_inw:			generic_inw,
+	mv_inl:			generic_inl,
+	mv_outb:		generic_outb,
+	mv_outw:		generic_outw,
+	mv_outl:		generic_outl,
+
+	mv_inb_p:		generic_inb_p,
+	mv_inw_p:		generic_inw_p,
+	mv_inl_p:		generic_inl_p,
+	mv_outb_p:		generic_outb_p,
+	mv_outw_p:		generic_outw_p,
+	mv_outl_p:		generic_outl_p,
+
+	mv_insb:		generic_insb,
+	mv_insw:		generic_insw,
+	mv_insl:		generic_insl,
+	mv_outsb:		generic_outsb,
+	mv_outsw:		generic_outsw,
+	mv_outsl:		generic_outsl,
+
+	mv_readb:		generic_readb,
+	mv_readw:		generic_readw,
+	mv_readl:		generic_readl,
+	mv_writeb:		generic_writeb,
+	mv_writew:		generic_writew,
+	mv_writel:		generic_writel,
+
+	mv_init_arch:		setup_sh2000,
+
+	mv_isa_port2addr:	sh2000_isa_port2addr,
+
+	mv_ioremap:		generic_ioremap,
+	mv_iounmap:		generic_iounmap,
+
+	mv_rtc_gettimeofday:	sh_rtc_gettimeofday,
+	mv_rtc_settimeofday:	sh_rtc_settimeofday,
+
+	mv_hw_sh2000:		1,
+};
+ALIAS_MV(sh2000)
diff -urN linux-2.4.6-pre5/arch/sh/kernel/sh_ksyms.c linux/arch/sh/kernel/sh_ksyms.c
--- linux-2.4.6-pre5/arch/sh/kernel/sh_ksyms.c	Wed Apr 11 21:24:52 2001
+++ linux/arch/sh/kernel/sh_ksyms.c	Mon Dec  3 22:49:10 2001
@@ -18,6 +18,7 @@
 #include <asm/hardirq.h>
 #include <asm/delay.h>
 #include <asm/pgalloc.h>
+#include <asm/pci.h>
 #include <linux/irq.h>
 
 extern void dump_thread(struct pt_regs *, struct user *);
@@ -44,14 +45,25 @@
 EXPORT_SYMBOL(strpbrk);
 EXPORT_SYMBOL(strstr);
 EXPORT_SYMBOL(strlen);
+EXPORT_SYMBOL(strnlen);
 EXPORT_SYMBOL(strchr);
 EXPORT_SYMBOL(strcat);
 EXPORT_SYMBOL(strncat);
 
+/* PCI exports */
+#ifdef CONFIG_PCI
+EXPORT_SYMBOL(pci_alloc_consistent);
+EXPORT_SYMBOL(pci_free_consistent);
+EXPORT_SYMBOL(pcibios_penalize_isa_irq);
+#endif
+
 /* mem exports */
 EXPORT_SYMBOL(memchr);
 EXPORT_SYMBOL(memcpy);
+EXPORT_SYMBOL(memcpy_fromio);
+EXPORT_SYMBOL(memcpy_toio);
 EXPORT_SYMBOL(memset);
+EXPORT_SYMBOL(memset_io);
 EXPORT_SYMBOL(memmove);
 EXPORT_SYMBOL(memcmp);
 
@@ -63,20 +75,32 @@
 
 EXPORT_SYMBOL(get_vm_area);
 
+/* semaphore exports */
+EXPORT_SYMBOL(__up);
+EXPORT_SYMBOL(__down);
+EXPORT_SYMBOL(__down_interruptible);
+
+EXPORT_SYMBOL(__udelay);
+EXPORT_SYMBOL(__const_udelay);
+
 #define DECLARE_EXPORT(name) extern void name(void);EXPORT_SYMBOL_NOVERS(name)
  
 /* These symbols are generated by the compiler itself */
 DECLARE_EXPORT(__udivsi3);
 DECLARE_EXPORT(__sdivsi3);
+DECLARE_EXPORT(__ashrdi3);
+DECLARE_EXPORT(__ashldi3);
+DECLARE_EXPORT(__lshrdi3);
+DECLARE_EXPORT(__movstr);
 
 #ifdef __SH4__
  
 DECLARE_EXPORT(__movstr_i4_even);
 DECLARE_EXPORT(__movstr_i4_odd);
-DECLARE_EXPORT(__ashrdi3);
-DECLARE_EXPORT(__ashldi3);
 
 /* needed by some modules */
+EXPORT_SYMBOL(flush_cache_all);
+EXPORT_SYMBOL(flush_cache_range);
 EXPORT_SYMBOL(flush_dcache_page);
 #endif
 EXPORT_SYMBOL(flush_tlb_page);
diff -urN linux-2.4.6-pre5/arch/sh/kernel/time.c linux/arch/sh/kernel/time.c
--- linux-2.4.6-pre5/arch/sh/kernel/time.c	Wed Apr 11 21:24:52 2001
+++ linux/arch/sh/kernel/time.c	Mon Dec  3 22:49:10 2001
@@ -64,7 +64,11 @@
 #define CCN_PVR_CHIP_MASK  0xff
 #define CCN_PVR_CHIP_ST40STB1 0x4
 
-#endif
+#ifdef CONFIG_CPU_SUBTYPE_ST40STB1
+#define CLOCKGEN_MEMCLKCR 0xbb040038
+#define MEMCLKCR_RATIO_MASK 0x7
+#endif /* CONFIG_CPU_SUBTYPE_ST40STB1 */
+#endif /* __sh3__ or __SH4__ */
 
 extern rwlock_t xtime_lock;
 extern unsigned long wall_jiffies;
@@ -285,6 +289,9 @@
 void __init time_init(void)
 {
 	unsigned int cpu_clock, master_clock, bus_clock, module_clock;
+#ifdef CONFIG_CPU_SUBTYPE_ST40STB1
+	unsigned int memory_clock;
+#endif
 	unsigned int timer_freq;
 	unsigned short frqcr, ifc, pfc, bfc;
 	unsigned long interval;
@@ -335,23 +342,35 @@
 		{ 0x123, {{1,4}, {1,4}, {1,8}}},
 		{ 0x16C, {{1,4}, {1,8}, {1,8}}},
 	};
+
+	struct memclk_data {
+		unsigned char multiplier;
+		unsigned char divisor;
+	};
+	static struct memclk_data st40_memclk_table[8] = {
+		{1,1},	// 000
+		{1,2},	// 001
+		{1,3},	// 010
+		{2,3},	// 011
+		{1,4},	// 100
+		{1,6},	// 101
+		{1,8},	// 110
+		{1,8}	// 111
+	};
 #endif
 #endif
 
-#if defined(CONFIG_SH_DREAMCAST)
-	xtime.tv_sec = 0;
-	xtime.tv_usec = 0;
-#else
-	rtc_gettimeofday(&xtime);
-#endif
+	if (MACH_DREAMCAST)
+		xtime.tv_sec = xtime.tv_usec = 0;
+	else
+		rtc_gettimeofday(&xtime);
 
 	setup_irq(TIMER_IRQ, &irq0);
 
-#if defined(CONFIG_SH_DREAMCAST)
-	timer_freq = 50*1000*1000/4;
-#else
-	timer_freq = get_timer_frequency();
-#endif
+	if (MACH_DREAMCAST)
+		timer_freq = 50*1000*1000/4;
+	else
+		timer_freq = get_timer_frequency();
 
 	module_clock = timer_freq * 4;
 
@@ -386,6 +405,8 @@
 			/* Unfortunatly the STB1 FRQCR values are different from the 7750 ones */
 			struct frqcr_data *d;
 			int a;
+			unsigned long memclkcr;
+			struct memclk_data *e;
 
 			for (a=0; a<ARRAY_SIZE(st40_frqcr_table); a++) {
 				d = &st40_frqcr_table[a];
@@ -397,13 +418,18 @@
 				printk("ERROR: Unrecognised FRQCR value, using default multipliers\n");
 			}
 
-			printk("Clock multipliers: CPU: %d/%d Bus: %d/%d Periph: %d/%d\n",
+			memclkcr = ctrl_inl(CLOCKGEN_MEMCLKCR);
+			e = &st40_memclk_table[memclkcr & MEMCLKCR_RATIO_MASK];
+
+			printk("Clock multipliers: CPU: %d/%d Bus: %d/%d Mem: %d/%d Periph: %d/%d\n",
 			       d->factor[0].multiplier, d->factor[0].divisor,
 			       d->factor[1].multiplier, d->factor[1].divisor,
+			       e->multiplier,           e->divisor,
 			       d->factor[2].multiplier, d->factor[2].divisor);
 			
 			master_clock = module_clock * d->factor[2].divisor    / d->factor[2].multiplier;
 			bus_clock    = master_clock * d->factor[1].multiplier / d->factor[1].divisor;
+			memory_clock = master_clock * e->multiplier           / e->divisor;
 			cpu_clock    = master_clock * d->factor[0].multiplier / d->factor[0].divisor;
 			goto skip_calc;
 		} else
@@ -418,11 +444,17 @@
 	master_clock = module_clock * pfc;
 	bus_clock = master_clock / bfc;
 	cpu_clock = master_clock / ifc;
+#ifdef CONFIG_CPU_SUBTYPE_ST40STB1
  skip_calc:
+#endif
 	printk("CPU clock: %d.%02dMHz\n",
 	       (cpu_clock / 1000000), (cpu_clock % 1000000)/10000);
 	printk("Bus clock: %d.%02dMHz\n",
 	       (bus_clock/1000000), (bus_clock % 1000000)/10000);
+#ifdef CONFIG_CPU_SUBTYPE_ST40STB1
+	printk("Memory clock: %d.%02dMHz\n",
+	       (memory_clock/1000000), (memory_clock % 1000000)/10000);
+#endif
 	printk("Module clock: %d.%02dMHz\n",
 	       (module_clock/1000000), (module_clock % 1000000)/10000);
 	interval = (module_clock/4 + HZ/2) / HZ;
@@ -432,6 +464,9 @@
 	current_cpu_data.cpu_clock    = cpu_clock;
 	current_cpu_data.master_clock = master_clock;
 	current_cpu_data.bus_clock    = bus_clock;
+#ifdef CONFIG_CPU_SUBTYPE_ST40STB1
+	current_cpu_data.memory_clock = memory_clock;
+#endif
 	current_cpu_data.module_clock = module_clock;
 
 	/* Start TMU0 */
diff -urN linux-2.4.6-pre5/arch/sh/mm/cache.c linux/arch/sh/mm/cache.c
--- linux-2.4.6-pre5/arch/sh/mm/cache.c	Sun May 20 12:11:38 2001
+++ linux/arch/sh/mm/cache.c	Mon Dec  3 22:49:10 2001
@@ -151,7 +151,8 @@
 #elif defined(__SH4__)
 #ifdef CONFIG_CPU_SUBTYPE_ST40STB1
 	cpu_data->type = CPU_ST40STB1;
-#elif defined(CONFIG_CPU_SUBTYPE_SH7750)
+#elif defined(CONFIG_CPU_SUBTYPE_SH7750) || \
+      defined(CONFIG_CPU_SUBTYPE_SH7751)
 	cpu_data->type = CPU_SH7750;
 #else
 #error Unknown SH4 CPU type
diff -urN linux-2.4.6-pre5/arch/sh/mm/fault.c linux/arch/sh/mm/fault.c
--- linux-2.4.6-pre5/arch/sh/mm/fault.c	Mon Mar 19 12:35:10 2001
+++ linux/arch/sh/mm/fault.c	Mon Dec  3 22:49:10 2001
@@ -281,11 +281,12 @@
 {
 	unsigned long flags;
 	unsigned long pteval;
-	unsigned long pteaddr;
+	unsigned long vpn;
+#if defined(__SH4__)
 	unsigned long ptea;
+#endif
 
 	save_and_cli(flags);
-
 #if defined(__SH4__)
 	if (pte_shared(pte)) {
 		struct page *pg;
@@ -305,13 +306,13 @@
 	}
 
 	/* Set PTEH register */
-	pteaddr = (address & MMU_VPN_MASK) | get_asid();
-	ctrl_outl(pteaddr, MMU_PTEH);
+	vpn = (address & MMU_VPN_MASK) | get_asid();
+	ctrl_outl(vpn, MMU_PTEH);
 
-	/* Set PTEA register */
-	/* TODO: make this look less hacky */
 	pteval = pte_val(pte);
 #if defined(__SH4__)
+	/* Set PTEA register */
+	/* TODO: make this look less hacky */
 	ptea = ((pteval >> 28) & 0xe) | (pteval & 0x1);
 	ctrl_outl(ptea, MMU_PTEA);
 #endif
@@ -341,9 +342,9 @@
 	data = (page & 0xfffe0000) | asid; /* VALID bit is off */
 	ctrl_outl(data, addr);
 #elif defined(__SH4__)
-	jump_to_P2();
 	addr = MMU_UTLB_ADDRESS_ARRAY | MMU_PAGE_ASSOC_BIT;
 	data = page | asid; /* VALID bit is off */
+	jump_to_P2();
 	ctrl_outl(data, addr);
 	back_to_P1();
 #endif
@@ -352,27 +353,34 @@
 #if defined(__SH4__)
 static void __flush_tlb_phys(unsigned long phys)
 {
-	int i;
-	unsigned long addr, data;
+	unsigned long addr, data, pte;
 
-	jump_to_P2();
-	for (i = 0; i < MMU_UTLB_ENTRIES; i++) {
-		addr = MMU_UTLB_DATA_ARRAY | (i<<MMU_U_ENTRY_SHIFT);
+	pte = phys | MMU_UTLB_VALID;
+	for (addr = MMU_UTLB_DATA_ARRAY;
+	     addr < MMU_UTLB_DATA_ARRAY+(MMU_UTLB_ENTRIES<<MMU_U_ENTRY_SHIFT);
+	     addr += (1<<MMU_U_ENTRY_SHIFT)) {
 		data = ctrl_inl(addr);
-		if ((data & MMU_UTLB_VALID) && (data&PAGE_MASK) == phys) {
+		if ((data & (MMU_UTLB_VALID|PAGE_MASK)) == pte) {
 			data &= ~MMU_UTLB_VALID;
+			jump_to_P2();
 			ctrl_outl(data, addr);
+			back_to_P1();
+			break;
 		}
 	}
-	for (i = 0; i < MMU_ITLB_ENTRIES; i++) {
-		addr = MMU_ITLB_DATA_ARRAY | (i<<MMU_I_ENTRY_SHIFT);
+	pte = phys | MMU_ITLB_VALID;
+	for (addr = MMU_ITLB_DATA_ARRAY;
+	     addr < MMU_ITLB_DATA_ARRAY+(MMU_ITLB_ENTRIES<<MMU_I_ENTRY_SHIFT);
+	     addr += (1<<MMU_I_ENTRY_SHIFT)) {
 		data = ctrl_inl(addr);
-		if ((data & MMU_ITLB_VALID) && (data&PAGE_MASK) == phys) {
+		if ((data & (MMU_ITLB_VALID|PAGE_MASK)) == pte) {
 			data &= ~MMU_ITLB_VALID;
+			jump_to_P2();
 			ctrl_outl(data, addr);
+			back_to_P1();
+			break;
 		}
 	}
-	back_to_P1();
 }
 #endif
 
diff -urN linux-2.4.6-pre5/arch/sh/mm/init.c linux/arch/sh/mm/init.c
--- linux-2.4.6-pre5/arch/sh/mm/init.c	Wed Apr 11 21:24:52 2001
+++ linux/arch/sh/mm/init.c	Mon Dec  3 22:49:10 2001
@@ -100,7 +100,7 @@
 extern char _text, _etext, _edata, __bss_start, _end;
 extern char __init_begin, __init_end;
 
-pgd_t swapper_pg_dir[1024];
+pgd_t swapper_pg_dir[PTRS_PER_PGD];
 
 /* It'd be good if these lines were in the standard header file. */
 #define START_PFN	(NODE_DATA(0)->bdata->node_boot_start >> PAGE_SHIFT)
@@ -120,7 +120,7 @@
 	/* We don't need kernel mapping as hardware support that. */
 	pg_dir = swapper_pg_dir;
 
-	for (i=0; i < USER_PTRS_PER_PGD*2; i++)
+	for (i=0; i < PTRS_PER_PGD; i++)
 		pgd_val(pg_dir[i]) = 0;
 
 	/* Enable MMU */
diff -urN linux-2.4.6-pre5/arch/sh/stboards/Makefile linux/arch/sh/stboards/Makefile
--- linux-2.4.6-pre5/arch/sh/stboards/Makefile	Wed Dec 31 16:00:00 1969
+++ linux/arch/sh/stboards/Makefile	Mon Dec  3 22:49:10 2001
@@ -0,0 +1,15 @@
+#
+# Makefile for STMicroelectronics board specific parts of the kernel
+#
+# Note! Dependencies are done automagically by 'make dep', which also
+# removes any old dependencies. DON'T put your own dependencies here
+# unless it's something special (ie not a .c file).
+#
+
+all: stboards.o
+O_TARGET := stboards.o
+obj-y := irq.o setup.o mach.o led.o
+
+clean:
+
+include $(TOPDIR)/Rules.make
diff -urN linux-2.4.6-pre5/arch/sh/stboards/harp.h linux/arch/sh/stboards/harp.h
--- linux-2.4.6-pre5/arch/sh/stboards/harp.h	Wed Dec 31 16:00:00 1969
+++ linux/arch/sh/stboards/harp.h	Mon Dec  3 22:49:10 2001
@@ -0,0 +1,43 @@
+/* 
+ * Copyright (C) 2001 David J. Mckay (david.mckay@st.com)
+ *
+ * May be copied or modified under the terms of the GNU General Public
+ * License.  See linux/COPYING for more information.                            
+ *
+ * Defintions applicable to the STMicroelectronics ST40STB1 HARP and
+ * compatible boards.
+ */
+
+#if defined(CONFIG_SH_STB1_HARP)
+
+#define EPLD_BASE     0xa0800000
+
+#define EPLD_LED      (EPLD_BASE+0x000c0000)
+#define EPLD_INTSTAT0 (EPLD_BASE+0x00200000)
+#define EPLD_INTSTAT1 (EPLD_BASE+0x00240000)
+#define EPLD_INTMASK0 (EPLD_BASE+0x00280000)
+#define EPLD_INTMASK1 (EPLD_BASE+0x002c0000)
+#define EPLD_PAGEADDR (EPLD_BASE+0x00300000)
+#define EPLD_REVID1   (EPLD_BASE+0x00380000)
+#define EPLD_REVID2   (EPLD_BASE+0x003c0000)
+
+#define EPLD_LED_ON  1
+#define EPLD_LED_OFF 0
+
+#elif defined(CONFIG_SH_STB1_OVERDRIVE)
+
+#define EPLD_BASE     0xa7000000
+
+#define EPLD_REVID    (EPLD_BASE+0x00000000)
+#define EPLD_LED      (EPLD_BASE+0x00040000)
+#define EPLD_INTMASK0 (EPLD_BASE+0x001c0000)
+#define EPLD_INTMASK1 (EPLD_BASE+0x00200000)
+#define EPLD_INTSTAT0 (EPLD_BASE+0x00240000)
+#define EPLD_INTSTAT1 (EPLD_BASE+0x00280000)
+
+#define EPLD_LED_ON  0
+#define EPLD_LED_OFF 1
+
+#else
+#error Unknown board
+#endif
diff -urN linux-2.4.6-pre5/arch/sh/stboards/irq.c linux/arch/sh/stboards/irq.c
--- linux-2.4.6-pre5/arch/sh/stboards/irq.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/sh/stboards/irq.c	Mon Dec  3 22:49:10 2001
@@ -0,0 +1,149 @@
+/* 
+ * Copyright (C) 2000 David J. Mckay (david.mckay@st.com)
+ *
+ * May be copied or modified under the terms of the GNU General Public
+ * License.  See linux/COPYING for more information.                            
+ *
+ * Looks after interrupts on the HARP board.
+ *
+ * Bases on the IPR irq system
+ */
+
+#include <linux/config.h>
+#include <linux/init.h>
+#include <linux/irq.h>
+
+#include <asm/system.h>
+#include <asm/io.h>
+
+#include "harp.h"
+
+
+#define NUM_EXTERNAL_IRQS 16
+
+// Early versions of the STB1 Overdrive required this nasty frig
+//#define INVERT_INTMASK_WRITES
+
+static void enable_harp_irq(unsigned int irq);
+static void disable_harp_irq(unsigned int irq);
+
+/* shutdown is same as "disable" */
+#define shutdown_harp_irq disable_harp_irq
+
+static void mask_and_ack_harp(unsigned int);
+static void end_harp_irq(unsigned int irq);
+
+static unsigned int startup_harp_irq(unsigned int irq)
+{
+	enable_harp_irq(irq);
+	return 0;		/* never anything pending */
+}
+
+static struct hw_interrupt_type harp_irq_type = {
+	"Harp-IRQ",
+	startup_harp_irq,
+	shutdown_harp_irq,
+	enable_harp_irq,
+	disable_harp_irq,
+	mask_and_ack_harp,
+	end_harp_irq
+};
+
+static void disable_harp_irq(unsigned int irq)
+{
+	unsigned val, flags;
+	unsigned maskReg;
+	unsigned mask;
+	int pri;
+
+	if (irq < 0 || irq >= NUM_EXTERNAL_IRQS)
+		return;
+
+	pri = 15 - irq;
+
+	if (pri < 8) {
+		maskReg = EPLD_INTMASK0;
+	} else {
+		maskReg = EPLD_INTMASK1;
+		pri -= 8;
+	}
+
+	save_and_cli(flags);
+	mask = ctrl_inl(maskReg);
+	mask &= (~(1 << pri));
+#if defined(INVERT_INTMASK_WRITES)
+	mask ^= 0xff;
+#endif
+	ctrl_outl(mask, maskReg);
+	restore_flags(flags);
+}
+
+static void enable_harp_irq(unsigned int irq)
+{
+	unsigned flags;
+	unsigned maskReg;
+	unsigned mask;
+	int pri;
+
+	if (irq < 0 || irq >= NUM_EXTERNAL_IRQS)
+		return;
+
+	pri = 15 - irq;
+
+	if (pri < 8) {
+		maskReg = EPLD_INTMASK0;
+	} else {
+		maskReg = EPLD_INTMASK1;
+		pri -= 8;
+	}
+
+	save_and_cli(flags);
+	mask = ctrl_inl(maskReg);
+
+
+	mask |= (1 << pri);
+
+#if defined(INVERT_INTMASK_WRITES)
+	mask ^= 0xff;
+#endif
+	ctrl_outl(mask, maskReg);
+
+	restore_flags(flags);
+}
+
+/* This functions sets the desired irq handler to be an overdrive type */
+static void __init make_harp_irq(unsigned int irq)
+{
+	disable_irq_nosync(irq);
+	irq_desc[irq].handler = &harp_irq_type;
+	disable_harp_irq(irq);
+}
+
+static void mask_and_ack_harp(unsigned int irq)
+{
+	disable_harp_irq(irq);
+}
+
+static void end_harp_irq(unsigned int irq)
+{
+	enable_harp_irq(irq);
+}
+
+void __init init_harp_irq(void)
+{
+	int i;
+
+#if !defined(INVERT_INTMASK_WRITES)
+	// On the harp these are set to enable an interrupt
+	ctrl_outl(0x00, EPLD_INTMASK0);
+	ctrl_outl(0x00, EPLD_INTMASK1);
+#else
+	// On the Overdrive the data is inverted before being stored in the reg
+	ctrl_outl(0xff, EPLD_INTMASK0);
+	ctrl_outl(0xff, EPLD_INTMASK1);
+#endif
+
+	for (i = 0; i < NUM_EXTERNAL_IRQS; i++) {
+		make_harp_irq(i);
+	}
+}
diff -urN linux-2.4.6-pre5/arch/sh/stboards/led.c linux/arch/sh/stboards/led.c
--- linux-2.4.6-pre5/arch/sh/stboards/led.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/sh/stboards/led.c	Mon Dec  3 22:49:10 2001
@@ -0,0 +1,52 @@
+/*
+ * linux/arch/sh/stboards/led.c
+ *
+ * Copyright (C) 2000 Stuart Menefy <stuart.menefy@st.com>
+ *
+ * May be copied or modified under the terms of the GNU General Public
+ * License.  See linux/COPYING for more information.
+ *
+ * This file contains ST40STB1 HARP and compatible code.
+ */
+
+#include <linux/config.h>
+#include <asm/io.h>
+#include "harp.h"
+
+/* Harp: Flash LD10 (front pannel) connected to EPLD (IC8) */
+/* Overdrive: Flash LD1 (front panel) connected to EPLD (IC4) */
+/* Works for HARP and overdrive */
+static void mach_led(int position, int value)
+{
+	if (value) {
+		ctrl_outl(EPLD_LED_ON, EPLD_LED);
+	} else {
+		ctrl_outl(EPLD_LED_OFF, EPLD_LED);
+	}
+}
+
+#ifdef CONFIG_HEARTBEAT
+
+#include <linux/sched.h>
+
+/* acts like an actual heart beat -- ie thump-thump-pause... */
+void heartbeat_harp(void)
+{
+	static unsigned cnt = 0, period = 0, dist = 0;
+
+	if (cnt == 0 || cnt == dist)
+		mach_led( -1, 1);
+	else if (cnt == 7 || cnt == dist+7)
+		mach_led( -1, 0);
+
+	if (++cnt > period) {
+		cnt = 0;
+		/* The hyperbolic function below modifies the heartbeat period
+		 * length in dependency of the current (5min) load. It goes
+		 * through the points f(0)=126, f(1)=86, f(5)=51,
+		 * f(inf)->30. */
+		period = ((672<<FSHIFT)/(5*avenrun[0]+(7<<FSHIFT))) + 30;
+		dist = period / 4;
+	}
+}
+#endif
diff -urN linux-2.4.6-pre5/arch/sh/stboards/mach.c linux/arch/sh/stboards/mach.c
--- linux-2.4.6-pre5/arch/sh/stboards/mach.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/sh/stboards/mach.c	Mon Dec  3 22:49:10 2001
@@ -0,0 +1,77 @@
+/*
+ * linux/arch/sh/stboards/mach.c
+ *
+ * Copyright (C) 2000 Stuart Menefy (stuart.menefy@st.com)
+ *
+ * May be copied or modified under the terms of the GNU General Public
+ * License.  See linux/COPYING for more information.
+ *
+ * Machine vector for the STMicroelectronics STB1 HARP and compatible boards
+ */
+
+#include <linux/init.h>
+
+#include <asm/machvec.h>
+#include <asm/rtc.h>
+#include <asm/machvec_init.h>
+#include <asm/io_hd64465.h>
+#include <asm/hd64465.h>
+
+void setup_harp(void);
+void init_harp_irq(void);
+void heartbeat_harp(void);
+
+/*
+ * The Machine Vector
+ */
+
+struct sh_machine_vector mv_harp __initmv = {
+	mv_name:		"STB1 Harp",
+
+	mv_nr_irqs:		89 + HD64465_IRQ_NUM,
+
+	mv_inb:			hd64465_inb,
+	mv_inw:			hd64465_inw,
+	mv_inl:			hd64465_inl,
+	mv_outb:		hd64465_outb,
+	mv_outw:		hd64465_outw,
+	mv_outl:		hd64465_outl,
+
+	mv_inb_p:		hd64465_inb_p,
+	mv_inw_p:		hd64465_inw,
+	mv_inl_p:		hd64465_inl,
+	mv_outb_p:		hd64465_outb_p,
+	mv_outw_p:		hd64465_outw,
+	mv_outl_p:		hd64465_outl,
+
+	mv_insb:		hd64465_insb,
+	mv_insw:		hd64465_insw,
+	mv_insl:		hd64465_insl,
+	mv_outsb:		hd64465_outsb,
+	mv_outsw:		hd64465_outsw,
+	mv_outsl:		hd64465_outsl,
+
+	mv_readb:		generic_readb,
+	mv_readw:		generic_readw,
+	mv_readl:		generic_readl,
+	mv_writeb:		generic_writeb,
+	mv_writew:		generic_writew,
+	mv_writel:		generic_writel,
+
+        mv_ioremap:             generic_ioremap,
+        mv_iounmap:             generic_iounmap,
+ 
+        mv_isa_port2addr:       hd64465_isa_port2addr,
+
+	mv_init_arch:		setup_harp,
+#ifdef CONFIG_PCI
+	mv_init_irq:		init_harp_irq,
+#endif
+#ifdef CONFIG_HEARTBEAT
+	mv_heartbeat:		heartbeat_harp,
+#endif
+        mv_rtc_gettimeofday:    sh_rtc_gettimeofday,
+        mv_rtc_settimeofday:    sh_rtc_settimeofday,
+};
+
+ALIAS_MV(harp)
diff -urN linux-2.4.6-pre5/arch/sh/stboards/pcidma.c linux/arch/sh/stboards/pcidma.c
--- linux-2.4.6-pre5/arch/sh/stboards/pcidma.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/sh/stboards/pcidma.c	Mon Dec  3 22:49:10 2001
@@ -0,0 +1,42 @@
+/* 
+ * Copyright (C) 2001 David J. Mckay (david.mckay@st.com)
+ *
+ * May be copied or modified under the terms of the GNU General Public
+ * License.  See linux/COPYING for more information.                            
+ *
+ * Dynamic DMA mapping support.
+ */
+
+#include <linux/types.h>
+#include <linux/mm.h>
+#include <linux/string.h>
+#include <linux/pci.h>
+#include <asm/io.h>
+#include <asm/addrspace.h>
+
+
+void *pci_alloc_consistent(struct pci_dev *hwdev, size_t size,
+			   dma_addr_t * dma_handle)
+{
+	void *ret;
+	int gfp = GFP_ATOMIC;
+
+	ret = (void *) __get_free_pages(gfp, get_order(size));
+
+	if (ret != NULL) {
+	        /* Is it neccessary to do the memset? */
+		memset(ret, 0, size);
+		*dma_handle = virt_to_bus(ret);
+	}
+	/* We must flush the cache before we pass it on to the device */
+	flush_cache_all();
+	return  P2SEGADDR(ret);
+}
+
+void pci_free_consistent(struct pci_dev *hwdev, size_t size,
+			 void *vaddr, dma_addr_t dma_handle)
+{
+        unsigned long p1addr=P1SEGADDR((unsigned long)vaddr);
+
+	free_pages(p1addr, get_order(size));
+}
diff -urN linux-2.4.6-pre5/arch/sh/stboards/setup.c linux/arch/sh/stboards/setup.c
--- linux-2.4.6-pre5/arch/sh/stboards/setup.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/sh/stboards/setup.c	Mon Dec  3 22:49:10 2001
@@ -0,0 +1,50 @@
+/*
+ * arch/sh/stboard/setup.c
+ *
+ * Copyright (C) 2001 Stuart Menefy (stuart.menefy@st.com)
+ *
+ * May be copied or modified under the terms of the GNU General Public
+ * License.  See linux/COPYING for more information.
+ *
+ * STMicroelectronics ST40STB1 HARP and compatible support.
+ */
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <asm/io.h>
+#include "harp.h"
+/*
+ * Initialize the board
+ */
+int __init setup_harp(void)
+{
+#ifdef CONFIG_SH_STB1_HARP
+	unsigned long ic8_version, ic36_version;
+
+	ic8_version = ctrl_inl(EPLD_REVID2);
+	ic36_version = ctrl_inl(EPLD_REVID1);
+
+        printk("STMicroelectronics STB1 HARP initialisaton\n");
+        printk("EPLD versions: IC8: %d.%02d, IC36: %d.%02d\n",
+               (ic8_version >> 4) & 0xf, ic8_version & 0xf,
+               (ic36_version >> 4) & 0xf, ic36_version & 0xf);
+#elif defined(CONFIG_SH_STB1_OVERDRIVE)
+	unsigned long version;
+
+	version = ctrl_inl(EPLD_REVID);
+
+        printk("STMicroelectronics STB1 Overdrive initialisaton\n");
+        printk("EPLD version: %d.%02d\n",
+	       (version >> 4) & 0xf, version & 0xf);
+#else
+#error Undefined machine
+#endif
+ 
+        /* Currently all STB1 chips have problems with the sleep instruction,
+         * so disable it here.
+         */
+	disable_hlt();
+
+	return 0;
+}
diff -urN linux-2.4.6-pre5/arch/sparc64/config.in linux/arch/sparc64/config.in
--- linux-2.4.6-pre5/arch/sparc64/config.in	Mon Dec  3 22:49:01 2001
+++ linux/arch/sparc64/config.in	Mon Dec  3 22:49:10 2001
@@ -1,4 +1,4 @@
-# $Id: config.in,v 1.144 2001/06/01 08:12:10 davem Exp $
+# $Id: config.in,v 1.146 2001/06/16 04:15:26 davem Exp $
 # For a description of the syntax of this configuration file,
 # see the Configure script.
 #
@@ -36,6 +36,7 @@
 define_bool CONFIG_RWSEM_GENERIC_SPINLOCK n
 define_bool CONFIG_RWSEM_XCHGADD_ALGORITHM y
 define_bool CONFIG_ISA n
+define_bool CONFIG_ISAPNP n
 define_bool CONFIG_EISA n
 define_bool CONFIG_MCA n
 define_bool CONFIG_PCMCIA n
@@ -235,71 +236,7 @@
 
    bool 'Network device support' CONFIG_NETDEVICES
    if [ "$CONFIG_NETDEVICES" = "y" ]; then
-      tristate '  Dummy net driver support' CONFIG_DUMMY
-      tristate '  Bonding driver support' CONFIG_BONDING
-      tristate '  Universal TUN/TAP device driver support' CONFIG_TUN
-      if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
-        if [ "$CONFIG_NETLINK" = "y" ]; then
-          tristate '  Ethertap network tap (OBSOLETE)' CONFIG_ETHERTAP
-        fi
-      fi
-      tristate '  PPP (point-to-point) support' CONFIG_PPP
-      if [ ! "$CONFIG_PPP" = "n" ]; then
-         dep_tristate '  PPP support for async serial ports' CONFIG_PPP_ASYNC $CONFIG_PPP
-         dep_tristate '  PPP support for sync tty ports' CONFIG_PPP_SYNC_TTY $CONFIG_PPP
-         dep_tristate '  PPP Deflate compression' CONFIG_PPP_DEFLATE $CONFIG_PPP
-         dep_tristate '  PPP BSD-Compress compression' CONFIG_PPP_BSDCOMP m
-         if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
-            dep_tristate '  PPP over Ethernet (EXPERIMENTAL)' CONFIG_PPPOE $CONFIG_PPP
-         fi
-      fi
-      tristate '  SLIP (serial line) support' CONFIG_SLIP
-      if [ "$CONFIG_SLIP" != "n" ]; then
-	 bool '    CSLIP compressed headers' CONFIG_SLIP_COMPRESSED
-	 bool '    Keepalive and linefill' CONFIG_SLIP_SMART
-	 bool '    Six bit SLIP encapsulation' CONFIG_SLIP_MODE_SLIP6
-      fi
-
-      mainmenu_option next_comment
-      comment 'Ethernet (10 or 100Mbit)'
-
-      tristate 'Sun LANCE support' CONFIG_SUNLANCE
-      tristate 'Sun Happy Meal 10/100baseT support' CONFIG_HAPPYMEAL
-      if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
-	 tristate 'Sun BigMAC 10/100baseT support (EXPERIMENTAL)' CONFIG_SUNBMAC
-      fi
-      tristate '  Sun QuadEthernet support' CONFIG_SUNQE
-      if [ "$CONFIG_PCI" = "y" ]; then
-	 tristate 'Generic DECchip & DIGITAL EtherWORKS PCI/EISA' CONFIG_DE4X5
-	 tristate 'DECchip Tulip (dc21x4x) PCI support' CONFIG_TULIP
-	 tristate '3c590/3c900 series (592/595/597) "Vortex/Boomerang" support' CONFIG_VORTEX
-	 tristate 'RealTek RTL-8139 support' CONFIG_8139TOO
-	 tristate 'PCI NE2000 support' CONFIG_NE2K_PCI
-	 tristate 'VIA Rhine support' CONFIG_VIA_RHINE
-	 tristate 'EtherExpressPro/100 support' CONFIG_EEPRO100
-	 tristate 'Adaptec Starfire support' CONFIG_ADAPTEC_STARFIRE
-      fi
-      endmenu
-
-      mainmenu_option next_comment
-      comment 'Ethernet (1000 Mbit)'
-
-      if [ "$CONFIG_PCI" = "y" ]; then
-	  tristate 'Alteon AceNIC/3Com 3C985/NetGear GA620 Gigabit support' CONFIG_ACENIC
-	  if [ "$CONFIG_ACENIC" != "n" ]; then
-	    bool '  Omit support for old Tigon I based AceNICs' CONFIG_ACENIC_OMIT_TIGON_I
-	  fi
-	  tristate 'SysKonnect SK-98xx support' CONFIG_SK98LIN
-	  tristate 'Sun GEM support' CONFIG_SUNGEM
-      fi
-      tristate 'MyriCOM Gigabit Ethernet support' CONFIG_MYRI_SBUS
-      endmenu
-
-      bool 'FDDI driver support' CONFIG_FDDI
-      if [ "$CONFIG_FDDI" = "y" ]; then
-          tristate '  SysKonnect FDDI PCI support' CONFIG_SKFP
-      fi
-
+      source drivers/net/Config.in
       if [ "$CONFIG_ATM" = "y" ]; then
 	source drivers/atm/Config.in
       fi
@@ -330,6 +267,11 @@
 comment 'XFree86 DRI support'
 bool 'Direct Rendering Manager (XFree86 DRI support)' CONFIG_DRM
 dep_tristate '  Creator/Creator3D' CONFIG_DRM_FFB $CONFIG_DRM
+dep_tristate '  3dfx Banshee/Voodoo3+' CONFIG_DRM_TDFX $CONFIG_DRM
+dep_tristate '  ATI Rage 128' CONFIG_DRM_R128 $CONFIG_DRM
+if [ "$CONFIG_DRM_R128" != "n" ]; then
+   define_bool CONFIG_AGP y
+fi
 endmenu
 
 source drivers/input/Config.in
diff -urN linux-2.4.6-pre5/arch/sparc64/defconfig linux/arch/sparc64/defconfig
--- linux-2.4.6-pre5/arch/sparc64/defconfig	Mon Dec  3 22:49:01 2001
+++ linux/arch/sparc64/defconfig	Mon Dec  3 22:49:10 2001
@@ -26,6 +26,7 @@
 # CONFIG_RWSEM_GENERIC_SPINLOCK is not set
 CONFIG_RWSEM_XCHGADD_ALGORITHM=y
 # CONFIG_ISA is not set
+# CONFIG_ISAPNP is not set
 # CONFIG_EISA is not set
 # CONFIG_MCA is not set
 # CONFIG_PCMCIA is not set
@@ -359,46 +360,119 @@
 # Network device support
 #
 CONFIG_NETDEVICES=y
+
+#
+# ARCnet devices
+#
+# CONFIG_ARCNET is not set
+
+#
+# Appletalk devices
+#
+# CONFIG_APPLETALK is not set
 CONFIG_DUMMY=m
 CONFIG_BONDING=m
+CONFIG_EQUALIZER=m
 CONFIG_TUN=m
-CONFIG_PPP=m
-# CONFIG_PPP_ASYNC is not set
-# CONFIG_PPP_SYNC_TTY is not set
-# CONFIG_PPP_DEFLATE is not set
-# CONFIG_PPP_BSDCOMP is not set
-CONFIG_PPPOE=m
-CONFIG_SLIP=m
-CONFIG_SLIP_COMPRESSED=y
-CONFIG_SLIP_SMART=y
-# CONFIG_SLIP_MODE_SLIP6 is not set
 
 #
 # Ethernet (10 or 100Mbit)
 #
+CONFIG_NET_ETHERNET=y
 CONFIG_SUNLANCE=y
 CONFIG_HAPPYMEAL=y
 CONFIG_SUNBMAC=m
 CONFIG_SUNQE=m
-CONFIG_DE4X5=m
-CONFIG_TULIP=m
+CONFIG_SUNLANCE=y
+CONFIG_SUNGEM=y
+CONFIG_NET_VENDOR_3COM=y
+# CONFIG_EL1 is not set
+# CONFIG_EL2 is not set
+# CONFIG_ELPLUS is not set
+# CONFIG_EL16 is not set
+# CONFIG_ELMC is not set
+# CONFIG_ELMC_II is not set
 CONFIG_VORTEX=m
-CONFIG_8139TOO=m
+# CONFIG_LANCE is not set
+# CONFIG_NET_VENDOR_SMC is not set
+# CONFIG_NET_VENDOR_RACAL is not set
+# CONFIG_HP100 is not set
+# CONFIG_NET_ISA is not set
+CONFIG_NET_PCI=y
+CONFIG_PCNET32=m
+CONFIG_ADAPTEC_STARFIRE=m
+# CONFIG_APRICOT is not set
+# CONFIG_CS89x0 is not set
+CONFIG_TULIP=m
+# CONFIG_TULIP_MWI is not set
+# CONFIG_TULIP_MMIO is not set
+CONFIG_DE4X5=m
+CONFIG_DGRS=m
+# CONFIG_DM9102 is not set
+CONFIG_EEPRO100=m
+# CONFIG_LNE390 is not set
+CONFIG_FEALNX=m
+CONFIG_NATSEMI=m
 CONFIG_NE2K_PCI=m
+# CONFIG_NE3210 is not set
+# CONFIG_ES3210 is not set
+CONFIG_8139TOO=m
+# CONFIG_8139TOO_PIO is not set
+# CONFIG_8139TOO_TUNE_TWISTER is not set
+# CONFIG_8139TOO_8129 is not set
+# CONFIG_SIS900 is not set
+CONFIG_EPIC100=m
+# CONFIG_SUNDANCE is not set
+# CONFIG_TLAN is not set
 CONFIG_VIA_RHINE=m
-CONFIG_EEPRO100=m
-CONFIG_ADAPTEC_STARFIRE=m
+CONFIG_WINBOND_840=m
+# CONFIG_NET_POCKET is not set
 
 #
 # Ethernet (1000 Mbit)
 #
 CONFIG_ACENIC=m
 # CONFIG_ACENIC_OMIT_TIGON_I is not set
-CONFIG_SK98LIN=m
-CONFIG_SUNGEM=y
 CONFIG_MYRI_SBUS=m
+# CONFIG_HAMACHI is not set
+# CONFIG_YELLOWFIN is not set
+CONFIG_SK98LIN=m
 CONFIG_FDDI=y
+# CONFIG_DEFXX is not set
 CONFIG_SKFP=m
+CONFIG_HIPPI=y
+# CONFIG_ROADRUNNER is not set
+CONFIG_PLIP=m
+CONFIG_PPP=m
+# CONFIG_PPP_MULTILINK is not set
+# CONFIG_PPP_FILTER is not set
+# CONFIG_PPP_ASYNC is not set
+# CONFIG_PPP_SYNC_TTY is not set
+# CONFIG_PPP_DEFLATE is not set
+# CONFIG_PPP_BSDCOMP is not set
+CONFIG_PPPOE=m
+CONFIG_SLIP=m
+CONFIG_SLIP_COMPRESSED=y
+CONFIG_SLIP_SMART=y
+# CONFIG_SLIP_MODE_SLIP6 is not set
+
+#
+# Wireless LAN (non-hamradio)
+#
+# CONFIG_NET_RADIO 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
+
+#
+# Wan interfaces
+#
+# CONFIG_WAN is not set
 
 #
 # Unix 98 PTY support
@@ -417,6 +491,9 @@
 #
 CONFIG_DRM=y
 CONFIG_DRM_FFB=m
+CONFIG_DRM_TDFX=m
+CONFIG_DRM_R128=m
+CONFIG_AGP=y
 
 #
 # Input core support
diff -urN linux-2.4.6-pre5/drivers/acorn/char/keyb_arc.c linux/drivers/acorn/char/keyb_arc.c
--- linux-2.4.6-pre5/drivers/acorn/char/keyb_arc.c	Fri Feb  9 11:30:22 2001
+++ linux/drivers/acorn/char/keyb_arc.c	Mon Dec  3 22:49:10 2001
@@ -390,7 +390,7 @@
 		kbd_state, keyval);
 #endif
 	mdelay(1);
-	inb(IOC_KARTRX);
+	ioc_readb(IOC_KARTRX);
 	a5kkbd_sendbyte (HRST);
 	kbd_state = KBD_INITRST;
 	return 0;
@@ -407,13 +407,13 @@
 static void a5kkbd_rx(int irq, void *dev_id, struct pt_regs *regs)
 {
 	kbd_pt_regs = regs;
-	if (handle_rawcode(inb(IOC_KARTRX)))
+	if (handle_rawcode(ioc_readb(IOC_KARTRX)))
 		tasklet_schedule(&keyboard_tasklet);
 }
 
 static void a5kkbd_tx(int irq, void *dev_id, struct pt_regs *regs)
 {
-	outb (kbd_txval[kbd_txtail], IOC_KARTTX);
+	ioc_writeb (kbd_txval[kbd_txtail], IOC_KARTTX);
 	KBD_INCTXPTR(kbd_txtail);
 	if (kbd_txtail == kbd_txhead)
 		disable_irq(irq);
@@ -431,7 +431,7 @@
 
 	if (request_irq (IRQ_KEYBOARDTX, a5kkbd_tx, 0, "keyboard", NULL) != 0)
 		panic("Could not allocate keyboard transmit IRQ!");
-	(void)inb(IOC_KARTRX);
+	(void)ioc_readb(IOC_KARTRX);
 	if (request_irq (IRQ_KEYBOARDRX, a5kkbd_rx, 0, "keyboard", NULL) != 0)
 		panic("Could not allocate keyboard receive IRQ!");
 
diff -urN linux-2.4.6-pre5/drivers/acorn/char/keyb_ps2.c linux/drivers/acorn/char/keyb_ps2.c
--- linux-2.4.6-pre5/drivers/acorn/char/keyb_ps2.c	Fri Feb  9 11:30:22 2001
+++ linux/drivers/acorn/char/keyb_ps2.c	Mon Dec  3 22:49:10 2001
@@ -24,6 +24,7 @@
 #include <linux/random.h>
 #include <linux/ctype.h>
 #include <linux/kbd_ll.h>
+#include <linux/delay.h>
 #include <linux/init.h>
 
 #include <asm/bitops.h>
@@ -37,6 +38,12 @@
 extern void kbd_reset_kdown(void);
 int kbd_read_mask;
 
+#define TX_DONE 0
+#define TX_SENT 1
+#define TX_SEND 2
+
+static volatile int tx_state;
+
 #define VERSION 100
 
 #define KBD_REPORT_ERR
@@ -233,8 +240,33 @@
 
 static inline void ps2kbd_sendbyte(unsigned char val)
 {
-	while(!(inb(IOMD_KCTRL) & (1 << 7)));
-	outb(val, IOMD_KARTTX);
+	int tries = 3, timeout = 1000;
+
+	tx_state = TX_SEND;
+
+	do {
+		switch (tx_state) {
+		case TX_SEND:
+			tx_state = TX_SENT;
+			timeout = 1000;
+			tries --;
+
+			while(!(iomd_readb(IOMD_KCTRL) & (1 << 7)));
+			iomd_writeb(val, IOMD_KARTTX);
+			break;
+
+		case TX_SENT:
+			udelay(1000);
+			if (--timeout == 0) {
+				printk(KERN_ERR "Keyboard timeout\n");
+				tx_state = TX_DONE;
+			}
+			break;
+
+		case TX_DONE:
+			break;
+		}
+	} while (tries > 0 && tx_state != TX_DONE);
 }
 
 static unsigned char status;
@@ -254,18 +286,30 @@
 
 	if (keyval > 0x83) {
 		switch (keyval) {
-			case KBD_ESCAPEE0:
-				ncodes = 2;
-				bi = 0;
-				break;
-			case KBD_ESCAPEE1:
-				ncodes = 3;
-				bi = 0;
-				break;
-			case KBD_BREAK:
-				status |= CODE_BREAK;
-			default:
-				return;
+		case KBD_ESCAPEE0:
+			ncodes = 2;
+			bi = 0;
+			break;
+
+		case KBD_ESCAPEE1:
+			ncodes = 3;
+			bi = 0;
+			break;
+
+		case KBD_ACK:
+			tx_state = TX_DONE;
+			return;
+
+		case KBD_RESEND:
+			tx_state = TX_SEND;
+			return;
+
+		case KBD_BREAK:
+			status |= CODE_BREAK;
+			return;
+
+		default:
+			return;
 		}
 	}
 
@@ -278,6 +322,13 @@
 		switch (buffer[0] << 8 | buffer[1]) {
 		case ESCE0(0x11): keysym = K_RALT; break;
 		case ESCE0(0x14): keysym = K_RCTL; break;
+		/*
+		 * take care of MS extra keys (actually
+		 * 0x7d - 0x7f, but last one is already K_NONE
+		 */
+		case ESCE0(0x1f): keysym = 124;    break;
+		case ESCE0(0x27): keysym = 125;    break;
+		case ESCE0(0x2f): keysym = 126;    break;
 		case ESCE0(0x4a): keysym = KP_SLH; break;
 		case ESCE0(0x5a): keysym = KP_ENT; break;
 		case ESCE0(0x69): keysym = K_END;  break;
@@ -320,8 +371,8 @@
 {
 	kbd_pt_regs = regs;
 
-	while (inb(IOMD_KCTRL) & (1 << 5))
-		handle_rawcode(inb(IOMD_KARTRX));
+	while (iomd_readb(IOMD_KCTRL) & (1 << 5))
+		handle_rawcode(iomd_readb(IOMD_KARTRX));
 	tasklet_schedule(&keyboard_tasklet);
 }
 
@@ -332,10 +383,10 @@
 int __init ps2kbd_init_hw(void)
 {
 	/* Reset the keyboard state machine. */
-	outb(0, IOMD_KCTRL);
-	outb(8, IOMD_KCTRL);
+	iomd_writeb(0, IOMD_KCTRL);
+	iomd_writeb(8, IOMD_KCTRL);
+	iomd_readb(IOMD_KARTRX);
 
-	(void)IOMD_KARTRX;
 	if (request_irq (IRQ_KEYBOARDRX, ps2kbd_rx, 0, "keyboard", NULL) != 0)
 		panic("Could not allocate keyboard receive IRQ!");
 	if (request_irq (IRQ_KEYBOARDTX, ps2kbd_tx, 0, "keyboard", NULL) != 0)
diff -urN linux-2.4.6-pre5/drivers/acorn/char/mouse_ps2.c linux/drivers/acorn/char/mouse_ps2.c
--- linux-2.4.6-pre5/drivers/acorn/char/mouse_ps2.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/acorn/char/mouse_ps2.c	Mon Dec  3 22:49:10 2001
@@ -0,0 +1,289 @@
+/* 
+ * Driver for PS/2 mouse on IOMD interface
+ */
+
+#include <linux/config.h>
+#include <linux/sched.h>
+#include <linux/interrupt.h>
+#include <linux/tty.h>
+#include <linux/tty_flip.h>
+#include <linux/mm.h>
+#include <linux/malloc.h>
+#include <linux/ptrace.h>
+#include <linux/signal.h>
+#include <linux/timer.h>
+#include <linux/random.h>
+#include <linux/ctype.h>
+#include <linux/kbd_ll.h>
+#include <linux/delay.h>
+#include <linux/init.h>
+#include <linux/poll.h>
+#include <linux/miscdevice.h>
+
+#include <asm/bitops.h>
+#include <asm/irq.h>
+#include <asm/hardware.h>
+#include <asm/io.h>
+#include <asm/hardware/iomd.h>
+#include <asm/system.h>
+#include <asm/uaccess.h>
+
+/*
+ *	PS/2 Auxiliary Device
+ */
+
+static struct aux_queue *queue;	/* Mouse data buffer. */
+static int aux_count = 0;
+/* used when we send commands to the mouse that expect an ACK. */
+static unsigned char mouse_reply_expected = 0;
+
+#define MAX_RETRIES	60		/* some aux operations take long time*/
+
+/*
+ *	Mouse Commands
+ */
+
+#define AUX_SET_RES		0xE8	/* Set resolution */
+#define AUX_SET_SCALE11		0xE6	/* Set 1:1 scaling */
+#define AUX_SET_SCALE21		0xE7	/* Set 2:1 scaling */
+#define AUX_GET_SCALE		0xE9	/* Get scaling factor */
+#define AUX_SET_STREAM		0xEA	/* Set stream mode */
+#define AUX_SET_SAMPLE		0xF3	/* Set sample rate */
+#define AUX_ENABLE_DEV		0xF4	/* Enable aux device */
+#define AUX_DISABLE_DEV		0xF5	/* Disable aux device */
+#define AUX_RESET		0xFF	/* Reset aux device */
+#define AUX_ACK			0xFA	/* Command byte ACK. */
+
+#define AUX_BUF_SIZE		2048	/* This might be better divisible by
+					   three to make overruns stay in sync
+					   but then the read function would 
+					   need a lock etc - ick */
+
+struct aux_queue {
+	unsigned long head;
+	unsigned long tail;
+	wait_queue_head_t proc_list;
+	struct fasync_struct *fasync;
+	unsigned char buf[AUX_BUF_SIZE];
+};
+
+/*
+ * Send a byte to the mouse.
+ */
+static void aux_write_dev(int val)
+{
+	while (!(iomd_readb(IOMD_MSECTL) & 0x80));
+	iomd_writeb(val, IOMD_MSEDAT);
+}
+
+/*
+ * Send a byte to the mouse & handle returned ack
+ */
+static void aux_write_ack(int val)
+{
+	while (!(iomd_readb(IOMD_MSECTL) & 0x80));
+	iomd_writeb(val, IOMD_MSEDAT);
+
+	/* we expect an ACK in response. */
+	mouse_reply_expected++;
+}
+
+static unsigned char get_from_queue(void)
+{
+	unsigned char result;
+
+	result = queue->buf[queue->tail];
+	queue->tail = (queue->tail + 1) & (AUX_BUF_SIZE-1);
+	return result;
+}
+
+static void psaux_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+	int val = iomd_readb(IOMD_MSEDAT);
+
+	if (mouse_reply_expected) {
+		if (val == AUX_ACK) {
+			mouse_reply_expected--;
+			return;
+		}
+		mouse_reply_expected = 0;
+	}
+
+	add_mouse_randomness(val);
+	if (aux_count) {
+		int head = queue->head;
+
+		queue->buf[head] = val;
+		head = (head + 1) & (AUX_BUF_SIZE-1);
+		if (head != queue->tail) {
+			queue->head = head;
+			kill_fasync(&queue->fasync, SIGIO, POLL_IN);
+			wake_up_interruptible(&queue->proc_list);
+		}
+	}
+}
+
+static inline int queue_empty(void)
+{
+	return queue->head == queue->tail;
+}
+
+static int fasync_aux(int fd, struct file *filp, int on)
+{
+	int retval;
+
+	retval = fasync_helper(fd, filp, on, &queue->fasync);
+	if (retval < 0)
+		return retval;
+	return 0;
+}
+
+
+/*
+ * Random magic cookie for the aux device
+ */
+#define AUX_DEV ((void *)queue)
+
+static int release_aux(struct inode * inode, struct file * file)
+{
+	fasync_aux(-1, file, 0);
+	if (--aux_count)
+		return 0;
+	free_irq(IRQ_MOUSERX, AUX_DEV);
+	return 0;
+}
+
+/*
+ * Install interrupt handler.
+ * Enable auxiliary device.
+ */
+
+static int open_aux(struct inode * inode, struct file * file)
+{
+	if (aux_count++)
+		return 0;
+
+	queue->head = queue->tail = 0;		/* Flush input queue */
+	if (request_irq(IRQ_MOUSERX, psaux_interrupt, SA_SHIRQ, "ps/2 mouse", 
+			AUX_DEV)) {
+		aux_count--;
+		return -EBUSY;
+	}
+
+	aux_write_ack(AUX_ENABLE_DEV); /* Enable aux device */
+
+	return 0;
+}
+
+/*
+ * Put bytes from input queue to buffer.
+ */
+
+static ssize_t read_aux(struct file * file, char * buffer,
+			size_t count, loff_t *ppos)
+{
+	DECLARE_WAITQUEUE(wait, current);
+	ssize_t i = count;
+	unsigned char c;
+
+	if (queue_empty()) {
+		if (file->f_flags & O_NONBLOCK)
+			return -EAGAIN;
+		add_wait_queue(&queue->proc_list, &wait);
+repeat:
+		current->state = TASK_INTERRUPTIBLE;
+		if (queue_empty() && !signal_pending(current)) {
+			schedule();
+			goto repeat;
+		}
+		current->state = TASK_RUNNING;
+		remove_wait_queue(&queue->proc_list, &wait);
+	}
+	while (i > 0 && !queue_empty()) {
+		c = get_from_queue();
+		put_user(c, buffer++);
+		i--;
+	}
+	if (count-i) {
+		file->f_dentry->d_inode->i_atime = CURRENT_TIME;
+		return count-i;
+	}
+	if (signal_pending(current))
+		return -ERESTARTSYS;
+	return 0;
+}
+
+/*
+ * Write to the aux device.
+ */
+
+static ssize_t write_aux(struct file * file, const char * buffer,
+			 size_t count, loff_t *ppos)
+{
+	ssize_t retval = 0;
+
+	if (count) {
+		ssize_t written = 0;
+
+		if (count > 32)
+			count = 32; /* Limit to 32 bytes. */
+		do {
+			char c;
+			get_user(c, buffer++);
+			aux_write_dev(c);
+			written++;
+		} while (--count);
+		retval = -EIO;
+		if (written) {
+			retval = written;
+			file->f_dentry->d_inode->i_mtime = CURRENT_TIME;
+		}
+	}
+
+	return retval;
+}
+
+static unsigned int aux_poll(struct file *file, poll_table * wait)
+{
+	poll_wait(file, &queue->proc_list, wait);
+	if (!queue_empty())
+		return POLLIN | POLLRDNORM;
+	return 0;
+}
+
+struct file_operations psaux_fops = {
+	read:		read_aux,
+	write:		write_aux,
+	poll:		aux_poll,
+	open:		open_aux,
+	release:	release_aux,
+	fasync:		fasync_aux,
+};
+
+/*
+ * Initialize driver.
+ */
+static struct miscdevice psaux_mouse = {
+	PSMOUSE_MINOR, "psaux", &psaux_fops
+};
+
+int __init psaux_init(void)
+{
+	/* Reset the mouse state machine. */
+	iomd_writeb(0, IOMD_MSECTL);
+	iomd_writeb(8, IOMD_MSECTL);
+  
+	misc_register(&psaux_mouse);
+	queue = (struct aux_queue *) kmalloc(sizeof(*queue), GFP_KERNEL);
+	memset(queue, 0, sizeof(*queue));
+	queue->head = queue->tail = 0;
+	init_waitqueue_head(&queue->proc_list);
+
+	aux_write_ack(AUX_SET_SAMPLE);
+	aux_write_ack(100);			/* 100 samples/sec */
+	aux_write_ack(AUX_SET_RES);
+	aux_write_ack(3);			/* 8 counts per mm */
+	aux_write_ack(AUX_SET_SCALE21);		/* 2:1 scaling */
+
+	return 0;
+}
diff -urN linux-2.4.6-pre5/drivers/acorn/char/mouse_rpc.c linux/drivers/acorn/char/mouse_rpc.c
--- linux-2.4.6-pre5/drivers/acorn/char/mouse_rpc.c	Mon Sep 18 15:15:21 2000
+++ linux/drivers/acorn/char/mouse_rpc.c	Mon Dec  3 22:49:10 2001
@@ -34,9 +34,9 @@
 	short x, y, dx, dy;
 	int buttons;
 
-	x = (short)inl(IOMD_MOUSEX);
-	y = (short)inl(IOMD_MOUSEY);
-	buttons = (inl (0x800C4000) >> 4) & 7;
+	x = (short)iomd_readl(IOMD_MOUSEX);
+	y = (short)iomd_readl(IOMD_MOUSEY);
+	buttons = (__raw_readl(0xe0310000) >> 4) & 7;
 
 	dx = x - old_x;
 	old_x = x;
@@ -60,9 +60,9 @@
 	if (mousedev < 0)
 		printk("rpcmouse: could not register mouse driver\n");
 	else {
-		old_x = (short)inl(IOMD_MOUSEX);
-		old_y = (short)inl(IOMD_MOUSEY);
-		old_b = (inl (0x800C4000) >> 4) & 7;
+		old_x = (short)iomd_readl(IOMD_MOUSEX);
+		old_y = (short)iomd_readl(IOMD_MOUSEY);
+		old_b = (__raw_readl(0xe0310000) >> 4) & 7;
 		if (request_irq(IRQ_VSYNCPULSE, mouse_rpc_irq, SA_SHIRQ, "mouse", &mousedev)) {
 			printk("rpcmouse: unable to allocate VSYNC interrupt\n");
 			unregister_busmouse(mousedev);
diff -urN linux-2.4.6-pre5/drivers/acorn/net/ether1.c linux/drivers/acorn/net/ether1.c
--- linux-2.4.6-pre5/drivers/acorn/net/ether1.c	Fri Feb  9 11:30:22 2001
+++ linux/drivers/acorn/net/ether1.c	Mon Dec  3 22:49:10 2001
@@ -75,7 +75,7 @@
 
 /* ------------------------------------------------------------------------- */
 
-static const char version[] __initdata = KERN_INFO "ether1 ethernet driver (c) 2000 Russell King v1.07\n";
+static char version[] __initdata = "ether1 ethernet driver (c) 2000 Russell King v1.07\n";
 
 #define BUS_16 16
 #define BUS_8  8
@@ -990,7 +990,7 @@
 	static unsigned int version_printed = 0;
 
 	if (net_debug && version_printed++ == 0)
-		printk (version);
+		printk(KERN_INFO "%s", version);
 }
 
 static struct net_device * __init ether1_init_one(struct expansion_card *ec)
@@ -1045,7 +1045,6 @@
 release:
 	release_region(dev->base_addr, 16);
 	release_region(dev->base_addr + 0x800, 4096);
-free:
 	unregister_netdev(dev);
 	kfree(dev);
 out:
diff -urN linux-2.4.6-pre5/drivers/acorn/net/ether3.c linux/drivers/acorn/net/ether3.c
--- linux-2.4.6-pre5/drivers/acorn/net/ether3.c	Fri Feb  9 11:30:22 2001
+++ linux/drivers/acorn/net/ether3.c	Mon Dec  3 22:49:10 2001
@@ -70,7 +70,7 @@
 #include <asm/io.h>
 #include <asm/irq.h>
 
-static const char version[] __initdata = "ether3 ethernet driver (c) 1995-2000 R.M.King v1.17\n";
+static char version[] __initdata = "ether3 ethernet driver (c) 1995-2000 R.M.King v1.17\n";
 
 #include "ether3.h"
 
@@ -777,7 +777,7 @@
 	static unsigned version_printed = 0;
 
 	if (net_debug && version_printed++ == 0)
-		printk(version);
+		printk(KERN_INFO "%s", version);
 }
 
 static const char * __init
diff -urN linux-2.4.6-pre5/drivers/acorn/scsi/acornscsi.c linux/drivers/acorn/scsi/acornscsi.c
--- linux-2.4.6-pre5/drivers/acorn/scsi/acornscsi.c	Fri Mar  2 18:38:37 2001
+++ linux/drivers/acorn/scsi/acornscsi.c	Mon Dec  3 22:49:10 2001
@@ -144,6 +144,7 @@
 #include <linux/ioport.h>
 #include <linux/blk.h>
 #include <linux/delay.h>
+#include <linux/init.h>
 
 #include <asm/bitops.h>
 #include <asm/system.h>
@@ -157,6 +158,8 @@
 #include "acornscsi.h"
 #include "msgqueue.h"
 
+#include <scsi/scsicam.h>
+
 #define VER_MAJOR 2
 #define VER_MINOR 0
 #define VER_PATCH 6
@@ -206,24 +209,24 @@
 static inline void
 sbic_arm_write(unsigned int io_port, int reg, int value)
 {
-    outb_t(reg, io_port);
-    outb_t(value, io_port + 4);
+    __raw_writeb(reg, io_port);
+    __raw_writeb(value, io_port + 4);
 }
 
 #define sbic_arm_writenext(io,val) \
-	outb_t((val), (io) + 4)
+	__raw_writeb((val), (io) + 4)
 
 static inline
 int sbic_arm_read(unsigned int io_port, int reg)
 {
     if(reg == ASR)
-	   return inl_t(io_port) & 255;
-    outb_t(reg, io_port);
-    return inl_t(io_port + 4) & 255;
+	   return __raw_readl(io_port) & 255;
+    __raw_writeb(reg, io_port);
+    return __raw_readl(io_port + 4) & 255;
 }
 
 #define sbic_arm_readnext(io) \
-	inb_t((io) + 4)
+	__raw_readb((io) + 4)
 
 #ifdef USE_DMAC
 #define dmac_read(io_port,reg) \
@@ -2858,7 +2861,7 @@
  * Params   : host - host to setup
  */
 static
-void acornscsi_init(AS_Host *host)
+void acornscsi_host_init(AS_Host *host)
 {
     memset(&host->stats, 0, sizeof (host->stats));
     queue_initialise(&host->queues.issue);
@@ -2926,7 +2929,7 @@
 	    host->scsi.irq = NO_IRQ;
 	}
 
-	acornscsi_init(host);
+	acornscsi_host_init(host);
 
 	++count;
     }
@@ -3118,9 +3121,40 @@
     return pos;
 }
 
-#ifdef MODULE
+static Scsi_Host_Template acornscsi_template = {
+	module:			THIS_MODULE,
+	proc_info:		acornscsi_proc_info,
+	name:			"AcornSCSI",
+	detect:			acornscsi_detect,
+	release:		acornscsi_release,
+	info:			acornscsi_info,
+	queuecommand:		acornscsi_queuecmd,
+	abort:			acornscsi_abort,
+	reset:			acornscsi_reset,
+	bios_param:		scsicam_bios_param,
+	can_queue:		16,
+	this_id:		7,
+	sg_tablesize:		SG_ALL,
+	cmd_per_lun:		2,
+	unchecked_isa_dma:	0,
+	use_clustering:		DISABLE_CLUSTERING
+};
 
-Scsi_Host_Template driver_template = ACORNSCSI_3;
+static int __init acornscsi_init(void)
+{
+	acornscsi_template.module = THIS_MODULE;
+	scsi_register_module(MODULE_SCSI_HA, &acornscsi_template);
+	if (acornscsi_template.present)
+		return 0;
 
-#include "../../scsi/scsi_module.c"
-#endif
+	scsi_unregister_module(MODULE_SCSI_HA, &acornscsi_template);
+	return -ENODEV;
+}
+
+static void __exit acornscsi_exit(void)
+{
+	scsi_unregister_module(MODULE_SCSI_HA, &acornscsi_template);
+}
+
+module_init(acornscsi_init);
+module_exit(acornscsi_exit);
diff -urN linux-2.4.6-pre5/drivers/acorn/scsi/acornscsi.h linux/drivers/acorn/scsi/acornscsi.h
--- linux-2.4.6-pre5/drivers/acorn/scsi/acornscsi.h	Mon Sep 18 15:15:22 2000
+++ linux/drivers/acorn/scsi/acornscsi.h	Mon Dec  3 22:49:10 2001
@@ -12,52 +12,6 @@
 #ifndef ACORNSCSI_H
 #define ACORNSCSI_H
 
-#ifndef ASM
-extern int acornscsi_detect (Scsi_Host_Template *);
-extern int acornscsi_release (struct Scsi_Host *);
-extern const char *acornscsi_info (struct Scsi_Host *);
-extern int acornscsi_queuecmd (Scsi_Cmnd *, void (*done)(Scsi_Cmnd *));
-extern int acornscsi_abort (Scsi_Cmnd *);
-extern int acornscsi_reset (Scsi_Cmnd *, unsigned int);
-extern int acornscsi_proc_info (char *, char **, off_t, int, int, int);
-extern int acornscsi_biosparam (Disk *, kdev_t, int []);
-
-#ifndef NULL
-#define NULL 0
-#endif
-
-#ifndef CMD_PER_LUN
-#define CMD_PER_LUN 2
-#endif
-
-#ifndef CAN_QUEUE
-#define CAN_QUEUE 16
-#endif
-
-#include "linux/proc_fs.h"
-
-#include <scsi/scsicam.h>
-
-#define ACORNSCSI_3 {							\
-proc_info:		acornscsi_proc_info,				\
-name:			"AcornSCSI",					\
-detect:			acornscsi_detect,				\
-release:		acornscsi_release,	/* Release */		\
-info:			acornscsi_info,					\
-queuecommand:		acornscsi_queuecmd,				\
-abort:			acornscsi_abort,				\
-reset:			acornscsi_reset,				\
-bios_param:		scsicam_bios_param,				\
-can_queue:		CAN_QUEUE,		/* can_queue */		\
-this_id:		7,			/* this id */		\
-sg_tablesize:		SG_ALL,			/* sg_tablesize */	\
-cmd_per_lun:		CMD_PER_LUN,		/* cmd_per_lun */	\
-unchecked_isa_dma:	0,			/* unchecked isa dma */	\
-use_clustering:		DISABLE_CLUSTERING				\
-	}
-
-#ifndef HOSTS_C
-
 /* SBIC registers */
 #define OWNID			0
 #define OWNID_FS1		(1<<7)
@@ -405,7 +359,4 @@
     struct status_entry status[9][STATUS_BUFFER_SIZE];
 } AS_Host;
 
-#endif /* ndef HOSTS_C */
-
-#endif /* ndef ASM */
 #endif /* ACORNSCSI_H */
diff -urN linux-2.4.6-pre5/drivers/acpi/os.c linux/drivers/acpi/os.c
--- linux-2.4.6-pre5/drivers/acpi/os.c	Mon Dec  3 22:49:01 2001
+++ linux/drivers/acpi/os.c	Mon Dec  3 22:49:11 2001
@@ -293,19 +293,19 @@
 void
 acpi_os_mem_out8 (ACPI_PHYSICAL_ADDRESS phys_addr, UINT8 value)
 {
-	*(u8*) (u32) phys_addr = value;
+	*(u8*) phys_to_virt(phys_addr) = value;
 }
 
 void
 acpi_os_mem_out16 (ACPI_PHYSICAL_ADDRESS phys_addr, UINT16 value)
 {
-	*(u16*) (u32) phys_addr = value;
+	*(u16*) phys_to_virt(phys_addr) = value;
 }
 
 void
 acpi_os_mem_out32 (ACPI_PHYSICAL_ADDRESS phys_addr, UINT32 value)
 {
-	*(u32*) (u32) phys_addr = value;
+	*(u32*) phys_to_virt(phys_addr) = value;
 }
 
 ACPI_STATUS
diff -urN linux-2.4.6-pre5/drivers/atm/ambassador.c linux/drivers/atm/ambassador.c
--- linux-2.4.6-pre5/drivers/atm/ambassador.c	Fri Dec 29 14:35:47 2000
+++ linux/drivers/atm/ambassador.c	Mon Dec  3 22:49:11 2001
@@ -613,19 +613,21 @@
     while (timeout) {
       // go to sleep
       // PRINTD (DBG_CMD, "wait: sleeping %lu for command", timeout);
+      set_current_state(TASK_UNINTERRUPTIBLE);
       timeout = schedule_timeout (timeout);
-      // woken up by timeout or signal
     }
     
     // wait for my slot to be reached (all waiters are here or above, until...)
     while (ptrs->out != my_slot) {
       PRINTD (DBG_CMD, "wait: command slot (now at %p)", ptrs->out);
+      set_current_state(TASK_UNINTERRUPTIBLE);
       schedule();
     }
     
     // wait on my slot (... one gets to its slot, and... )
     while (ptrs->out->request != cpu_to_be32 (SRB_COMPLETE)) {
       PRINTD (DBG_CMD, "wait: command slot completion");
+      set_current_state(TASK_UNINTERRUPTIBLE);
       schedule();
     }
     
@@ -1986,6 +1988,7 @@
   
   while (!lb->result || lb->result == cpu_to_be32 (COMMAND_IN_PROGRESS))
     if (timeout) {
+      set_current_state(TASK_UNINTERRUPTIBLE);
       timeout = schedule_timeout (timeout);
     } else {
       PRINTD (DBG_LOAD|DBG_ERR, "command %d timed out", cmd);
@@ -2110,12 +2113,15 @@
     unsigned long timeout;
     // 4.2 second wait
     timeout = HZ*42/10;
-    while (timeout)
+    while (timeout) {
+      set_current_state(TASK_UNINTERRUPTIBLE);
       timeout = schedule_timeout (timeout);
+    }
     // half second time-out
     timeout = HZ/2;
     while (!rd_plain (dev, offsetof(amb_mem, mb.loader.ready)))
       if (timeout) {
+        set_current_state(TASK_UNINTERRUPTIBLE);
 	timeout = schedule_timeout (timeout);
       } else {
 	PRINTD (DBG_LOAD|DBG_ERR, "reset timed out");
@@ -2255,8 +2261,10 @@
   u32 minor;
   command cmd;
   cmd.request = cpu_to_be32 (SRB_GET_VERSION);
-  while (command_do (dev, &cmd))
+  while (command_do (dev, &cmd)) {
+    set_current_state(TASK_UNINTERRUPTIBLE);
     schedule();
+  }
   major = be32_to_cpu (cmd.args.version.major);
   minor = be32_to_cpu (cmd.args.version.minor);
   PRINTK (KERN_INFO, "microcode version is %u.%u", major, minor);
@@ -2280,8 +2288,10 @@
   }
   
   cmd.request = cpu_to_be32 (SRB_GET_BIA);
-  while (command_do (dev, &cmd))
+  while (command_do (dev, &cmd)) {
+    set_current_state(TASK_UNINTERRUPTIBLE);
     schedule();
+  }
   lower4 = be32_to_cpu (cmd.args.bia.lower4);
   upper2 = be32_to_cpu (cmd.args.bia.upper2);
   PRINTD (DBG_LOAD, "BIA: lower4: %08x, upper2 %04x", lower4, upper2);
@@ -2362,7 +2372,7 @@
   struct pci_dev * pci_dev;
   int devs;
   
-  void do_pci_device (void) {
+  void __init do_pci_device (void) {
     amb_dev * dev;
     
     // read resources from PCI configuration space
diff -urN linux-2.4.6-pre5/drivers/atm/fore200e.c linux/drivers/atm/fore200e.c
--- linux-2.4.6-pre5/drivers/atm/fore200e.c	Mon Dec  3 22:49:01 2001
+++ linux/drivers/atm/fore200e.c	Mon Dec  3 22:49:11 2001
@@ -2024,8 +2024,10 @@
     if (!prom)
 	return -ENOMEM;
     ok = fore200e->bus->prom_read(fore200e, prom);
-    if (ok < 0)
+    if (ok < 0) {
+	fore200e_kfree(prom);
 	return -EBUSY;
+    }
 	
     printk(FORE200E "device %s, rev. %c, S/N: %d, ESI: %02x:%02x:%02x:%02x:%02x:%02x\n", 
 	   fore200e->name, 
diff -urN linux-2.4.6-pre5/drivers/atm/idt77105.c linux/drivers/atm/idt77105.c
--- linux-2.4.6-pre5/drivers/atm/idt77105.c	Thu Jul  6 21:37:24 2000
+++ linux/drivers/atm/idt77105.c	Mon Dec  3 22:49:11 2001
@@ -144,18 +144,18 @@
 static int fetch_stats(struct atm_dev *dev,struct idt77105_stats *arg,int zero)
 {
 	unsigned long flags;
-	int error;
+	struct idt77105_stats stats;
 
-	error = 0;
 	save_flags(flags);
 	cli();
-	if (arg)
-		error = copy_to_user(arg,&PRIV(dev)->stats,
-		    sizeof(struct idt77105_stats));
-	if (zero && !error)
-		memset(&PRIV(dev)->stats,0,sizeof(struct idt77105_stats));
+	memcpy(&stats, &PRIV(dev)->stats, sizeof(struct idt77105_stats));
+	if (zero)
+		memset(&PRIV(dev)->stats, 0, sizeof(struct idt77105_stats));
 	restore_flags(flags);
-	return error ? -EFAULT : sizeof(struct idt77105_stats);
+	if (arg == NULL)
+		return 0;
+	return copy_to_user(arg, &PRIV(dev)->stats,
+		    sizeof(struct idt77105_stats)) ? -EFAULT : 0;
 }
 
 
diff -urN linux-2.4.6-pre5/drivers/atm/iphase.c linux/drivers/atm/iphase.c
--- linux-2.4.6-pre5/drivers/atm/iphase.c	Sun Feb  4 10:05:29 2001
+++ linux/drivers/atm/iphase.c	Mon Dec  3 22:49:11 2001
@@ -97,6 +97,10 @@
 MODULE_PARM(IADebugFlag, "i");
 #endif
 
+#if BITS_PER_LONG != 32
+#  error FIXME: this driver only works on 32-bit platforms
+#endif
+
 /**************************** IA_LIB **********************************/
 
 static void ia_init_rtn_q (IARTN_Q *que) 
diff -urN linux-2.4.6-pre5/drivers/atm/nicstar.c linux/drivers/atm/nicstar.c
--- linux-2.4.6-pre5/drivers/atm/nicstar.c	Sun Mar 25 18:24:31 2001
+++ linux/drivers/atm/nicstar.c	Mon Dec  3 22:49:11 2001
@@ -62,6 +62,9 @@
 #include "idt77105.h"
 #endif /* CONFIG_ATM_NICSTAR_USE_IDT77105 */
 
+#if BITS_PER_LONG != 32
+#  error FIXME: this driver requires a 32-bit platform
+#endif
 
 /* Additional code ************************************************************/
 
diff -urN linux-2.4.6-pre5/drivers/atm/uPD98402.c linux/drivers/atm/uPD98402.c
--- linux-2.4.6-pre5/drivers/atm/uPD98402.c	Fri Apr 14 09:37:10 2000
+++ linux/drivers/atm/uPD98402.c	Mon Dec  3 22:49:11 2001
@@ -86,16 +86,17 @@
 static int get_sense(struct atm_dev *dev,u8 *arg)
 {
 	unsigned long flags;
- 	int error;
+	unsigned char s[3];
 
 	save_flags(flags);
 	cli();
-	error = put_user(GET(C11R),arg) || put_user(GET(C12R),arg+1) ||
-	    put_user(GET(C13R),arg+2);
+	s[0] = GET(C11R);
+	s[1] = GET(C12R);
+	s[2] = GET(C13R);
 	restore_flags(flags);
-	error = error || put_user(0xff,arg+3) || put_user(0xff,arg+4) ||
-	    put_user(0xff,arg+5);
-	return error ? -EFAULT : 0;
+	return (put_user(s[0], arg) || put_user(s[1], arg+1) ||
+	    put_user(s[2], arg+2) || put_user(0xff, arg+3) ||
+	    put_user(0xff, arg+4) || put_user(0xff, arg+5)) ? -EFAULT : 0;
 }
 
 
diff -urN linux-2.4.6-pre5/drivers/atm/zatm.c linux/drivers/atm/zatm.c
--- linux-2.4.6-pre5/drivers/atm/zatm.c	Wed Apr 11 19:02:30 2001
+++ linux/drivers/atm/zatm.c	Mon Dec  3 22:49:11 2001
@@ -255,9 +255,7 @@
 
 static void drain_free(struct atm_dev *dev,int pool)
 {
-	struct sk_buff *skb;
-
-	while ((skb = skb_dequeue(&ZATM_DEV(dev)->pool[pool]))) kfree_skb(skb);
+	skb_queue_purge(&ZATM_DEV(dev)->pool[pool]);
 }
 
 
@@ -1464,6 +1462,9 @@
 
 	DPRINTK("zatm_start\n");
 	zatm_dev = ZATM_DEV(dev);
+	zatm_dev->rx_map = zatm_dev->tx_map = NULL;
+	for (i = 0; i < NR_MBX; i++)
+		zatm_dev->mbx_start[i] = 0;
 	if (request_irq(zatm_dev->irq,&zatm_int,SA_SHIRQ,DEV_LABEL,dev)) {
 		printk(KERN_ERR DEV_LABEL "(itf %d): IRQ%d is already in use\n",
 		    dev->number,zatm_dev->irq);
@@ -1496,25 +1497,27 @@
 	    "%ld VCs\n",dev->number,NR_SHAPERS,pools,rx,
 	    (zatm_dev->mem-curr*4)/VC_SIZE);
 	/* create mailboxes */
-	for (i = 0; i < NR_MBX; i++) zatm_dev->mbx_start[i] = 0;
 	for (i = 0; i < NR_MBX; i++)
 		if (mbx_entries[i]) {
 			unsigned long here;
 
 			here = (unsigned long) kmalloc(2*MBX_SIZE(i),
 			    GFP_KERNEL);
-			if (!here) return -ENOMEM;
+			if (!here) {
+				error = -ENOMEM;
+				goto out;
+			}
 			if ((here^(here+MBX_SIZE(i))) & ~0xffffUL)/* paranoia */
 				here = (here & ~0xffffUL)+0x10000;
+			zatm_dev->mbx_start[i] = here;
 			if ((here^virt_to_bus((void *) here)) & 0xffff) {
 				printk(KERN_ERR DEV_LABEL "(itf %d): system "
 				    "bus incompatible with driver\n",
 				    dev->number);
-				kfree((void *) here);
-				return -ENODEV;
+				error = -ENODEV;
+				goto out;
 			}
 			DPRINTK("mbx@0x%08lx-0x%08lx\n",here,here+MBX_SIZE(i));
-			zatm_dev->mbx_start[i] = here;
 			zatm_dev->mbx_end[i] = (here+MBX_SIZE(i)) & 0xffff;
 			zout(virt_to_bus((void *) here) >> 16,MSH(i));
 			zout(virt_to_bus((void *) here),MSL(i));
@@ -1523,15 +1526,25 @@
 			zout(here & 0xffff,MWA(i));
 		}
 	error = start_tx(dev);
-	if (error) return error;
+	if (error) goto out;
 	error = start_rx(dev);
-	if (error) return error;
+	if (error) goto out;
 	error = dev->phy->start(dev);
-	if (error) return error;
+	if (error) goto out;
 	zout(0xffffffff,IMR); /* enable interrupts */
 	/* enable TX & RX */
 	zout(zin(GMR) | uPD98401_GMR_SE | uPD98401_GMR_RE,GMR);
 	return 0;
+    out:
+	for (i = 0; i < NR_MBX; i++)
+		if (zatm_dev->mbx_start[i] != 0)
+			kfree((void *) zatm_dev->mbx_start[i]);
+	if (zatm_dev->rx_map != NULL)
+		kfree(zatm_dev->rx_map);
+	if (zatm_dev->tx_map != NULL)
+		kfree(zatm_dev->tx_map);
+	free_irq(zatm_dev->irq, dev);
+	return error;
 }
 
 
@@ -1681,22 +1694,16 @@
 		case ZATM_GETTHIST:
 			{
 				int i;
-
+				struct zatm_t_hist hs[ZATM_TIMER_HISTORY_SIZE];
 				save_flags(flags);
 				cli();
-				for (i = 0; i < ZATM_TIMER_HISTORY_SIZE; i++) {
-					if (!copy_to_user(
-					    (struct zatm_t_hist *) arg+i,
-					    &zatm_dev->timer_history[
+				for (i = 0; i < ZATM_TIMER_HISTORY_SIZE; i++)
+					hs[i] = zatm_dev->timer_history[
 					    (zatm_dev->th_curr+i) &
-					    (ZATM_TIMER_HISTORY_SIZE-1)],
-					    sizeof(struct zatm_t_hist)))
-						 continue;
-					restore_flags(flags);
-					return -EFAULT;
-				}
+					    (ZATM_TIMER_HISTORY_SIZE-1)];
 				restore_flags(flags);
-				return 0;
+				return copy_to_user((struct zatm_t_hist *) arg,
+				    hs, sizeof(hs)) ? -EFAULT : 0;
 			}
 #endif
 		default:
@@ -1828,11 +1835,11 @@
 			    zatm_dev),GFP_KERNEL);
 			if (!zatm_dev) {
 				printk(KERN_EMERG "zatm.c: memory shortage\n");
-				goto out;
+				return devs;
 			}
 		}
 	}
-out:
+	kfree(zatm_dev);
 	return devs;
 }
 
diff -urN linux-2.4.6-pre5/drivers/block/cciss.c linux/drivers/block/cciss.c
--- linux-2.4.6-pre5/drivers/block/cciss.c	Tue May 22 10:23:16 2001
+++ linux/drivers/block/cciss.c	Mon Dec  3 22:49:11 2001
@@ -610,7 +610,10 @@
 		{
 			/* Copy the data into the buffer we created */ 
 			if (copy_from_user(buff, iocommand.buf, iocommand.buf_size))
+			{
+				kfree(buff);
 				return -EFAULT;
+			}
 		}
 		if ((c = cmd_alloc(h , 0)) == NULL)
 		{
@@ -680,6 +683,7 @@
 			{
                         	kfree(buff);
 				cmd_free(h, c, 0);
+				return -EFAULT;
 			}
                 }
                 kfree(buff);
diff -urN linux-2.4.6-pre5/drivers/block/paride/pt.c linux/drivers/block/paride/pt.c
--- linux-2.4.6-pre5/drivers/block/paride/pt.c	Fri Feb  9 11:30:22 2001
+++ linux/drivers/block/paride/pt.c	Mon Dec  3 22:49:11 2001
@@ -753,6 +753,10 @@
 			pt_rewind(unit);
 			return 0;
 
+		    case MTWEOF:
+			pt_write_fm(unit);
+			return 0;
+
 		    default:	
 			printk("%s: Unimplemented mt_op %d\n",PT.name,
 					mtop.mt_op);
diff -urN linux-2.4.6-pre5/drivers/block/ps2esdi.c linux/drivers/block/ps2esdi.c
--- linux-2.4.6-pre5/drivers/block/ps2esdi.c	Thu May 24 15:14:08 2001
+++ linux/drivers/block/ps2esdi.c	Mon Dec  3 22:49:11 2001
@@ -420,6 +420,7 @@
 	request_dma(dma_arb_level, "ed");
 	request_region(io_base, 4, "ed");
 	blksize_size[MAJOR_NR] = ps2esdi_blocksizes;
+	max_sectors[MAJOR_NR] = ps2esdi_maxsect;
 
 	for (i = 0; i < ps2esdi_drives; i++) {
 		register_disk(&ps2esdi_gendisk,MKDEV(MAJOR_NR,i<<6),1<<6,
diff -urN linux-2.4.6-pre5/drivers/block/swim3.c linux/drivers/block/swim3.c
--- linux-2.4.6-pre5/drivers/block/swim3.c	Tue May 22 10:23:16 2001
+++ linux/drivers/block/swim3.c	Mon Dec  3 22:49:11 2001
@@ -33,6 +33,7 @@
 
 #define MAJOR_NR	FLOPPY_MAJOR
 #include <linux/blk.h>
+#include <linux/devfs_fs_kernel.h>
 
 static int floppy_blocksizes[2] = {512,512};
 static int floppy_sizes[2] = {2880,2880};
@@ -248,10 +249,7 @@
 int swim3_init(void);
 
 #ifndef CONFIG_PMAC_PBOOK
-static inline int check_media_bay(struct device_node *which_bay, int what)
-{
-	return 1;
-}
+#define check_media_bay(which, what)	1
 #endif
 
 static void swim3_select(struct floppy_state *fs, int sel)
@@ -1014,10 +1012,14 @@
 	revalidate:		floppy_revalidate,
 };
 
+static devfs_handle_t floppy_devfs_handle;
+
 int swim3_init(void)
 {
 	struct device_node *swim;
 
+	floppy_devfs_handle = devfs_mk_dir(NULL, "floppy", NULL);
+
 	swim = find_devices("floppy");
 	while (swim && (floppy_count < MAX_FLOPPIES))
 	{
@@ -1034,7 +1036,7 @@
 
 	if (floppy_count > 0)
 	{
-		if (register_blkdev(MAJOR_NR, "fd", &floppy_fops)) {
+		if (devfs_register_blkdev(MAJOR_NR, "fd", &floppy_fops)) {
 			printk(KERN_ERR "Unable to get major %d for floppy\n",
 			       MAJOR_NR);
 			return -EBUSY;
@@ -1051,7 +1053,9 @@
 {
 	struct device_node *mediabay;
 	struct floppy_state *fs = &floppy_states[floppy_count];
-	
+	char floppy_name[16];
+	devfs_handle_t floppy_handle;
+
 	if (swim->n_addrs < 2)
 	{
 		printk(KERN_INFO "swim3: expecting 2 addrs (n_addrs:%d, n_intrs:%d)\n",
@@ -1108,6 +1112,12 @@
 
 	printk(KERN_INFO "fd%d: SWIM3 floppy controller %s\n", floppy_count,
 		mediabay ? "in media bay" : "");
+	sprintf(floppy_name, "%s%d", floppy_devfs_handle ? "" : "floppy",
+			floppy_count);
+	floppy_handle = devfs_register(floppy_devfs_handle, floppy_name, 
+			DEVFS_FL_DEFAULT, MAJOR_NR, floppy_count, 
+			S_IFBLK | S_IRUSR | S_IWUSR | S_IRGRP |S_IWGRP, 
+			&floppy_fops, NULL);
 
 	floppy_count++;
 	
diff -urN linux-2.4.6-pre5/drivers/cdrom/mcdx.c linux/drivers/cdrom/mcdx.c
--- linux-2.4.6-pre5/drivers/cdrom/mcdx.c	Fri Feb  9 11:30:22 2001
+++ linux/drivers/cdrom/mcdx.c	Mon Dec  3 22:49:11 2001
@@ -80,6 +80,10 @@
 #define	mcdx_drive_map mcdx
 #include "mcdx.h"
 
+#if BITS_PER_LONG != 32
+#  error FIXME: this driver only works on 32-bit platforms
+#endif
+
 #ifndef HZ
 #error HZ not defined
 #endif
diff -urN linux-2.4.6-pre5/drivers/char/agp/agpgart_fe.c linux/drivers/char/agp/agpgart_fe.c
--- linux-2.4.6-pre5/drivers/char/agp/agpgart_fe.c	Tue May 15 01:29:34 2001
+++ linux/drivers/char/agp/agpgart_fe.c	Mon Dec  3 22:49:11 2001
@@ -875,6 +875,9 @@
 	} else {
 		agp_segment *segment;
 
+		if (reserve.seg_count >= 16384)
+			return -EINVAL;
+			
 		segment = kmalloc((sizeof(agp_segment) * reserve.seg_count),
 				  GFP_KERNEL);
 
diff -urN linux-2.4.6-pre5/drivers/char/cyclades.c linux/drivers/char/cyclades.c
--- linux-2.4.6-pre5/drivers/char/cyclades.c	Fri Apr  6 10:42:55 2001
+++ linux/drivers/char/cyclades.c	Mon Dec  3 22:49:11 2001
@@ -743,7 +743,7 @@
 #define NR_ISA_ADDRS (sizeof(cy_isa_addresses)/sizeof(unsigned char*))
 
 #ifdef MODULE
-static int maddr[NR_CARDS] = { 0, };
+static long maddr[NR_CARDS] = { 0, };
 static int irq[NR_CARDS]  = { 0, };
 
 MODULE_PARM(maddr, "1-" __MODULE_STRING(NR_CARDS) "l");
@@ -2983,10 +2983,11 @@
         return 0;
     }
 
-    CY_LOCK(info, flags);
     if (from_user) {
 	down(&tmp_buf_sem);
 	while (1) {
+	    int c1;
+	    
 	    c = MIN(count, MIN(SERIAL_XMIT_SIZE - info->xmit_cnt - 1,
 				SERIAL_XMIT_SIZE - info->xmit_head));
 	    if (c <= 0)
@@ -2999,23 +3000,30 @@
 		}
 		break;
 	    }
-	    c = MIN(c, MIN(SERIAL_XMIT_SIZE - info->xmit_cnt - 1,
+	    CY_LOCK(info, flags);
+	    c1 = MIN(c, MIN(SERIAL_XMIT_SIZE - info->xmit_cnt - 1,
 			SERIAL_XMIT_SIZE - info->xmit_head));
+			
+	    if (c1 < c)
+	    	c = c1;
 	    memcpy(info->xmit_buf + info->xmit_head, tmp_buf, c);
 	    info->xmit_head = ((info->xmit_head + c) & (SERIAL_XMIT_SIZE-1));
 	    info->xmit_cnt += c;
+            CY_UNLOCK(info, flags);
 	    buf += c;
 	    count -= c;
 	    ret += c;
 	}
 	up(&tmp_buf_sem);
     } else {
+	CY_LOCK(info, flags);
 	while (1) {
 	    c = MIN(count, MIN(SERIAL_XMIT_SIZE - info->xmit_cnt - 1, 
 			SERIAL_XMIT_SIZE - info->xmit_head));
-	    if (c <= 0) {
+	        
+	    if (c <= 0)
 		break;
-	    }
+
 	    memcpy(info->xmit_buf + info->xmit_head, buf, c);
 	    info->xmit_head = (info->xmit_head + c) & (SERIAL_XMIT_SIZE-1);
 	    info->xmit_cnt += c;
@@ -3023,8 +3031,8 @@
 	    count -= c;
 	    ret += c;
 	}
+        CY_UNLOCK(info, flags);
     }
-    CY_UNLOCK(info, flags);
 
     info->idle_stats.xmit_bytes += ret;
     info->idle_stats.xmit_idle   = jiffies;
diff -urN linux-2.4.6-pre5/drivers/char/drm/context.c linux/drivers/char/drm/context.c
--- linux-2.4.6-pre5/drivers/char/drm/context.c	Tue Aug 29 14:09:15 2000
+++ linux/drivers/char/drm/context.c	Mon Dec  3 22:49:11 2001
@@ -91,10 +91,13 @@
 		atomic_dec(&dev->queuelist[i]->use_count);
 	}
 				/* Allocate a new queue */
-	down(&dev->struct_sem);
 	
 	queue = drm_alloc(sizeof(*queue), DRM_MEM_QUEUES);
+	if(queue == NULL)
+		return -ENOMEM;	
+
 	memset(queue, 0, sizeof(*queue));
+	down(&dev->struct_sem);
 	atomic_set(&queue->use_count, 1);
 	
 	++dev->queue_count;
diff -urN linux-2.4.6-pre5/drivers/char/drm/dma.c linux/drivers/char/drm/dma.c
--- linux-2.4.6-pre5/drivers/char/drm/dma.c	Wed Nov 15 00:41:03 2000
+++ linux/drivers/char/drm/dma.c	Mon Dec  3 22:49:11 2001
@@ -38,7 +38,10 @@
 {
 	int i;
 	
-	dev->dma = drm_alloc(sizeof(*dev->dma), DRM_MEM_DRIVER);
+	if (!(dev->dma = drm_alloc(sizeof(*dev->dma), DRM_MEM_DRIVER))) {
+                printk(KERN_ERR "drm_dma_setup: can't drm_alloc dev->dma");
+                return;
+        }       
 	memset(dev->dma, 0, sizeof(*dev->dma));
 	for (i = 0; i <= DRM_MAX_ORDER; i++)
 		memset(&dev->dma->bufs[i], 0, sizeof(dev->dma->bufs[0]));
diff -urN linux-2.4.6-pre5/drivers/char/drm/i810_dma.c linux/drivers/char/drm/i810_dma.c
--- linux-2.4.6-pre5/drivers/char/drm/i810_dma.c	Mon Mar 19 12:35:08 2001
+++ linux/drivers/char/drm/i810_dma.c	Mon Dec  3 22:49:11 2001
@@ -1286,6 +1286,8 @@
 	DRM_DEBUG("i810 dma vertex, idx %d used %d discard %d\n",
 		  vertex.idx, vertex.used, vertex.discard);
 
+	if(vertex.idx < 0 || vertex.idx > dma->buf_count) return -EINVAL;
+
 	i810_dma_dispatch_vertex( dev, 
 				  dma->buflist[ vertex.idx ], 
 				  vertex.discard, vertex.used );
@@ -1409,7 +1411,7 @@
    	if (copy_from_user(&d, (drm_i810_copy_t *)arg, sizeof(d)))
 		return -EFAULT;
 
-	if(d.idx > dma->buf_count) return -EINVAL;
+	if(d.idx < 0 || d.idx > dma->buf_count) return -EINVAL;
 	buf = dma->buflist[ d.idx ];
    	buf_priv = buf->dev_private;
 	if (buf_priv->currently_mapped != I810_BUF_MAPPED) return -EPERM;
diff -urN linux-2.4.6-pre5/drivers/char/drm/mga_state.c linux/drivers/char/drm/mga_state.c
--- linux-2.4.6-pre5/drivers/char/drm/mga_state.c	Thu Jan  4 14:06:18 2001
+++ linux/drivers/char/drm/mga_state.c	Mon Dec  3 22:49:11 2001
@@ -832,6 +832,7 @@
 		return -EINVAL;
 	}
 
+	if(iload.idx < 0 || iload.idx > dma->buf_count) return -EINVAL;
 	buf = dma->buflist[iload.idx];
 	buf_priv = buf->dev_private;
 	bus_address = buf->bus_address;
@@ -874,6 +875,8 @@
 		return -EINVAL;
 	}
 
+	if(vertex.idx < 0 || vertex.idx > dma->buf_count) return -EINVAL;
+
 	buf = dma->buflist[vertex.idx];
 	buf_priv = buf->dev_private;
 
@@ -920,6 +923,7 @@
 		return -EINVAL;
 	}
 
+	if(indices.idx < 0 || indices.idx > dma->buf_count) return -EINVAL;
 	buf = dma->buflist[indices.idx];
 	buf_priv = buf->dev_private;
 
diff -urN linux-2.4.6-pre5/drivers/char/drm/proc.c linux/drivers/char/drm/proc.c
--- linux-2.4.6-pre5/drivers/char/drm/proc.c	Thu Jul 27 15:10:22 2000
+++ linux/drivers/char/drm/proc.c	Mon Dec  3 22:49:11 2001
@@ -92,6 +92,7 @@
 		if (!drm_dev_root) {
 			DRM_ERROR("Cannot create /proc/%s\n", drm_slot_name);
 			remove_proc_entry("dri", NULL);
+			break;
 		}
 		if (drm_dev_root->nlink == 2) break;
 		drm_dev_root = NULL;
diff -urN linux-2.4.6-pre5/drivers/char/drm/radeon_bufs.c linux/drivers/char/drm/radeon_bufs.c
--- linux-2.4.6-pre5/drivers/char/drm/radeon_bufs.c	Mon Mar 19 12:35:08 2001
+++ linux/drivers/char/drm/radeon_bufs.c	Mon Dec  3 22:49:11 2001
@@ -132,6 +132,11 @@
 		buf->dev_priv_size = sizeof(drm_radeon_buf_priv_t);
 		buf->dev_private   = drm_alloc(sizeof(drm_radeon_buf_priv_t),
 					       DRM_MEM_BUFS);
+                if (!buf->dev_private) {
+                        up(&dev->struct_sem);
+                        atomic_dec(&dev->buf_alloc);
+                        return -ENOMEM;
+                }
 		memset(buf->dev_private, 0, buf->dev_priv_size);
 
 #if DRM_DMA_HISTOGRAM
diff -urN linux-2.4.6-pre5/drivers/char/epca.c linux/drivers/char/epca.c
--- linux-2.4.6-pre5/drivers/char/epca.c	Tue May 22 10:23:16 2001
+++ linux/drivers/char/epca.c	Mon Dec  3 22:49:11 2001
@@ -60,6 +60,10 @@
 #include "epca.h"
 #include "epcaconfig.h"
 
+#if BITS_PER_LONG != 32
+#  error FIXME: this driver only works on 32-bit platforms
+#endif
+
 /* ---------------------- Begin defines ------------------------ */
 
 #define VERSION            "1.3.0.1-LK"
diff -urN linux-2.4.6-pre5/drivers/char/esp.c linux/drivers/char/esp.c
--- linux-2.4.6-pre5/drivers/char/esp.c	Fri Apr  6 10:42:55 2001
+++ linux/drivers/char/esp.c	Mon Dec  3 22:49:11 2001
@@ -957,7 +957,7 @@
 		if (!dma_buffer)
 			info->stat_flags |= ESP_STAT_USE_PIO;
 		else if (request_dma(dma, "esp serial")) {
-			free_pages((unsigned int)dma_buffer,
+			free_pages((unsigned long)dma_buffer,
 				   get_order(DMA_BUFFER_SZ));
 			dma_buffer = 0;
 			info->stat_flags |= ESP_STAT_USE_PIO;
@@ -1061,7 +1061,7 @@
 
 		if (!current_port) {
 			free_dma(dma);
-			free_pages((unsigned int)dma_buffer,
+			free_pages((unsigned long)dma_buffer,
 				   get_order(DMA_BUFFER_SZ));
 			dma_buffer = 0;
 		}		
@@ -2770,7 +2770,7 @@
 	}
 
 	if (dma_buffer)
-		free_pages((unsigned int)dma_buffer,
+		free_pages((unsigned long)dma_buffer,
 			get_order(DMA_BUFFER_SZ));
 
 	if (tmp_buf)
diff -urN linux-2.4.6-pre5/drivers/char/i810-tco.c linux/drivers/char/i810-tco.c
--- linux-2.4.6-pre5/drivers/char/i810-tco.c	Thu May 24 15:14:08 2001
+++ linux/drivers/char/i810-tco.c	Mon Dec  3 22:49:11 2001
@@ -232,19 +232,40 @@
 	}
 }
 
+/*
+ * Data for PCI driver interface
+ *
+ * This data only exists for exporting the supported
+ * PCI ids via MODULE_DEVICE_TABLE.  We do not actually
+ * register a pci_driver, because someone else might one day
+ * want to register another driver on the same PCI id.
+ */
+static struct pci_device_id i810tco_pci_tbl[] __initdata = {
+	{ PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801AA_0,	PCI_ANY_ID, PCI_ANY_ID, },
+	{ PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801AB_0,	PCI_ANY_ID, PCI_ANY_ID, },
+	{ PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801BA_0,	PCI_ANY_ID, PCI_ANY_ID, },
+	{ PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801BA_10,	PCI_ANY_ID, PCI_ANY_ID, },
+	{ 0, },
+};
+MODULE_DEVICE_TABLE (pci, i810tco_pci_tbl);
+
 static struct pci_dev *i810tco_pci;
 
 static unsigned char i810tco_getdevice (void)
 {
+	struct pci_dev *dev;
 	u8 val1, val2;
 	u16 badr;
 	/*
-	 *      Find the PCI device which has vendor id 0x8086
-	 *      and device ID 0x2410
+	 *      Find the PCI device
 	 */
-	i810tco_pci = pci_find_device (PCI_VENDOR_ID_INTEL,
-				       PCI_DEVICE_ID_INTEL_82801AA_0, NULL);
-	if (i810tco_pci) {
+
+	pci_for_each_dev(dev) {
+		if (pci_match_device(i810tco_pci_tbl, dev))
+			break;
+	}
+
+	if ((i810tco_pci = dev)) {
 		/*
 		 *      Find the ACPI base I/O address which is the base
 		 *      for the TCO registers (TCOBASE=ACPIBASE + 0x60)
diff -urN linux-2.4.6-pre5/drivers/char/n_r3964.c linux/drivers/char/n_r3964.c
--- linux-2.4.6-pre5/drivers/char/n_r3964.c	Fri Apr 13 20:26:07 2001
+++ linux/drivers/char/n_r3964.c	Mon Dec  3 22:49:11 2001
@@ -132,10 +132,10 @@
 
 static int  r3964_open(struct tty_struct *tty);
 static void r3964_close(struct tty_struct *tty);
-static int  r3964_read(struct tty_struct *tty, struct file *file,
-                     unsigned char *buf, unsigned int nr);
-static int  r3964_write(struct tty_struct * tty, struct file * file,
-                      const unsigned char * buf, unsigned int nr);
+static ssize_t r3964_read(struct tty_struct *tty, struct file *file,
+                     unsigned char *buf, size_t nr);
+static ssize_t r3964_write(struct tty_struct * tty, struct file * file,
+                      const unsigned char * buf, size_t nr);
 static int r3964_ioctl(struct tty_struct * tty, struct file * file,
                        unsigned int cmd, unsigned long arg);
 static void r3964_set_termios(struct tty_struct *tty, struct termios * old);
@@ -1238,8 +1238,8 @@
     MOD_DEC_USE_COUNT;
 }
 
-static int r3964_read(struct tty_struct *tty, struct file *file,
-                     unsigned char *buf, unsigned int nr)
+static ssize_t r3964_read(struct tty_struct *tty, struct file *file,
+			  unsigned char *buf, size_t nr)
 {
    struct r3964_info *pInfo=(struct r3964_info*)tty->disc_data;
    struct r3964_client_info *pClient;
@@ -1299,8 +1299,8 @@
    return -EPERM;
 }
 
-static int r3964_write(struct tty_struct * tty, struct file * file,
-                      const unsigned char *data, unsigned int count)
+static ssize_t r3964_write(struct tty_struct * tty, struct file * file,
+			   const unsigned char *data, size_t count)
 {
    struct r3964_info *pInfo=(struct r3964_info*)tty->disc_data;
    struct r3964_block_header *pHeader;
diff -urN linux-2.4.6-pre5/drivers/char/nvram.c linux/drivers/char/nvram.c
--- linux-2.4.6-pre5/drivers/char/nvram.c	Fri Feb  9 11:40:02 2001
+++ linux/drivers/char/nvram.c	Mon Dec  3 22:49:11 2001
@@ -113,7 +113,7 @@
 #define	NVRAM_EXCL		2		/* opened with O_EXCL */
 
 #define	RTC_FIRST_BYTE		14	/* RTC register number of first NVRAM byte */
-#define	NVRAM_BYTES			50	/* number of NVRAM bytes */
+#define	NVRAM_BYTES			128	/* number of NVRAM bytes */
 
 
 static int mach_check_checksum( void );
diff -urN linux-2.4.6-pre5/drivers/char/nwflash.c linux/drivers/char/nwflash.c
--- linux-2.4.6-pre5/drivers/char/nwflash.c	Mon Sep 18 15:15:22 2000
+++ linux/drivers/char/nwflash.c	Mon Dec  3 22:49:11 2001
@@ -4,6 +4,14 @@
  *
  * 20/08/2000	RMK	use __ioremap to map flash into virtual memory
  *			make a few more places use "volatile"
+ * 22/05/2001	RMK	- Lock read against write
+ *			- merge printk level changes (with mods) from Alan Cox.
+ *			- use *ppos as the file position, not file->f_pos.
+ *			- fix check for out of range pos and r/w size
+ *
+ * Please note that we are tampering with the only flash chip in the
+ * machine, which contains the bootup code.  We therefore have the
+ * power to convert these machines into doorstops...
  */
 
 #include <linux/module.h>
@@ -16,6 +24,7 @@
 #include <linux/sched.h>
 #include <linux/miscdevice.h>
 #include <linux/spinlock.h>
+#include <linux/rwsem.h>
 #include <linux/init.h>
 
 #include <asm/hardware/dec21285.h>
@@ -28,21 +37,12 @@
 /*****************************************************************************/
 #include <asm/nwflash.h>
 
-//#define MINIKERNEL 1          //export flash write, erase routines for MiniKernel
+#define	NWFLASH_VERSION "6.4"
 
-#ifndef MINIKERNEL
-#define MSTATIC static
-#else
-#define MSTATIC
-#endif
-
-#define	NWFLASH_VERSION "6.3"
-
-MSTATIC void kick_open(void);
-MSTATIC int get_flash_id(void);
-MSTATIC int erase_block(int nBlock);
-MSTATIC int write_block(unsigned long p, const char *buf, int count);
-static int open_flash(struct inode *inodep, struct file *filep);
+static void kick_open(void);
+static int get_flash_id(void);
+static int erase_block(int nBlock);
+static int write_block(unsigned long p, const char *buf, int count);
 static int flash_ioctl(struct inode *inodep, struct file *filep, unsigned int cmd, unsigned long arg);
 static ssize_t flash_read(struct file *file, char *buf, size_t count, loff_t * ppos);
 static ssize_t flash_write(struct file *file, const char *buf, size_t count, loff_t * ppos);
@@ -58,27 +58,10 @@
 static int gbWriteEnable;
 static int gbWriteBase64Enable;
 static volatile unsigned char *FLASH_BASE;
-MSTATIC int gbFlashSize = KFLASH_SIZE;
+static int gbFlashSize = KFLASH_SIZE;
 
 extern spinlock_t gpio_lock;
 
-static struct file_operations flash_fops =
-{
-	owner:		THIS_MODULE,
-	llseek:		flash_llseek,
-	read:		flash_read,
-	write:		flash_write,
-	ioctl:		flash_ioctl,
-	open:		open_flash,
-};
-
-static struct miscdevice flash_miscdev =
-{
-	FLASH_MINOR,
-	"nwflash",
-	&flash_fops
-};
-
 /*
  * the delay routine - it is often required to let the flash "breeze"...
  */
@@ -88,7 +71,7 @@
 	schedule_timeout(timeout);
 }
 
-MSTATIC int get_flash_id(void)
+static int get_flash_id(void)
 {
 	volatile unsigned int c1, c2;
 
@@ -123,23 +106,8 @@
 	return c2;
 }
 
-static int open_flash(struct inode *inodep, struct file *filep)
-{
-	int id;
-
-	id = get_flash_id();
-	if ((id != KFLASH_ID) && (id != KFLASH_ID4)) {
-		printk("Flash: incorrect ID 0x%04X.\n", id);
-		return -ENXIO;
-	}
-
-	return 0;
-}
-
 static int flash_ioctl(struct inode *inodep, struct file *filep, unsigned int cmd, unsigned long arg)
 {
-//      printk("Flash_ioctl: cmd = 0x%X.\n",cmd);
-
 	switch (cmd) {
 	case CMD_WRITE_DISABLE:
 		gbWriteBase64Enable = 0;
@@ -159,41 +127,48 @@
 		gbWriteEnable = 0;
 		return -EINVAL;
 	}
-
 	return 0;
 }
 
-
-
-static ssize_t flash_read(struct file *file, char *buf, size_t count, loff_t * ppos)
+static ssize_t flash_read(struct file *file, char *buf, size_t size, loff_t * ppos)
 {
-	unsigned long p = file->f_pos;
-	int read;
+	struct inode *inode = file->f_dentry->d_inode;
+	unsigned long p = *ppos;
+	unsigned int count = size;
+	int ret = 0;
 
 	if (flashdebug)
-		printk("Flash_dev: flash_read: offset=0x%X, buffer=0x%X, count=0x%X.\n",
-		       (unsigned int) p, (unsigned int) buf, count);
-
+		printk(KERN_DEBUG "flash_read: flash_read: offset=0x%lX, buffer=%p, count=0x%X.\n",
+		       p, buf, count);
 
-	if (count < 0)
-		return -EINVAL;
+	if (count)
+		ret = -ENXIO;
 
-	if (count > gbFlashSize - p)
-		count = gbFlashSize - p;
+	if (p < gbFlashSize) {
+		if (count > gbFlashSize - p)
+			count = gbFlashSize - p;
 
-	read = 0;
+		/*
+		 * We now lock against reads and writes. --rmk
+		 */
+		if (down_interruptible(&inode->i_sem))
+			return -ERESTARTSYS;
 
-	if (copy_to_user(buf, (void *)(FLASH_BASE + p), count))
-		return -EFAULT;
-	read += count;
-	file->f_pos += read;
-	return read;
+		ret = copy_to_user(buf, (void *)(FLASH_BASE + p), count);
+		if (ret == 0) {
+			ret = count;
+			*ppos += count;
+		}
+		up(&inode->i_sem);
+	}
+	return ret;
 }
 
-static ssize_t flash_write(struct file *file, const char *buf, size_t count, loff_t * ppos)
+static ssize_t flash_write(struct file *file, const char *buf, size_t size, loff_t * ppos)
 {
 	struct inode *inode = file->f_dentry->d_inode;
-	unsigned long p = file->f_pos;
+	unsigned long p = *ppos;
+	unsigned int count = size;
 	int written;
 	int nBlock, temp, rc;
 	int i, j;
@@ -209,20 +184,19 @@
 		return -EINVAL;
 
 	/*
-	 * if byte count is -ve or to big - error!
+	 * check for out of range pos or count
 	 */
-	if (count < 0 || count > gbFlashSize - p)
-		return -EINVAL;
+	if (p >= gbFlashSize)
+		return count ? -ENXIO : 0;
 
+	if (count > gbFlashSize - p)
+		count = gbFlashSize - p;
+			
 	if (verify_area(VERIFY_READ, buf, count))
 		return -EFAULT;
 
-
 	/*
-	 * We now should lock around writes.  Really, we shouldn't
-	 * allow the flash to be opened more than once in write
-	 * mode though (note that you can't stop two processes having
-	 * it open even then). --rmk
+	 * We now lock against reads and writes. --rmk
 	 */
 	if (down_interruptible(&inode->i_sem))
 		return -ERESTARTSYS;
@@ -246,11 +220,12 @@
 		temp -= 1;
 
 	if (flashdebug)
-		printk("FlashWrite: writing %d block(s) starting at %d.\n", temp, nBlock);
+		printk(KERN_DEBUG "flash_write: writing %d block(s) "
+			"starting at %d.\n", temp, nBlock);
 
 	for (; temp; temp--, nBlock++) {
 		if (flashdebug)
-			printk("FlashWrite: erasing block %d.\n", nBlock);
+			printk(KERN_DEBUG "flash_write: erasing block %d.\n", nBlock);
 
 		/*
 		 * first we have to erase the block(s), where we will write...
@@ -264,14 +239,12 @@
 		} while (rc && i < 10);
 
 		if (rc) {
-			if (flashdebug)
-				printk("FlashWrite: erase error %X. Aborting...\n", rc);
-
+			printk(KERN_ERR "flash_write: erase error %x\n", rc);
 			break;
 		}
 		if (flashdebug)
-			printk("FlashWrite: writing offset %X, from buf %X, bytes left %X.\n",
-			       (unsigned int) p, (unsigned int) buf, count - written);
+			printk(KERN_DEBUG "flash_write: writing offset %lX, from buf "
+				"%p, bytes left %X.\n", p, buf, count - written);
 
 		/*
 		 * write_block will limit write to space left in this block
@@ -296,17 +269,16 @@
 
 		}
 		if (rc < 0) {
-			if (flashdebug)
-				printk("FlashWrite: write error %X. Aborting...\n", rc);
+			printk(KERN_ERR "flash_write: write error %X\n", rc);
 			break;
 		}
 		p += rc;
 		buf += rc;
 		written += rc;
-		file->f_pos += rc;
+		*ppos += rc;
 
 		if (flashdebug)
-			printk("FlashWrite: written 0x%X bytes OK.\n", written);
+			printk(KERN_DEBUG "flash_write: written 0x%X bytes OK.\n", written);
 	}
 
 	/*
@@ -331,8 +303,8 @@
 static long long flash_llseek(struct file *file, long long offset, int orig)
 {
 	if (flashdebug)
-		printk("Flash_dev: flash_lseek, offset=0x%X, orig=0x%X.\n",
-		       (unsigned int) offset, (unsigned int) orig);
+		printk(KERN_DEBUG "flash_llseek: offset=0x%X, orig=0x%X.\n",
+		       (unsigned int) offset, orig);
 
 	switch (orig) {
 	case 0:
@@ -362,7 +334,7 @@
  * so just go ahead and erase, what requested!
  */
 
-MSTATIC int erase_block(int nBlock)
+static int erase_block(int nBlock)
 {
 	volatile unsigned int c1;
 	volatile unsigned char *pWritePtr;
@@ -440,13 +412,12 @@
 	 * check if erase errors were reported
 	 */
 	if (c1 & 0x20) {
-		if (flashdebug)
-			printk("Flash_erase: err at %X.\n", (unsigned int) pWritePtr);
+		printk(KERN_ERR "flash_erase: err at %p\n", pWritePtr);
+
 		/*
 		 * reset error
 		 */
 		*(volatile unsigned char *) (FLASH_BASE + 0x8000) = 0x50;
-
 		return -2;
 	}
 
@@ -459,9 +430,8 @@
 
 	for (temp = 0; temp < 16 * 1024; temp++, pWritePtr += 4) {
 		if ((temp1 = *(volatile unsigned int *) pWritePtr) != 0xFFFFFFFF) {
-			if (flashdebug)
-				printk("Flash_erase: verify err at %X = %X.\n",
-				       (unsigned int) pWritePtr, temp1);
+			printk(KERN_ERR "flash_erase: verify err at %p = %X\n",
+			       pWritePtr, temp1);
 			return -1;
 		}
 	}
@@ -473,7 +443,7 @@
 /*
  * write_block will limit number of bytes written to the space in this block
  */
-MSTATIC int write_block(unsigned long p, const char *buf, int count)
+static int write_block(unsigned long p, const char *buf, int count)
 {
 	volatile unsigned int c1;
 	volatile unsigned int c2;
@@ -591,7 +561,7 @@
 			 */
 			if (time_before(jiffies, timeout)) {
 				if (flashdebug)
-					printk("FlashWrite: Retrying write (addr=0x%X)...\n",
+					printk(KERN_DEBUG "write_block: Retrying write at 0x%X)n",
 					       pWritePtr - FLASH_BASE);
 
 				/*
@@ -609,7 +579,7 @@
 
 				goto WriteRetry;
 			} else {
-				printk("Timeout in flash write! (addr=0x%X) Aborting...\n",
+				printk(KERN_ERR "write_block: timeout at 0x%X\n",
 				       pWritePtr - FLASH_BASE);
 				/*
 				 * return error -2
@@ -636,9 +606,8 @@
 			return -EFAULT;
 		buf++;
 		if ((c1 = *pWritePtr++) != c) {
-			if (flashdebug)
-				printk("flash write verify error at 0x%X! (%02X!=%02X) Retrying...\n",
-				       (unsigned int) pWritePtr, c1, c);
+			printk(KERN_ERR "write_block: verify error at 0x%X (%02X!=%02X)\n",
+			       pWritePtr - FLASH_BASE, c1, c);
 			return 0;
 		}
 	}
@@ -647,7 +616,7 @@
 }
 
 
-MSTATIC void kick_open(void)
+static void kick_open(void)
 {
 	unsigned long flags;
 
@@ -665,7 +634,23 @@
 	udelay(25);
 }
 
-MSTATIC int __init nwflash_init(void)
+static struct file_operations flash_fops =
+{
+	owner:		THIS_MODULE,
+	llseek:		flash_llseek,
+	read:		flash_read,
+	write:		flash_write,
+	ioctl:		flash_ioctl,
+};
+
+static struct miscdevice flash_miscdev =
+{
+	FLASH_MINOR,
+	"nwflash",
+	&flash_fops
+};
+
+static int __init nwflash_init(void)
 {
 	int ret = -ENODEV;
 
@@ -677,6 +662,13 @@
 			goto out;
 
 		id = get_flash_id();
+		if ((id != KFLASH_ID) && (id != KFLASH_ID4)) {
+			ret = -ENXIO;
+			iounmap((void *)FLASH_BASE);
+			printk("Flash: incorrect ID 0x%04X.\n", id);
+			goto out;
+		}
+
 		printk("Flash ROM driver v.%s, flash device ID 0x%04X, size %d Mb.\n",
 		       NWFLASH_VERSION, id, gbFlashSize / (1024 * 1024));
 
@@ -688,7 +680,7 @@
 	return ret;
 }
 
-MSTATIC void __exit nwflash_exit(void)
+static void __exit nwflash_exit(void)
 {
 	misc_deregister(&flash_miscdev);
 	iounmap((void *)FLASH_BASE);
diff -urN linux-2.4.6-pre5/drivers/char/raw.c linux/drivers/char/raw.c
--- linux-2.4.6-pre5/drivers/char/raw.c	Sun May 20 11:34:05 2001
+++ linux/drivers/char/raw.c	Mon Dec  3 22:49:11 2001
@@ -194,7 +194,7 @@
 			break;
 		
 		minor = rq.raw_minor;
-		if (minor == 0 || minor > MINORMASK) {
+		if (minor <= 0 || minor > MINORMASK) {
 			err = -EINVAL;
 			break;
 		}
diff -urN linux-2.4.6-pre5/drivers/char/sbc60xxwdt.c linux/drivers/char/sbc60xxwdt.c
--- linux-2.4.6-pre5/drivers/char/sbc60xxwdt.c	Tue May 22 10:23:16 2001
+++ linux/drivers/char/sbc60xxwdt.c	Mon Dec  3 22:49:11 2001
@@ -174,9 +174,13 @@
 
 		/* now scan */
 		for(ofs = 0; ofs != count; ofs++) 
+		{
+			char c;
+			if(get_user(c, buf+ofs))
+				return -EFAULT;
 			if(buf[ofs] == 'V')
 				wdt_expect_close = 1;
-
+		}
 		/* Well, anyhow someone wrote to us, we should return that favour */
 		next_heartbeat = jiffies + WDT_HEARTBEAT;
 		return 1;
diff -urN linux-2.4.6-pre5/drivers/char/sh-sci.c linux/drivers/char/sh-sci.c
--- linux-2.4.6-pre5/drivers/char/sh-sci.c	Wed Apr 11 21:24:52 2001
+++ linux/drivers/char/sh-sci.c	Mon Dec  3 22:49:11 2001
@@ -1035,7 +1035,11 @@
 	memset(&sci_driver, 0, sizeof(sci_driver));
 	sci_driver.magic = TTY_DRIVER_MAGIC;
 	sci_driver.driver_name = "sci";
+#ifdef CONFIG_DEVFS_FS
+	sci_driver.name = "ttsc/%d";
+#else
 	sci_driver.name = "ttySC";
+#endif
 	sci_driver.major = SCI_MAJOR;
 	sci_driver.minor_start = SCI_MINOR_START;
 	sci_driver.num = SCI_NPORTS;
@@ -1070,7 +1074,11 @@
 #endif
 
 	sci_callout_driver = sci_driver;
+#ifdef CONFIG_DEVFS_FS
+	sci_callout_driver.name = "cusc/%d";
+#else
 	sci_callout_driver.name = "cusc";
+#endif
 	sci_callout_driver.major = SCI_MAJOR+1;
 	sci_callout_driver.subtype = SERIAL_TYPE_CALLOUT;
 	sci_callout_driver.read_proc = NULL;
diff -urN linux-2.4.6-pre5/drivers/char/sh-sci.h linux/drivers/char/sh-sci.h
--- linux-2.4.6-pre5/drivers/char/sh-sci.h	Wed Apr 11 21:24:52 2001
+++ linux/drivers/char/sh-sci.h	Mon Dec  3 22:49:11 2001
@@ -46,7 +46,7 @@
 # define SCPDR  0xA4000136 /* 8  bit SCI and SCIF */
 # define SCSCR_INIT(port)          0x30 /* TIE=0,RIE=0,TE=1,RE=1 */
 # define SCI_AND_SCIF
-#elif defined(CONFIG_CPU_SUBTYPE_SH7750)
+#elif defined(CONFIG_CPU_SUBTYPE_SH7750) || defined(CONFIG_CPU_SUBTYPE_SH7751)
 # define SCI_NPORTS 2
 # define SCI_INIT { \
   { {}, PORT_SCI,  0xffe00000, SCI_IRQS,      sci_init_pins_sci  }, \
@@ -294,7 +294,7 @@
 		return ctrl_inb(SCPDR)&0x04 ? 1 : 0; /* IRDA */
 	return 1;
 }
-#elif defined(CONFIG_CPU_SUBTYPE_SH7750)
+#elif defined(CONFIG_CPU_SUBTYPE_SH7750) || defined(CONFIG_CPU_SUBTYPE_SH7751)
 static inline int sci_rxd_in(struct sci_port *port)
 {
 #ifndef SCIF_ONLY
diff -urN linux-2.4.6-pre5/drivers/char/sx.c linux/drivers/char/sx.c
--- linux-2.4.6-pre5/drivers/char/sx.c	Fri Apr  6 10:42:55 2001
+++ linux/drivers/char/sx.c	Mon Dec  3 22:49:11 2001
@@ -467,7 +467,7 @@
 	int i, j, ch;
 
 	for (i=0;i<len;i+=16) {
-		printk ("%08x ", (int) addr+i);
+		printk ("%p ", addr+i);
 		for (j=0;j<16;j++) {
 			printk ("%02x %s", addr[j+i], (j==7)?" ":"");
 		}
@@ -1639,7 +1639,8 @@
 	int rc = 0;
 	int *descr = (int *)arg, i;
 	static struct sx_board *board = NULL;
-	int nbytes, offset, data;
+	int nbytes, offset;
+	unsigned long data;
 	char *tmp;
 
 	func_enter();
@@ -2098,7 +2099,7 @@
 	func_enter();
 
 	if (!IS_CF_BOARD (board)) {    
-		sx_dprintk (SX_DEBUG_PROBE, "Going to verify vpd prom at %x.\n", 
+		sx_dprintk (SX_DEBUG_PROBE, "Going to verify vpd prom at %lx.\n", 
 		            board->base + SX_VPD_ROM);
 
 		if (sx_debug & SX_DEBUG_PROBE)
@@ -2123,7 +2124,7 @@
 	printheader ();
 
 	if (!IS_CF_BOARD (board)) {
-		printk (KERN_DEBUG "sx: Found an SX board at %x\n", board->hw_base);
+		printk (KERN_DEBUG "sx: Found an SX board at %lx\n", board->hw_base);
 		printk (KERN_DEBUG "sx: hw_rev: %d, assembly level: %d, uniq ID:%08x, ", 
 		        vpdp.hwrev, vpdp.hwass, vpdp.uniqid);
 		printk (           "Manufactured: %d/%d\n", 
@@ -2140,7 +2141,7 @@
 
 		if (((vpdp.uniqid >> 24) & SX_UNIQUEID_MASK) == SX_ISA_UNIQUEID1) {
 			if (board->base & 0x8000) {
-				printk (KERN_WARNING "sx: Warning: There may be hardware problems with the card at %x.\n", board->base);
+				printk (KERN_WARNING "sx: Warning: There may be hardware problems with the card at %lx.\n", board->base);
 				printk (KERN_WARNING "sx: Read sx.txt for more info.\n");
 			}
 		}
@@ -2172,7 +2173,7 @@
 	int i;
 
 	func_enter();
-	sx_dprintk (SX_DEBUG_PROBE, "Going to verify SI signature %x.\n", 
+	sx_dprintk (SX_DEBUG_PROBE, "Going to verify SI signature %lx.\n", 
 	            board->base + SI2_ISA_ID_BASE);
 
 	if (sx_debug & SX_DEBUG_PROBE)
@@ -2188,7 +2189,7 @@
 
 	printheader ();
 
-	printk (KERN_DEBUG "sx: Found an SI board at %x\n", board->hw_base);
+	printk (KERN_DEBUG "sx: Found an SI board at %lx\n", board->hw_base);
 	/* Compared to the SX boards, it is a complete guess as to what
 		 this card is up to... */
 
@@ -2507,7 +2508,7 @@
 
 			board->irq = get_irq (pdev);
 
-			sx_dprintk (SX_DEBUG_PROBE, "Got a specialix card: %x/%x(%d) %x.\n", 
+			sx_dprintk (SX_DEBUG_PROBE, "Got a specialix card: %x/%lx(%d) %x.\n", 
 			            tint, boards[found].base, board->irq, board->flags);
 
 			if (probe_sx (board)) {
@@ -2569,8 +2570,8 @@
 			board->base2 =
 			board->base = (ulong) ioremap(board->hw_base, SI2_EISA_WINDOW_LEN);
 
-			sx_dprintk(SX_DEBUG_PROBE, "IO hw_base address: %x\n", board->hw_base);
-			sx_dprintk(SX_DEBUG_PROBE, "base: %x\n", board->base);
+			sx_dprintk(SX_DEBUG_PROBE, "IO hw_base address: %lx\n", board->hw_base);
+			sx_dprintk(SX_DEBUG_PROBE, "base: %lx\n", board->base);
 			board->irq = inb(board->eisa_base+0xc02)>>4; 
 			sx_dprintk(SX_DEBUG_PROBE, "IRQ: %d\n", board->irq);
 			
@@ -2602,7 +2603,7 @@
 	for (i = 0; i < SX_NBOARDS; i++) {
 		board = &boards[i];
 		if (board->flags & SX_BOARD_INITIALIZED) {
-			sx_dprintk (SX_DEBUG_CLEANUP, "Cleaning up board at %x\n", board->base);
+			sx_dprintk (SX_DEBUG_CLEANUP, "Cleaning up board at %lx\n", board->base);
 			/* The board should stop messing with us.
 			   (actually I mean the interrupt) */
 			sx_reset (board);
diff -urN linux-2.4.6-pre5/drivers/char/sx.h linux/drivers/char/sx.h
--- linux-2.4.6-pre5/drivers/char/sx.h	Mon Dec 11 13:38:29 2000
+++ linux/drivers/char/sx.h	Mon Dec  3 22:49:11 2001
@@ -36,9 +36,9 @@
 
 struct sx_board {
   int magic;
-  unsigned int base;
-  unsigned int base2;
-  unsigned int hw_base;
+  unsigned long base;
+  unsigned long base2;
+  unsigned long hw_base;
   int eisa_base;
   int port_base; /* Number of the first port */
   struct sx_port *ports;
diff -urN linux-2.4.6-pre5/drivers/char/tty_io.c linux/drivers/char/tty_io.c
--- linux-2.4.6-pre5/drivers/char/tty_io.c	Thu Apr 26 17:35:49 2001
+++ linux/drivers/char/tty_io.c	Mon Dec  3 22:49:11 2001
@@ -148,6 +148,7 @@
 extern long serial167_console_init(void);
 extern void console_8xx_init(void);
 extern int rs_8xx_init(void);
+extern void mac_scc_console_init(void);
 extern void hwc_console_init(void);
 extern void hwc_tty_init(void);
 extern void con3215_init(void);
@@ -2184,6 +2185,8 @@
 #ifdef CONFIG_SERIAL_CONSOLE
 #if (defined(CONFIG_8xx) || defined(CONFIG_8260))
 	console_8xx_init();
+#elif defined(CONFIG_MAC_SERIAL)
+	mac_scc_console_init();
 #elif defined(CONFIG_SERIAL)
 	serial_console_init();
 #endif /* CONFIG_8xx */
@@ -2306,9 +2309,6 @@
 #endif
 #ifdef CONFIG_COMPUTONE
 	ip2_init();
-#endif
-#ifdef CONFIG_MAC_SERIAL
-	macserial_init();
 #endif
 #ifdef CONFIG_ROCKETPORT
 	rp_init();
diff -urN linux-2.4.6-pre5/drivers/ide/hpt366.c linux/drivers/ide/hpt366.c
--- linux-2.4.6-pre5/drivers/ide/hpt366.c	Sat May 19 17:43:06 2001
+++ linux/drivers/ide/hpt366.c	Mon Dec  3 22:49:11 2001
@@ -51,6 +51,16 @@
 };
 
 const char *bad_ata100_5[] = {
+	"IBM-DTLA-307075",
+	"IBM-DTLA-307060",
+	"IBM-DTLA-307045",
+	"IBM-DTLA-307030",
+	"IBM-DTLA-307020",
+	"IBM-DTLA-307015",
+	"IBM-DTLA-305040",
+	"IBM-DTLA-305030",
+	"IBM-DTLA-305020",
+	"WDC AC310200R",
 	NULL
 };
 
diff -urN linux-2.4.6-pre5/drivers/ide/ide-pci.c linux/drivers/ide/ide-pci.c
--- linux-2.4.6-pre5/drivers/ide/ide-pci.c	Mon Dec  3 22:49:01 2001
+++ linux/drivers/ide/ide-pci.c	Mon Dec  3 22:49:11 2001
@@ -283,13 +283,16 @@
 #endif
 
 #ifdef CONFIG_BLK_DEV_SL82C105
+extern unsigned int pci_init_sl82c105(struct pci_dev *, const char *);
+extern void dma_init_sl82c105(ide_hwif_t *, unsigned long);
 extern void ide_init_sl82c105(ide_hwif_t *);
-extern void ide_dmacapable_sl82c105(ide_hwif_t *, unsigned long);
+#define PCI_W82C105	&pci_init_sl82c105
+#define DMA_W82C105	&dma_init_sl82c105
 #define INIT_W82C105	&ide_init_sl82c105
-#define DMA_W82C105	&ide_dmacapable_sl82c105
 #else
-#define INIT_W82C105	IDE_IGNORE
+#define PCI_W82C105	NULL
 #define DMA_W82C105	NULL
+#define INIT_W82C105	IDE_IGNORE
 #endif
 
 #ifdef CONFIG_BLK_DEV_TRM290
@@ -369,7 +372,7 @@
 	{DEVID_AEC6210,	"AEC6210",	PCI_AEC62XX,	NULL,		INIT_AEC62XX,	DMA_AEC62XX,	{{0x4a,0x02,0x02}, {0x4a,0x04,0x04}}, 	OFF_BOARD,	0 },
 	{DEVID_AEC6260,	"AEC6260",	PCI_AEC62XX,	ATA66_AEC62XX,	INIT_AEC62XX,	NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}},	NEVER_BOARD,	0 },
 	{DEVID_AEC6260R,"AEC6260R",	PCI_AEC62XX,	ATA66_AEC62XX,	INIT_AEC62XX,	NULL,		{{0x4a,0x02,0x02}, {0x4a,0x04,0x04}},	OFF_BOARD,	0 },
-	{DEVID_W82C105,	"W82C105",	NULL,		NULL,		INIT_W82C105,	DMA_W82C105,	{{0x40,0x01,0x01}, {0x40,0x10,0x10}}, 	ON_BOARD,	0 },
+	{DEVID_W82C105,	"W82C105",	PCI_W82C105,	NULL,		INIT_W82C105,	DMA_W82C105,	{{0x40,0x01,0x01}, {0x40,0x10,0x10}}, 	ON_BOARD,	0 },
 	{DEVID_UM8673F,	"UM8673F",	NULL,		NULL,		NULL,		NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}},	ON_BOARD,	0 },
 	{DEVID_UM8886A,	"UM8886A",	NULL,		NULL,		NULL,		NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}},	ON_BOARD,	0 },
 	{DEVID_UM8886BF,"UM8886BF",	NULL,		NULL,		NULL,		NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}}, 	ON_BOARD,	0 },
diff -urN linux-2.4.6-pre5/drivers/ide/rapide.c linux/drivers/ide/rapide.c
--- linux-2.4.6-pre5/drivers/ide/rapide.c	Fri Feb  9 11:30:23 2001
+++ linux/drivers/ide/rapide.c	Mon Dec  3 22:49:11 2001
@@ -17,7 +17,7 @@
 
 #include <asm/ecard.h>
 
-static const card_ids __init rapide_cids[] = {
+static card_ids __init rapide_cids[] = {
 	{ MANU_YELLOWSTONE, PROD_YELLOWSTONE_RAPIDE32 },
 	{ 0xffff, 0xffff }
 };
diff -urN linux-2.4.6-pre5/drivers/ide/sl82c105.c linux/drivers/ide/sl82c105.c
--- linux-2.4.6-pre5/drivers/ide/sl82c105.c	Tue Nov  7 11:02:24 2000
+++ linux/drivers/ide/sl82c105.c	Mon Dec  3 22:49:11 2001
@@ -56,10 +56,9 @@
 }
 
 /*
- * We only deal with PIO mode here - DMA mode 'using_dma' is not
- * initialised at the point that this function is called.
+ * Configure the drive and chipset for PIO
  */
-static void tune_sl82c105(ide_drive_t *drive, byte pio)
+static void config_for_pio(ide_drive_t *drive, int pio, int report)
 {
 	ide_hwif_t *hwif = HWIF(drive);
 	struct pci_dev *dev = hwif->pci_dev;
@@ -83,42 +82,212 @@
 	if (ide_config_drive_speed(drive, xfer_mode) == 0)
 		drv_ctrl = get_timing_sl82c105(&p);
 
+	if (drive->using_dma == 0) {
+		/*
+		 * If we are actually using MW DMA, then we can not
+		 * reprogram the interface drive control register.
+		 */
+		pci_write_config_word(dev, reg, drv_ctrl);
+		pci_read_config_word(dev, reg, &drv_ctrl);
+
+		if (report) {
+			printk("%s: selected %s (%dns) (%04X)\n", drive->name,
+			       ide_xfer_verbose(xfer_mode), p.cycle_time, drv_ctrl);
+		}
+	}
+}
+
+/*
+ * Configure the drive and the chipset for DMA
+ */
+static int config_for_dma(ide_drive_t *drive)
+{
+	ide_hwif_t *hwif = HWIF(drive);
+	struct pci_dev *dev = hwif->pci_dev;
+	unsigned short drv_ctrl = 0x909;
+	unsigned int reg;
+
+	reg = (hwif->channel ? 0x4c : 0x44) + (drive->select.b.unit ? 4 : 0);
+
+	if (ide_config_drive_speed(drive, XFER_MW_DMA_2) == 0)
+		drv_ctrl = 0x0240;
+
 	pci_write_config_word(dev, reg, drv_ctrl);
-	pci_read_config_word(dev, reg, &drv_ctrl);
 
-	printk("%s: selected %s (%dns) (%04X)\n", drive->name,
-	       ide_xfer_verbose(xfer_mode), p.cycle_time, drv_ctrl);
+	return 0;
 }
-#endif
 
-void __init ide_dmacapable_sl82c105(ide_hwif_t *hwif, unsigned long dmabase)
+/*
+ * Check to see if the drive and
+ * chipset is capable of DMA mode
+ */
+static int sl82c105_check_drive(ide_drive_t *drive)
+{
+	ide_dma_action_t dma_func = ide_dma_off_quietly;
+
+	do {
+		struct hd_driveid *id = drive->id;
+		ide_hwif_t *hwif = HWIF(drive);
+
+		if (!hwif->autodma)
+			break;
+
+		if (!id || !(id->capability & 1))
+			break;
+
+		/* Consult the list of known "bad" drives */
+		if (ide_dmaproc(ide_dma_bad_drive, drive)) {
+			dma_func = ide_dma_off;
+			break;
+		}
+
+		if (id->field_valid & 2) {
+			if  (id->dma_mword & 7 || id->dma_1word & 7)
+				dma_func = ide_dma_on;
+			break;
+		}
+
+		if (ide_dmaproc(ide_dma_good_drive, drive)) {
+			dma_func = ide_dma_on;
+			break;
+		}
+	} while (0);
+
+	return HWIF(drive)->dmaproc(dma_func, drive);
+}
+
+/*
+ * Our own dmaproc, only to intercept ide_dma_check
+ */
+static int sl82c105_dmaproc(ide_dma_action_t func, ide_drive_t *drive)
+{
+	switch (func) {
+	case ide_dma_check:
+		return sl82c105_check_drive(drive);
+	case ide_dma_on:
+		if (config_for_dma(drive))
+			func = ide_dma_off;
+		/* fall through */
+	case ide_dma_off_quietly:
+	case ide_dma_off:
+		config_for_pio(drive, 4, 0);
+		break;
+	default:
+		break;
+	}
+	return ide_dmaproc(func, drive);
+}
+
+/*
+ * We only deal with PIO mode here - DMA mode 'using_dma' is not
+ * initialised at the point that this function is called.
+ */
+static void tune_sl82c105(ide_drive_t *drive, byte pio)
+{
+	config_for_pio(drive, pio, 1);
+
+	/*
+	 * We support 32-bit I/O on this interface, and it
+	 * doesn't have problems with interrupts.
+	 */
+	drive->io_32bit = 1;
+	drive->unmask = 1;
+}
+
+/*
+ * Return the revision of the Winbond bridge
+ * which this function is part of.
+ */
+static unsigned int sl82c105_bridge_revision(struct pci_dev *dev)
 {
+	struct pci_dev *bridge;
 	unsigned char rev;
 
-	pci_read_config_byte(hwif->pci_dev, PCI_REVISION_ID, &rev);
+	bridge = pci_find_device(PCI_VENDOR_ID_WINBOND, PCI_DEVICE_ID_WINBOND_83C553, NULL);
 
+	/*
+	 * If we are part of a Winbond 553
+	 */
+	if (!bridge || bridge->class >> 8 != PCI_CLASS_BRIDGE_ISA)
+		return -1;
+
+	if (bridge->bus != dev->bus ||
+	    PCI_SLOT(bridge->devfn) != PCI_SLOT(dev->devfn))
+		return -1;
+
+	/*
+	 * We need to find function 0's revision, not function 1
+	 */
+	pci_read_config_byte(bridge, PCI_REVISION_ID, &rev);
+
+	return rev;
+}
+
+/*
+ * Enable the PCI device
+ */
+unsigned int __init pci_init_sl82c105(struct pci_dev *dev, const char *msg)
+{
+	unsigned char ctrl_stat;
+
+	/*
+	 * Enable the ports
+	 */
+	pci_read_config_byte(dev, 0x40, &ctrl_stat);
+	pci_write_config_byte(dev, 0x40, ctrl_stat | 0x33);
+
+	return dev->irq;
+}
+
+void __init dma_init_sl82c105(ide_hwif_t *hwif, unsigned long dma_base)
+{
+	unsigned int rev;
+	byte dma_state;
+
+	dma_state = inb(dma_base + 2);
+	rev = sl82c105_bridge_revision(hwif->pci_dev);
 	if (rev <= 5) {
 		hwif->autodma = 0;
 		hwif->drives[0].autotune = 1;
 		hwif->drives[1].autotune = 1;
-		printk("    %s: revision %d, Bus-Master DMA disabled\n",
+		printk("    %s: Winbond 553 bridge revision %d, BM-DMA disabled\n",
 		       hwif->name, rev);
+		dma_state &= ~0x60;
+	} else {
+		dma_state |= 0x60;
+		hwif->autodma = 1;
 	}
-	ide_setup_dma(hwif, dmabase, 8);
+	outb(dma_state, dma_base + 2);
+
+	hwif->dmaproc = NULL;
+	ide_setup_dma(hwif, dma_base, 8);
+	if (hwif->dmaproc)
+		hwif->dmaproc = sl82c105_dmaproc;
 }
 
+/*
+ * Initialise the chip
+ */
 void __init ide_init_sl82c105(ide_hwif_t *hwif)
 {
-	struct pci_dev *dev = hwif->pci_dev;
+	hwif->tuneproc = tune_sl82c105;
+}
 
-#ifdef CONFIG_ARCH_NETWINDER
-	unsigned char ctrl_stat;
+#else
 
-	pci_read_config_byte(dev, 0x40, &ctrl_stat);
-	pci_write_config_byte(dev, 0x40, ctrl_stat | 0x33);
+unsigned int pci_init_sl82c105(struct pci_dev *dev, const char *msg)
+{
+	return ide_special_settings(dev, msg);
+}
 
-	hwif->tuneproc = tune_sl82c105;
-#else
+void dma_init_sl82c105(ide_hwif_t *hwif, unsigned long dma_base)
+{
+	ide_setup_dma(hwif, dma_base, 8);
+}
+
+void __init ide_init_sl82c105(ide_hwif_t *hwif)
+{
+	struct pci_dev *dev = hwif->pci_dev;
 	unsigned short t16;
 	unsigned int t32;
 	pci_read_config_word(dev, PCI_COMMAND, &t16);
@@ -134,5 +303,6 @@
 	printk("IDE control/status register: %08x\n",t32);
 	pci_write_config_dword(dev, 0x40, 0x10ff08a1);
 #endif /* CONFIG_MBX */
-#endif
 }
+#endif
+
diff -urN linux-2.4.6-pre5/drivers/isdn/avmb1/c4.c linux/drivers/isdn/avmb1/c4.c
--- linux-2.4.6-pre5/drivers/isdn/avmb1/c4.c	Mon Dec  3 22:49:01 2001
+++ linux/drivers/isdn/avmb1/c4.c	Mon Dec  3 22:49:11 2001
@@ -1,5 +1,5 @@
 /*
- * $Id: c4.c,v 1.20.6.8 2001/05/17 21:15:33 kai Exp $
+ * $Id: c4.c,v 1.20.6.10 2001/06/09 15:14:15 kai Exp $
  * 
  * Module for AVM C4 & C2 card.
  * 
@@ -27,7 +27,7 @@
 #include "capilli.h"
 #include "avmcard.h"
 
-static char *revision = "$Revision: 1.20.6.9 $";
+static char *revision = "$Revision: 1.20.6.10 $";
 
 #undef CONFIG_C4_DEBUG
 #undef CONFIG_C4_POLLDEBUG
diff -urN linux-2.4.6-pre5/drivers/isdn/avmb1/capi.c linux/drivers/isdn/avmb1/capi.c
--- linux-2.4.6-pre5/drivers/isdn/avmb1/capi.c	Sat May 19 17:54:14 2001
+++ linux/drivers/isdn/avmb1/capi.c	Mon Dec  3 22:49:11 2001
@@ -1,5 +1,5 @@
 /*
- * $Id: capi.c,v 1.44.6.11 2001/05/17 20:41:51 kai Exp $
+ * $Id: capi.c,v 1.44.6.12 2001/06/09 15:14:15 kai Exp $
  *
  * CAPI 2.0 Interface for Linux
  *
@@ -43,7 +43,7 @@
 #include "capifs.h"
 #endif
 
-static char *revision = "$Revision: 1.44.6.11 $";
+static char *revision = "$Revision: 1.44.6.12 $";
 
 MODULE_AUTHOR("Carsten Paeth (calle@calle.in-berlin.de)");
 
@@ -256,7 +256,6 @@
 void capiminor_free(struct capiminor *mp)
 {
 	struct capiminor **pp;
-	struct sk_buff *skb;
 
 	pp = &minors;
 	while (*pp) {
@@ -264,12 +263,9 @@
 			*pp = (*pp)->next;
 			if (mp->ttyskb) kfree_skb(mp->ttyskb);
 			mp->ttyskb = 0;
-			while ((skb = skb_dequeue(&mp->recvqueue)) != 0)
-				kfree_skb(skb);
-			while ((skb = skb_dequeue(&mp->inqueue)) != 0)
-				kfree_skb(skb);
-			while ((skb = skb_dequeue(&mp->outqueue)) != 0)
-				kfree_skb(skb);
+			skb_queue_purge(&mp->recvqueue);
+			skb_queue_purge(&mp->inqueue);
+			skb_queue_purge(&mp->outqueue);
 			capiminor_del_all_ack(mp);
 			kmem_cache_free(capiminor_cachep, mp);
 			MOD_DEC_USE_COUNT;
@@ -411,15 +407,12 @@
 static void capidev_free(struct capidev *cdev)
 {
 	struct capidev **pp;
-	struct sk_buff *skb;
 
 	if (cdev->applid)
 		(*capifuncs->capi_release) (cdev->applid);
 	cdev->applid = 0;
 
-	while ((skb = skb_dequeue(&cdev->recvqueue)) != 0) {
-		kfree_skb(skb);
-	}
+	skb_queue_purge(&cdev->recvqueue);
 	
 	pp=&capidev_openlist;
 	while (*pp && *pp != cdev) pp = &(*pp)->next;
diff -urN linux-2.4.6-pre5/drivers/isdn/avmb1/kcapi.c linux/drivers/isdn/avmb1/kcapi.c
--- linux-2.4.6-pre5/drivers/isdn/avmb1/kcapi.c	Mon Dec  3 22:49:01 2001
+++ linux/drivers/isdn/avmb1/kcapi.c	Mon Dec  3 22:49:11 2001
@@ -1,5 +1,5 @@
 /*
- * $Id: kcapi.c,v 1.21.6.6 2001/05/17 20:41:51 kai Exp $
+ * $Id: kcapi.c,v 1.21.6.7 2001/06/09 15:14:15 kai Exp $
  * 
  * Kernel CAPI 2.0 Module
  * 
@@ -30,7 +30,7 @@
 #include <linux/b1lli.h>
 #endif
 
-static char *revision = "$Revision: 1.21.6.6 $";
+static char *revision = "$Revision: 1.21.6.7 $";
 
 /* ------------------------------------------------------------- */
 
@@ -1129,14 +1129,12 @@
 
 static __u16 capi_release(__u16 applid)
 {
-	struct sk_buff *skb;
 	int i;
 
 	if (!VALID_APPLID(applid) || APPL(applid)->releasing)
 		return CAPI_ILLAPPNR;
 	APPL(applid)->releasing++;
-	while ((skb = skb_dequeue(&APPL(applid)->recv_queue)) != 0)
-		kfree_skb(skb);
+	skb_queue_purge(&APPL(applid)->recv_queue);
 	for (i = 0; i < CAPI_MAXCONTR; i++) {
 		if (cards[i].cardstate != CARD_RUNNING)
 			continue;
diff -urN linux-2.4.6-pre5/drivers/isdn/eicon/common.c linux/drivers/isdn/eicon/common.c
--- linux-2.4.6-pre5/drivers/isdn/eicon/common.c	Sat May 19 17:43:06 2001
+++ linux/drivers/isdn/eicon/common.c	Mon Dec  3 22:49:11 2001
@@ -857,7 +857,7 @@
 {
 	int i;
 
-	bzero(card_list, sizeof(dia_card_list_t));
+	memset(card_list, 0, sizeof(dia_card_list_t));
 
 	for(i = 0; i < DivasCardNext; i++)
 	{
diff -urN linux-2.4.6-pre5/drivers/isdn/eicon/linchr.c linux/drivers/isdn/eicon/linchr.c
--- linux-2.4.6-pre5/drivers/isdn/eicon/linchr.c	Fri Mar  2 11:12:08 2001
+++ linux/drivers/isdn/eicon/linchr.c	Mon Dec  3 22:49:11 2001
@@ -46,161 +46,110 @@
 int do_ioctl(struct inode *pDivasInode, struct file *pDivasFile, 
 			 unsigned int command, unsigned long arg)
 {
-	dia_load_t *pDivaLoad;
-	dia_start_t *pDivaStart;
-	dia_config_t *pDivaConfig;
-	dia_log_t *pDivaLog;
 	byte *pUserCards, card_i;
 	word wCardNum;
-	mem_block_t *mem_block;
 
 	switch (command)
 	{
 		case DIA_IOCTL_CONFIG:
-			pDivaConfig = (dia_config_t *) arg;
-			
-			if (!verify_area(VERIFY_READ, pDivaConfig, sizeof(dia_config_t)))
-			{
-				DivasCardConfig(pDivaConfig);
-			}
-			else
-			{
-				printk(KERN_WARNING "Divas: Unable to complete CONFIG ioctl (verify area failed)\n");
-				return -1;
-			}
-				return 0;
+		{
+			dia_config_t DivaConfig;
+			if (copy_from_user(&DivaConfig, (void *)arg, sizeof(dia_config_t)))
+				return -EFAULT;
+			DivasCardConfig(&DivaConfig);
+			return 0;
+		}
 
 		case DIA_IOCTL_DETECT:
 			pUserCards = (byte *) arg;
 
 			if (!verify_area(VERIFY_WRITE, pUserCards, 20))
 			{
-				put_user(DivasCardNext, pUserCards++);
+				if(__put_user(DivasCardNext, pUserCards++))
+					return -EFAULT;
 
 				for (card_i=1; card_i < 20; card_i++)
 				{
-					put_user((byte) DivasCards[card_i - 1].cfg.card_type, pUserCards++);
+					if(__put_user((byte) DivasCards[card_i - 1].cfg.card_type, pUserCards++))
+						return -EFAULT;
 				}
 			}
-			else
-			{
-				printk(KERN_WARNING "Divas: Unable to complete DETECT ioctl (verify area failed)\n");
-				return -1;
-			}
+			else return -EFAULT;
+
 			return 0;
 
 		case DIA_IOCTL_START:
-			pDivaStart = (dia_start_t *) arg;
-			
-			if (!verify_area(VERIFY_READ, pDivaStart, sizeof(dia_start_t)))
-			{
-				return DivasCardStart(pDivaStart->card_id);
-			}
-			else
-			{
-				printk(KERN_WARNING "Divas: Unable to complete START ioctl (verify area failed)\n");
-				return -1;
-			}
-
+		{
+			dia_start_t DivaStart;
+			if (copy_from_user(&DivaStart, (void *)arg, sizeof(dia_start_t)))
+				return -EFAULT;
+			return DivasCardStart(DivaStart.card_id);
+		}
 
 		case DIA_IOCTL_FLAVOUR:
 			return 0;
 
 		case DIA_IOCTL_LOAD:
-			pDivaLoad = (dia_load_t *) arg;
-			if (!verify_area(VERIFY_READ, pDivaLoad->code,pDivaLoad->length))
+		{
+			dia_load_t DivaLoad;
+			if(copy_from_user(&DivaLoad, (void *)arg, sizeof(dia_load_t)))
+				return -EFAULT;
+			if (!verify_area(VERIFY_READ, DivaLoad.code,DivaLoad.length))
 			{
-				if (DivasCardLoad(pDivaLoad))
+				if (DivasCardLoad(&DivaLoad))
 				{
 					printk(KERN_WARNING "Divas: Error loading DIVA Server adapter\n");
 					return -EINVAL;
 				}
+				return 0;
 			}
-			else
-			{
-				printk(KERN_WARNING "Divas: Error in LOAD parameters (verify failed)\n");
-				return -EINVAL;
-			}
-			return 0;
-
+			return -EFAULT;
+		}
 		case DIA_IOCTL_LOG:
-			pDivaLog = (dia_log_t *) arg;
-			
-			if (!verify_area(VERIFY_READ, pDivaLog, sizeof(dia_log_t)))
-			{
-				DivasLog(pDivaLog);
-			}
-			else
-			{
-				printk(KERN_WARNING "Divas: Unable to complete LOG ioctl (verify area failed)\n");
-				return -1;
-			}
+		{
+			dia_log_t DivaLog;
+			if (copy_from_user(&DivaLog, (void *) arg, sizeof(dia_log_t)))
+				return -EFAULT;
+			DivasLog(&DivaLog);
 			return 0;
+		}
 
 		case DIA_IOCTL_XLOG_REQ:
-			
-			if (!verify_area(VERIFY_READ, (void *)arg, sizeof(word)))
-			{
-				wCardNum = * (word *) arg;
-				DivasXlogReq(wCardNum);
-			}
-			else
-			{
-				printk(KERN_WARNING "Divas: Unable to complete XLOG_REQ ioctl (verify area failed)\n");
-				return -1;
-			}
+			if(get_user(wCardNum, (word *) arg))
+				return -EFAULT;
+			DivasXlogReq(wCardNum);
 			return 0;
 
 		case DIA_IOCTL_GET_NUM:
-			
-			if (!verify_area(VERIFY_WRITE, (void *)arg, sizeof(int)))
-			{
-				* (int *) arg = DivasCardNext;
-			}
-			else
-			{
-				printk(KERN_WARNING "Divas: Unable to complete GET_NUM ioctl (verify area failed)\n");
-				return -1;
-			}
+			if(put_user(DivasCardNext, (int *)arg))
+				return -EFAULT;
 			return 0;
 
 		case DIA_IOCTL_GET_LIST:
+		{
+			dia_card_list_t cards;
 			DPRINTF(("divas: DIA_IOCTL_GET_LIST"));
-			
-			if (!verify_area(VERIFY_WRITE, (void *)arg, sizeof(dia_card_list_t)))
-			{
-				DivasGetList((dia_card_list_t *)arg);
-			}
-			else
-			{
-				printk(KERN_WARNING "Divas: Unable to complete GET_LIST ioctl (verify area failed)\n");
-				return -1;
-			}
+			DivasGetList(&cards);
+			if(copy_to_user((void *)arg, &cards, sizeof(cards)))
+				return -EFAULT;
 			return 0;
-
+		}
 		case DIA_IOCTL_GET_MEM:
-			mem_block = (mem_block_t *) arg;
-			
-			if (!verify_area(VERIFY_WRITE, mem_block, sizeof(mem_block_t)))
-			{
-				DivasGetMem(mem_block);
-			}
-			else
-			{
-				printk(KERN_WARNING "Divas: Unable to complete GET_MEM ioctl (verify area failed)\n");
-				return -1;
-			}
+		{
+			mem_block_t mem_block;
+			if (copy_from_user(&mem_block, (void *)arg, sizeof(mem_block_t)))
+				return -EFAULT;
+			DivasGetMem(&mem_block);
 			return 0;
+		}
 
 		case DIA_IOCTL_UNLOCK:
 			UnlockDivas();
 			return 0;
 
 		default:
-			printk(KERN_WARNING "Divas: Unknown IOCTL Received by DIVA Server Driver(%d)\n", command);
 			return -EINVAL;
 	}
-	
 	return -EINVAL;
 }
 
diff -urN linux-2.4.6-pre5/drivers/macintosh/mac_hid.c linux/drivers/macintosh/mac_hid.c
--- linux-2.4.6-pre5/drivers/macintosh/mac_hid.c	Sun Sep 17 09:48:05 2000
+++ linux/drivers/macintosh/mac_hid.c	Mon Dec  3 22:49:11 2001
@@ -15,6 +15,7 @@
 #include <linux/proc_fs.h>
 #include <linux/sysctl.h>
 #include <linux/input.h>
+#include <linux/module.h>
 
 #ifdef CONFIG_MAC_ADBKEYCODES
 #include <linux/keyboard.h>
@@ -401,6 +402,8 @@
 	return keyboard_sends_linux_keycodes;
 }
 
+EXPORT_SYMBOL(mac_hid_keyboard_sends_linux_keycodes);
+
 static int __init mac_hid_setup(char *str)
 {
 	int ints[2];
@@ -448,6 +451,8 @@
 	return 0;
 }
 
+EXPORT_SYMBOL(mac_hid_mouse_emulate_buttons);
+
 static void emumousebtn_input_register(void)
 {
 	emumousebtn.name = "Macintosh mouse button emulation";
@@ -473,9 +478,19 @@
 #ifdef CONFIG_MAC_ADBKEYCODES
 	memcpy(pc_key_maps_save, key_maps, sizeof(key_maps));
 
-	if (!keyboard_sends_linux_keycodes)
+	if (!keyboard_sends_linux_keycodes) {
+#ifdef CONFIG_MAGIC_SYSRQ
+		ppc_md.ppc_kbd_sysrq_xlate   = mac_hid_kbd_sysrq_xlate;
+		SYSRQ_KEY                = 0x69;
+#endif
 		memcpy(key_maps, mac_key_maps_save, sizeof(key_maps));
+	} else {
+#ifdef CONFIG_MAGIC_SYSRQ
+		ppc_md.ppc_kbd_sysrq_xlate   = pckbd_sysrq_xlate;
+		SYSRQ_KEY                = 0x54;
 #endif
+	}
+#endif /* CONFIG_MAC_ADBKEYCODES */
 
 #ifdef CONFIG_MAC_EMUMOUSEBTN
 	emumousebtn_input_register();
diff -urN linux-2.4.6-pre5/drivers/macintosh/mac_keyb.c linux/drivers/macintosh/mac_keyb.c
--- linux-2.4.6-pre5/drivers/macintosh/mac_keyb.c	Sun Dec  3 17:48:19 2000
+++ linux/drivers/macintosh/mac_keyb.c	Mon Dec  3 22:49:11 2001
@@ -305,7 +305,7 @@
 	return 1;
 }
 
-int mackbd_unexpected_up(unsigned char keycode)
+char mackbd_unexpected_up(unsigned char keycode)
 {
 	return 0x80;
 }
diff -urN linux-2.4.6-pre5/drivers/macintosh/macserial.c linux/drivers/macintosh/macserial.c
--- linux-2.4.6-pre5/drivers/macintosh/macserial.c	Sun Feb  4 10:21:25 2001
+++ linux/drivers/macintosh/macserial.c	Mon Dec  3 22:49:11 2001
@@ -448,7 +448,7 @@
 		goto out;
 	info->tx_active = 0;
 
-	if (info->x_char) {
+	if (info->x_char && !info->power_wait) {
 		/* Send next char */
 		write_zsdata(info->zs_channel, info->x_char);
 		info->x_char = 0;
@@ -456,7 +456,8 @@
 		goto out;
 	}
 
-	if ((info->xmit_cnt <= 0) || info->tty->stopped || info->tx_stopped) {
+	if ((info->xmit_cnt <= 0) || info->tty->stopped || info->tx_stopped
+	    || info->power_wait) {
 		write_zsreg(info->zs_channel, 0, RES_Tx_P);
 		goto out;
 	}
@@ -474,6 +475,14 @@
 	restore_flags(flags);
 }
 
+static void powerup_done(unsigned long data)
+{
+	struct mac_serial *info = (struct mac_serial *) data;
+
+	info->power_wait = 0;
+	transmit_chars(info);
+}
+
 static _INLINE_ void status_handle(struct mac_serial *info)
 {
 	unsigned char status;
@@ -730,7 +739,7 @@
 	}
 }
 
-static int startup(struct mac_serial * info, int can_sleep)
+static int startup(struct mac_serial * info)
 {
 	int delay;
 
@@ -753,6 +762,18 @@
 
 	setup_scc(info);
 
+	if (delay) {
+		unsigned long flags;
+
+		/* delay is in ms */
+		save_flags(flags);
+		cli();
+		info->power_wait = 1;
+		mod_timer(&info->powerup_timer,
+			  jiffies + (delay * HZ + 999) / 1000);
+		restore_flags(flags);
+	}
+
 	OPNDBG("enabling IRQ on ttyS%d (irq %d)...\n", info->line, info->irq);
 
 	info->flags |= ZILOG_INITIALIZED;
@@ -761,15 +782,6 @@
 		enable_irq(info->rx_dma_irq);
 	}
 
-	if (delay) {
-		if (can_sleep) {
-			/* we need to wait a bit before using the port */
-			current->state = TASK_INTERRUPTIBLE;
-			schedule_timeout(delay * HZ / 1000);
-		} else
-			mdelay(delay);
-	}
-
 	return 0;
 }
 
@@ -863,7 +875,7 @@
 		queue_task(&tty->flip.tqueue, &tq_timer);
 }
 
-static void poll_rxdma(void *private_)
+static void poll_rxdma(unsigned long private_)
 {
 	struct mac_serial	*info = (struct mac_serial *) private_;
 	unsigned long flags;
@@ -2325,7 +2337,7 @@
 	 * Start up serial port
 	 */
 
-	retval = startup(info, 1);
+	retval = startup(info);
 	if (retval)
 		return retval;
 
@@ -2426,6 +2438,10 @@
 		zss->rx_dma_irq = ch->intrs[2].line;
 		spin_lock_init(&zss->rx_dma_lock);
 	}
+
+	init_timer(&zss->powerup_timer);
+	zss->powerup_timer.function = powerup_done;
+	zss->powerup_timer.data = (unsigned long) zss;
 }
 
 /* Ask the PROM how many Z8530s we have and initialize their zs_channels */
@@ -2680,14 +2696,7 @@
 	return 0;
 }
 
-#ifdef MODULE
-int init_module(void)
-{
-	macserial_init();
-	return 0;
-}
-
-void cleanup_module(void)
+void macserial_cleanup(void)
 {
 	int i;
 	unsigned long flags;
@@ -2717,7 +2726,9 @@
 		pmu_unregister_sleep_notifier(&serial_sleep_notifier);
 #endif /* CONFIG_PMAC_PBOOK */
 }
-#endif /* MODULE */
+
+module_init(macserial_init);
+module_exit(macserial_cleanup);
 
 #if 0
 /*
@@ -3119,7 +3130,7 @@
 			struct mac_serial *info = &zs_soft[i];
 			if (info->flags & ZILOG_SLEEPING) {
 				info->flags &= ~ZILOG_SLEEPING;
-				startup(info, 0);
+				startup(info);
 			}
 		}
 		break;
diff -urN linux-2.4.6-pre5/drivers/macintosh/macserial.h linux/drivers/macintosh/macserial.h
--- linux-2.4.6-pre5/drivers/macintosh/macserial.h	Sun Feb  4 10:21:25 2001
+++ linux/drivers/macintosh/macserial.h	Mon Dec  3 22:49:11 2001
@@ -115,6 +115,7 @@
 	char is_irda;		/* is connected to an IrDA codec */
 	unsigned char tx_active; /* character is being xmitted */
 	unsigned char tx_stopped; /* output is suspended */
+	unsigned char power_wait; /* waiting for power-up delay to expire */
 
 	/* We need to know the current clock divisor
 	 * to read the bps rate the chip has currently
@@ -186,6 +187,8 @@
 	void			*dma_priv;
 	struct timer_list	poll_dma_timer;
 #define RX_DMA_TIMER	(jiffies + 10*HZ/1000)
+
+	struct timer_list	powerup_timer;
 };
 
 
diff -urN linux-2.4.6-pre5/drivers/media/video/i2c-parport.c linux/drivers/media/video/i2c-parport.c
--- linux-2.4.6-pre5/drivers/media/video/i2c-parport.c	Wed Jul 12 16:24:33 2000
+++ linux/drivers/media/video/i2c-parport.c	Mon Dec  3 22:49:11 2001
@@ -74,6 +74,10 @@
 {
   struct parport_i2c_bus *b = kmalloc(sizeof(struct parport_i2c_bus), 
 				      GFP_KERNEL);
+  if (!b) {
+	  printk(KERN_ERR "i2c_parport: Memory allocation failed. Not attaching.\n");
+	  return;
+  }
   b->i2c = parport_i2c_bus_template;
   b->i2c.data = parport_get_port (port);
   strncpy(b->i2c.name, port->name, 32);
diff -urN linux-2.4.6-pre5/drivers/media/video/planb.c linux/drivers/media/video/planb.c
--- linux-2.4.6-pre5/drivers/media/video/planb.c	Sat May 19 17:43:06 2001
+++ linux/drivers/media/video/planb.c	Mon Dec  3 22:49:11 2001
@@ -50,6 +50,7 @@
 #include <asm/pgtable.h>
 #include <asm/page.h>
 #include <asm/irq.h>
+#include <asm/semaphore.h>
 
 #include "planb.h"
 #include "saa7196.h"
@@ -326,41 +327,14 @@
 /* misc. supporting functions */
 /******************************/
 
-static void __planb_wait(struct planb *pb)
-{
-	DECLARE_WAITQUEUE(wait, current);
-
-	add_wait_queue(&pb->lockq, &wait);
-repeat:
-	set_current_state(TASK_UNINTERRUPTIBLE);
-	if (pb->lock) {
-		schedule();
-		goto repeat;
-	}
-	remove_wait_queue(&pb->lockq, &wait);
-	current->state = TASK_RUNNING;
-}
-
-static inline void planb_wait(struct planb *pb)
-{
-	DEBUG("PlanB: planb_wait\n");
-	if(pb->lock)
-		__planb_wait(pb);
-}
-
 static inline void planb_lock(struct planb *pb)
 {
-	DEBUG("PlanB: planb_lock\n");
-	if(pb->lock)
-		__planb_wait(pb);
-	pb->lock = 1;
+	down(&pb->lock);
 }
 
 static inline void planb_unlock(struct planb *pb)
 {
-	DEBUG("PlanB: planb_unlock\n");
-	pb->lock = 0;
-	wake_up(&pb->lockq);
+	up(&pb->lock);
 }
 
 /***************/
@@ -2098,7 +2072,7 @@
 	pb->tab_size = PLANB_MAXLINES + 40;
 	pb->suspend = 0;
 	pb->lock = 0;
-	init_waitqueue_head(&pb->lockq);
+	init_MUTEX(&pb->lock);
 	pb->ch1_cmd = 0;
 	pb->ch2_cmd = 0;
 	pb->mask = 0;
diff -urN linux-2.4.6-pre5/drivers/media/video/planb.h linux/drivers/media/video/planb.h
--- linux-2.4.6-pre5/drivers/media/video/planb.h	Wed Apr 12 09:38:53 2000
+++ linux/drivers/media/video/planb.h	Mon Dec  3 22:49:11 2001
@@ -174,8 +174,7 @@
 	int	user;
 	unsigned int tab_size;
 	int     maxlines;
-	int lock;
-	wait_queue_head_t lockq;
+	struct semaphore lock;
 	unsigned int	irq;			/* interrupt number */
 	volatile unsigned int intr_mask;
 
diff -urN linux-2.4.6-pre5/drivers/media/video/videodev.c linux/drivers/media/video/videodev.c
--- linux-2.4.6-pre5/drivers/media/video/videodev.c	Sat May 19 18:13:15 2001
+++ linux/drivers/media/video/videodev.c	Mon Dec  3 22:49:11 2001
@@ -373,6 +373,8 @@
 		return;
 
 	p = create_proc_entry(name, S_IFREG|S_IRUGO|S_IWUSR, video_dev_proc_entry);
+	if (!p)
+		return;
 	p->data = vfd;
 	p->read_proc = videodev_proc_read;
 
diff -urN linux-2.4.6-pre5/drivers/media/video/zr36120.c linux/drivers/media/video/zr36120.c
--- linux-2.4.6-pre5/drivers/media/video/zr36120.c	Mon May 21 17:06:00 2001
+++ linux/drivers/media/video/zr36120.c	Mon Dec  3 22:49:11 2001
@@ -1025,7 +1025,7 @@
 		v.norm=VIDEO_MODE_PAL;
 #endif
 		/* too many inputs? no decoder -> no channels */
-		if (!ztv->have_decoder || v.channel >= ztv->card->video_inputs)
+		if (!ztv->have_decoder || v.channel < 0 ||  v.channel >= ztv->card->video_inputs)
 			return -EINVAL;
 
 		/* now determine the name of the channel */
diff -urN linux-2.4.6-pre5/drivers/mtd/Config.in linux/drivers/mtd/Config.in
--- linux-2.4.6-pre5/drivers/mtd/Config.in	Mon Dec  3 22:49:01 2001
+++ linux/drivers/mtd/Config.in	Mon Dec  3 22:49:11 2001
@@ -26,14 +26,15 @@
    if [ "$CONFIG_NFTL" = "y" -o "$CONFIG_NFTL" = "m" ]; then
       bool '    Write support for NFTL (BETA)' CONFIG_NFTL_RW
    fi
-fi
 
-source drivers/mtd/chips/Config.in
+   source drivers/mtd/chips/Config.in
+
+   source drivers/mtd/maps/Config.in
 
-source drivers/mtd/maps/Config.in
+   source drivers/mtd/devices/Config.in
 
-source drivers/mtd/devices/Config.in
+   source drivers/mtd/nand/Config.in
 
-source drivers/mtd/nand/Config.in
+fi
 
 endmenu
diff -urN linux-2.4.6-pre5/drivers/net/3c509.c linux/drivers/net/3c509.c
--- linux-2.4.6-pre5/drivers/net/3c509.c	Mon Dec  3 22:49:01 2001
+++ linux/drivers/net/3c509.c	Mon Dec  3 22:49:11 2001
@@ -192,6 +192,9 @@
 		ISAPNP_VENDOR('T', 'C', 'M'), ISAPNP_FUNCTION(0x5098),
 		(long) "3Com Etherlink III (TPC)" },
 	{	ISAPNP_ANY_ID, ISAPNP_ANY_ID,
+		ISAPNP_VENDOR('P', 'N', 'P'), ISAPNP_FUNCTION(0x80f7),
+		(long) "3Com Etherlink III compatible" },
+	{	ISAPNP_ANY_ID, ISAPNP_ANY_ID,
 		ISAPNP_VENDOR('P', 'N', 'P'), ISAPNP_FUNCTION(0x80f8),
 		(long) "3Com Etherlink III compatible" },
 	{ }	/* terminate list */
@@ -1011,8 +1014,10 @@
 MODULE_PARM_DESC(irq, "EtherLink III IRQ number(s) (assigned)");
 MODULE_PARM_DESC(xcvr,"EtherLink III tranceiver(s) (0=internal, 1=external)");
 MODULE_PARM_DESC(max_interrupt_work, "EtherLink III maximum events handled per interrupt");
+#ifdef CONFIG_ISAPNP
 MODULE_PARM(nopnp, "i");
 MODULE_PARM_DESC(nopnp, "EtherLink III disable ISA PnP support (0-1)");
+#endif	/* CONFIG_ISAPNP */
 
 int
 init_module(void)
diff -urN linux-2.4.6-pre5/drivers/net/Config.in linux/drivers/net/Config.in
--- linux-2.4.6-pre5/drivers/net/Config.in	Mon Dec  3 22:49:01 2001
+++ linux/drivers/net/Config.in	Mon Dec  3 22:49:11 2001
@@ -15,7 +15,9 @@
    fi
 fi
 
-tristate 'General Instruments Surfboard 1000' CONFIG_NET_SB1000
+if [ "$CONFIG_ISAPNP" = "y" ]; then
+   tristate 'General Instruments Surfboard 1000' CONFIG_NET_SB1000 $CONFIG_ISAPNP
+fi
 
 #
 #	Ethernet
@@ -26,12 +28,9 @@
 
 bool 'Ethernet (10 or 100Mbit)' CONFIG_NET_ETHERNET
 if [ "$CONFIG_NET_ETHERNET" = "y" ]; then
-   if [ "$CONFIG_ARM" = "y" ]; then
-      if [ "$CONFIG_ARCH_ACORN" != "y" ]; then
-	 tristate '  AM79C961A support' CONFIG_ARM_AM79C961A
-      else
-	 source drivers/acorn/net/Config.in
-      fi
+   dep_bool '  ARM EBSA110 AM79C961A support' CONFIG_ARM_AM79C961A $CONFIG_ARCH_EBSA110
+   if [ "$CONFIG_ARCH_ACORN" = "y" ]; then
+      source drivers/acorn/net/Config.in
    fi
    if [ "$CONFIG_PPC" = "y" ]; then
       tristate '  MACE (Power Mac ethernet) support' CONFIG_MACE
@@ -64,6 +63,14 @@
    if [ "$CONFIG_SUPERH" = "y" ]; then
       tristate '  National DP83902AV  support' CONFIG_STNIC
    fi
+   dep_tristate '  Sun LANCE support' CONFIG_SUNLANCE $CONFIG_SBUS
+   if [ "$CONFIG_SBUS" = "y" -o "$CONFIG_PCI" = "y" ]; then
+      tristate '  Sun Happy Meal 10/100baseT support' CONFIG_HAPPYMEAL
+   fi
+   dep_tristate '  Sun BigMAC 10/100baseT support (EXPERIMENTAL)' CONFIG_SUNBMAC $CONFIG_SBUS $CONFIG_EXPERIMENTAL
+   dep_tristate '  Sun QuadEthernet support' CONFIG_SUNQE $CONFIG_SBUS
+   dep_tristate '  Sun LANCE support' CONFIG_SUNLANCE $CONFIG_SBUS
+   dep_tristate '  Sun GEM support' CONFIG_SUNGEM $CONFIG_PCI
    bool '  3COM cards' CONFIG_NET_VENDOR_3COM
    if [ "$CONFIG_NET_VENDOR_3COM" = "y" ]; then
       dep_tristate '    3c501 "EtherLink" support' CONFIG_EL1 $CONFIG_ISA
@@ -85,24 +92,28 @@
    dep_tristate '  AMD LANCE and PCnet (AT1500 and NE2100) support' CONFIG_LANCE $CONFIG_ISA
    bool '  Western Digital/SMC cards' CONFIG_NET_VENDOR_SMC
    if [ "$CONFIG_NET_VENDOR_SMC" = "y" ]; then
-      tristate '    WD80*3 support' CONFIG_WD80x3
-      if [ "$CONFIG_MCA" = "y" ]; then
-	 tristate '    SMC Ultra MCA support' CONFIG_ULTRAMCA
+      dep_tristate '    WD80*3 support' CONFIG_WD80x3 $CONFIG_ISA
+      dep_tristate '    SMC Ultra MCA support' CONFIG_ULTRAMCA $CONFIG_MCA
+      if [ "$CONFIG_ISA" = "y" -o "$CONFIG_ISAPNP" = "y" ]; then
+         tristate '    SMC Ultra support' CONFIG_ULTRA
       fi
-      tristate '    SMC Ultra support' CONFIG_ULTRA
       dep_tristate '    SMC Ultra32 EISA support' CONFIG_ULTRA32 $CONFIG_EISA
-      tristate '    SMC 9194 support' CONFIG_SMC9194
+      dep_tristate '    SMC 9194 support' CONFIG_SMC9194 $CONFIG_ISA
    fi
    bool '  Racal-Interlan (Micom) NI cards' CONFIG_NET_VENDOR_RACAL
    if [ "$CONFIG_NET_VENDOR_RACAL" = "y" ]; then
-      dep_tristate '    NI5010 support (EXPERIMENTAL)' CONFIG_NI5010 $CONFIG_EXPERIMENTAL
-      tristate '    NI5210 support' CONFIG_NI52
-      tristate '    NI6510 support' CONFIG_NI65
+      dep_tristate '    NI5010 support (EXPERIMENTAL)' CONFIG_NI5010 $CONFIG_ISA $CONFIG_EXPERIMENTAL
+      dep_tristate '    NI5210 support' CONFIG_NI52 $CONFIG_ISA
+      dep_tristate '    NI6510 support' CONFIG_NI65 $CONFIG_ISA
    fi
    if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
-      tristate '  AT1700/1720 support (EXPERIMENTAL)' CONFIG_AT1700
+      if [ "$CONFIG_ISA" = "y" -o "$CONFIG_MCA" = "y" ]; then
+         tristate '  AT1700/1720 support (EXPERIMENTAL)' CONFIG_AT1700
+      fi
+   fi
+   if [ "$CONFIG_ISA" = "y" -o "$CONFIG_EISA" = "y" -o "$CONFIG_MCA" = "y" ]; then
+      tristate '  DEPCA, DE10x, DE200, DE201, DE202, DE422 support' CONFIG_DEPCA
    fi
-   tristate '  DEPCA, DE10x, DE200, DE201, DE202, DE422 support' CONFIG_DEPCA
    if [ "$CONFIG_ISA" = "y" -o "$CONFIG_EISA" = "y" -o "$CONFIG_PCI" = "y" ]; then
       tristate '  HP 10/100VG PCLAN (ISA, EISA, PCI) support' CONFIG_HP100
    fi
@@ -131,7 +142,7 @@
       tristate '  NE/2 (ne2000 MCA version) support' CONFIG_NE2_MCA
       tristate '  IBM LAN Adapter/A support' CONFIG_IBMLANA
    fi
-   bool '  EISA, VLB, PCI and on board controllers' CONFIG_NET_PCI
+   dep_bool '  EISA, VLB, PCI and on board controllers' CONFIG_NET_PCI
    if [ "$CONFIG_NET_PCI" = "y" ]; then
       dep_tristate '    AMD PCnet32 PCI support' CONFIG_PCNET32 $CONFIG_PCI
       dep_tristate '    Adaptec Starfire support (EXPERIMENTAL)' CONFIG_ADAPTEC_STARFIRE $CONFIG_PCI $CONFIG_EXPERIMENTAL
@@ -139,16 +150,19 @@
 	 dep_tristate '    Ansel Communications EISA 3200 support (EXPERIMENTAL)' CONFIG_AC3200 $CONFIG_EXPERIMENTAL
       fi
 
-      tristate '    Apricot Xen-II on board Ethernet' CONFIG_APRICOT
+      dep_tristate '    Apricot Xen-II on board Ethernet' CONFIG_APRICOT $CONFIG_ISA
       dep_tristate '    CS89x0 support' CONFIG_CS89x0 $CONFIG_ISA
       dep_tristate '    DECchip Tulip (dc21x4x) PCI support' CONFIG_TULIP $CONFIG_PCI
+      if [ "$CONFIG_TULIP" = "y" -o "$CONFIG_TULIP" = "m" ]; then
+         dep_bool '      New bus configuration (EXPERIMENTAL)' CONFIG_TULIP_MWI $CONFIG_EXPERIMENTAL
+         bool '      Use PCI shared mem for NIC registers' CONFIG_TULIP_MMIO
+      fi
       if [ "$CONFIG_PCI" = "y" -o "$CONFIG_EISA" = "y" ]; then
          tristate '    Generic DECchip & DIGITAL EtherWORKS PCI/EISA' CONFIG_DE4X5
          tristate '    Digi Intl. RightSwitch SE-X support' CONFIG_DGRS
       fi
       dep_tristate '    Davicom DM910x/DM980x support' CONFIG_DM9102 $CONFIG_PCI
       dep_tristate '    EtherExpressPro/100 support' CONFIG_EEPRO100 $CONFIG_PCI
-      dep_mbool '      Enable Power Management (EXPERIMENTAL)' CONFIG_EEPRO100_PM $CONFIG_EEPRO100 $CONFIG_EXPERIMENTAL
       dep_tristate '    Mylex EISA LNE390A/B support (EXPERIMENTAL)' CONFIG_LNE390 $CONFIG_EISA $CONFIG_EXPERIMENTAL
       dep_tristate '    Myson MTD-8xx PCI Ethernet support' CONFIG_FEALNX $CONFIG_PCI
       dep_tristate '    National Semiconductor DP8381x series PCI Ethernet support' CONFIG_NATSEMI $CONFIG_PCI
@@ -167,9 +181,8 @@
       fi
       dep_tristate '    VIA Rhine support' CONFIG_VIA_RHINE $CONFIG_PCI
       dep_tristate '    Winbond W89c840 Ethernet support' CONFIG_WINBOND_840 $CONFIG_PCI
-      dep_tristate '    Sun Happy Meal 10/100baseT PCI support' CONFIG_HAPPYMEAL $CONFIG_PCI
       if [ "$CONFIG_OBSOLETE" = "y" ]; then
-	 bool '    Zenith Z-Note support (EXPERIMENTAL)' CONFIG_ZNET
+	 dep_bool '    Zenith Z-Note support (EXPERIMENTAL)' CONFIG_ZNET $CONFIG_ISA
       fi
       if [ "$CONFIG_EXPERIMENTAL" = "y" -a "$CONFIG_ORION" = "y" ]; then
 	 bool '    Philips SAA9730 Ethernet support (EXPERIMENTAL)' CONFIG_LAN_SAA9730
@@ -180,8 +193,8 @@
       if [ "$CONFIG_ISA" = "y" -a "$CONFIG_X86" = "y" ]; then
          tristate '    AT-LAN-TEC/RealTek pocket adapter support' CONFIG_ATP
       fi
-      tristate '    D-Link DE600 pocket adapter support' CONFIG_DE600
-      tristate '    D-Link DE620 pocket adapter support' CONFIG_DE620
+      dep_tristate '    D-Link DE600 pocket adapter support' CONFIG_DE600 $CONFIG_ISA
+      dep_tristate '    D-Link DE620 pocket adapter support' CONFIG_DE620 $CONFIG_ISA
    fi
 fi
 
@@ -198,10 +211,9 @@
 if [ "$CONFIG_ACENIC" != "n" ]; then
    bool '  Omit support for old Tigon I based AceNICs' CONFIG_ACENIC_OMIT_TIGON_I
 fi
+dep_tristate 'MyriCOM Gigabit Ethernet support' CONFIG_MYRI_SBUS $CONFIG_SBUS
 dep_tristate 'Packet Engines Hamachi GNIC-II support' CONFIG_HAMACHI $CONFIG_PCI
-if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
-   dep_tristate 'Packet Engines Yellowfin Gigabit-NIC support (EXPERIMENTAL)' CONFIG_YELLOWFIN $CONFIG_PCI
-fi
+dep_tristate 'Packet Engines Yellowfin Gigabit-NIC support (EXPERIMENTAL)' CONFIG_YELLOWFIN $CONFIG_PCI $CONFIG_EXPERIMENTAL
 dep_tristate 'SysKonnect SK-98xx support' CONFIG_SK98LIN $CONFIG_PCI
 
 endmenu
@@ -211,14 +223,14 @@
    if [ "$CONFIG_PCI" = "y" -o "$CONFIG_EISA" = "y" ]; then
       tristate '  Digital DEFEA and DEFPA adapter support' CONFIG_DEFXX
    fi
-   tristate '  SysKonnect FDDI PCI support' CONFIG_SKFP
+   dep_tristate '  SysKonnect FDDI PCI support' CONFIG_SKFP $CONFIG_PCI
 fi
 
 if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
    if [ "$CONFIG_INET" = "y" ]; then
       bool 'HIPPI driver support (EXPERIMENTAL)' CONFIG_HIPPI
       if [ "$CONFIG_HIPPI" = "y" -a "$CONFIG_PCI" = "y" ]; then
-         tristate '  Essential RoadRunner HIPPI PCI adapter support' CONFIG_ROADRUNNER
+         dep_tristate '  Essential RoadRunner HIPPI PCI adapter support' CONFIG_ROADRUNNER $CONFIG_PCI
          if [ "$CONFIG_ROADRUNNER" != "n" ]; then
    	    bool '    Use large TX/RX rings' CONFIG_ROADRUNNER_LARGE_RINGS
          fi
@@ -226,9 +238,7 @@
    fi
 fi
 
-if [ ! "$CONFIG_PARPORT" = "n" ]; then
-   dep_tristate 'PLIP (parallel port) support' CONFIG_PLIP $CONFIG_PARPORT
-fi
+dep_tristate 'PLIP (parallel port) support' CONFIG_PLIP $CONFIG_PARPORT
 
 tristate 'PPP (point-to-point protocol) support' CONFIG_PPP
 if [ ! "$CONFIG_PPP" = "n" ]; then
diff -urN linux-2.4.6-pre5/drivers/net/am79c961a.c linux/drivers/net/am79c961a.c
--- linux-2.4.6-pre5/drivers/net/am79c961a.c	Thu Apr 12 12:15:25 2001
+++ linux/drivers/net/am79c961a.c	Mon Dec  3 22:49:11 2001
@@ -1,7 +1,7 @@
 /*
  *  linux/drivers/net/am79c961.c
  *
- *  by Russell King <rmk@arm.linux.org.uk> 1995-2000.
+ *  by Russell King <rmk@arm.linux.org.uk> 1995-2001.
  *
  * 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
@@ -10,9 +10,9 @@
  * Derived from various things including skeleton.c
  *
  * This is a special driver for the am79c961A Lance chip used in the
- * Intel (formally Digital Equipment Corp) EBSA110 platform.
+ * Intel (formally Digital Equipment Corp) EBSA110 platform.  Please
+ * note that this can not be built as a module (it doesn't make sense).
  */
-#include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/sched.h>
 #include <linux/types.h>
@@ -35,7 +35,6 @@
 #include <asm/irq.h>
 #include <asm/io.h>
 #include <asm/dma.h>
-#include <asm/ecard.h>
 
 #define TX_BUFFERS 15
 #define RX_BUFFERS 25
@@ -46,45 +45,42 @@
 
 static unsigned int net_debug = NET_DEBUG;
 
-static char *version = "am79c961 ethernet driver (c) 1995 R.M.King v0.02\n";
+static const char version[] =
+	"am79c961 ethernet driver (C) 1995-2001 Russell King v0.04\n";
 
 /* --------------------------------------------------------------------------- */
 
 #ifdef __arm__
-static void
-write_rreg (unsigned long base, unsigned int reg, unsigned short val)
+static void write_rreg(u_long base, u_int reg, u_int val)
 {
 	__asm__("str%?h	%1, [%2]	@ NET_RAP
 		str%?h	%0, [%2, #-4]	@ NET_RDP
-		" : : "r" (val), "r" (reg), "r" (0xf0000464));
+		" : : "r" (val), "r" (reg), "r" (ISAIO_BASE + 0x0464));
 }
 
-static inline unsigned short
-read_rreg (unsigned int base_addr, unsigned int reg)
+static inline unsigned short read_rreg(u_long base_addr, u_int reg)
 {
 	unsigned short v;
 	__asm__("str%?h	%1, [%2]	@ NET_RAP
 		ldr%?h	%0, [%2, #-4]	@ NET_RDP
-		" : "=r" (v): "r" (reg), "r" (0xf0000464));
+		" : "=r" (v): "r" (reg), "r" (ISAIO_BASE + 0x0464));
 	return v;
 }
 
-static inline void
-write_ireg (unsigned long base, unsigned int reg, unsigned short val)
+static inline void write_ireg(u_long base, u_int reg, u_int val)
 {
 	__asm__("str%?h	%1, [%2]	@ NET_RAP
 		str%?h	%0, [%2, #8]	@ NET_IDP
-		" : : "r" (val), "r" (reg), "r" (0xf0000464));
+		" : : "r" (val), "r" (reg), "r" (ISAIO_BASE + 0x0464));
 }
 
-#define am_writeword(dev,off,val)\
-	__asm__("str%?h	%0, [%1]" : : \
-		"r" ((val) & 0xffff), "r" (0xe0000000 + ((off) << 1)));
+#define am_writeword(dev,off,val) __raw_writew(val, ISAMEM_BASE + ((off) << 1))
+#define am_readword(dev,off)      __raw_readw(ISAMEM_BASE + ((off) << 1))
 
 static inline void
 am_writebuffer(struct net_device *dev, u_int offset, unsigned char *buf, unsigned int length)
 {
-	offset = 0xe0000000 + (offset << 1);
+	offset = ISAMEM_BASE + (offset << 1);
 	length = (length + 1) & ~1;
 	if ((int)buf & 2) {
 		__asm__ __volatile__("str%?h	%2, [%0], #4"
@@ -114,23 +110,10 @@
 	}
 }
 
-/*
- * This reads a 16-bit quantity in little-endian
- * mode from the am79c961 buffer.
- */
-static inline unsigned short am_readword(struct net_device *dev, u_int off)
-{
-	unsigned long address = 0xe0000000 + (off << 1);
-	unsigned short val;
-
-	__asm__("ldr%?h	%0, [%1]" : "=r" (val): "r" (address));
-	return val;
-}
-
 static inline void
 am_readbuffer(struct net_device *dev, u_int offset, unsigned char *buf, unsigned int length)
 {
-	offset = 0xe0000000 + (offset << 1);
+	offset = ISAMEM_BASE + (offset << 1);
 	length = (length + 1) & ~1;
 	if ((int)buf & 2) {
 		unsigned int tmp;
@@ -274,12 +257,7 @@
 }
 
 /*
- * Open/initialize the board.  This is called (in the current kernel)
- * sometime after booting when the 'ifconfig' program is run.
- *
- * This routine should set everything up anew at each open, even
- * registers that "should" only need to be set once at boot, so that
- * there is non-reboot way to recover if something goes wrong.
+ * Open/initialize the board.
  */
 static int
 am79c961_open(struct net_device *dev)
@@ -322,8 +300,7 @@
 }
 
 /*
- * Get the current statistics.	This may be called with the card open or
- * closed.
+ * Get the current statistics.
  */
 static struct net_device_stats *am79c961_getstats (struct net_device *dev)
 {
@@ -367,7 +344,7 @@
 }
 
 /*
- * Set or clear promiscuous/multicast mode filter for this adaptor.
+ * Set or clear promiscuous/multicast mode filter for this adapter.
  */
 static void am79c961_setmulticastlist (struct net_device *dev)
 {
@@ -478,10 +455,8 @@
 	 * then the tx ring is full and we can't add another
 	 * packet.
 	 */
-	if (am_readword(dev, priv->txhdr + (priv->txhead << 3) + 2) & TMD_OWN) {
-		printk(KERN_DEBUG"tx ring full, stopping queue\n");
+	if (am_readword(dev, priv->txhdr + (priv->txhead << 3) + 2) & TMD_OWN)
 		netif_stop_queue(dev);
-	}
 
 	dev_kfree_skb(skb);
 
@@ -557,9 +532,7 @@
 	do {
 		u_int hdraddr;
 		u_int status;
-int bufnum;
 
-bufnum = priv->txtail;
 		hdraddr = priv->txhdr + (priv->txtail << 3);
 		status = am_readword (dev, hdraddr + 2);
 		if (status & TMD_OWN)
@@ -654,7 +627,6 @@
 	if (!dev)
 		goto out;
 
-	SET_MODULE_OWNER(dev);
 	priv = dev->priv;
 
 	/*
@@ -668,7 +640,7 @@
 	/*
 	 * Reset the device.
 	 */
-	inb((dev->base_addr + NET_RESET) >> 1);
+	inb(dev->base_addr + NET_RESET);
 	udelay(5);
 
 	/*
@@ -676,21 +648,20 @@
 	 * ether address.
 	 */
     	ret = -ENODEV;
-	if (inb(dev->base_addr >> 1) != 0x08 ||
-	    inb((dev->base_addr >> 1) + 1) != 00 ||
-	    inb((dev->base_addr >> 1) + 2) != 0x2b)
+	if (inb(dev->base_addr) != 0x08 ||
+	    inb(dev->base_addr + 2) != 0x00 ||
+	    inb(dev->base_addr + 4) != 0x2b)
 	    	goto nodev;
 
 	if (!request_region(dev->base_addr, 0x18, dev->name))
 		goto nodev;
 
 	am79c961_banner();
-	printk(KERN_INFO "%s: am79c961 found at %08lx, IRQ%d, ether address ",
-		dev->name, dev->base_addr, dev->irq);
+	printk(KERN_INFO "%s: ether address ", dev->name);
 
 	/* Retrive and print the ethernet address. */
 	for (i = 0; i < 6; i++) {
-		dev->dev_addr[i] = inb((dev->base_addr >> 1) + i) & 0xff;
+		dev->dev_addr[i] = inb(dev->base_addr + i * 2) & 0xff;
 		printk (i == 5 ? "%02x\n" : "%02x:", dev->dev_addr[i]);
 	}
 
@@ -715,4 +686,4 @@
 	return ret;
 }
 
-module_init(am79c961_init);
+__initcall(am79c961_init);
diff -urN linux-2.4.6-pre5/drivers/net/appletalk/ipddp.c linux/drivers/net/appletalk/ipddp.c
--- linux-2.4.6-pre5/drivers/net/appletalk/ipddp.c	Wed May 16 10:31:27 2001
+++ linux/drivers/net/appletalk/ipddp.c	Mon Dec  3 22:49:11 2001
@@ -255,22 +255,26 @@
 static int ipddp_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
 {
         struct ipddp_route *rt = (struct ipddp_route *)ifr->ifr_data;
+        struct ipddp_route rcp;
 
         if(!capable(CAP_NET_ADMIN))
                 return -EPERM;
 
+	if(copy_from_user(&rcp, rt, sizeof(rcp)))
+		return -EFAULT;
+
         switch(cmd)
         {
 		case SIOCADDIPDDPRT:
-                        return (ipddp_create(rt));
+                        return (ipddp_create(&rcp));
 
                 case SIOCFINDIPDDPRT:
-                        if(copy_to_user(rt, ipddp_find_route(rt), sizeof(struct ipddp_route)))
+                        if(copy_to_user(rt, ipddp_find_route(&rcp), sizeof(struct ipddp_route)))
                                 return -EFAULT;
                         return 0;
 
                 case SIOCDELIPDDPRT:
-                        return (ipddp_delete(rt));
+                        return (ipddp_delete(&rcp));
 
                 default:
                         return -EINVAL;
diff -urN linux-2.4.6-pre5/drivers/net/dmfe.c linux/drivers/net/dmfe.c
--- linux-2.4.6-pre5/drivers/net/dmfe.c	Mon Dec  3 22:49:02 2001
+++ linux/drivers/net/dmfe.c	Mon Dec  3 22:49:11 2001
@@ -77,6 +77,10 @@
 #include <asm/io.h>
 #include <asm/dma.h>
 
+#if BITS_PER_LONG == 64
+#error FIXME: driver does not support 64-bit platforms
+#endif
+
 
 /* Board/System/Debug information/definition ---------------- */
 #define PCI_DM9132_ID   0x91321282      /* Davicom DM9132 ID */
diff -urN linux-2.4.6-pre5/drivers/net/ewrk3.c linux/drivers/net/ewrk3.c
--- linux-2.4.6-pre5/drivers/net/ewrk3.c	Mon Dec  3 22:49:02 2001
+++ linux/drivers/net/ewrk3.c	Mon Dec  3 22:49:11 2001
@@ -1633,38 +1633,44 @@
 	u_long iobase = dev->base_addr;
 	int i, j, status = 0;
 	u_char csr;
-	union {
+	union ewrk3_addr {
 		u_char addr[HASH_TABLE_LEN * ETH_ALEN];
 		u_short val[(HASH_TABLE_LEN * ETH_ALEN) >> 1];
-	} tmp;
+	};
+	
+	union ewrk3_addr *tmp;
+
+	tmp = kmalloc(sizeof(union ewrk3_addr), GFP_KERNEL);
+	if(tmp==NULL)
+		return -ENOMEM;
 
 	switch (ioc->cmd) {
 	case EWRK3_GET_HWADDR:	/* Get the hardware address */
 		for (i = 0; i < ETH_ALEN; i++) {
-			tmp.addr[i] = dev->dev_addr[i];
+			tmp->addr[i] = dev->dev_addr[i];
 		}
 		ioc->len = ETH_ALEN;
-		if (copy_to_user(ioc->data, tmp.addr, ioc->len)) {
+		if (copy_to_user(ioc->data, tmp->addr, ioc->len))
 			status = -EFAULT;
-			break;
-		}
+		break;
+		
 	case EWRK3_SET_HWADDR:	/* Set the hardware address */
 		if (capable(CAP_NET_ADMIN)) {
-				csr = inb(EWRK3_CSR);
-				csr |= (CSR_TXD | CSR_RXD);
-				outb(csr, EWRK3_CSR);	/* Disable the TX and RX */
-
-				if (copy_from_user(tmp.addr, ioc->data, ETH_ALEN)) {
-					status = -EFAULT;
-					break;
-				}
-				for (i = 0; i < ETH_ALEN; i++) {
-					dev->dev_addr[i] = tmp.addr[i];
-					outb(tmp.addr[i], EWRK3_PAR0 + i);
-				}
+			csr = inb(EWRK3_CSR);
+			csr |= (CSR_TXD | CSR_RXD);
+			outb(csr, EWRK3_CSR);	/* Disable the TX and RX */
+
+			if (copy_from_user(tmp->addr, ioc->data, ETH_ALEN)) {
+				status = -EFAULT;
+				break;
+			}
+			for (i = 0; i < ETH_ALEN; i++) {
+				dev->dev_addr[i] = tmp->addr[i];
+				outb(tmp->addr[i], EWRK3_PAR0 + i);
+			}
 
-				csr &= ~(CSR_TXD | CSR_RXD);	/* Enable the TX and RX */
-				outb(csr, EWRK3_CSR);
+			csr &= ~(CSR_TXD | CSR_RXD);	/* Enable the TX and RX */
+			outb(csr, EWRK3_CSR);
 		} else {
 			status = -EPERM;
 		}
@@ -1691,32 +1697,28 @@
 		}
 
 		break;
-	case EWRK3_SAY_BOO:	/* Say "Boo!" to the kernel log file */
-		printk("%s: Boo!\n", dev->name);
-
-		break;
 	case EWRK3_GET_MCA:	/* Get the multicast address table */
 		spin_lock_irq(&lp->hw_lock);
 		if (lp->shmem_length == IO_ONLY) {
 			outb(0, EWRK3_IOPR);
 			outw(PAGE0_HTE, EWRK3_PIR1);
 			for (i = 0; i < (HASH_TABLE_LEN >> 3); i++) {
-				tmp.addr[i] = inb(EWRK3_DATA);
+				tmp->addr[i] = inb(EWRK3_DATA);
 			}
 		} else {
 			outb(0, EWRK3_MPR);
-			isa_memcpy_fromio(tmp.addr, lp->shmem_base + PAGE0_HTE, (HASH_TABLE_LEN >> 3));
+			isa_memcpy_fromio(tmp->addr, lp->shmem_base + PAGE0_HTE, (HASH_TABLE_LEN >> 3));
 		}
 		spin_unlock_irq(&lp->hw_lock);
 
 		ioc->len = (HASH_TABLE_LEN >> 3);
-		if (copy_to_user(ioc->data, tmp.addr, ioc->len))
+		if (copy_to_user(ioc->data, tmp->addr, ioc->len))
 			status = -EFAULT;
 
 		break;
 	case EWRK3_SET_MCA:	/* Set a multicast address */
 		if (capable(CAP_NET_ADMIN)) {
-			if (copy_from_user(tmp.addr, ioc->data, ETH_ALEN * ioc->len)) {
+			if (copy_from_user(tmp->addr, ioc->data, ETH_ALEN * ioc->len)) {
 				status = -EFAULT;
 				break;
 			}
@@ -1764,18 +1766,18 @@
 
 		break;
 	case EWRK3_GET_CSR:	/* Get the CSR Register contents */
-		tmp.addr[0] = inb(EWRK3_CSR);
+		tmp->addr[0] = inb(EWRK3_CSR);
 		ioc->len = 1;
-		if (copy_to_user(ioc->data, tmp.addr, ioc->len))
+		if (copy_to_user(ioc->data, tmp->addr, ioc->len))
 			status = -EFAULT;
 		break;
 	case EWRK3_SET_CSR:	/* Set the CSR Register contents */
 		if (capable(CAP_NET_ADMIN)) {
-			if (copy_from_user(tmp.addr, ioc->data, 1)) {
+			if (copy_from_user(tmp->addr, ioc->data, 1)) {
 				status = -EFAULT;
 				break;
 			}
-			outb(tmp.addr[0], EWRK3_CSR);
+			outb(tmp->addr[0], EWRK3_CSR);
 		} else {
 			status = -EPERM;
 		}
@@ -1784,15 +1786,15 @@
 	case EWRK3_GET_EEPROM:	/* Get the EEPROM contents */
 		if (capable(CAP_NET_ADMIN)) {
 			for (i = 0; i < (EEPROM_MAX >> 1); i++) {
-				tmp.val[i] = (short) Read_EEPROM(iobase, i);
+				tmp->val[i] = (short) Read_EEPROM(iobase, i);
 			}
 			i = EEPROM_MAX;
-			tmp.addr[i++] = inb(EWRK3_CMR);		/* Config/Management Reg. */
+			tmp->addr[i++] = inb(EWRK3_CMR);		/* Config/Management Reg. */
 			for (j = 0; j < ETH_ALEN; j++) {
-				tmp.addr[i++] = inb(EWRK3_PAR0 + j);
+				tmp->addr[i++] = inb(EWRK3_PAR0 + j);
 			}
 			ioc->len = EEPROM_MAX + 1 + ETH_ALEN;
-			if (copy_to_user(ioc->data, tmp.addr, ioc->len))
+			if (copy_to_user(ioc->data, tmp->addr, ioc->len))
 				status = -EFAULT;
 		} else {
 			status = -EPERM;
@@ -1801,12 +1803,12 @@
 		break;
 	case EWRK3_SET_EEPROM:	/* Set the EEPROM contents */
 		if (capable(CAP_NET_ADMIN)) {
-			if (copy_from_user(tmp.addr, ioc->data, EEPROM_MAX)) {
+			if (copy_from_user(tmp->addr, ioc->data, EEPROM_MAX)) {
 				status = -EFAULT;
 				break;
 			}
 			for (i = 0; i < (EEPROM_MAX >> 1); i++) {
-				Write_EEPROM(tmp.val[i], iobase, i);
+				Write_EEPROM(tmp->val[i], iobase, i);
 			}
 		} else {
 			status = -EPERM;
@@ -1814,9 +1816,9 @@
 
 		break;
 	case EWRK3_GET_CMR:	/* Get the CMR Register contents */
-		tmp.addr[0] = inb(EWRK3_CMR);
+		tmp->addr[0] = inb(EWRK3_CMR);
 		ioc->len = 1;
-		if (copy_to_user(ioc->data, tmp.addr, ioc->len))
+		if (copy_to_user(ioc->data, tmp->addr, ioc->len))
 			status = -EFAULT;
 		break;
 	case EWRK3_SET_TX_CUT_THRU:	/* Set TX cut through mode */
@@ -1838,7 +1840,7 @@
 	default:
 		status = -EOPNOTSUPP;
 	}
-
+	kfree(tmp);
 	return status;
 }
 
diff -urN linux-2.4.6-pre5/drivers/net/fealnx.c linux/drivers/net/fealnx.c
--- linux-2.4.6-pre5/drivers/net/fealnx.c	Mon Dec  3 22:49:02 2001
+++ linux/drivers/net/fealnx.c	Mon Dec  3 22:49:11 2001
@@ -886,7 +886,7 @@
 	   1 1 1   256
 	   Wait the specified 50 PCI cycles after a reset by initializing
 	   Tx and Rx queues and the address filter list. */
-#if defined(__powerpc__)
+#if defined(__powerpc__) || defined(__sparc__)
 // 89/9/1 modify, 
 //   np->bcrvalue=0x04 | 0x0x38;  /* big-endian, 256 burst length */
 	np->bcrvalue = 0x04 | 0x10;	/* big-endian, tx 8 burst length */
@@ -1166,19 +1166,17 @@
 	printk(KERN_WARNING "%s: Transmit timed out, status %8.8x,"
 	       " resetting...\n", dev->name, readl(ioaddr + ISR));
 
-#ifndef __alpha__
 	{
 		int i;
 
-		printk(KERN_DEBUG "  Rx ring %8.8x: ", (int) np->rx_ring);
+		printk(KERN_DEBUG "  Rx ring %p: ", np->rx_ring);
 		for (i = 0; i < RX_RING_SIZE; i++)
 			printk(" %8.8x", (unsigned int) np->rx_ring[i].status);
-		printk("\n" KERN_DEBUG "  Tx ring %8.8x: ", (int) np->tx_ring);
+		printk("\n" KERN_DEBUG "  Tx ring %p: ", np->tx_ring);
 		for (i = 0; i < TX_RING_SIZE; i++)
 			printk(" %4.4x", np->tx_ring[i].status);
 		printk("\n");
 	}
-#endif
 
 	/* Perhaps we should reinitialize the hardware here.  Just trigger a
 	   Tx demand for now. */
diff -urN linux-2.4.6-pre5/drivers/net/hamradio/bpqether.c linux/drivers/net/hamradio/bpqether.c
--- linux-2.4.6-pre5/drivers/net/hamradio/bpqether.c	Wed Apr 18 14:40:06 2001
+++ linux/drivers/net/hamradio/bpqether.c	Mon Dec  3 22:49:11 2001
@@ -166,7 +166,7 @@
  */
 static int bpq_check_devices(struct net_device *dev)
 {
-	struct bpqdev *bpq, *bpq_prev;
+	struct bpqdev *bpq, *bpq_prev, *bpq_next;
 	int result = 0;
 	unsigned long flags;
 
@@ -175,7 +175,8 @@
 
 	bpq_prev = NULL;
 
-	for (bpq = bpq_devices; bpq != NULL; bpq = bpq->next) {
+	for (bpq = bpq_devices; bpq != NULL; bpq = bpq_next) {
+		bpq_next = bpq->next;
 		if (!dev_get(bpq->ethname)) {
 			if (bpq_prev)
 				bpq_prev->next = bpq->next;
@@ -192,8 +193,8 @@
 			unregister_netdevice(&bpq->axdev);
 			kfree(bpq);
 		}
-
-		bpq_prev = bpq;
+		else
+			bpq_prev = bpq;
 	}
 
 	restore_flags(flags);
diff -urN linux-2.4.6-pre5/drivers/net/hamradio/scc.c linux/drivers/net/hamradio/scc.c
--- linux-2.4.6-pre5/drivers/net/hamradio/scc.c	Thu Apr 19 09:34:52 2001
+++ linux/drivers/net/hamradio/scc.c	Mon Dec  3 22:49:11 2001
@@ -216,7 +216,7 @@
 
 static unsigned char SCC_DriverName[] = "scc";
 
-static struct irqflags { unsigned char used : 1; } Ivec[16];
+static struct irqflags { unsigned char used : 1; } Ivec[NR_IRQS];
 	
 static struct scc_channel SCC_Info[2 * SCC_MAXCHIPS];	/* information per channel */
 
@@ -1484,7 +1484,7 @@
 	printk(KERN_INFO "Init Z8530 driver: %u channels, IRQ", Nchips*2);
 	
 	flag=" ";
-	for (k = 0; k < 16; k++)
+	for (k = 0; k < NR_IRQS; k++)
 		if (Ivec[k].used) 
 		{
 			printk("%s%d", flag, k);
@@ -1764,6 +1764,9 @@
 
 			if (hwcfg.irq == 2) hwcfg.irq = 9;
 
+			if (hwcfg.irq <0 || hwcfg.irq > NR_IRQS)
+				return -EINVAL;
+				
 			if (!Ivec[hwcfg.irq].used && hwcfg.irq)
 			{
 				if (request_irq(hwcfg.irq, scc_isr, SA_INTERRUPT, "AX.25 SCC", NULL))
@@ -2162,7 +2165,7 @@
 		}
 	}
 	
-	for (k=0; k < 16 ; k++)
+	for (k=0; k < NR_IRQS ; k++)
 		if (Ivec[k].used) free_irq(k, NULL);
 		
 	if (Vector_Latch)
diff -urN linux-2.4.6-pre5/drivers/net/hamradio/soundmodem/sm.h linux/drivers/net/hamradio/soundmodem/sm.h
--- linux-2.4.6-pre5/drivers/net/hamradio/soundmodem/sm.h	Mon Dec 11 13:22:15 2000
+++ linux/drivers/net/hamradio/soundmodem/sm.h	Mon Dec  3 22:49:11 2001
@@ -299,6 +299,8 @@
 
 #ifdef __i386__
 
+#include <asm/msr.h>
+
 /*
  * only do 32bit cycle counter arithmetic; we hope we won't overflow.
  * in fact, overflowing modems would require over 2THz CPU clock speeds :-)
@@ -307,10 +309,10 @@
 #define time_exec(var,cmd)                                              \
 ({                                                                      \
 	if (cpu_has_tsc) {                                              \
-		unsigned int cnt1, cnt2, cnt3;                          \
-		__asm__(".byte 0x0f,0x31" : "=a" (cnt1), "=d" (cnt3));  \
+		unsigned int cnt1, cnt2;                                \
+		rdtscl(cnt1);                                           \
 		cmd;                                                    \
-		__asm__(".byte 0x0f,0x31" : "=a" (cnt2), "=d" (cnt3));  \
+		rdtscl(cnt2);                                           \
 		var = cnt2-cnt1;                                        \
 	} else {                                                        \
 		cmd;                                                    \
diff -urN linux-2.4.6-pre5/drivers/net/hamradio/soundmodem/sm_wss.c linux/drivers/net/hamradio/soundmodem/sm_wss.c
--- linux-2.4.6-pre5/drivers/net/hamradio/soundmodem/sm_wss.c	Tue Jul 18 16:55:19 2000
+++ linux/drivers/net/hamradio/soundmodem/sm_wss.c	Mon Dec  3 22:49:11 2001
@@ -172,8 +172,10 @@
 		/* MCE and interface config reg */
 		write_codec(dev, 0x49, fdx ? 0x8 : 0xc);
 	outb(0xb, WSS_CODEC_IA(dev->base_addr)); /* leave MCE */
-	if (SCSTATE->crystal && !fullcalib)
+	if (SCSTATE->crystal && !fullcalib) {
+		restore_flags(flags);
 		return 0;
+	}
 	/*
 	 * wait for ACI start
 	 */
diff -urN linux-2.4.6-pre5/drivers/net/natsemi.c linux/drivers/net/natsemi.c
--- linux-2.4.6-pre5/drivers/net/natsemi.c	Mon Dec  3 22:49:02 2001
+++ linux/drivers/net/natsemi.c	Mon Dec  3 22:49:11 2001
@@ -833,18 +833,16 @@
 	printk(KERN_WARNING "%s: Transmit timed out, status %8.8x,"
 		   " resetting...\n", dev->name, (int)readl(ioaddr + TxRingPtr));
 
-#ifndef __alpha__
 	{
 		int i;
-		printk(KERN_DEBUG "  Rx ring %8.8x: ", (int)np->rx_ring);
+		printk(KERN_DEBUG "  Rx ring %p: ", np->rx_ring);
 		for (i = 0; i < RX_RING_SIZE; i++)
 			printk(" %8.8x", (unsigned int)np->rx_ring[i].cmd_status);
-		printk("\n"KERN_DEBUG"  Tx ring %8.8x: ", (int)np->tx_ring);
+		printk("\n"KERN_DEBUG"  Tx ring %p: ", np->tx_ring);
 		for (i = 0; i < TX_RING_SIZE; i++)
 			printk(" %4.4x", np->tx_ring[i].cmd_status);
 		printk("\n");
 	}
-#endif
 	spin_lock_irq(&np->lock);
 	natsemi_reset(dev);
 	drain_ring(dev);
diff -urN linux-2.4.6-pre5/drivers/net/shaper.c linux/drivers/net/shaper.c
--- linux-2.4.6-pre5/drivers/net/shaper.c	Mon Dec  3 22:49:02 2001
+++ linux/drivers/net/shaper.c	Mon Dec  3 22:49:11 2001
@@ -283,7 +283,7 @@
 				shaper->dev->name,newskb->priority);
 		dev_queue_xmit(newskb);
 
-                shaper->stats.tx_bytes+=newskb->len;
+                shaper->stats.tx_bytes += skb->len;
 		shaper->stats.tx_packets++;
 
                 if(sh_debug)
diff -urN linux-2.4.6-pre5/drivers/net/sis900.c linux/drivers/net/sis900.c
--- linux-2.4.6-pre5/drivers/net/sis900.c	Mon Dec  3 22:49:02 2001
+++ linux/drivers/net/sis900.c	Mon Dec  3 22:49:11 2001
@@ -1002,7 +1002,7 @@
 static void sis630_set_eq(struct net_device *net_dev, u8 revision)
 {
 	struct sis900_private *sis_priv = net_dev->priv;
-	u16 reg14h, eq_value, max_value=0, min_value=0;
+	u16 reg14h, eq_value=0, max_value=0, min_value=0;
 	u8 host_bridge_rev;
 	int i, maxcount=10;
 	struct pci_dev *dev=NULL;
diff -urN linux-2.4.6-pre5/drivers/net/sundance.c linux/drivers/net/sundance.c
--- linux-2.4.6-pre5/drivers/net/sundance.c	Mon Dec  3 22:49:02 2001
+++ linux/drivers/net/sundance.c	Mon Dec  3 22:49:11 2001
@@ -740,18 +740,16 @@
 	printk(KERN_WARNING "%s: Transmit timed out, status %2.2x,"
 		   " resetting...\n", dev->name, readb(ioaddr + TxStatus));
 
-#ifndef __alpha__
 	{
 		int i;
-		printk(KERN_DEBUG "  Rx ring %8.8x: ", (int)np->rx_ring);
+		printk(KERN_DEBUG "  Rx ring %p: ", np->rx_ring);
 		for (i = 0; i < RX_RING_SIZE; i++)
 			printk(" %8.8x", (unsigned int)np->rx_ring[i].status);
-		printk("\n"KERN_DEBUG"  Tx ring %8.8x: ", (int)np->tx_ring);
+		printk("\n"KERN_DEBUG"  Tx ring %p: ", np->tx_ring);
 		for (i = 0; i < TX_RING_SIZE; i++)
 			printk(" %4.4x", np->tx_ring[i].status);
 		printk("\n");
 	}
-#endif
 
 	/* Perhaps we should reinitialize the hardware here. */
 	dev->if_port = 0;
diff -urN linux-2.4.6-pre5/drivers/net/tokenring/smctr.c linux/drivers/net/tokenring/smctr.c
--- linux-2.4.6-pre5/drivers/net/tokenring/smctr.c	Mon Dec  3 22:49:02 2001
+++ linux/drivers/net/tokenring/smctr.c	Mon Dec  3 22:49:11 2001
@@ -26,10 +26,6 @@
  *    1. Multicast support.
  */
 
-#if defined(__alpha__) || defined(__ia64__)
-#error FIXME: driver does not support 64-bit platforms
-#endif
-
 #ifdef MODULE
 #include <linux/module.h>
 #include <linux/version.h>
@@ -62,6 +58,10 @@
 #include <linux/etherdevice.h>
 #include <linux/skbuff.h>
 #include <linux/trdevice.h>
+
+#if BITS_PER_LONG == 64
+#error FIXME: driver does not support 64-bit platforms
+#endif
 
 #include "smctr.h"               /* Our Stuff */
 #include "smctr_firmware.h"      /* SMC adapter firmware */
diff -urN linux-2.4.6-pre5/drivers/net/wan/comx-hw-mixcom.c linux/drivers/net/wan/comx-hw-mixcom.c
--- linux-2.4.6-pre5/drivers/net/wan/comx-hw-mixcom.c	Mon Dec 11 13:38:29 2000
+++ linux/drivers/net/wan/comx-hw-mixcom.c	Mon Dec  3 22:49:11 2001
@@ -487,15 +487,18 @@
 	struct mixcom_privdata *hw = ch->HW_privdata;
 	struct proc_dir_entry *procfile = ch->procdir->subdir;
 	unsigned long flags; 
+	int ret = -ENODEV;
 
-	if (!dev->base_addr || !dev->irq) return -ENODEV;
+	if (!dev->base_addr || !dev->irq)
+		goto err_ret;
 
 
 	if(hw->channel==1) {
 		if(!TWIN(dev) || !(COMX_CHANNEL(TWIN(dev))->init_status & 
 		    IRQ_ALLOCATED)) {
 			printk(KERN_ERR "%s: channel 0 not yet initialized\n",dev->name);
-			return -EAGAIN;
+			ret = -EAGAIN;
+			goto err_ret;
 		}
 	}
 
@@ -503,28 +506,29 @@
 	/* Is our hw present at all ? Not checking for channel 0 if it is already 
 	   open */
 	if(hw->channel!=0 || !(ch->init_status & IRQ_ALLOCATED)) {
-		if (check_region(dev->base_addr, MIXCOM_IO_EXTENT)) {
-			return -EAGAIN;
+		if (!request_region(dev->base_addr, MIXCOM_IO_EXTENT, dev->name)) {
+			ret = -EAGAIN;
+			goto err_ret;
 		}
 		if (mixcom_probe(dev)) {
-			return -ENODEV;
+			ret = -ENODEV;
+			goto err_release_region;
 		}
 	}
 
-	save_flags(flags); cli();
-
-	if(hw->channel==1) {
-		request_region(dev->base_addr, MIXCOM_IO_EXTENT, dev->name);
-	} 
-
 	if(hw->channel==0 && !(ch->init_status & IRQ_ALLOCATED)) {
 		if (request_irq(dev->irq, MIXCOM_interrupt, 0, 
 		    dev->name, (void *)dev)) {
 			printk(KERN_ERR "MIXCOM: unable to obtain irq %d\n", dev->irq);
-			return -EAGAIN;
+			ret = -EAGAIN;
+			goto err_release_region;
 		}
+	}
+
+	save_flags(flags); cli();
+
+	if(hw->channel==0 && !(ch->init_status & IRQ_ALLOCATED)) {
 		ch->init_status|=IRQ_ALLOCATED;
-		request_region(dev->base_addr, MIXCOM_IO_EXTENT, dev->name);
 		mixcom_board_on(dev);
 	}
 
@@ -560,6 +564,13 @@
 	}
 
 	return 0;
+	
+err_restore_flags:
+	restore_flags(flags);
+err_release_region:
+	release_region(dev->base_addr, MIXCOM_IO_EXTENT);
+err_ret:
+	return ret;
 }
 
 static int MIXCOM_close(struct net_device *dev)
diff -urN linux-2.4.6-pre5/drivers/net/wan/comx-proto-fr.c linux/drivers/net/wan/comx-proto-fr.c
--- linux-2.4.6-pre5/drivers/net/wan/comx-proto-fr.c	Sat Mar  3 10:55:48 2001
+++ linux/drivers/net/wan/comx-proto-fr.c	Mon Dec  3 22:49:11 2001
@@ -503,6 +503,8 @@
 
 	if (dev != fr->master) {
 		struct sk_buff *newskb=skb_clone(skb, GFP_ATOMIC);
+		if (!newskb)
+			return -ENOMEM;
 		newskb->dev=fr->master;
 		dev_queue_xmit(newskb);
 		ch->stats.tx_bytes += skb->len;
@@ -701,7 +703,7 @@
 	} else {
 		printk(KERN_ERR "comxfr_write_proc: internal error, filename %s\n", 
 			entry->name);
-		return -EBADF;
+		count = -EBADF;
 	}
 
 	free_page((unsigned long)page);
@@ -960,30 +962,27 @@
 }
 
 static struct comx_protocol fr_master_protocol = {
-	"frad", 
-	VERSION,
-	ARPHRD_FRAD, 
-	fr_master_init, 
-	fr_exit, 
-	NULL 
+	name:		"frad", 
+	version:	VERSION,
+	encap_type:	ARPHRD_FRAD, 
+	line_init:	fr_master_init, 
+	line_exit:	fr_exit, 
 };
 
 static struct comx_protocol fr_slave_protocol = {
-	"ietf-ip", 
-	VERSION,
-	ARPHRD_DLCI, 
-	fr_slave_init, 
-	fr_exit, 
-	NULL 
+	name:		"ietf-ip", 
+	version:	VERSION,
+	encap_type:	ARPHRD_DLCI, 
+	line_init:	fr_slave_init, 
+	line_exit:	fr_exit, 
 };
 
 static struct comx_hardware fr_dlci = { 
-	"dlci", 
-	VERSION,
-	dlci_init, 
-	dlci_exit, 
-	dlci_dump, 
-	NULL 
+	name:		"dlci", 
+	version:	VERSION,
+	hw_init:	dlci_init, 
+	hw_exit:	dlci_exit, 
+	hw_dump:	dlci_dump, 
 };
 
 #ifdef MODULE
diff -urN linux-2.4.6-pre5/drivers/net/wan/cosa.c linux/drivers/net/wan/cosa.c
--- linux-2.4.6-pre5/drivers/net/wan/cosa.c	Tue Mar  6 19:44:36 2001
+++ linux/drivers/net/wan/cosa.c	Mon Dec  3 22:49:11 2001
@@ -1046,15 +1046,15 @@
 	    __get_user(code, &(d->code)))
 		return -EFAULT;
 
-	if (d->addr < 0 || d->addr > COSA_MAX_FIRMWARE_SIZE)
+	if (addr < 0 || addr > COSA_MAX_FIRMWARE_SIZE)
 		return -EINVAL;
-	if (d->len < 0 || d->len > COSA_MAX_FIRMWARE_SIZE)
+	if (len < 0 || len > COSA_MAX_FIRMWARE_SIZE)
 		return -EINVAL;
 
 	/* If something fails, force the user to reset the card */
 	cosa->firmware_status &= ~(COSA_FW_RESET|COSA_FW_DOWNLOAD);
 
-	if ((i=download(cosa, d->code, len, addr)) < 0) {
+	if ((i=download(cosa, code, len, addr)) < 0) {
 		printk(KERN_NOTICE "cosa%d: microcode download failed: %d\n",
 			cosa->num, i);
 		return -EIO;
diff -urN linux-2.4.6-pre5/drivers/net/wan/lapbether.c linux/drivers/net/wan/lapbether.c
--- linux-2.4.6-pre5/drivers/net/wan/lapbether.c	Wed Apr 18 14:40:07 2001
+++ linux/drivers/net/wan/lapbether.c	Mon Dec  3 22:49:11 2001
@@ -89,7 +89,7 @@
  */
 static int lapbeth_check_devices(struct net_device *dev)
 {
-	struct lapbethdev *lapbeth, *lapbeth_prev;
+	struct lapbethdev *lapbeth, *lapbeth_prev, *lapbeth_next;
 	int result = 0;
 	unsigned long flags;
 
@@ -98,7 +98,8 @@
 
 	lapbeth_prev = NULL;
 
-	for (lapbeth = lapbeth_devices; lapbeth != NULL; lapbeth = lapbeth->next) {
+	for (lapbeth = lapbeth_devices; lapbeth != NULL; lapbeth = lapbeth_next) {
+		lapbeth_next = lapbeth->next;
 		if (!dev_get(lapbeth->ethname)) {
 			if (lapbeth_prev)
 				lapbeth_prev->next = lapbeth->next;
@@ -112,8 +113,8 @@
 			dev_put(lapbeth->ethdev);
 			kfree(lapbeth);
 		}
-
-		lapbeth_prev = lapbeth;
+		else
+			lapbeth_prev = lapbeth;
 	}
 
 	restore_flags(flags);
diff -urN linux-2.4.6-pre5/drivers/net/wan/lmc/lmc_main.c linux/drivers/net/wan/lmc/lmc_main.c
--- linux-2.4.6-pre5/drivers/net/wan/lmc/lmc_main.c	Sun Mar 25 18:24:31 2001
+++ linux/drivers/net/wan/lmc/lmc_main.c	Mon Dec  3 22:49:11 2001
@@ -507,7 +507,12 @@
                             break;
                     }
                     
-                    LMC_COPY_FROM_USER(data, xc.data, xc.len);
+                    if(copy_from_user(data, xc.data, xc.len))
+                    {
+                    	kfree(data);
+                    	ret = -ENOMEM;
+                    	break;
+                    }
 
                     printk("%s: Starting load of data Len: %d at 0x%p == 0x%p\n", dev->name, xc.len, xc.data, data);
 
diff -urN linux-2.4.6-pre5/drivers/net/wan/syncppp.c linux/drivers/net/wan/syncppp.c
--- linux-2.4.6-pre5/drivers/net/wan/syncppp.c	Tue May 22 10:23:16 2001
+++ linux/drivers/net/wan/syncppp.c	Mon Dec  3 22:49:11 2001
@@ -147,7 +147,7 @@
 static char *sppp_ipcp_type_name (u8 type);
 static void sppp_print_bytes (u8 *p, u16 len);
 
-static int debug = 0;
+static int debug;
 
 
 /*
@@ -518,8 +518,10 @@
 		}
 		/* Send Configure-Ack packet. */
 		sp->pp_loopcnt = 0;
-		sppp_cp_send (sp, PPP_LCP, LCP_CONF_ACK,
-				h->ident, len-4, h+1);
+		if (sp->lcp.state != LCP_STATE_OPENED) {
+			sppp_cp_send (sp, PPP_LCP, LCP_CONF_ACK,
+					h->ident, len-4, h+1);
+		}
 		/* Change the state. */
 		switch (sp->lcp.state) {
 		case LCP_STATE_CLOSED:
@@ -535,7 +537,9 @@
 			sp->ipcp.state = IPCP_STATE_CLOSED;
 			/* Initiate renegotiation. */
 			sppp_lcp_open (sp);
-			/* An ACK has already been sent. */
+			/* Send ACK after our REQ in attempt to break loop */
+			sppp_cp_send (sp, PPP_LCP, LCP_CONF_ACK,
+					h->ident, len-4, h+1);
 			sp->lcp.state = LCP_STATE_ACK_SENT;
 			break;
 		}
@@ -1388,25 +1392,21 @@
 	return 0;
 }
 
-
-struct packet_type sppp_packet_type=
-{
-	0,
-	NULL,
-	sppp_rcv,
-	NULL,
-	NULL
+struct packet_type sppp_packet_type = {
+	type:	__constant_htons(ETH_P_WAN_PPP),
+	func:	sppp_rcv,
 };
 
-
+static const char banner[] __initdata = 
+	KERN_INFO "Cronyx Ltd, Synchronous PPP and CISCO HDLC (c) 1994\n"
+	KERN_INFO "Linux port (c) 1998 Building Number Three Ltd & "
+		  "Jan \"Yenya\" Kasprzak.\n";
 
 static int __init sync_ppp_init(void)
 {
 	if(debug)
 		debug=PP_DEBUG;
-	printk(KERN_INFO "Cronyx Ltd, Synchronous PPP and CISCO HDLC (c) 1994\n");
-	printk(KERN_INFO "Linux port (c) 1998 Building Number Three Ltd & Jan \"Yenya\" Kasprzak.\n");
-	sppp_packet_type.type=htons(ETH_P_WAN_PPP);	
+	printk(banner);
 	dev_add_pack(&sppp_packet_type);
 	return 0;
 }
diff -urN linux-2.4.6-pre5/drivers/net/winbond-840.c linux/drivers/net/winbond-840.c
--- linux-2.4.6-pre5/drivers/net/winbond-840.c	Mon Dec  3 22:49:02 2001
+++ linux/drivers/net/winbond-840.c	Mon Dec  3 22:49:11 2001
@@ -839,7 +839,7 @@
 		C000	32  longwords		0400 4 longwords
 	   Wait the specified 50 PCI cycles after a reset by initializing
 	   Tx and Rx queues and the address filter list. */
-#if defined(__powerpc__)		/* Big-endian */
+#if defined(__powerpc__) || defined(__sparc__)		/* Big-endian */
 	writel(0x00100080 | 0xE010, ioaddr + PCIBusCfg);
 #elif defined(__alpha__)
 	writel(0xE010, ioaddr + PCIBusCfg);
@@ -884,13 +884,12 @@
 	printk(KERN_WARNING "%s: Transmit timed out, status %8.8x,"
 		   " resetting...\n", dev->name, (int)readl(ioaddr + IntrStatus));
 
-#ifndef __alpha__
 	{
 		int i;
-		printk(KERN_DEBUG "  Rx ring %8.8x: ", (int)np->rx_ring);
+		printk(KERN_DEBUG "  Rx ring %p: ", np->rx_ring);
 		for (i = 0; i < RX_RING_SIZE; i++)
 			printk(" %8.8x", (unsigned int)np->rx_ring[i].status);
-		printk("\n"KERN_DEBUG"  Tx ring %8.8x: ", (int)np->tx_ring);
+		printk("\n"KERN_DEBUG"  Tx ring %p: ", np->tx_ring);
 		for (i = 0; i < TX_RING_SIZE; i++)
 			printk(" %8.8x", np->tx_ring[i].status);
 		printk("\n");
@@ -899,7 +898,6 @@
 				np->cur_tx, np->dirty_tx, np->tx_full,np->tx_q_bytes);
 	printk(KERN_DEBUG "Tx Descriptor addr %xh.\n",readl(ioaddr+0x4C));
 
-#endif
 	spin_lock_irq(&np->lock);
 	/*
 	 * Under high load dirty_tx and the internal tx descriptor pointer
@@ -1376,7 +1374,6 @@
 {
 	long ioaddr = dev->base_addr;
 	struct netdev_private *np = dev->priv;
-	int i;
 
 	netif_stop_queue(dev);
 
@@ -1399,6 +1396,8 @@
 
 #ifdef __i386__
 	if (debug > 2) {
+		int i;
+
 		printk("\n"KERN_DEBUG"  Tx ring at %8.8x:\n",
 			   (int)np->tx_ring);
 		for (i = 0; i < TX_RING_SIZE; i++)
diff -urN linux-2.4.6-pre5/drivers/nubus/nubus.c linux/drivers/nubus/nubus.c
--- linux-2.4.6-pre5/drivers/nubus/nubus.c	Sun Dec  3 17:48:19 2000
+++ linux/drivers/nubus/nubus.c	Mon Dec  3 22:49:11 2001
@@ -574,7 +574,7 @@
 		/* Now clobber the whole thing */
 		if (size > sizeof(mode) - 1)
 			size = sizeof(mode) - 1;
-		memset(&mode, sizeof(mode), 0);
+		memset(&mode, 0, sizeof(mode));
 		nubus_get_rsrc_mem(&mode, &ent, size);
 		printk (KERN_INFO "      %02X: (%02X) %s\n", ent.type,
 			mode.id, mode.name);
diff -urN linux-2.4.6-pre5/drivers/scsi/3w-xxxx.c linux/drivers/scsi/3w-xxxx.c
--- linux-2.4.6-pre5/drivers/scsi/3w-xxxx.c	Fri Apr 27 13:59:17 2001
+++ linux/drivers/scsi/3w-xxxx.c	Mon Dec  3 22:49:11 2001
@@ -76,6 +76,20 @@
                  Make tw_setfeature() call with interrupts disabled.
                  Register interrupt handler before enabling interrupts.
                  Clear attention interrupt before draining aen queue.
+   1.02.00.005 - Allocate bounce buffers and custom queue depth for raid5 for
+                 6000 and 5000 series controllers.
+                 Reduce polling mdelays causing problems on some systems.
+                 Fix use_sg = 1 calculation bug.
+                 Check for scsi_register returning NULL.
+                 Add aen count to /proc/scsi/3w-xxxx.
+                 Remove aen code unit masking in tw_aen_complete().
+   1.02.00.006 - Remove unit from printk in tw_scsi_eh_abort(), causing
+                 possible oops.
+                 Fix possible null pointer dereference in tw_scsi_queue()
+                 if done function pointer was invalid.
+   1.02.00.007 - Fix possible null pointer dereferences in tw_ioctl().
+                 Remove check for invalid done function pointer from
+                 tw_scsi_queue().
 */
 
 #include <linux/module.h>
@@ -121,7 +135,7 @@
 };
 
 /* Globals */
-char *tw_driver_version="1.02.00.004";
+char *tw_driver_version="1.02.00.007";
 TW_Device_Extension *tw_device_extension_list[TW_MAX_SLOT];
 int tw_device_extension_count = 0;
 
@@ -131,7 +145,7 @@
 int tw_aen_complete(TW_Device_Extension *tw_dev, int request_id) 
 {
 	TW_Param *param;
-	unsigned short aen, aen_code;
+	unsigned short aen;
 
 	if (tw_dev->alignment_virtual_address[request_id] == NULL) {
 		printk(KERN_WARNING "3w-xxxx: tw_aen_complete(): Bad alignment virtual address.\n");
@@ -139,10 +153,9 @@
 	}
 	param = (TW_Param *)tw_dev->alignment_virtual_address[request_id];
 	aen = *(unsigned short *)(param->data);
-	aen_code = (aen & 0x0ff);
-	dprintk(KERN_NOTICE "3w-xxxx: tw_aen_complete(): Queue'd code 0x%x\n", aen_code);
+	dprintk(KERN_NOTICE "3w-xxxx: tw_aen_complete(): Queue'd code 0x%x\n", aen);
 	/* Now queue the code */
-	tw_dev->aen_queue[tw_dev->aen_tail] = aen_code;
+	tw_dev->aen_queue[tw_dev->aen_tail] = aen;
 	if (tw_dev->aen_tail == TW_Q_LENGTH - 1) {
 		tw_dev->aen_tail = TW_Q_START;
 	} else {
@@ -241,7 +254,7 @@
     
 		/* Now poll for completion */
 		for (i=0;i<imax;i++) {
-			mdelay(10);
+			mdelay(5);
 			status_reg_value = inl(status_reg_addr);
 			if (tw_check_bits(status_reg_value)) {
 				printk(KERN_WARNING "3w-xxxx: tw_aen_drain_queue(): Unexpected bits.\n");
@@ -437,13 +450,21 @@
 		return 1;
 	}
 
-	if (which == 0) {
+	switch(which) {
+	case 0:
 		tw_dev->command_packet_virtual_address[request_id] = virt_addr;
-		tw_dev->command_packet_physical_address[request_id] = 
-		virt_to_bus(virt_addr);
-	} else {
+		tw_dev->command_packet_physical_address[request_id] = virt_to_bus(virt_addr);
+		break;
+	case 1:
 		tw_dev->alignment_virtual_address[request_id] = virt_addr;
 		tw_dev->alignment_physical_address[request_id] = virt_to_bus(virt_addr);
+		break;
+	case 2:
+		tw_dev->bounce_buffer[request_id] = virt_addr;
+		break;
+	default:
+		printk(KERN_WARNING "3w-xxxx: tw_allocate_memory(): case slip in tw_allocate_memory()\n");
+		return 1;
 	}
 	return 0;
 } /* End tw_allocate_memory() */
@@ -709,8 +730,8 @@
 
 		/* Register the card with the kernel SCSI layer */
 			host = scsi_register(tw_host, sizeof(TW_Device_Extension));
-			if( host == NULL)
-			{
+			if (host == NULL) {
+				printk(KERN_WARNING "3w-xxxx: tw_findcards(): scsi_register() failed for card %d.\n", numcards-1);
 				release_region((tw_dev->tw_pci_dev->resource[0].start), TW_IO_ADDRESS_RANGE);
 				tw_free_device_extension(tw_dev);
 				kfree(tw_dev);
@@ -788,6 +809,9 @@
 
 		if (tw_dev->alignment_virtual_address[i])
 			kfree(tw_dev->alignment_virtual_address[i]);
+
+		if (tw_dev->bounce_buffer[i])
+			kfree(tw_dev->bounce_buffer[i]);
 	}
 } /* End tw_free_device_extension() */
 
@@ -853,7 +877,7 @@
 	/* Poll for completion */
 	imax = TW_POLL_MAX_RETRIES;
 	for (i=0;i<imax;i++) {
-		mdelay(10);
+		mdelay(5);
 		status_reg_value = inl(status_reg_addr);
 		if (tw_check_bits(status_reg_value)) {
 			printk(KERN_WARNING "3w-xxxx: tw_initconnection(): Unexpected bits.\n");
@@ -909,8 +933,10 @@
 		tw_dev->aen_queue[i] = 0;
 	}
 
-	for (i=0;i<TW_MAX_UNITS;i++)
+	for (i=0;i<TW_MAX_UNITS;i++) {
 		tw_dev->is_unit_present[i] = 0;
+		tw_dev->is_raid_five[i] = 0;
+	}
 
 	tw_dev->num_units = 0;
 	tw_dev->num_aborts = 0;
@@ -928,6 +954,8 @@
 	tw_dev->aen_tail = 0;
 	tw_dev->sector_count = 0;
 	tw_dev->max_sector_count = 0;
+	tw_dev->aen_count = 0;
+	tw_dev->num_raid_five = 0;
 	spin_lock_init(&tw_dev->tw_lock);
 	tw_dev->flags = 0;
 	return 0;
@@ -940,13 +968,14 @@
 	unsigned char request_id = 0;
 	TW_Command *command_packet;
 	TW_Param *param;
-	int i, imax, num_units = 0;
+	int i, j, imax, num_units = 0, num_raid_five = 0;
 	u32 status_reg_addr, status_reg_value;
 	u32 command_que_addr, command_que_value;
 	u32 response_que_addr;
 	TW_Response_Queue response_queue;
 	u32 param_value;
 	unsigned char *is_unit_present;
+	unsigned char *raid_level;
 
 	dprintk(KERN_NOTICE "3w-xxxx: tw_initialize_units()\n");
 
@@ -1001,7 +1030,7 @@
 	/* Poll for completion */
 	imax = TW_POLL_MAX_RETRIES;
 	for(i=0; i<imax; i++) {
-		mdelay(10);
+		mdelay(5);
 		status_reg_value = inl(status_reg_addr);
 		if (tw_check_bits(status_reg_value)) {
 			printk(KERN_WARNING "3w-xxxx: tw_initialize_units(): Unexpected bits.\n");
@@ -1052,6 +1081,110 @@
 		printk(KERN_NOTICE "3w-xxxx: tw_initialize_units(): No units found.\n");
 		return 1;
 	}
+
+	/* Find raid 5 arrays */
+	for (j=0;j<TW_MAX_UNITS;j++) {
+		if (tw_dev->is_unit_present[j] == 0)
+			continue;
+		command_packet = (TW_Command *)tw_dev->command_packet_virtual_address[request_id];
+		if (command_packet == NULL) {
+			printk(KERN_WARNING "3w-xxxx: tw_initialize_units(): Bad command packet virtual address.\n");
+			return 1;
+		}
+		memset(command_packet, 0, sizeof(TW_Sector));
+		command_packet->byte0.opcode      = TW_OP_GET_PARAM;
+		command_packet->byte0.sgl_offset  = 2;
+		command_packet->size              = 4;
+		command_packet->request_id        = request_id;
+		command_packet->byte3.unit        = 0;
+		command_packet->byte3.host_id     = 0;
+		command_packet->status            = 0;
+		command_packet->flags             = 0;
+		command_packet->byte6.block_count = 1;
+
+		/* Now setup the param */
+		if (tw_dev->alignment_virtual_address[request_id] == NULL) {
+			printk(KERN_WARNING "3w-xxxx: tw_initialize_units(): Bad alignment virtual address.\n");
+			return 1;
+		}
+		param = (TW_Param *)tw_dev->alignment_virtual_address[request_id];
+		memset(param, 0, sizeof(TW_Sector));
+		param->table_id = 0x300+j; /* unit summary table */
+		param->parameter_id = 0x6; /* unit descriptor */
+		param->parameter_size_bytes = 0xc;
+		param_value = tw_dev->alignment_physical_address[request_id];
+		if (param_value == 0) {
+			printk(KERN_WARNING "3w-xxxx: tw_initialize_units(): Bad alignment physical address.\n");
+			return 1;
+		}
+
+		command_packet->byte8.param.sgl[0].address = param_value;
+		command_packet->byte8.param.sgl[0].length = sizeof(TW_Sector);
+
+		/* Post the command packet to the board */
+		command_que_value = tw_dev->command_packet_physical_address[request_id];
+		if (command_que_value == 0) {
+			printk(KERN_WARNING "3w-xxxx: tw_initialize_units(): Bad command packet physical address.\n");
+			return 1;
+		}
+		outl(command_que_value, command_que_addr);
+
+		/* Poll for completion */
+		imax = TW_POLL_MAX_RETRIES;
+		for(i=0; i<imax; i++) {
+			mdelay(5);
+			status_reg_value = inl(status_reg_addr);
+			if (tw_check_bits(status_reg_value)) {
+				printk(KERN_WARNING "3w-xxxx: tw_initialize_units(): Unexpected bits.\n");
+				return 1;
+			}
+			if ((status_reg_value & TW_STATUS_RESPONSE_QUEUE_EMPTY) == 0) {
+				response_queue.value = inl(response_que_addr);
+				request_id = (unsigned char)response_queue.u.response_id;
+				if (request_id != 0) {
+					/* unexpected request id */
+					printk(KERN_WARNING "3w-xxxx: tw_initia
+lize_units(): Unexpected request id.\n");
+					return 1;
+				}
+				if (command_packet->status != 0) {
+					/* bad response */
+					printk(KERN_WARNING "3w-xxxx: tw_initia
+lize_units(): Bad response, status = 0x%x, flags = 0x%x.\n", command_packet->status, command_packet->flags);
+					return 1;
+				}
+				found = 1;
+				break;
+			}
+		}
+		if (found == 0) {
+			/* response never received */
+			printk(KERN_WARNING "3w-xxxx: tw_initialize_units(): No
+ response.\n");
+			return 1;
+		}
+
+		param = (TW_Param *)tw_dev->alignment_virtual_address[request_id];
+		raid_level = (unsigned char *)&(param->data[1]);
+		if (*raid_level == 5) {
+			dprintk(KERN_WARNING "3w-xxxx: Found unit %d to be a raid5 unit.\n", j);
+			tw_dev->is_raid_five[j] = 1;
+			num_raid_five++;
+		}
+	}
+	tw_dev->num_raid_five = num_raid_five;
+
+	/* Now allocate raid5 bounce buffers */
+	if ((num_raid_five != 0) && (tw_dev->tw_pci_dev->device == TW_DEVICE_ID)) {
+		for (i=0;i<TW_Q_LENGTH;i++) {
+			tw_allocate_memory(tw_dev, i, sizeof(TW_Sector)*256, 2);
+			if (tw_dev->bounce_buffer[i] == NULL) {
+				printk(KERN_WARNING "3w-xxxx: tw_initialize_units(): Bounce buffer allocation failed.\n");
+				return 1;
+			}
+			memset(tw_dev->bounce_buffer[i], 0, sizeof(TW_Sector)*256);
+		}
+	}
   
 	return 0;
 } /* End tw_initialize_units() */
@@ -1288,12 +1421,17 @@
 		case TW_OP_SET_PARAM:
 			dprintk(KERN_NOTICE "3w-xxxx: tw_ioctl(): caught TW_OP_SET_PARAM: table_id = %d, parameter_id = %d, parameter_size_bytes = %d.\n",
 			ioctl->table_id, ioctl->parameter_id, ioctl->parameter_size_bytes);
-			command_packet->byte0.opcode = TW_OP_SET_PARAM;
-			param->table_id = ioctl->table_id;
-			param->parameter_id = ioctl->parameter_id;
-			param->parameter_size_bytes = ioctl->parameter_size_bytes;
-			memcpy(param->data, ioctl->data, ioctl->parameter_size_bytes);
-			break;
+			if (ioctl->data != NULL) {
+				command_packet->byte0.opcode = TW_OP_SET_PARAM;
+				param->table_id = ioctl->table_id;
+				param->parameter_id = ioctl->parameter_id;
+				param->parameter_size_bytes = ioctl->parameter_size_bytes;
+				memcpy(param->data, ioctl->data, ioctl->parameter_size_bytes);
+				break;
+			} else {
+				printk(KERN_WARNING "3w-xxxx: tw_ioctl(): ioctl->data NULL.\n");
+				return 1;
+			}
 		case TW_OP_AEN_LISTEN:
 			dprintk(KERN_NOTICE "3w-xxxx: tw_ioctl(): caught TW_OP_AEN_LISTEN.\n");
 			if (tw_dev->aen_head == tw_dev->aen_tail) {
@@ -1318,11 +1456,15 @@
 			tw_dev->srb[request_id]->scsi_done(tw_dev->srb[request_id]);
 			return 0;
 	        case TW_CMD_PACKET:
-		  memcpy(command_packet, ioctl->data, sizeof(TW_Command));
-		  command_packet->request_id = request_id;
-		  tw_post_command_packet(tw_dev, request_id);
-
-		  return 0;
+			if (ioctl->data != NULL) {
+				memcpy(command_packet, ioctl->data, sizeof(TW_Command));
+				command_packet->request_id = request_id;
+				tw_post_command_packet(tw_dev, request_id);
+				return 0;
+			} else {
+				printk(KERN_WARNING "3w-xxxx: tw_ioctl(): ioctl->data NULL.\n");
+				return 1;
+			}
 		default:
 			printk(KERN_WARNING "3w-xxxx: Unknown ioctl 0x%x.\n", opcode);
 			tw_dev->state[request_id] = TW_S_COMPLETED;
@@ -1602,10 +1744,8 @@
 		return 0;
 	}
 
-	spin_unlock_irq(&io_request_lock);
 	ret = tw_findcards(tw_host);
-	spin_lock_irq(&io_request_lock);
-	
+
 	return ret;
 } /* End tw_scsi_detect() */
 
@@ -1763,6 +1903,7 @@
 		tw_copy_info(&info, "Max sector count:              %3d\n", tw_dev->max_sector_count);
 		tw_copy_info(&info, "Resets:                        %3d\n", tw_dev->num_resets);
 		tw_copy_info(&info, "Aborts:                        %3d\n", tw_dev->num_aborts);
+		tw_copy_info(&info, "AEN's:                         %3d\n", tw_dev->aen_count);
 	}
 	if (info.position > info.offset) {
 		return (info.position - info.offset);
@@ -1780,6 +1921,13 @@
 	int flags = 0;
 	TW_Device_Extension *tw_dev = (TW_Device_Extension *)SCpnt->host->hostdata;
 
+	if (tw_dev == NULL) {
+		printk(KERN_WARNING "3w-xxxx: tw_scsi_queue(): Invalid device extension.\n");
+		SCpnt->result = (DID_ERROR << 16);
+		done(SCpnt);
+		return 0;
+	}
+
 	spin_lock_irqsave(&tw_dev->tw_lock, flags);
 	dprintk(KERN_NOTICE "3w-xxxx: tw_scsi_queue()\n");
 
@@ -1790,20 +1938,6 @@
 		spin_unlock_irqrestore(&tw_dev->tw_lock, flags);
 		return 0;
 	}
-	if (done == NULL) {
-		printk(KERN_WARNING "3w-xxxx: tw_scsi_queue(): Invalid done function.\n");
-		SCpnt->result = (DID_ERROR << 16);
-		done(SCpnt);
-		spin_unlock_irqrestore(&tw_dev->tw_lock, flags);
-		return 0;
-	}
-	if (tw_dev == NULL) {
-		printk(KERN_WARNING "3w-xxxx: tw_scsi_queue(): Invalid device extension.\n");
-		SCpnt->result = (DID_ERROR << 16);
-		done(SCpnt);
-		spin_unlock_irqrestore(&tw_dev->tw_lock, flags);
-		return 0;
-	}
 	
 	/* Save done function into Scsi_Cmnd struct */
 	SCpnt->scsi_done = done;
@@ -2104,7 +2238,7 @@
 	TW_Command *command_packet;
 	u32 command_que_addr, command_que_value = 0;
 	u32 lba = 0x0, num_sectors = 0x0;
-	int i;
+	int i, count = 0;
 	Scsi_Cmnd *srb;
 	struct scatterlist *sglist;
 
@@ -2161,23 +2295,45 @@
 	command_packet->byte8.io.lba = lba;
 	command_packet->byte6.block_count = num_sectors;
 
-	/* Do this if there are no sg list entries */
-	if (tw_dev->srb[request_id]->use_sg == 0) {    
-		dprintk(KERN_NOTICE "3w-xxxx: tw_scsiop_read_write(): SG = 0\n");
-		command_packet->byte8.io.sgl[0].address = virt_to_bus(tw_dev->srb[request_id]->request_buffer);
-		command_packet->byte8.io.sgl[0].length = tw_dev->srb[request_id]->request_bufflen;
-	}
-
-	/* Do this if we have multiple sg list entries */
-	if (tw_dev->srb[request_id]->use_sg > 0) {
-		for (i=0;i<tw_dev->srb[request_id]->use_sg; i++) {
-			command_packet->byte8.io.sgl[i].address = virt_to_bus(sglist[i].address);
-			command_packet->byte8.io.sgl[i].length = sglist[i].length;
-			command_packet->size+=2;
+	if ((tw_dev->is_raid_five[tw_dev->srb[request_id]->target] == 0) || (srb->cmnd[0] == READ_6) || (srb->cmnd[0] == READ_10) || (tw_dev->tw_pci_dev->device == TW_DEVICE_ID2)) {
+		/* Do this if there are no sg list entries */
+		if (tw_dev->srb[request_id]->use_sg == 0) {    
+			dprintk(KERN_NOTICE "3w-xxxx: tw_scsiop_read_write(): SG = 0\n");
+			command_packet->byte8.io.sgl[0].address = virt_to_bus(tw_dev->srb[request_id]->request_buffer);
+			command_packet->byte8.io.sgl[0].length = tw_dev->srb[request_id]->request_bufflen;
+		}
+
+		/* Do this if we have multiple sg list entries */
+		if (tw_dev->srb[request_id]->use_sg > 0) {
+			for (i=0;i<tw_dev->srb[request_id]->use_sg; i++) {
+				command_packet->byte8.io.sgl[i].address = virt_to_bus(sglist[i].address);
+				command_packet->byte8.io.sgl[i].length = sglist[i].length;
+				command_packet->size+=2;
+			}
+			if (tw_dev->srb[request_id]->use_sg >= 1)
+				command_packet->size-=2;
 		}
-		if (tw_dev->srb[request_id]->use_sg > 1)
-			command_packet->size-=2;
-	}
+	} else {
+                /* Do this if there are no sg list entries for raid 5 */
+                if (tw_dev->srb[request_id]->use_sg == 0) {
+			dprintk(KERN_WARNING "doing raid 5 write use_sg = 0, bounce_buffer[%d] = 0x%p\n", request_id, tw_dev->bounce_buffer[request_id]);
+			memcpy(tw_dev->bounce_buffer[request_id], tw_dev->srb[request_id]->request_buffer, tw_dev->srb[request_id]->request_bufflen);
+			command_packet->byte8.io.sgl[0].address = virt_to_bus(tw_dev->bounce_buffer[request_id]);
+			command_packet->byte8.io.sgl[0].length = tw_dev->srb[request_id]->request_bufflen;
+                }
+
+                /* Do this if we have multiple sg list entries for raid 5 */
+                if (tw_dev->srb[request_id]->use_sg > 0) {
+                        dprintk(KERN_WARNING "doing raid 5 write use_sg = %d, sglist[0].length = %d\n", tw_dev->srb[request_id]->use_sg, sglist[0].length);
+                        for (i=0;i<tw_dev->srb[request_id]->use_sg; i++) {
+                                memcpy((char *)(tw_dev->bounce_buffer[request_id])+count, sglist[i].address, sglist[i].length);
+				count+=sglist[i].length;
+                        }
+                        command_packet->byte8.io.sgl[0].address = virt_to_bus(tw_dev->bounce_buffer[request_id]);
+                        command_packet->byte8.io.sgl[0].length = count;
+                        command_packet->size = 5; /* single sgl */
+                }
+        }
 
 	/* Update SG statistics */
 	tw_dev->sgl_entries = tw_dev->srb[request_id]->use_sg;
@@ -2287,7 +2443,7 @@
 	/* Poll for completion */
 	imax = TW_POLL_MAX_RETRIES;
 	for (i=0;i<imax;i++) {
-		mdelay(10);
+		mdelay(5);
 		status_reg_value = inl(status_reg_addr);
 		if (tw_check_bits(status_reg_value)) {
 			printk(KERN_WARNING "3w-xxxx: tw_setfeature(): Unexpected bits.\n");
diff -urN linux-2.4.6-pre5/drivers/scsi/3w-xxxx.h linux/drivers/scsi/3w-xxxx.h
--- linux-2.4.6-pre5/drivers/scsi/3w-xxxx.h	Fri Mar  2 18:38:38 2001
+++ linux/drivers/scsi/3w-xxxx.h	Mon Dec  3 22:49:11 2001
@@ -129,9 +129,9 @@
 #define TW_COMMAND_ALIGNMENT_MASK	      0x1ff
 #define TW_INIT_MESSAGE_CREDITS		      0x100
 #define TW_INIT_COMMAND_PACKET_SIZE	      0x3
-#define TW_POLL_MAX_RETRIES        	      10000
+#define TW_POLL_MAX_RETRIES        	      20000
 #define TW_MAX_SGL_LENGTH		      62
-#define TW_Q_LENGTH			      256
+#define TW_Q_LENGTH			      16
 #define TW_Q_START			      0
 #define TW_MAX_SLOT			      32
 #define TW_MAX_PCI_BUSES		      255
@@ -262,8 +262,11 @@
 	TW_Registers		registers;
 	u32			*alignment_virtual_address[TW_Q_LENGTH];
 	u32			alignment_physical_address[TW_Q_LENGTH];
+	u32			*bounce_buffer[TW_Q_LENGTH];
 	int			is_unit_present[TW_MAX_UNITS];
+	int			is_raid_five[TW_MAX_UNITS];
 	int			num_units;
+	int			num_raid_five;
 	u32			*command_packet_virtual_address[TW_Q_LENGTH];
 	u32			command_packet_physical_address[TW_Q_LENGTH];
 	struct pci_dev		*tw_pci_dev;
@@ -286,6 +289,7 @@
 	u32			num_resets;
 	u32			sector_count;
 	u32			max_sector_count;
+	u32			aen_count;
 	struct Scsi_Host	*host;
 	spinlock_t		tw_lock;
 	unsigned char		ioctl_size[TW_Q_LENGTH];
diff -urN linux-2.4.6-pre5/drivers/scsi/NCR53c406a.c linux/drivers/scsi/NCR53c406a.c
--- linux-2.4.6-pre5/drivers/scsi/NCR53c406a.c	Mon Dec  3 22:49:02 2001
+++ linux/drivers/scsi/NCR53c406a.c	Mon Dec  3 22:49:11 2001
@@ -665,7 +665,7 @@
 }
 
 
-static void wait_intr() {
+static void wait_intr(void) {
     int i = jiffies + WATCHDOG;
     
     while(time_after(i,jiffies) && !(inb(STAT_REG)&0xe0)) /* wait for a pseudo-interrupt */
@@ -981,7 +981,7 @@
 }
 
 #ifndef IRQ_LEV
-static int irq_probe()
+static int irq_probe(void)
 {
     int irqs, irq;
     int i;
@@ -1013,7 +1013,7 @@
 }
 #endif /* IRQ_LEV */
 
-static void chip_init()
+static void chip_init(void)
 {
     REG1;
 #if USE_DMA
diff -urN linux-2.4.6-pre5/drivers/scsi/aha152x.c linux/drivers/scsi/aha152x.c
--- linux-2.4.6-pre5/drivers/scsi/aha152x.c	Tue Mar  6 19:44:37 2001
+++ linux/drivers/scsi/aha152x.c	Mon Dec  3 22:49:11 2001
@@ -1998,14 +1998,14 @@
 			if (!HOSTDATA(shpnt)->commands)
 				SETPORT(PORTA, 0);	/* turn led off */
 
-			kfree(DONE_SC->host_scribble);
-			DONE_SC->host_scribble=0;
-
 			DO_UNLOCK(flags);
 			DPRINTK(debug_done, DEBUG_LEAD "calling scsi_done(%p)\n", CMDINFO(DONE_SC), DONE_SC);
                 	DONE_SC->scsi_done(DONE_SC);
 			DPRINTK(debug_done, DEBUG_LEAD "scsi_done(%p) returned\n", CMDINFO(DONE_SC), DONE_SC);
 			DO_LOCK(flags);
+
+			kfree(DONE_SC->host_scribble);
+			DONE_SC->host_scribble=0;
 		}
 
 		DONE_SC=0;
@@ -2872,11 +2872,11 @@
 		if (!ptr->device->soft_reset) {
 			remove_SC(&DISCONNECTED_SC, ptr);
 
-			kfree(ptr->host_scribble);
-			ptr->host_scribble=0;
-
 			ptr->result =  DID_RESET << 16;
 			ptr->scsi_done(ptr);
+
+			kfree(ptr->host_scribble);
+			ptr->host_scribble=0;
 		}
 
 		ptr = next;
diff -urN linux-2.4.6-pre5/drivers/scsi/dmx3191d.c linux/drivers/scsi/dmx3191d.c
--- linux-2.4.6-pre5/drivers/scsi/dmx3191d.c	Fri Apr 27 13:59:18 2001
+++ linux/drivers/scsi/dmx3191d.c	Mon Dec  3 22:49:11 2001
@@ -59,7 +59,7 @@
 	struct pci_dev *pdev = NULL;
 
 	if (!pci_present()) {
-		dmx3191d_printk("PCI support not enabled\n");
+		printk(KERN_WARNING "dmx3191: PCI support not enabled\n");
 		return 0;
 	}
 
@@ -75,7 +75,7 @@
 		port = pci_resource_start (pdev, 0);
 		
 		if (!request_region(port, DMX3191D_REGION, DMX3191D_DRIVER_NAME)) {
-			dmx3191d_printk("region 0x%lx-0x%lx already reserved\n",
+			printk(KERN_ERR "dmx3191: region 0x%lx-0x%lx already reserved\n",
 				port, port + DMX3191D_REGION);
 			continue;
 		}
@@ -93,7 +93,7 @@
 
 		if (request_irq(pdev->irq, dmx3191d_do_intr, SA_SHIRQ,
 				DMX3191D_DRIVER_NAME, instance)) {
-			dmx3191d_printk("irq %d not available\n", pdev->irq);
+			printk(KERN_WARNING "dmx3191: IRQ %d not available - switching to polled mode.\n", pdev->irq);
 			/* Steam powered scsi controllers run without an IRQ
 			   anyway */
 			instance->irq = IRQ_NONE;
diff -urN linux-2.4.6-pre5/drivers/scsi/dmx3191d.h linux/drivers/scsi/dmx3191d.h
--- linux-2.4.6-pre5/drivers/scsi/dmx3191d.h	Mon Sep 18 14:12:01 2000
+++ linux/drivers/scsi/dmx3191d.h	Mon Dec  3 22:49:11 2001
@@ -20,8 +20,6 @@
 #define PCI_DEVICE_ID_DOMEX_DMX3191D	0x0001
 #endif
 
-#define dmx3191d_printk( args... )	printk(__FILE__": " ##args)
-
 #ifndef ASM
 int dmx3191d_abort(Scsi_Cmnd *);
 int dmx3191d_detect(Scsi_Host_Template *);
diff -urN linux-2.4.6-pre5/drivers/scsi/eata_dma.c linux/drivers/scsi/eata_dma.c
--- linux-2.4.6-pre5/drivers/scsi/eata_dma.c	Fri Feb  9 11:30:23 2001
+++ linux/drivers/scsi/eata_dma.c	Mon Dec  3 22:49:11 2001
@@ -482,6 +482,7 @@
         DBG(DBG_REQSENSE, printk(KERN_DEBUG "Tried to REQUEST SENSE\n"));
 	cmd->result = DID_OK << 16;
 	done(cmd);
+	restore_flags(flags);
 
 	return(0);
     }
diff -urN linux-2.4.6-pre5/drivers/scsi/hosts.c linux/drivers/scsi/hosts.c
--- linux-2.4.6-pre5/drivers/scsi/hosts.c	Mon Oct 30 14:44:29 2000
+++ linux/drivers/scsi/hosts.c	Mon Dec  3 22:49:11 2001
@@ -168,6 +168,11 @@
     retval->loaded_as_module = 1;
     if (flag_new) {
 	shn = (Scsi_Host_Name *) kmalloc(sizeof(Scsi_Host_Name), GFP_ATOMIC);
+        if (!shn) {
+                kfree(retval);
+                printk(KERN_ERR "scsi: out of memory(2) in scsi_register.\n");
+                return NULL;
+        }
 	shn->name = kmalloc(hname_len + 1, GFP_ATOMIC);
 	if (hname_len > 0)
 	    strncpy(shn->name, hname, hname_len);
diff -urN linux-2.4.6-pre5/drivers/scsi/qla1280.c linux/drivers/scsi/qla1280.c
--- linux-2.4.6-pre5/drivers/scsi/qla1280.c	Fri Apr 27 13:59:19 2001
+++ linux/drivers/scsi/qla1280.c	Mon Dec  3 22:49:12 2001
@@ -1528,6 +1528,7 @@
     if(test_and_set_bit(QLA1280_IN_ISR_BIT, &ha->flags))
     {
         COMTRACE('X')
+        spin_unlock_irqrestore(&io_request_lock, cpu_flags);
         return;
     }
     ha->isr_count++;
diff -urN linux-2.4.6-pre5/drivers/scsi/scsi_proc.c linux/drivers/scsi/scsi_proc.c
--- linux-2.4.6-pre5/drivers/scsi/scsi_proc.c	Sat May 19 17:43:06 2001
+++ linux/drivers/scsi/scsi_proc.c	Mon Dec  3 22:49:12 2001
@@ -99,6 +99,9 @@
 	char * page;
 	char *start;
     
+	if (hpnt->hostt->proc_info == NULL)
+		ret = -ENOSYS;
+
 	if (count > PROC_BLOCK_SIZE)
 		return -EOVERFLOW;
 
@@ -110,11 +113,9 @@
 		return -EFAULT;
 	}
 
-	if (hpnt->hostt->proc_info == NULL)
-		ret = -ENOSYS;
-	else
-		ret = hpnt->hostt->proc_info(page, &start, 0, count,
-						hpnt->host_no, 1);
+	ret = hpnt->hostt->proc_info(page, &start, 0, count,
+				     hpnt->host_no, 1);
+
 	free_page((ulong) page);
 	return(ret);
 }
@@ -125,6 +126,10 @@
 	char name[10];	/* see scsi_unregister_host() */
 
 	tpnt->proc_dir = proc_mkdir(tpnt->proc_name, proc_scsi);
+        if (!tpnt->proc_dir) {
+                printk(KERN_ERR "Unable to proc_mkdir in scsi.c/build_proc_dir_entries");
+                return;
+        }
 	tpnt->proc_dir->owner = tpnt->module;
 
 	hpnt = scsi_hostlist;
diff -urN linux-2.4.6-pre5/drivers/scsi/sym53c416.c linux/drivers/scsi/sym53c416.c
--- linux-2.4.6-pre5/drivers/scsi/sym53c416.c	Tue Mar  6 19:44:37 2001
+++ linux/drivers/scsi/sym53c416.c	Mon Dec  3 22:49:12 2001
@@ -6,6 +6,9 @@
  *  Changes : 
  * 
  *  Marcelo Tosatti <marcelo@conectiva.com.br> : Added io_request_lock locking
+ *  Alan Cox <alan@redhat.com> : Cleaned up code formatting
+ *				 Fixed an irq locking bug
+ *				 Added ISAPnP support
  * 
  *  LILO command line usage: sym53c416=<PORTBASE>[,<IRQ>]
  *
@@ -36,12 +39,13 @@
 #include <asm/io.h>
 #include <linux/blk.h>
 #include <linux/version.h>
+#include <linux/isapnp.h>
 #include "scsi.h"
 #include "hosts.h"
 #include "sd.h"
 #include "sym53c416.h"
 
-#define VERSION_STRING        "Version 1.0.0"
+#define VERSION_STRING        "Version 1.0.0-ac"
 
 #define TC_LOW       0x00     /* Transfer counter low        */
 #define TC_MID       0x01     /* Transfer counter mid        */
@@ -203,24 +207,24 @@
 #define MAXHOSTS 4
 
 enum phases
-  {
-  idle,
-  data_out,
-  data_in,
-  command_ph,
-  status_ph,
-  message_out,
-  message_in
-  };
+{
+	idle,
+	data_out,
+	data_in,
+	command_ph,
+	status_ph,
+	message_out,
+	message_in
+};
 
 typedef struct
-  {
-  int base;
-  int irq;
-  int scsi_id;
-  } host;
+{
+	int base;
+	int irq;
+	int scsi_id;
+} host;
 
-host hosts[MAXHOSTS] = {
+static host hosts[MAXHOSTS] = {
                        {0, 0, SYM53C416_SCSI_ID},
                        {0, 0, SYM53C416_SCSI_ID},
                        {0, 0, SYM53C416_SCSI_ID},
@@ -228,579 +232,616 @@
                        };
 
 static int host_index = 0;
-
 static char info[120];
-
 static Scsi_Cmnd *current_command = NULL;
+static int fastpio = 1;
 
-int fastpio = 1;
-
-int probeaddrs[] = {0x200, 0x220, 0x240, 0};
+static int probeaddrs[] = {0x200, 0x220, 0x240, 0};
 
 static void sym53c416_set_transfer_counter(int base, unsigned int len)
-  {
-  /* Program Transfer Counter */
-  outb(len & 0x0000FF, base + TC_LOW);
-  outb((len & 0x00FF00) >> 8, base + TC_MID);
-  outb((len & 0xFF0000) >> 16, base + TC_HIGH);
-  }
+{
+	/* Program Transfer Counter */
+	outb(len & 0x0000FF, base + TC_LOW);
+	outb((len & 0x00FF00) >> 8, base + TC_MID);
+	outb((len & 0xFF0000) >> 16, base + TC_HIGH);
+}
 
 /* Returns the number of bytes read */
 static __inline__ unsigned int sym53c416_read(int base, unsigned char *buffer, unsigned int len)
-  {
-  unsigned int orig_len = len;
-  unsigned long flags = 0;
-  unsigned int bytes_left;
-  int i;
-  int timeout = READ_TIMEOUT;
-
-  /* Do transfer */
-  save_flags(flags);
-  cli();
-  while(len && timeout)
-    {
-    bytes_left = inb(base + PIO_FIFO_CNT); /* Number of bytes in the PIO FIFO */
-    if(fastpio && bytes_left > 3)
-      {
-      insl(base + PIO_FIFO_1, buffer, bytes_left >> 2);
-      buffer += bytes_left & 0xFC;
-      len -= bytes_left & 0xFC;
-      }
-    else if(bytes_left > 0)
-      {
-      len -= bytes_left;
-      for(; bytes_left > 0; bytes_left--)
-        *(buffer++) = inb(base + PIO_FIFO_1);
-      }
-    else
-      {
-      i = jiffies + timeout;
-      restore_flags(flags);
-      while(jiffies < i && (inb(base + PIO_INT_REG) & EMPTY) && timeout)
-        if(inb(base + PIO_INT_REG) & SCI)
-          timeout = 0;
-      save_flags(flags);
-      cli();
-      if(inb(base + PIO_INT_REG) & EMPTY)
-        timeout = 0;
-      }
-    }
-  restore_flags(flags);
-  return orig_len - len;
-  }
+{
+	unsigned int orig_len = len;
+	unsigned long flags = 0;
+	unsigned int bytes_left;
+	int i;
+	int timeout = READ_TIMEOUT;
+
+	/* Do transfer */
+	save_flags(flags);
+	cli();
+	while(len && timeout)
+	{
+		bytes_left = inb(base + PIO_FIFO_CNT); /* Number of bytes in the PIO FIFO */
+		if(fastpio && bytes_left > 3)
+		{
+			insl(base + PIO_FIFO_1, buffer, bytes_left >> 2);
+			buffer += bytes_left & 0xFC;
+			len -= bytes_left & 0xFC;
+		}
+		else if(bytes_left > 0)
+		{
+			len -= bytes_left;
+			for(; bytes_left > 0; bytes_left--)
+				*(buffer++) = inb(base + PIO_FIFO_1);
+		}
+		else
+		{
+			i = jiffies + timeout;
+			restore_flags(flags);
+			while(jiffies < i && (inb(base + PIO_INT_REG) & EMPTY) && timeout)
+				if(inb(base + PIO_INT_REG) & SCI)
+					timeout = 0;
+			save_flags(flags);
+			cli();
+			if(inb(base + PIO_INT_REG) & EMPTY)
+				timeout = 0;
+		}
+	}
+	restore_flags(flags);
+	return orig_len - len;
+}
 
 /* Returns the number of bytes written */
 static __inline__ unsigned int sym53c416_write(int base, unsigned char *buffer, unsigned int len)
-  {
-  unsigned int orig_len = len;
-  unsigned long flags = 0;
-  unsigned int bufferfree;
-  unsigned int i;
-  unsigned int timeout = WRITE_TIMEOUT;
-
-  /* Do transfer */
-  save_flags(flags);
-  cli();
-  while(len && timeout)
-    {
-    bufferfree = PIO_SIZE - inb(base + PIO_FIFO_CNT);
-    if(bufferfree > len)
-      bufferfree = len;
-    if(fastpio && bufferfree > 3)
-      {
-      outsl(base + PIO_FIFO_1, buffer, bufferfree >> 2);
-      buffer += bufferfree & 0xFC;
-      len -= bufferfree & 0xFC;
-      }
-    else if(bufferfree > 0)
-      {
-      len -= bufferfree;
-      for(; bufferfree > 0; bufferfree--)
-        outb(*(buffer++), base + PIO_FIFO_1);
-      }
-    else
-      {
-      i = jiffies + timeout;
-      restore_flags(flags);
-      while(jiffies < i && (inb(base + PIO_INT_REG) & FULL) && timeout)
-        ;
-      save_flags(flags);
-      cli();
-      if(inb(base + PIO_INT_REG) & FULL)
-        timeout = 0;
-      }
-    }
-  restore_flags(flags);
-  return orig_len - len;
-  }
+{
+	unsigned int orig_len = len;
+	unsigned long flags = 0;
+	unsigned int bufferfree;
+	unsigned int i;
+	unsigned int timeout = WRITE_TIMEOUT;
+
+	/* Do transfer */
+	save_flags(flags);
+	cli();
+	while(len && timeout)
+	{
+		bufferfree = PIO_SIZE - inb(base + PIO_FIFO_CNT);
+		if(bufferfree > len)
+			bufferfree = len;
+		if(fastpio && bufferfree > 3)
+		{
+			outsl(base + PIO_FIFO_1, buffer, bufferfree >> 2);
+			buffer += bufferfree & 0xFC;
+			len -= bufferfree & 0xFC;
+		}
+		else if(bufferfree > 0)
+		{
+			len -= bufferfree;
+			for(; bufferfree > 0; bufferfree--)
+				outb(*(buffer++), base + PIO_FIFO_1);
+		}
+		else
+		{
+			i = jiffies + timeout;
+			restore_flags(flags);
+			while(jiffies < i && (inb(base + PIO_INT_REG) & FULL) && timeout)
+				;
+			save_flags(flags);
+			cli();
+			if(inb(base + PIO_INT_REG) & FULL)
+				timeout = 0;
+		}
+	}
+	restore_flags(flags);
+	return orig_len - len;
+}
 
 static void sym53c416_intr_handle(int irq, void *dev_id, struct pt_regs *regs)
-  {
-  int base = 0;
-  int i;
-  unsigned long flags = 0;
-  unsigned char status_reg, pio_int_reg, int_reg;
-  struct scatterlist *sglist;
-  unsigned int sgcount;
-  unsigned int tot_trans = 0;
-
-  /* We search the base address of the host adapter which caused the interrupt */
-  for(i = 0; i < host_index && !base; i++)
-    if(irq == hosts[i].irq)
-      base = hosts[i].base;
-  /* If no adapter found, we cannot handle the interrupt. Leave a message */
-  /* and continue. This should never happen...                            */
-  if(!base)
-    {
-    printk("sym53c416: No host adapter defined for interrupt %d\n", irq);
-    return;
-    }
-  /* Now we have the base address and we can start handling the interrupt */
-  save_flags(flags);
-  cli();
-  status_reg = inb(base + STATUS_REG);
-  pio_int_reg = inb(base + PIO_INT_REG);
-  int_reg = inb(base + INT_REG);
-  restore_flags(flags);
-
-  /* First, we handle error conditions */
-  if(int_reg & SCI)         /* SCSI Reset */
-    {
-    printk("sym53c416: Warning: Reset received\n");
-    current_command->SCp.phase = idle;
-    current_command->result = DID_RESET << 16;
-    spin_lock_irqsave(&io_request_lock, flags);
-    current_command->scsi_done(current_command);
-    spin_unlock_irqrestore(&io_request_lock, flags);
-    return;
-    }
-  if(int_reg & ILCMD)       /* Illegal Command */
-    {
-    printk("sym53c416: Warning: Illegal Command: 0x%02x\n", inb(base + COMMAND_REG));
-    current_command->SCp.phase = idle;
-    current_command->result = DID_ERROR << 16;
-    spin_lock_irqsave(&io_request_lock, flags);
-    current_command->scsi_done(current_command);
-    spin_unlock_irqrestore(&io_request_lock, flags);
-    return;
-    }
-  if(status_reg & GE)         /* Gross Error */
-    {
-    printk("sym53c416: Warning: Gross Error\n");
-    current_command->SCp.phase = idle;
-    current_command->result = DID_ERROR << 16;
-    spin_lock_irqsave(&io_request_lock, flags);
-    current_command->scsi_done(current_command);
-    spin_unlock_irqrestore(&io_request_lock, flags);
-    return;
-    }
-  if(status_reg & PE)         /* Parity Error */
-    {
-    printk("sym53c416: Warning: Parity Error\n");
-    current_command->SCp.phase = idle;
-    current_command->result = DID_PARITY << 16;
-    spin_lock_irqsave(&io_request_lock, flags);
-    current_command->scsi_done(current_command);
-    spin_unlock_irqrestore(&io_request_lock, flags);
-    return;
-    }
-  if(pio_int_reg & (CE | OUE))
-    {
-    printk("sym53c416: Warning: PIO Interrupt Error\n");
-    current_command->SCp.phase = idle;
-    current_command->result = DID_ERROR << 16;
-    spin_lock_irqsave(&io_request_lock, flags);
-    current_command->scsi_done(current_command);
-    spin_unlock_irqrestore(&io_request_lock, flags);
-    return;
-    }
-  if(int_reg & DIS)           /* Disconnect */
-    {
-    if(current_command->SCp.phase != message_in)
-      current_command->result = DID_NO_CONNECT << 16;
-    else
-      current_command->result = (current_command->SCp.Status & 0xFF) | ((current_command->SCp.Message & 0xFF) << 8) | (DID_OK << 16);
-    current_command->SCp.phase = idle;
-
-    spin_lock_irqsave(&io_request_lock, flags);
-    current_command->scsi_done(current_command);
-    spin_unlock_irqrestore(&io_request_lock, flags);
-    return;
-    }
-  /* Now we handle SCSI phases         */
-  switch(status_reg & PHBITS)       /* Filter SCSI phase out of status reg */
-    {
-    case PHASE_DATA_OUT:
-      {
-      if(int_reg & BS)
-        {
-        current_command->SCp.phase = data_out;
-        outb(FLUSH_FIFO, base + COMMAND_REG);
-        sym53c416_set_transfer_counter(base, current_command->request_bufflen);
-        outb(TRANSFER_INFORMATION | PIO_MODE, base + COMMAND_REG);
-        if(!current_command->use_sg)
-          tot_trans = sym53c416_write(base, current_command->request_buffer, current_command->request_bufflen);
-        else
-          {
-          sgcount = current_command->use_sg;
-          sglist = current_command->request_buffer;
-          while(sgcount--)
-            {
-            tot_trans += sym53c416_write(base, sglist->address, sglist->length);
-            sglist++;
-            }
-          }
-        if(tot_trans < current_command->underflow)
-          printk("sym53c416: Warning: underflow, wrote %d bytes, request for %d bytes\n", tot_trans, current_command->underflow);
-        }
-      break;
-      }
-    case PHASE_DATA_IN:
-      {
-      if(int_reg & BS)
-        {
-        current_command->SCp.phase = data_in;
-        outb(FLUSH_FIFO, base + COMMAND_REG);
-        sym53c416_set_transfer_counter(base, current_command->request_bufflen);
-        outb(TRANSFER_INFORMATION | PIO_MODE, base + COMMAND_REG);
-        if(!current_command->use_sg)
-          tot_trans = sym53c416_read(base, current_command->request_buffer, current_command->request_bufflen);
-        else
-          {
-          sgcount = current_command->use_sg;
-          sglist = current_command->request_buffer;
-          while(sgcount--)
-            {
-            tot_trans += sym53c416_read(base, sglist->address, sglist->length);
-            sglist++;
-            }
-          }
-        if(tot_trans < current_command->underflow)
-          printk("sym53c416: Warning: underflow, read %d bytes, request for %d bytes\n", tot_trans, current_command->underflow);
-        }
-      break;
-      }
-    case PHASE_COMMAND:
-      {
-      current_command->SCp.phase = command_ph;
-      printk("sym53c416: Warning: Unknown interrupt in command phase\n");
-      break;
-      }
-    case PHASE_STATUS:
-      {
-      current_command->SCp.phase = status_ph;
-      outb(FLUSH_FIFO, base + COMMAND_REG);
-      outb(INIT_COMM_COMPLETE_SEQ, base + COMMAND_REG);
-      break;
-      }
-    case PHASE_RESERVED_1:
-    case PHASE_RESERVED_2:
-      {
-      printk("sym53c416: Warning: Reserved phase\n");
-      break;
-      }
-    case PHASE_MESSAGE_OUT:
-      {
-      current_command->SCp.phase = message_out;
-      outb(SET_ATN, base + COMMAND_REG);
-      outb(MSG_ACCEPTED, base + COMMAND_REG);
-      break;
-      }
-    case PHASE_MESSAGE_IN:
-      {
-      current_command->SCp.phase = message_in;
-      current_command->SCp.Status = inb(base + SCSI_FIFO);
-      current_command->SCp.Message = inb(base + SCSI_FIFO);
-      if(current_command->SCp.Message == SAVE_POINTERS || current_command->SCp.Message == DISCONNECT)
-        outb(SET_ATN, base + COMMAND_REG);
-      outb(MSG_ACCEPTED, base + COMMAND_REG);
-      break;
-      }
-    }
-  }
+{
+	int base = 0;
+	int i;
+	unsigned long flags = 0;
+	unsigned char status_reg, pio_int_reg, int_reg;
+	struct scatterlist *sglist;
+	unsigned int sgcount;
+	unsigned int tot_trans = 0;
+
+	/* We search the base address of the host adapter which caused the interrupt */
+	/* FIXME: should pass dev_id sensibly as hosts[i] */
+	for(i = 0; i < host_index && !base; i++)
+		if(irq == hosts[i].irq)
+			base = hosts[i].base;
+	/* If no adapter found, we cannot handle the interrupt. Leave a message */
+	/* and continue. This should never happen...                            */
+	if(!base)
+	{
+		printk(KERN_ERR "sym53c416: No host adapter defined for interrupt %d\n", irq);
+		return;
+	}
+	/* Now we have the base address and we can start handling the interrupt */
+
+	spin_lock_irqsave(&io_request_lock,flags);
+	status_reg = inb(base + STATUS_REG);
+	pio_int_reg = inb(base + PIO_INT_REG);
+	int_reg = inb(base + INT_REG);
+	spin_unlock_irqrestore(&io_request_lock, flags);
+
+	/* First, we handle error conditions */
+	if(int_reg & SCI)         /* SCSI Reset */
+	{
+		printk(KERN_DEBUG "sym53c416: Reset received\n");
+		current_command->SCp.phase = idle;
+		current_command->result = DID_RESET << 16;
+		spin_lock_irqsave(&io_request_lock, flags);
+		current_command->scsi_done(current_command);
+		spin_unlock_irqrestore(&io_request_lock, flags);
+		return;
+	}
+	if(int_reg & ILCMD)       /* Illegal Command */
+	{
+		printk(KERN_WARNING "sym53c416: Illegal Command: 0x%02x.\n", inb(base + COMMAND_REG));
+		current_command->SCp.phase = idle;
+		current_command->result = DID_ERROR << 16;
+		spin_lock_irqsave(&io_request_lock, flags);
+		current_command->scsi_done(current_command);
+		spin_unlock_irqrestore(&io_request_lock, flags);
+		return;
+	}
+	if(status_reg & GE)         /* Gross Error */
+	{
+		printk(KERN_WARNING "sym53c416: Controller reports gross error.\n");
+		current_command->SCp.phase = idle;
+		current_command->result = DID_ERROR << 16;
+		spin_lock_irqsave(&io_request_lock, flags);
+		current_command->scsi_done(current_command);
+		spin_unlock_irqrestore(&io_request_lock, flags);
+		return;
+	}
+	if(status_reg & PE)         /* Parity Error */
+	{
+		printk(KERN_WARNING "sym53c416:SCSI parity error.\n");
+		current_command->SCp.phase = idle;
+		current_command->result = DID_PARITY << 16;
+		spin_lock_irqsave(&io_request_lock, flags);
+		current_command->scsi_done(current_command);
+		spin_unlock_irqrestore(&io_request_lock, flags);
+		return;
+	}
+	if(pio_int_reg & (CE | OUE))
+	{
+		printk(KERN_WARNING "sym53c416: PIO interrupt error.\n");
+		current_command->SCp.phase = idle;
+		current_command->result = DID_ERROR << 16;
+		spin_lock_irqsave(&io_request_lock, flags);
+		current_command->scsi_done(current_command);
+		spin_unlock_irqrestore(&io_request_lock, flags);
+		return;
+	}
+	if(int_reg & DIS)           /* Disconnect */
+	{
+		if(current_command->SCp.phase != message_in)
+			current_command->result = DID_NO_CONNECT << 16;
+		else
+			current_command->result = (current_command->SCp.Status & 0xFF) | ((current_command->SCp.Message & 0xFF) << 8) | (DID_OK << 16);
+		current_command->SCp.phase = idle;
+		spin_lock_irqsave(&io_request_lock, flags);
+		current_command->scsi_done(current_command);
+		spin_unlock_irqrestore(&io_request_lock, flags);
+		return;
+	}
+	/* Now we handle SCSI phases         */
+
+	switch(status_reg & PHBITS)       /* Filter SCSI phase out of status reg */
+	{
+		case PHASE_DATA_OUT:
+		{
+			if(int_reg & BS)
+			{
+				current_command->SCp.phase = data_out;
+				outb(FLUSH_FIFO, base + COMMAND_REG);
+				sym53c416_set_transfer_counter(base, current_command->request_bufflen);
+				outb(TRANSFER_INFORMATION | PIO_MODE, base + COMMAND_REG);
+				if(!current_command->use_sg)
+					tot_trans = sym53c416_write(base, current_command->request_buffer, current_command->request_bufflen);
+				else
+				{
+					sgcount = current_command->use_sg;
+					sglist = current_command->request_buffer;
+					while(sgcount--)
+					{
+						tot_trans += sym53c416_write(base, sglist->address, sglist->length);
+						sglist++;
+					}
+				}
+				if(tot_trans < current_command->underflow)
+					printk(KERN_WARNING "sym53c416: Underflow, wrote %d bytes, request for %d bytes.\n", tot_trans, current_command->underflow);
+			}
+			break;
+		}
+
+		case PHASE_DATA_IN:
+		{
+			if(int_reg & BS)
+			{
+				current_command->SCp.phase = data_in;
+				outb(FLUSH_FIFO, base + COMMAND_REG);
+				sym53c416_set_transfer_counter(base, current_command->request_bufflen);
+				outb(TRANSFER_INFORMATION | PIO_MODE, base + COMMAND_REG);
+				if(!current_command->use_sg)
+					tot_trans = sym53c416_read(base, current_command->request_buffer, current_command->request_bufflen);
+				else
+				{
+					sgcount = current_command->use_sg;
+					sglist = current_command->request_buffer;
+					while(sgcount--)
+					{
+						tot_trans += sym53c416_read(base, sglist->address, sglist->length);
+						sglist++;
+					}
+				}
+				if(tot_trans < current_command->underflow)
+					printk(KERN_WARNING "sym53c416: Underflow, read %d bytes, request for %d bytes.\n", tot_trans, current_command->underflow);
+			}
+			break;
+		}
+
+		case PHASE_COMMAND:
+		{
+			current_command->SCp.phase = command_ph;
+			printk(KERN_ERR "sym53c416: Unknown interrupt in command phase.\n");
+			break;
+		}
+
+		case PHASE_STATUS:
+		{
+			current_command->SCp.phase = status_ph;
+			outb(FLUSH_FIFO, base + COMMAND_REG);
+			outb(INIT_COMM_COMPLETE_SEQ, base + COMMAND_REG);
+			break;
+		}
+		
+		case PHASE_RESERVED_1:
+		case PHASE_RESERVED_2:
+		{
+			printk(KERN_ERR "sym53c416: Reserved phase occurred.\n");
+			break;
+		}
+
+		case PHASE_MESSAGE_OUT:
+		{
+			current_command->SCp.phase = message_out;
+			outb(SET_ATN, base + COMMAND_REG);
+			outb(MSG_ACCEPTED, base + COMMAND_REG);
+			break;
+		}
+
+		case PHASE_MESSAGE_IN:
+		{
+			current_command->SCp.phase = message_in;
+			current_command->SCp.Status = inb(base + SCSI_FIFO);
+			current_command->SCp.Message = inb(base + SCSI_FIFO);
+			if(current_command->SCp.Message == SAVE_POINTERS || current_command->SCp.Message == DISCONNECT)
+				outb(SET_ATN, base + COMMAND_REG);
+			outb(MSG_ACCEPTED, base + COMMAND_REG);
+			break;
+		}
+	}
+}
 
 static void sym53c416_init(int base, int scsi_id)
-  {
-  outb(RESET_CHIP, base + COMMAND_REG);
-  outb(NOOP, base + COMMAND_REG);
-  outb(0x99, base + TOM); /* Time out of 250 ms */
-  outb(0x05, base + STP);
-  outb(0x00, base + SYNC_OFFSET);
-  outb(EPC | scsi_id, base + CONF_REG_1);
-  outb(FE | SCSI2 | TBPA, base + CONF_REG_2);
-  outb(IDMRC | QTE | CDB10 | FSCSI | FCLK, base + CONF_REG_3);
-  outb(0x83 | EAN, base + CONF_REG_4);
-  outb(IE | WSE0, base + CONF_REG_5);
-  outb(0, base + FEATURE_EN);
-  }
+{
+	outb(RESET_CHIP, base + COMMAND_REG);
+	outb(NOOP, base + COMMAND_REG);
+	outb(0x99, base + TOM); /* Time out of 250 ms */
+	outb(0x05, base + STP);
+	outb(0x00, base + SYNC_OFFSET);
+	outb(EPC | scsi_id, base + CONF_REG_1);
+	outb(FE | SCSI2 | TBPA, base + CONF_REG_2);
+	outb(IDMRC | QTE | CDB10 | FSCSI | FCLK, base + CONF_REG_3);
+	outb(0x83 | EAN, base + CONF_REG_4);
+	outb(IE | WSE0, base + CONF_REG_5);
+	outb(0, base + FEATURE_EN);
+}
 
 static int sym53c416_probeirq(int base, int scsi_id)
-  {
-  int irq, irqs, i;
+{
+	int irq, irqs, i;
 
-  /* Clear interrupt register */
-  inb(base + INT_REG);
-  /* Start probing for irq's */
-  irqs = probe_irq_on();
-  /* Reinit chip */
-  sym53c416_init(base, scsi_id);
-  /* Cause interrupt */
-  outb(NOOP, base + COMMAND_REG);
-  outb(ILLEGAL, base + COMMAND_REG);
-  outb(0x07, base + DEST_BUS_ID);
-  outb(0x00, base + DEST_BUS_ID);
-  /* Wait for interrupt to occur */
-  i = jiffies + 20;
-  while(i > jiffies && !(inb(base + STATUS_REG) & SCI))
-    barrier();
-  if(i <= jiffies) /* timed out */
-    return 0;
-  /* Get occurred irq */
-  irq = probe_irq_off(irqs);
-  sym53c416_init(base, scsi_id);
-  return irq;
-  }
+	/* Clear interrupt register */
+	inb(base + INT_REG);
+	/* Start probing for irq's */
+	irqs = probe_irq_on();
+	/* Reinit chip */
+	sym53c416_init(base, scsi_id);
+	/* Cause interrupt */
+	outb(NOOP, base + COMMAND_REG);
+	outb(ILLEGAL, base + COMMAND_REG);
+	outb(0x07, base + DEST_BUS_ID);
+	outb(0x00, base + DEST_BUS_ID);
+	/* Wait for interrupt to occur */
+	i = jiffies + 20;
+	while(i > jiffies && !(inb(base + STATUS_REG) & SCI))
+		barrier();
+	if(i <= jiffies) /* timed out */
+		return 0;
+	/* Get occurred irq */
+	irq = probe_irq_off(irqs);
+	sym53c416_init(base, scsi_id);
+	return irq;
+}
 
 /* Setup: sym53c416=base,irq */
 void sym53c416_setup(char *str, int *ints)
-  {
-  int i;
+{
+	int i;
 
-  if(host_index >= MAXHOSTS)
-    {
-    printk("sym53c416.c: Too many hosts defined\n");
-    }
-  else
-    {
-    if(ints[0] < 1 || ints[0] > 2)
-      {
-      printk("sym53c416.c: Wrong number of parameters:\n");
-      printk("sym53c416.c: usage: sym53c416=<base>[,<irq>]\n");
-      }
-    else
-      {
-      for(i = 0; i < host_index && i >= 0; i++)
-        if(hosts[i].base == ints[1])
-          i = -2;
-      if(i >= 0)
-        {
-        hosts[host_index].base = ints[1];
-        hosts[host_index].irq = (ints[0] == 2)? ints[2] : 0;
-        host_index++;
-        }
-      }
-    }
-  }
+	if(host_index >= MAXHOSTS)
+	{
+		printk(KERN_WARNING "sym53c416: Too many hosts defined\n");
+		return;
+	}
+	if(ints[0] < 1 || ints[0] > 2)
+	{
+		printk(KERN_ERR "sym53c416: Wrong number of parameters:\n");
+		printk(KERN_ERR "sym53c416: usage: sym53c416=<base>[,<irq>]\n");
+		return;
+	}
+	for(i = 0; i < host_index && i >= 0; i++)
+	        if(hosts[i].base == ints[1])
+        		i = -2;
+	if(i >= 0)
+	{
+        	hosts[host_index].base = ints[1];
+        	hosts[host_index].irq = (ints[0] == 2)? ints[2] : 0;
+        	host_index++;
+	}
+}
 
 static int sym53c416_test(int base)
-  {
-  outb(RESET_CHIP, base + COMMAND_REG);
-  outb(NOOP, base + COMMAND_REG);
-  if(inb(base + COMMAND_REG) != NOOP)
-    return 0;
-  if(!inb(base + TC_HIGH) || inb(base + TC_HIGH) == 0xFF)
-    return 0;
-  if((inb(base + PIO_INT_REG) & (FULL | EMPTY | CE | OUE | FIE | EIE)) != EMPTY)
-    return 0;
-  return 1;
-  }
+{
+	outb(RESET_CHIP, base + COMMAND_REG);
+	outb(NOOP, base + COMMAND_REG);
+	if(inb(base + COMMAND_REG) != NOOP)
+		return 0;
+	if(!inb(base + TC_HIGH) || inb(base + TC_HIGH) == 0xFF)
+		return 0;
+	if((inb(base + PIO_INT_REG) & (FULL | EMPTY | CE | OUE | FIE | EIE)) != EMPTY)
+		return 0;
+	return 1;
+}
+
+
+static struct isapnp_device_id id_table[] = {
+	{	ISAPNP_ANY_ID, ISAPNP_ANY_ID,
+		ISAPNP_VENDOR('S','L','I'), ISAPNP_FUNCTION(0x4163), 0 },
+	{0}
+};
+
+MODULE_DEVICE_TABLE(isapnp, id_table);
 
 void sym53c416_probe(void)
-  {
-  int *base = probeaddrs;
-  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);
-      }
-  }
+{
+	int *base = probeaddrs;
+	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);
+		}
+	}
+}
 
 int sym53c416_detect(Scsi_Host_Template *tpnt)
-  {
-  unsigned long flags;
-  struct Scsi_Host * shpnt = NULL;
-  int i;
-  int count;
-
+{
+	unsigned long flags;
+	struct Scsi_Host * shpnt = NULL;
+	int i;
+	int count;
+	struct pci_dev *idev = NULL;
+	
 #ifdef MODULE
-  int ints[3];
+	int ints[3];
 
-  ints[0] = 2;
-  if(sym53c416_base)
-    {
-    ints[1] = sym53c416_base[0];
-    ints[2] = sym53c416_base[1];
-    sym53c416_setup(NULL, ints);
-    }
-  if(sym53c416_base_1)
-    {
-    ints[1] = sym53c416_base_1[0];
-    ints[2] = sym53c416_base_1[1];
-    sym53c416_setup(NULL, ints);
-    }
-  if(sym53c416_base_2)
-    {
-    ints[1] = sym53c416_base_2[0];
-    ints[2] = sym53c416_base_2[1];
-    sym53c416_setup(NULL, ints);
-    }
-  if(sym53c416_base_3)
-    {
-    ints[1] = sym53c416_base_3[0];
-    ints[2] = sym53c416_base_3[1];
-    sym53c416_setup(NULL, ints);
-    }
+	ints[0] = 2;
+	if(sym53c416_base)
+	{
+		ints[1] = sym53c416_base[0];
+		ints[2] = sym53c416_base[1];
+		sym53c416_setup(NULL, ints);
+	}
+	if(sym53c416_base_1)
+	{
+		ints[1] = sym53c416_base_1[0];
+		ints[2] = sym53c416_base_1[1];
+		sym53c416_setup(NULL, ints);
+	}
+	if(sym53c416_base_2)
+	{
+		ints[1] = sym53c416_base_2[0];
+		ints[2] = sym53c416_base_2[1];
+		sym53c416_setup(NULL, ints);
+	}
+	if(sym53c416_base_3)
+	{
+		ints[1] = sym53c416_base_3[0];
+		ints[2] = sym53c416_base_3[1];
+		sym53c416_setup(NULL, ints);
+	}
 #endif
+	printk(KERN_INFO "sym53c416.c: %s\n", VERSION_STRING);
 
-  printk("sym53c416.c: %s\n", VERSION_STRING);
-
-  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))
-      printk("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("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;
-        save_flags(flags);
-        cli();
-        /* Request for specified IRQ */
-        if(request_irq(hosts[i].irq, sym53c416_intr_handle, 0, ID, NULL))
-          {
-          restore_flags(flags);
-          printk("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++;
-          restore_flags(flags);
-          }
-        }
-      }
-  return count;
-  }
+	while((idev=isapnp_find_dev(NULL, ISAPNP_VENDOR('S','L','I'), 
+				ISAPNP_FUNCTION(0x4163), idev))!=NULL)
+	{
+		int i[3];
+		
+		if(idev->prepare(idev)<0)
+		{
+			printk(KERN_WARNING "sym53c416: unable to prepare PnP card.\n");
+			continue;
+		}
+		if(idev->activate(idev)<0)
+		{
+			printk(KERN_WARNING "sym53c416: unable to activate PnP card.\n");
+			continue;
+		}
+		
+		i[0] = 2;
+		i[1] = idev->resource[0].start;
+		i[2] = idev->irq_resource[0].start;
+		
+		printk(KERN_INFO "sym53c416: ISAPnP card found and configured at 0x%X, IRQ %d.\n",
+			i[1], i[2]);
+		sym53c416_setup(NULL, i);
+	}
+	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))
+			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;
+				save_flags(flags);
+				cli();
+				/* FIXME: Request_irq with CLI is not safe */
+				/* Request for specified IRQ */
+				if(request_irq(hosts[i].irq, sym53c416_intr_handle, 0, ID, NULL))
+				{
+					restore_flags(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++;
+					restore_flags(flags);
+				}
+			}
+		}
+	}
+	return count;
+}
 
 const char *sym53c416_info(struct Scsi_Host *SChost)
-  {
-  int i;
-  int base = SChost->io_port;
-  int irq = SChost->irq;
-  int scsi_id = 0;
-  int rev = inb(base + TC_HIGH);
-
-  for(i = 0; i < host_index; i++)
-    if(hosts[i].base == base)
-      scsi_id = hosts[i].scsi_id;
-  sprintf(info, "Symbios Logic 53c416 (rev. %d) at 0x%03x, irq %d, SCSI-ID %d, %s pio", rev, base, irq, scsi_id, (fastpio)? "fast" : "slow");
-  return info;
-  }
+{
+	int i;
+	int base = SChost->io_port;
+	int irq = SChost->irq;
+	int scsi_id = 0;
+	int rev = inb(base + TC_HIGH);
+
+	for(i = 0; i < host_index; i++)
+		if(hosts[i].base == base)
+			scsi_id = hosts[i].scsi_id;
+	sprintf(info, "Symbios Logic 53c416 (rev. %d) at 0x%03x, irq %d, SCSI-ID %d, %s pio", rev, base, irq, scsi_id, (fastpio)? "fast" : "slow");
+	return info;
+}
 
 int sym53c416_queuecommand(Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *))
-  {
-  int base;
-  unsigned long flags = 0;
-  int i;
-
-  /* Store base register as we can have more than one controller in the system */
-  base = SCpnt->host->io_port;
-  current_command = SCpnt;                  /* set current command                */
-  current_command->scsi_done = done;        /* set ptr to done function           */
-  current_command->SCp.phase = command_ph;  /* currect phase is the command phase */
-  current_command->SCp.Status = 0;
-  current_command->SCp.Message = 0;
-
-  save_flags(flags);
-  cli();
-  outb(SCpnt->target, base + DEST_BUS_ID); /* Set scsi id target        */
-  outb(FLUSH_FIFO, base + COMMAND_REG);    /* Flush SCSI and PIO FIFO's */
-  /* Write SCSI command into the SCSI fifo */
-  for(i = 0; i < SCpnt->cmd_len; i++)
-    outb(SCpnt->cmnd[i], base + SCSI_FIFO);
-  /* Start selection sequence */
-  outb(SEL_WITHOUT_ATN_SEQ, base + COMMAND_REG);
-  /* Now an interrupt will be generated which we will catch in out interrupt routine */
-  restore_flags(flags);
-  return 0;
-  }
+{
+	int base;
+	unsigned long flags = 0;
+	int i;
+
+	/* Store base register as we can have more than one controller in the system */
+	base = SCpnt->host->io_port;
+	current_command = SCpnt;                  /* set current command                */
+	current_command->scsi_done = done;        /* set ptr to done function           */
+	current_command->SCp.phase = command_ph;  /* currect phase is the command phase */
+	current_command->SCp.Status = 0;
+	current_command->SCp.Message = 0;
+
+	save_flags(flags);
+	cli();
+	outb(SCpnt->target, base + DEST_BUS_ID); /* Set scsi id target        */
+	outb(FLUSH_FIFO, base + COMMAND_REG);    /* Flush SCSI and PIO FIFO's */
+	/* Write SCSI command into the SCSI fifo */
+	for(i = 0; i < SCpnt->cmd_len; i++)
+		outb(SCpnt->cmnd[i], base + SCSI_FIFO);
+	/* Start selection sequence */
+	outb(SEL_WITHOUT_ATN_SEQ, base + COMMAND_REG);
+	/* Now an interrupt will be generated which we will catch in out interrupt routine */
+	restore_flags(flags);
+	return 0;
+}
 
 static void internal_done(Scsi_Cmnd *SCpnt)
-  {
-  SCpnt->SCp.Status++;
-  }
-
-int sym53c416_command(Scsi_Cmnd *SCpnt)
-  {
-  sym53c416_queuecommand(SCpnt, internal_done);
-  SCpnt->SCp.Status = 0;
-  while(!SCpnt->SCp.Status)
-    barrier();
-  return SCpnt->result;
-  }
-
-int sym53c416_abort(Scsi_Cmnd *SCpnt)
-  {
-  printk("sym53c416_abort\n");
-
-  /* We don't know how to abort for the moment */
-  return SCSI_ABORT_SNOOZE;
-  }
-
-int sym53c416_reset(Scsi_Cmnd *SCpnt, unsigned int reset_flags)
-  {
-  int base;
-  int scsi_id = -1;
-  int i;
-
-  printk("sym53c416_reset\n");
-  base = SCpnt->host->io_port;
-  /* search scsi_id */
-  for(i = 0; i < host_index && scsi_id != -1; i++)
-    if(hosts[i].base == base)
-      scsi_id = hosts[i].scsi_id;
-  outb(RESET_CHIP, base + COMMAND_REG);
-  outb(NOOP | PIO_MODE, base + COMMAND_REG);
-  outb(RESET_SCSI_BUS, base + COMMAND_REG);
-  sym53c416_init(base, scsi_id);
-  return SCSI_RESET_PENDING;
-  }
-
-int sym53c416_bios_param(Disk *disk, kdev_t dev, int *ip)
-  {
-  int size;
-
-  size = disk->capacity;
-  ip[0] = 64;                         /* heads                        */
-  ip[1] = 32;                         /* sectors                      */
-  if((ip[2] = size >> 11) > 1024)     /* cylinders, test for big disk */
-    {
-    ip[0] = 255;                      /* heads                        */
-    ip[1] = 63;                       /* sectors                      */
-    ip[2] = size / (255 * 63);        /* cylinders                    */
-    }
-  return 0;
-  }
+{
+	SCpnt->SCp.Status++;
+}
+
+static int sym53c416_command(Scsi_Cmnd *SCpnt)
+{
+	sym53c416_queuecommand(SCpnt, internal_done);
+	SCpnt->SCp.Status = 0;
+	while(!SCpnt->SCp.Status)
+		barrier();
+	return SCpnt->result;
+}
+
+static int sym53c416_abort(Scsi_Cmnd *SCpnt)
+{
+	//printk("sym53c416_abort\n");
+	/* We don't know how to abort for the moment */
+	return SCSI_ABORT_SNOOZE;
+}
+
+static int sym53c416_reset(Scsi_Cmnd *SCpnt, unsigned int reset_flags)
+{
+	int base;
+	int scsi_id = -1;	
+	int i;
+
+	//printk("sym53c416_reset\n");
+	base = SCpnt->host->io_port;
+	/* search scsi_id */
+	for(i = 0; i < host_index && scsi_id != -1; i++)
+		if(hosts[i].base == base)
+			scsi_id = hosts[i].scsi_id;
+	outb(RESET_CHIP, base + COMMAND_REG);
+	outb(NOOP | PIO_MODE, base + COMMAND_REG);
+	outb(RESET_SCSI_BUS, base + COMMAND_REG);
+	sym53c416_init(base, scsi_id);
+	return SCSI_RESET_PENDING;
+}
+
+static int sym53c416_bios_param(Disk *disk, kdev_t dev, int *ip)
+{
+	int size;
+
+	size = disk->capacity;
+	ip[0] = 64;				/* heads                        */
+	ip[1] = 32;				/* sectors                      */
+	if((ip[2] = size >> 11) > 1024)		/* cylinders, test for big disk */
+	{
+		ip[0] = 255;			/* heads                        */
+		ip[1] = 63;			/* sectors                      */
+		ip[2] = size / (255 * 63);	/* cylinders                    */
+	}
+	return 0;
+}
 
 /* Loadable module support */
 #ifdef MODULE
diff -urN linux-2.4.6-pre5/drivers/scsi/sym53c416.h linux/drivers/scsi/sym53c416.h
--- linux-2.4.6-pre5/drivers/scsi/sym53c416.h	Mon Dec 11 13:19:20 2000
+++ linux/drivers/scsi/sym53c416.h	Mon Dec  3 22:49:12 2001
@@ -31,14 +31,14 @@
 
 #define SYM53C416_SCSI_ID 7
 
-extern int sym53c416_detect(Scsi_Host_Template *);
-extern const char *sym53c416_info(struct Scsi_Host *);
-extern int sym53c416_command(Scsi_Cmnd *);
-extern int sym53c416_queuecommand(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *));
-extern int sym53c416_abort(Scsi_Cmnd *);
-extern int sym53c416_reset(Scsi_Cmnd *, unsigned int);
-extern int sym53c416_bios_param(Disk *, kdev_t, int *);
-extern void sym53c416_setup(char *str, int *ints);
+static int sym53c416_detect(Scsi_Host_Template *);
+static const char *sym53c416_info(struct Scsi_Host *);
+static int sym53c416_command(Scsi_Cmnd *);
+static int sym53c416_queuecommand(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *));
+static int sym53c416_abort(Scsi_Cmnd *);
+static int sym53c416_reset(Scsi_Cmnd *, unsigned int);
+static int sym53c416_bios_param(Disk *, kdev_t, int *);
+static void sym53c416_setup(char *str, int *ints);
 
 #define SYM53C416 {                                          \
                   proc_name:         "sym53c416",   \
diff -urN linux-2.4.6-pre5/drivers/sound/cmpci.c linux/drivers/sound/cmpci.c
--- linux-2.4.6-pre5/drivers/sound/cmpci.c	Fri Feb  9 11:30:23 2001
+++ linux/drivers/sound/cmpci.c	Mon Dec  3 22:49:12 2001
@@ -1,12 +1,16 @@
 /*****************************************************************************/
-
 /*
  *      cmpci.c  --  C-Media PCI audio driver.
  *
- *      Copyright (C) 1999  ChenLi Tien (cltien@home.com)
+ *      Copyright (C) 1999  ChenLi Tien (cltien@cmedia.com.tw)
+ *      		    C-media support (support@cmedia.com.tw)
  *
- *	Based on the PCI drivers by Thomas Sailer (sailer@ife.ee.ethz.ch)
+ *      Based on the PCI drivers by Thomas Sailer (sailer@ife.ee.ethz.ch)
  *
+ * 	For update, visit:
+ * 		http://members.home.net/puresoft/cmedia.html
+ * 		http://www.cmedia.com.tw
+ * 	
  *      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
@@ -57,8 +61,6 @@
  *                     reported by Johan Maes <joma@telindus.be>
  *    22.03.99   0.12  return EAGAIN instead of EBUSY when O_NONBLOCK
  *                     read/write cannot be executed
- *    20 09 99   0.13  merged the generic changes in sonicvibes since this
- *		       diverged.
  *    18.08.99   1.5   Only deallocate DMA buffer when unloading.
  *    02.09.99   1.6   Enable SPDIF LOOP
  *                     Change the mixer read back
@@ -66,47 +68,32 @@
  *                     Add support for modem, S/PDIF loop and 4 channels.
  *                     (8738 only)
  *                     Fix bug cause x11amp cannot play.
- *    $Log: cmpci.c,v $
- *    Revision 2.41  1999/10/27 02:00:05  cltien
- *    Now the fragsize for modem is activated by parameter.
- *
- *    Revision 2.40  1999/10/26 23:38:26  cltien
- *    Remove debugging message in cm_write which may cause module counter not 0.
- *
- *    Revision 2.39  1999/10/26 21:52:50  cltien
- *    I forgor too adjust mic recording volume, as it should be moved to 5MUTEMONO.
- *    Change the DYNAMIC macro to FIXEDDMA, which means static DMA buffer.
- *
- *    Revision 2.38  1999/10/08 21:59:03  cltien
- *    Set FLINKON and reset FLINKOFF for modem.
- *
- *    Revision 2.37  1999/09/28 02:57:04  cltien
- *    Add set_bus_master() to make sure bus master enabled.
- *
- *    Revision 2.36  1999/09/22 14:15:03  cltien
- *    Use open_sem to avoid multiple access to open_mode.
- *    Use wakeup in IntrClose to activate process in waiting queue.
- *
- *    Revision 2.35  1999/09/22 13:20:53  cltien
- *    Use open_mode to check if DAC in used. Also more check in IntrWrite and IntrClose. Now the modem can access DAC safely.
- *
- *    Revision 2.34  1999/09/22 03:29:57  cltien
- *    Use module count to decide which one to access the dac.
  *
+ *    Fixes:
+ *    Arnaldo Carvalho de Melo <acme@conectiva.com.br>
+ *    18/05/2001 - .bss nitpicks, fix a bug in set_dac_channels where it
+ *    		   was calling prog_dmabuf with s->lock held, call missing
+ *    		   unlock_kernel in cm_midi_release
+ *
+ *    Fri May 25 2001 - Carlos Eduardo Gorges <carlos@techlinux.com.br>
+ *    - some driver cleanups
+ *    - spin[un]lock* revision ( fix SMP support )
+ *    - cosmetic code changes
  *
  */
- 
+
 /*****************************************************************************/
       
-#include <linux/config.h>
+#define EXPORT_SYMTAB
 #include <linux/version.h>
+#include <linux/config.h>
 #include <linux/module.h>
 #include <linux/string.h>
 #include <linux/ioport.h>
 #include <linux/sched.h>
 #include <linux/delay.h>
 #include <linux/sound.h>
-#include <linux/slab.h>
+#include <linux/malloc.h>
 #include <linux/soundcard.h>
 #include <linux/pci.h>
 #include <linux/wrapper.h>
@@ -139,6 +126,9 @@
 #ifndef PCI_DEVICE_ID_CMEDIA_CM8738
 #define PCI_DEVICE_ID_CMEDIA_CM8738  0x0111
 #endif
+#ifndef PCI_DEVICE_ID_CMEDIA_CM8738B
+#define PCI_DEVICE_ID_CMEDIA_CM8738B 0x0112
+#endif
 
 #define CM_MAGIC  ((PCI_VENDOR_ID_CMEDIA<<16)|PCI_DEVICE_ID_CMEDIA_CM8338A)
 
@@ -217,14 +207,14 @@
 #define CM_CFMT_STEREO     0x01
 #define CM_CFMT_16BIT      0x02
 #define CM_CFMT_MASK       0x03
-#define CM_CFMT_DACSHIFT   0   
-#define CM_CFMT_ADCSHIFT   2
+#define CM_CFMT_DACSHIFT   2
+#define CM_CFMT_ADCSHIFT   0
 
 static const unsigned sample_size[] = { 1, 2, 2, 4 };
 static const unsigned sample_shift[] = { 0, 1, 1, 2 };
 
-#define CM_CENABLE_RE      0x2
-#define CM_CENABLE_PE      0x1
+#define CM_ENABLE_CH1      0x2
+#define CM_ENABLE_CH0      0x1
 
 
 /* MIDI buffer sizes */
@@ -238,6 +228,8 @@
 
 #define FMODE_DMFM 0x10
 
+#define SND_DEV_DSP16   5 
+
 /* --------------------------------------------------------------------- */
 
 struct cm_state {
@@ -255,6 +247,7 @@
 
 	/* hardware resources */
 	unsigned int iosb, iobase, iosynth, iomidi, iogame, irq;
+	unsigned short deviceid;
 
         /* mixer stuff */
         struct {
@@ -275,6 +268,7 @@
 
 	struct dmabuf {
 		void *rawbuf;
+		unsigned rawphys;
 		unsigned buforder;
 		unsigned numfrag;
 		unsigned fragshift;
@@ -307,12 +301,48 @@
 		unsigned char ibuf[MIDIINBUF];
 		unsigned char obuf[MIDIOUTBUF];
 	} midi;
+	
+	/* misc stuff */
+	int	chip_version;
+	int	max_channels;
+	int	curr_channels;
+	int	speakers;	// number of speakers
+	int	capability;	// HW capability, various for chip versions
+	int	status;		// HW or SW state
+	
+	/* spdif frame counter */
+	int	spdif_counter;
 };
 
+/* flags used for capability */
+#define	CAN_AC3_HW	0x00000001	// 037 or later
+#define	CAN_AC3_SW	0x00000002	// 033 or later
+#define	CAN_AC3		(CAN_AC3_HW | CAN_AC3_SW)
+#define CAN_DUAL_DAC	0x00000004	// 033 or later
+#define	CAN_MULTI_CH_HW	0x00000008	// 039 or later
+#define	CAN_MULTI_CH	(CAN_MULTI_CH_HW | CAN_DUAL_DAC)
+#define	CAN_LINE_AS_REAR	0x00000010	// 033 or later
+#define	CAN_LINE_AS_BASS	0x00000020	// 039 or later
+#define	CAN_MIC_AS_BASS		0x00000040	// 039 or later
+
+/* flags used for status */
+#define	DO_AC3_HW	0x00000001
+#define	DO_AC3_SW	0x00000002
+#define	DO_AC3		(DO_AC3_HW | DO_AC3_SW)
+#define	DO_DUAL_DAC	0x00000004
+#define	DO_MULTI_CH_HW	0x00000008
+#define	DO_MULTI_CH	(DO_MULTI_CH_HW | DO_DUAL_DAC)
+#define	DO_LINE_AS_REAR	0x00000010	// 033 or later
+#define	DO_LINE_AS_BASS	0x00000020	// 039 or later
+#define	DO_MIC_AS_BASS	0x00000040	// 039 or later
+#define	DO_SPDIF_OUT	0x00000100
+#define	DO_SPDIF_IN	0x00000200
+#define	DO_SPDIF_LOOP	0x00000400
+
 /* --------------------------------------------------------------------- */
 
-static struct cm_state *devs = NULL;
-static unsigned long wavetable_mem = 0;
+static struct cm_state *devs;
+static unsigned long wavetable_mem;
 
 /* --------------------------------------------------------------------- */
 
@@ -361,35 +391,76 @@
 
 /* --------------------------------------------------------------------- */
 
-static void set_dmadac(struct cm_state *s, unsigned int addr, unsigned int count)
+/*
+ * Why use byte IO? Nobody knows, but S3 does it also in their Windows driver.
+ */
+
+#undef DMABYTEIO
+
+static void maskb(unsigned int addr, unsigned int mask, unsigned int value)
 {
-	count--;
-	outl(addr, s->iobase + CODEC_CMI_CH0_FRAME1);
-	outw(count, s->iobase + CODEC_CMI_CH0_FRAME2);
-	outb(inb(s->iobase + CODEC_CMI_FUNCTRL0) & ~1, s->iobase + CODEC_CMI_FUNCTRL0);
-//	outb(inb(s->iobase + CODEC_CMI_FUNCTRL0 + 2) | 1, s->iobase + CODEC_CMI_FUNCTRL0 + 2);
+	outb((inb(addr) & mask) | value, addr);
+}
+
+static void maskw(unsigned int addr, unsigned int mask, unsigned int value)
+{
+	outw((inw(addr) & mask) | value, addr);
+}
+
+static void maskl(unsigned int addr, unsigned int mask, unsigned int value)
+{
+	outl((inl(addr) & mask) | value, addr);
+}
+
+static void set_dmadac1(struct cm_state *s, unsigned int addr, unsigned int count)
+{
+	if (addr)
+	    outl(addr, s->iobase + CODEC_CMI_CH0_FRAME1);
+	outw(count - 1, s->iobase + CODEC_CMI_CH0_FRAME2);
+	maskb(s->iobase + CODEC_CMI_FUNCTRL0, ~1, 0);
 }
 
 static void set_dmaadc(struct cm_state *s, unsigned int addr, unsigned int count)
 {
-	count--;
+	outl(addr, s->iobase + CODEC_CMI_CH0_FRAME1);
+	outw(count - 1, s->iobase + CODEC_CMI_CH0_FRAME2);
+	maskb(s->iobase + CODEC_CMI_FUNCTRL0, ~0, 1);
+}
+
+static void set_dmadac(struct cm_state *s, unsigned int addr, unsigned int count)
+{
 	outl(addr, s->iobase + CODEC_CMI_CH1_FRAME1);
-	outw(count, s->iobase + CODEC_CMI_CH1_FRAME2);
-	outb(inb(s->iobase + CODEC_CMI_FUNCTRL0) | 2, s->iobase + CODEC_CMI_FUNCTRL0);
-//	outb(inb(s->iobase + CODEC_CMI_FUNCTRL0 + 2) | 2, s->iobase + CODEC_CMI_FUNCTRL0 + 2);
+	outw(count - 1, s->iobase + CODEC_CMI_CH1_FRAME2);
+	maskb(s->iobase + CODEC_CMI_FUNCTRL0, ~2, 0);
+	if (s->status & DO_DUAL_DAC)
+		set_dmadac1(s, 0, count);
+}
+
+static void set_countadc(struct cm_state *s, unsigned count)
+{
+	outw(count - 1, s->iobase + CODEC_CMI_CH0_FRAME2 + 2);
+}
+
+static void set_countdac(struct cm_state *s, unsigned count)
+{
+	outw(count - 1, s->iobase + CODEC_CMI_CH1_FRAME2 + 2);
+	if (s->status & DO_DUAL_DAC)
+	    set_countadc(s, count);
 }
 
 extern __inline__ unsigned get_dmadac(struct cm_state *s)
 {
 	unsigned int curr_addr;
 
-	if (!s->dma_dac.dmasize || !(s->enable & CM_CENABLE_PE))
-		return 0;
-
-	curr_addr = inl(s->iobase + CODEC_CMI_CH0_FRAME1);
-	curr_addr -= virt_to_bus(s->dma_dac.rawbuf);
+#if 1
+	curr_addr = inw(s->iobase + CODEC_CMI_CH1_FRAME2) + 1;
+	curr_addr <<= sample_shift[(s->fmt >> CM_CFMT_DACSHIFT) & CM_CFMT_MASK];
 	curr_addr = s->dma_dac.dmasize - curr_addr;
+#else
+	curr_addr = inl(s->iobase + CODEC_CMI_CH1_FRAME1);
 	curr_addr &= ~(sample_size[(s->fmt >> CM_CFMT_DACSHIFT) & CM_CFMT_MASK]-1);
+	curr_addr -= s->dma_dac.rawphys;
+#endif
 	return curr_addr;
 }
 
@@ -397,22 +468,22 @@
 {
 	unsigned int curr_addr;
 
-	if (!s->dma_adc.dmasize || !(s->enable & CM_CENABLE_RE))
-		return 0;
-
-	curr_addr = inl(s->iobase + CODEC_CMI_CH1_FRAME1);
-	curr_addr -= virt_to_bus(s->dma_adc.rawbuf);
+#if 1
+	curr_addr = inw(s->iobase + CODEC_CMI_CH0_FRAME2) + 1;
+	curr_addr <<= sample_shift[(s->fmt >> CM_CFMT_ADCSHIFT) & CM_CFMT_MASK];
 	curr_addr = s->dma_adc.dmasize - curr_addr;
+#else
+	curr_addr = inl(s->iobase + CODEC_CMI_CH0_FRAME1);
 	curr_addr &= ~(sample_size[(s->fmt >> CM_CFMT_ADCSHIFT) & CM_CFMT_MASK]-1);
+	curr_addr -= s->dma_adc.rawphys;
+#endif
 	return curr_addr;
 }
 
 static void wrmixer(struct cm_state *s, unsigned char idx, unsigned char data)
 {
 	outb(idx, s->iobase + CODEC_SB16_ADDR);
-	udelay(10);
 	outb(data, s->iobase + CODEC_SB16_DATA);
-	udelay(10);
 }
 
 static unsigned char rdmixer(struct cm_state *s, unsigned char idx)
@@ -420,33 +491,31 @@
 	unsigned char v;
 
 	outb(idx, s->iobase + CODEC_SB16_ADDR);
-	udelay(10);
 	v = inb(s->iobase + CODEC_SB16_DATA);
-	udelay(10);
 	return v;
 }
 
+static void set_fmt_unlocked(struct cm_state *s, unsigned char mask, unsigned char data)
+{
+	if (mask)
+		s->fmt = inb(s->iobase + CODEC_CMI_CHFORMAT);
+	s->fmt = (s->fmt & mask) | data;
+	outb(s->fmt, s->iobase + CODEC_CMI_CHFORMAT);
+}
+
 static void set_fmt(struct cm_state *s, unsigned char mask, unsigned char data)
 {
 	unsigned long flags;
 
 	spin_lock_irqsave(&s->lock, flags);
-	if (mask) {
-		s->fmt = inb(s->iobase + CODEC_CMI_CHFORMAT);
-		udelay(10);
-	}
-	s->fmt = (s->fmt & mask) | data;
-	outb(s->fmt, s->iobase + CODEC_CMI_CHFORMAT);
+	set_fmt_unlocked(s,mask,data);
 	spin_unlock_irqrestore(&s->lock, flags);
-	udelay(10);
 }
 
 static void frobindir(struct cm_state *s, unsigned char idx, unsigned char mask, unsigned char data)
 {
 	outb(idx, s->iobase + CODEC_SB16_ADDR);
-	udelay(10);
 	outb((inb(s->iobase + CODEC_SB16_DATA) & mask) | data, s->iobase + CODEC_SB16_DATA);
-	udelay(10);
 }
 
 static struct {
@@ -463,125 +532,461 @@
 	{ 22050,	(16000 + 22050) / 2,	(22050 + 32000) / 2,	2 },
 	{ 32000,	(22050 + 32000) / 2,	(32000 + 44100) / 2,	6 },
 	{ 44100,	(32000 + 44100) / 2,	(44100 + 48000) / 2,	3 },
-	{ 48000,	(44100 + 48000) /2,	48000,			7 }
+	{ 48000,	(44100 + 48000) / 2,	48000,			7 }
 };
 
-static void set_dac_rate(struct cm_state *s, unsigned rate)
+static void set_spdifout_unlocked(struct cm_state *s, unsigned rate)
+{
+	if (rate == 48000 || rate == 44100) {
+		// SPDIFI48K SPDF_ACc97
+		maskl(s->iobase + CODEC_CMI_MISC_CTRL, ~0x01008000, rate == 48000 ? 0x01008000 : 0);
+		// ENSPDOUT
+		maskb(s->iobase + CODEC_CMI_LEGACY_CTRL + 2, ~0, 0x80);
+		// SPDF_1 SPD2DAC
+		maskw(s->iobase + CODEC_CMI_FUNCTRL1, ~0, 0x240);
+		// CDPLAY
+		if (s->chip_version >= 39)
+			maskb(s->iobase + CODEC_CMI_MIXER1, ~0, 1);
+		s->status |= DO_SPDIF_OUT;
+	} else {
+		maskb(s->iobase + CODEC_CMI_LEGACY_CTRL + 2, ~0x80, 0);
+		maskw(s->iobase + CODEC_CMI_FUNCTRL1, ~0x240, 0);
+		if (s->chip_version >= 39)
+			maskb(s->iobase + CODEC_CMI_MIXER1, ~1, 0);
+		s->status &= ~DO_SPDIF_OUT;
+	}
+}
+
+static void set_spdifout(struct cm_state *s, unsigned rate)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&s->lock, flags);
+	set_spdifout_unlocked(s,rate);
+	spin_unlock_irqrestore(&s->lock, flags);
+}
+
+/* find parity for bit 4~30 */
+static unsigned parity(unsigned data)
+{
+	unsigned parity = 0;
+	int counter = 4;
+
+	data >>= 4;	// start from bit 4
+	while (counter <= 30) {
+		if (data & 1)
+			parity++;
+		data >>= 1;
+		counter++;
+	}
+	return parity & 1;
+}
+
+static void set_ac3_unlocked(struct cm_state *s, unsigned rate)
+{
+	/* enable AC3 */
+	if (rate == 48000 || rate == 44100) {
+		// mute DAC
+		maskb(s->iobase + CODEC_CMI_MIXER1, ~0, 0x40);
+		// AC3EN for 037, 0x10
+		maskb(s->iobase + CODEC_CMI_CHFORMAT + 2, ~0, 0x10);
+		// AC3EN for 039, 0x04
+		maskb(s->iobase + CODEC_CMI_MISC_CTRL + 2, ~0, 0x04);
+		if (s->capability & CAN_AC3_HW) {
+			// SPD24SEL for 037, 0x02
+			// SPD24SEL for 039, 0x20, but cannot be set
+			maskb(s->iobase + CODEC_CMI_CHFORMAT + 2, ~0, 0x02);
+			s->status |= DO_AC3_HW;
+			if (s->chip_version >= 39)
+				maskb(s->iobase + CODEC_CMI_MIXER1, ~1, 0);
+		 } else {
+			// SPD32SEL for 037 & 039, 0x20
+			maskb(s->iobase + CODEC_CMI_MISC_CTRL + 2, ~0, 0x20);
+			// set 176K sample rate to fix 033 HW bug
+			if (s->chip_version == 33) {
+				if (rate == 48000)
+					maskb(s->iobase + CODEC_CMI_CHFORMAT + 1, ~0, 0x08);
+				else
+					maskb(s->iobase + CODEC_CMI_CHFORMAT + 1, ~0x08, 0);
+			}
+			s->status |= DO_AC3_SW;
+		}
+	} else {
+		maskb(s->iobase + CODEC_CMI_MIXER1, ~0x40, 0);
+		maskb(s->iobase + CODEC_CMI_CHFORMAT + 2, ~0x32, 0);
+		maskb(s->iobase + CODEC_CMI_MISC_CTRL + 2, ~0x24, 0);
+		maskb(s->iobase + CODEC_CMI_CHFORMAT + 1, ~0x08, 0);
+		if (s->chip_version == 33)
+			maskb(s->iobase + CODEC_CMI_CHFORMAT + 1, ~0x08, 0);
+		if (s->chip_version >= 39)
+			maskb(s->iobase + CODEC_CMI_MIXER1, ~0, 1);
+		s->status &= ~DO_AC3;
+	}
+	s->spdif_counter = 0;
+
+}
+
+static void set_ac3(struct cm_state *s, unsigned rate)
 {
 	unsigned long flags;
-	unsigned char freq = 4, val;
+
+	spin_lock_irqsave(&s->lock, flags);
+	set_spdifout_unlocked(s, rate);
+	set_ac3_unlocked(s,rate);
+	spin_unlock_irqrestore(&s->lock, flags);
+}
+
+static void trans_ac3(struct cm_state *s, void *dest, const char *source, int size)
+{
+	int   i = size / 2;
+	unsigned long data;
+	unsigned long *dst = (unsigned long *) dest;
+	unsigned short *src = (unsigned short *)source;
+
+	do {
+		data = (unsigned long) *src++;
+		data <<= 12;			// ok for 16-bit data
+		if (s->spdif_counter == 2 || s->spdif_counter == 3)
+			data |= 0x40000000;	// indicate AC-3 raw data
+		if (parity(data))
+			data |= 0x80000000;	// parity
+		if (s->spdif_counter == 0)
+			data |= 3;		// preamble 'M'
+		else if (s->spdif_counter & 1)
+			data |= 5;		// odd, 'W'
+		else
+			data |= 9;		// even, 'M'
+		*dst++ = data;
+		s->spdif_counter++;
+		if (s->spdif_counter == 384)
+			s->spdif_counter = 0;
+	} while (--i);
+}
+
+static void set_adc_rate_unlocked(struct cm_state *s, unsigned rate)
+{
+	unsigned char freq = 4;
 	int	i;
 
 	if (rate > 48000)
 		rate = 48000;
-	if (rate < 5512)
-		rate = 5512;
-	for (i = 0; i < sizeof(rate_lookup) / sizeof(rate_lookup[0]); i++)
-	{
-		if (rate > rate_lookup[i].lower && rate <= rate_lookup[i].upper)
-		{
+	if (rate < 8000)
+		rate = 8000;
+	for (i = 0; i < sizeof(rate_lookup) / sizeof(rate_lookup[0]); i++) {
+		if (rate > rate_lookup[i].lower && rate <= rate_lookup[i].upper) {
 			rate = rate_lookup[i].rate;
 			freq = rate_lookup[i].freq;
 			break;
 	    	}
 	}
-	s->ratedac = rate;
+	s->rateadc = rate;
 	freq <<= 2;
-	spin_lock_irqsave(&s->lock, flags);
-	val = inb(s->iobase + CODEC_CMI_FUNCTRL1 + 1) & ~0x1c; 
-	outb(val | freq, s->iobase + CODEC_CMI_FUNCTRL1 + 1);
-	spin_unlock_irqrestore(&s->lock, flags);
+
+	maskb(s->iobase + CODEC_CMI_FUNCTRL1 + 1, ~0x1c, freq);
 }
 
 static void set_adc_rate(struct cm_state *s, unsigned rate)
 {
 	unsigned long flags;
-	unsigned char freq = 4, val;
+	unsigned char freq = 4;
 	int	i;
 
 	if (rate > 48000)
 		rate = 48000;
-	if (rate < 5512)
-		rate = 5512;
-	for (i = 0; i < sizeof(rate_lookup) / sizeof(rate_lookup[0]); i++)
-	{
-		if (rate > rate_lookup[i].lower && rate <= rate_lookup[i].upper)
-		{
+	if (rate < 8000)
+		rate = 8000;
+	for (i = 0; i < sizeof(rate_lookup) / sizeof(rate_lookup[0]); i++) {
+		if (rate > rate_lookup[i].lower && rate <= rate_lookup[i].upper) {
 			rate = rate_lookup[i].rate;
 			freq = rate_lookup[i].freq;
 			break;
 	    	}
 	}
 	s->rateadc = rate;
+	freq <<= 2;
+
+	spin_lock_irqsave(&s->lock, flags);
+	maskb(s->iobase + CODEC_CMI_FUNCTRL1 + 1, ~0x1c, freq);
+	spin_unlock_irqrestore(&s->lock, flags);
+}
+
+static void set_dac_rate(struct cm_state *s, unsigned rate)
+{
+	unsigned long flags;
+	unsigned char freq = 4;
+	int	i;
+
+	if (rate > 48000)
+		rate = 48000;
+	if (rate < 8000)
+		rate = 8000;
+	for (i = 0; i < sizeof(rate_lookup) / sizeof(rate_lookup[0]); i++) {
+		if (rate > rate_lookup[i].lower && rate <= rate_lookup[i].upper) {
+			rate = rate_lookup[i].rate;
+			freq = rate_lookup[i].freq;
+			break;
+	    	}
+	}
+	s->ratedac = rate;
 	freq <<= 5;
+
 	spin_lock_irqsave(&s->lock, flags);
-	val = inb(s->iobase + CODEC_CMI_FUNCTRL1 + 1) & ~0xe0; 
-	outb(val | freq, s->iobase + CODEC_CMI_FUNCTRL1 + 1);
+	maskb(s->iobase + CODEC_CMI_FUNCTRL1 + 1, ~0xe0, freq);
+
+
+	if (s->curr_channels <=  2)
+		set_spdifout_unlocked(s, rate);
+	if (s->status & DO_DUAL_DAC)
+		set_adc_rate_unlocked(s, rate);
+
 	spin_unlock_irqrestore(&s->lock, flags);
 }
 
 /* --------------------------------------------------------------------- */
+static inline void reset_adc(struct cm_state *s)
+{
+	/* reset bus master */
+	outb(s->enable | CM_CH0_RESET, s->iobase + CODEC_CMI_FUNCTRL0 + 2);
+	outb(s->enable & ~CM_CH0_RESET, s->iobase + CODEC_CMI_FUNCTRL0 + 2);
+}
+
+static inline void reset_dac(struct cm_state *s)
+{
+	/* reset bus master */
+	outb(s->enable | CM_CH1_RESET, s->iobase + CODEC_CMI_FUNCTRL0 + 2);
+	outb(s->enable & ~CM_CH1_RESET, s->iobase + CODEC_CMI_FUNCTRL0 + 2);
+	if (s->status & DO_DUAL_DAC)
+		reset_adc(s);
+}
+
+static inline void pause_adc(struct cm_state *s)
+{
+	maskb(s->iobase + CODEC_CMI_FUNCTRL0, ~0, 4);
+}
+
+static inline void pause_dac(struct cm_state *s)
+{
+	maskb(s->iobase + CODEC_CMI_FUNCTRL0, ~0, 8);
+	if (s->status & DO_DUAL_DAC)
+		pause_adc(s);
+}
+
+extern inline void disable_adc(struct cm_state *s)
+{
+	/* disable channel */
+	s->enable &= ~CM_ENABLE_CH0;
+	outb(s->enable, s->iobase + CODEC_CMI_FUNCTRL0 + 2);
+	reset_adc(s);
+}
+
+extern inline void disable_dac(struct cm_state *s)
+{
+	/* disable channel */
+	s->enable &= ~CM_ENABLE_CH1;
+	outb(s->enable, s->iobase + CODEC_CMI_FUNCTRL0 + 2);
+	reset_dac(s);
+	if (s->status & DO_DUAL_DAC)
+		disable_adc(s);
+}
+
+extern inline void enable_adc(struct cm_state *s)
+{
+	if (!(s->enable & CM_ENABLE_CH0)) {
+		/* enable channel */
+		s->enable |= CM_ENABLE_CH0;
+		outb(s->enable, s->iobase + CODEC_CMI_FUNCTRL0 + 2);
+	}
+	maskb(s->iobase + CODEC_CMI_FUNCTRL0, ~4, 0);
+}
+
+extern inline void enable_dac_unlocked(struct cm_state *s)
+{
+	if (!(s->enable & CM_ENABLE_CH1)) {
+		/* enable channel */
+		s->enable |= CM_ENABLE_CH1;
+		outb(s->enable, s->iobase + CODEC_CMI_FUNCTRL0 + 2);
+	}
+	maskb(s->iobase + CODEC_CMI_FUNCTRL0, ~8, 0);
+
+	if (s->status & DO_DUAL_DAC)
+		enable_adc(s);
+}
+
+extern inline void enable_dac(struct cm_state *s)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&s->lock, flags);
+	enable_dac_unlocked(s);
+	spin_unlock_irqrestore(&s->lock, flags);
+}
+
+extern inline void stop_adc_unlocked(struct cm_state *s)
+{
+	if (s->enable & CM_ENABLE_CH0) {
+		/* disable interrupt */
+		maskb(s->iobase + CODEC_CMI_INT_HLDCLR + 2, ~1, 0);
+		disable_adc(s);
+	}
+}
 
 extern inline void stop_adc(struct cm_state *s)
 {
 	unsigned long flags;
 
 	spin_lock_irqsave(&s->lock, flags);
-	/* disable channel */
-	outb(s->enable, s->iobase + CODEC_CMI_FUNCTRL0 + 2);
-	s->enable &= ~CM_CENABLE_RE;
-	/* disable interrupt */
-	outb(inb(s->iobase + CODEC_CMI_INT_HLDCLR + 2) & ~2, s->iobase + CODEC_CMI_INT_HLDCLR + 2);
-	/* reset */
-	outb(s->enable | CM_CH1_RESET, s->iobase + CODEC_CMI_FUNCTRL0 + 2);
-	udelay(10);
-	outb(s->enable & ~CM_CH1_RESET, s->iobase + CODEC_CMI_FUNCTRL0 + 2);
+	stop_adc_unlocked(s);
 	spin_unlock_irqrestore(&s->lock, flags);
-}	
+
+}
+
+extern inline void stop_dac_unlocked(struct cm_state *s)
+{
+	if (s->enable & CM_ENABLE_CH1) {
+		/* disable interrupt */
+		maskb(s->iobase + CODEC_CMI_INT_HLDCLR + 2, ~2, 0);
+		disable_dac(s);
+	}
+	if (s->status & DO_DUAL_DAC)
+		stop_adc_unlocked(s);
+}
 
 extern inline void stop_dac(struct cm_state *s)
 {
 	unsigned long flags;
 
 	spin_lock_irqsave(&s->lock, flags);
-	/* disable channel */
-	s->enable &= ~CM_CENABLE_PE;
-	outb(s->enable, s->iobase + CODEC_CMI_FUNCTRL0 + 2);
-	/* disable interrupt */
-	outb(inb(s->iobase + CODEC_CMI_INT_HLDCLR + 2) & ~1, s->iobase + CODEC_CMI_INT_HLDCLR + 2);
-	/* reset */
-	outb(s->enable | CM_CH0_RESET, s->iobase + CODEC_CMI_FUNCTRL0 + 2);
-	udelay(10);
-	outb(s->enable & ~CM_CH0_RESET, s->iobase + CODEC_CMI_FUNCTRL0 + 2);
+	stop_dac_unlocked(s);
 	spin_unlock_irqrestore(&s->lock, flags);
-}	
+}
 
-static void start_dac(struct cm_state *s)
+static void start_adc_unlocked(struct cm_state *s)
+{
+	if ((s->dma_adc.mapped || s->dma_adc.count < (signed)(s->dma_adc.dmasize - 2*s->dma_adc.fragsize))
+	    && s->dma_adc.ready) {
+		/* enable interrupt */
+		maskb(s->iobase + CODEC_CMI_INT_HLDCLR + 2, ~0, 1);
+		enable_adc(s);
+	}
+}
+
+static void start_adc(struct cm_state *s)
 {
 	unsigned long flags;
 
 	spin_lock_irqsave(&s->lock, flags);
+	start_adc_unlocked(s);
+	spin_unlock_irqrestore(&s->lock, flags);
+}	
+
+static void start_dac1_unlocked(struct cm_state *s)
+{
+	if ((s->dma_adc.mapped || s->dma_adc.count > 0) && s->dma_adc.ready) {
+		/* enable interrupt */
+//		maskb(s->iobase + CODEC_CMI_INT_HLDCLR + 2, ~0, 1);
+ 		enable_dac_unlocked(s);
+	}
+}
+
+//static void start_dac1(struct cm_state *s)
+//{
+//	unsigned long flags;
+//
+//	spin_lock_irqsave(&s->lock, flags);
+//	start_dac1_unlocked(s);
+//	spin_unlock_irqrestore(&s->lock, flags);
+//}	
+
+static void start_dac_unlocked(struct cm_state *s)
+{
 	if ((s->dma_dac.mapped || s->dma_dac.count > 0) && s->dma_dac.ready) {
-		outb(inb(s->iobase + CODEC_CMI_INT_HLDCLR + 2) | 1, s->iobase + CODEC_CMI_INT_HLDCLR + 2);
-		s->enable |= CM_CENABLE_PE;
-		outb(s->enable, s->iobase + CODEC_CMI_FUNCTRL0 + 2);
+		/* enable interrupt */
+		maskb(s->iobase + CODEC_CMI_INT_HLDCLR + 2, ~0, 2);
+		enable_dac_unlocked(s);
 	}
+		if (s->status & DO_DUAL_DAC)
+			start_dac1_unlocked(s);
+}
+
+static void start_dac(struct cm_state *s)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&s->lock, flags);
+	start_dac_unlocked(s);
 	spin_unlock_irqrestore(&s->lock, flags);
 }	
 
-static void start_adc(struct cm_state *s)
+static int prog_dmabuf(struct cm_state *s, unsigned rec);
+
+static int set_dac_channels(struct cm_state *s, int channels)
 {
 	unsigned long flags;
-
 	spin_lock_irqsave(&s->lock, flags);
-	if ((s->dma_adc.mapped || s->dma_adc.count < (signed)(s->dma_adc.dmasize - 2*s->dma_adc.fragsize)) 
-	    && s->dma_adc.ready) {
-		outb(inb(s->iobase + CODEC_CMI_INT_HLDCLR + 2) | 2, s->iobase + CODEC_CMI_INT_HLDCLR + 2);
-		s->enable |= CM_CENABLE_RE;
-		outb(s->enable, s->iobase + CODEC_CMI_FUNCTRL0 + 2);
+
+	if ((channels > 2) && (channels <= s->max_channels)
+	 && (((s->fmt >> CM_CFMT_DACSHIFT) & CM_CFMT_MASK) == (CM_CFMT_STEREO | CM_CFMT_16BIT))) {
+	    set_spdifout_unlocked(s, 0);
+	    if (s->capability & CAN_MULTI_CH_HW) {
+		// NXCHG
+		maskb(s->iobase + CODEC_CMI_LEGACY_CTRL + 3, ~0, 0x80);
+		// CHB3D or CHB3D5C
+	       	maskb(s->iobase + CODEC_CMI_CHFORMAT + 3, ~0xa0, channels > 4 ? 0x80 : 0x20);
+		// CHB3D6C
+		maskb(s->iobase + CODEC_CMI_LEGACY_CTRL + 1, ~0x80, channels == 6 ? 0x80 : 0);
+		// ENCENTER 
+		maskb(s->iobase + CODEC_CMI_MISC_CTRL, ~0x80, channels == 6 ? 0x80 : 0);
+		s->status |= DO_MULTI_CH_HW;
+	    } else if (s->capability & CAN_DUAL_DAC) {
+		unsigned char fmtm = ~0, fmts = 0;
+		ssize_t ret;
+
+		// ENDBDAC, turn on double DAC mode
+		// XCHGDAC, CH0 -> back, CH1->front
+		maskb(s->iobase + CODEC_CMI_MISC_CTRL + 2, ~0, 0xC0);
+		s->status |= DO_DUAL_DAC;
+		// prepare secondary buffer
+
+		spin_unlock_irqrestore(&s->lock, flags);
+		ret = prog_dmabuf(s, 1);
+		spin_lock_irqsave(&s->lock, flags);
+
+		if (ret) return ret;
+		// copy the hw state
+		fmtm &= ~((CM_CFMT_STEREO | CM_CFMT_16BIT) << CM_CFMT_DACSHIFT);
+		fmtm &= ~((CM_CFMT_STEREO | CM_CFMT_16BIT) << CM_CFMT_ADCSHIFT);
+		// the HW only support 16-bit stereo
+		fmts |= CM_CFMT_16BIT << CM_CFMT_DACSHIFT;
+		fmts |= CM_CFMT_16BIT << CM_CFMT_ADCSHIFT;
+		fmts |= CM_CFMT_STEREO << CM_CFMT_DACSHIFT;
+		fmts |= CM_CFMT_STEREO << CM_CFMT_ADCSHIFT;
+		
+		set_fmt_unlocked(s, fmtm, fmts);
+		set_adc_rate_unlocked(s, s->ratedac);
+
+	    }
+	    // N4SPK3D, disable 4 speaker mode (analog duplicate)
+	    if (s->speakers > 2)
+		maskb(s->iobase + CODEC_CMI_MISC_CTRL + 3, ~0x04, 0);
+	    s->curr_channels = channels;
+	} else {
+	    if (s->status & DO_MULTI_CH_HW) {
+		maskb(s->iobase + CODEC_CMI_LEGACY_CTRL + 3, ~0x80, 0);
+		maskb(s->iobase + CODEC_CMI_CHFORMAT + 3, ~0xa0, 0);
+		maskb(s->iobase + CODEC_CMI_LEGACY_CTRL + 1, ~0x80, 0);
+	    } else if (s->status & DO_DUAL_DAC) {
+		maskb(s->iobase + CODEC_CMI_MISC_CTRL + 2, ~0x80, 0);
+	    }
+	    // N4SPK3D, enable 4 speaker mode (analog duplicate)
+	    if (s->speakers > 2)
+		maskb(s->iobase + CODEC_CMI_MISC_CTRL + 3, ~0, 0x04);
+	    s->status &= ~DO_MULTI_CH;
+	    s->curr_channels = s->fmt & (CM_CFMT_STEREO << CM_CFMT_DACSHIFT) ? 2 : 1;
 	}
+
 	spin_unlock_irqrestore(&s->lock, flags);
-}	
+	return s->curr_channels;
+}
 
 /* --------------------------------------------------------------------- */
 
@@ -591,7 +996,7 @@
 static void dealloc_dmabuf(struct dmabuf *db)
 {
 	struct page *pstart, *pend;
-
+	
 	if (db->rawbuf) {
 		/* undo marking the pages as reserved */
 		pend = virt_to_page(db->rawbuf + (PAGE_SIZE << db->buforder) - 1);
@@ -603,8 +1008,7 @@
 	db->mapped = db->ready = 0;
 }
 
-
-/* Ch0 is used for playback, Ch1 is used for recording */
+/* Ch1 is used for playback, Ch0 is used for recording */
 
 static int prog_dmabuf(struct cm_state *s, unsigned rec)
 {
@@ -617,17 +1021,15 @@
 	unsigned char fmt;
 	unsigned long flags;
 
-	spin_lock_irqsave(&s->lock, flags);
 	fmt = s->fmt;
 	if (rec) {
-		s->enable &= ~CM_CENABLE_RE;
+		stop_adc(s);
 		fmt >>= CM_CFMT_ADCSHIFT;
 	} else {
-		s->enable &= ~CM_CENABLE_PE;
+		stop_dac(s);
 		fmt >>= CM_CFMT_DACSHIFT;
 	}
-	outb(s->enable, s->iobase + CODEC_CMI_FUNCTRL0 + 2);
-	spin_unlock_irqrestore(&s->lock, flags);
+
 	fmt &= CM_CFMT_MASK;
 	db->hwptr = db->swptr = db->total_bytes = db->count = db->error = db->endcleared = 0;
 	if (!db->rawbuf) {
@@ -638,12 +1040,13 @@
 		if (!db->rawbuf)
 			return -ENOMEM;
 		db->buforder = order;
-		if ((virt_to_bus(db->rawbuf) ^ (virt_to_bus(db->rawbuf) + (PAGE_SIZE << db->buforder) - 1)) & ~0xffff)
-			printk(KERN_DEBUG "cmpci: DMA buffer crosses 64k boundary: busaddr 0x%lx  size %ld\n", 
-			       virt_to_bus(db->rawbuf), PAGE_SIZE << db->buforder);
-		if ((virt_to_bus(db->rawbuf) + (PAGE_SIZE << db->buforder) - 1) & ~0xffffff)
-			printk(KERN_DEBUG "cmpci: DMA buffer beyond 16MB: busaddr 0x%lx  size %ld\n", 
-			       virt_to_bus(db->rawbuf), PAGE_SIZE << db->buforder);
+		db->rawphys = virt_to_bus(db->rawbuf);
+		if ((db->rawphys ^ (db->rawphys + (PAGE_SIZE << db->buforder) - 1)) & ~0xffff)
+			printk(KERN_DEBUG "cm: DMA buffer crosses 64k boundary: busaddr 0x%lx  size %ld\n", 
+			       (long) db->rawphys, PAGE_SIZE << db->buforder);
+		if ((db->rawphys + (PAGE_SIZE << db->buforder) - 1) & ~0xffffff)
+			printk(KERN_DEBUG "cm: DMA buffer beyond 16MB: busaddr 0x%lx  size %ld\n", 
+			       (long) db->rawphys, PAGE_SIZE << db->buforder);
 		/* now mark the pages as reserved; otherwise remap_page_range doesn't do what we want */
 		pend = virt_to_page(db->rawbuf + (PAGE_SIZE << db->buforder) - 1);
 		for (pstart = virt_to_page(db->rawbuf); pstart <= pend; pstart++)
@@ -670,30 +1073,22 @@
 	if (db->ossmaxfrags >= 4 && db->ossmaxfrags < db->numfrag)
 		db->numfrag = db->ossmaxfrags;
  	/* to make fragsize >= 4096 */
-#if 0 	
- 	if(s->modem)
- 	{
-	 	while (db->fragsize < 4096 && db->numfrag >= 4)
-		{
-			db->fragsize *= 2;
- 			db->fragshift++;
- 			db->numfrag /= 2;
- 		}
-	}
-#endif	
 	db->fragsamples = db->fragsize >> sample_shift[fmt];
 	db->dmasize = db->numfrag << db->fragshift;
 	db->dmasamples = db->dmasize >> sample_shift[fmt];
 	memset(db->rawbuf, (fmt & CM_CFMT_16BIT) ? 0 : 0x80, db->dmasize);
 	spin_lock_irqsave(&s->lock, flags);
 	if (rec) {
-		set_dmaadc(s, virt_to_bus(db->rawbuf), db->dmasize >> sample_shift[fmt]);
+		if (s->status & DO_DUAL_DAC)
+		    set_dmadac1(s, db->rawphys, db->dmasize >> sample_shift[fmt]);
+		else
+		    set_dmaadc(s, db->rawphys, db->dmasize >> sample_shift[fmt]);
 		/* program sample counts */
-		outw(db->fragsamples-1, s->iobase + CODEC_CMI_CH1_FRAME2 + 2);
+		set_countdac(s, db->fragsamples);
 	} else {
-		set_dmadac(s, virt_to_bus(db->rawbuf), db->dmasize >> sample_shift[fmt]);
+		set_dmadac(s, db->rawphys, db->dmasize >> sample_shift[fmt]);
 		/* program sample counts */
-		outw(db->fragsamples-1, s->iobase + CODEC_CMI_CH0_FRAME2 + 2);
+		set_countdac(s, db->fragsamples);
 	}
 	spin_unlock_irqrestore(&s->lock, flags);
 	db->ready = 1;
@@ -704,6 +1099,7 @@
 {
 	unsigned char c = (s->fmt & (CM_CFMT_16BIT << CM_CFMT_DACSHIFT)) ? 0 : 0x80;
 	unsigned char *buf = s->dma_dac.rawbuf;
+	unsigned char *buf1 = s->dma_adc.rawbuf;
 	unsigned bsize = s->dma_dac.dmasize;
 	unsigned bptr = s->dma_dac.swptr;
 	unsigned len = s->dma_dac.fragsize;
@@ -711,11 +1107,14 @@
 	if (bptr + len > bsize) {
 		unsigned x = bsize - bptr;
 		memset(buf + bptr, c, x);
+		if (s->status & DO_DUAL_DAC)
+			memset(buf1 + bptr, c, x);
 		bptr = 0;
 		len -= x;
 	}
 	memset(buf + bptr, c, len);
-	outb(s->enable, s->iobase + CODEC_CMI_FUNCTRL0 + 2);
+	if (s->status & DO_DUAL_DAC)
+		memset(buf1 + bptr, c, len);
 }
 
 /* call with spinlock held! */
@@ -726,7 +1125,29 @@
 
 	/* update ADC pointer */
 	if (s->dma_adc.ready) {
-		hwptr = (s->dma_adc.dmasize - get_dmaadc(s)) % s->dma_adc.dmasize;
+	    if (s->status & DO_DUAL_DAC) {
+		hwptr = get_dmaadc(s) % s->dma_adc.dmasize;
+		diff = (s->dma_adc.dmasize + hwptr - s->dma_adc.hwptr) % s->dma_adc.dmasize;
+		s->dma_adc.hwptr = hwptr;
+		s->dma_adc.total_bytes += diff;
+		if (s->dma_adc.mapped) {
+			s->dma_adc.count += diff;
+			if (s->dma_adc.count >= (signed)s->dma_adc.fragsize)
+				wake_up(&s->dma_adc.wait);
+		} else {
+			s->dma_adc.count -= diff;
+			if (s->dma_adc.count <= 0) {
+				pause_adc(s);
+				s->dma_adc.error++;
+			} else if (s->dma_adc.count <= (signed)s->dma_adc.fragsize && !s->dma_adc.endcleared) {
+				clear_advance(s);
+				s->dma_adc.endcleared = 1;
+			}
+			if (s->dma_dac.count + (signed)s->dma_dac.fragsize <= (signed)s->dma_dac.dmasize)
+				wake_up(&s->dma_adc.wait);
+		}
+	    } else {
+		hwptr = get_dmaadc(s) % s->dma_adc.dmasize;
 		diff = (s->dma_adc.dmasize + hwptr - s->dma_adc.hwptr) % s->dma_adc.dmasize;
 		s->dma_adc.hwptr = hwptr;
 		s->dma_adc.total_bytes += diff;
@@ -735,15 +1156,15 @@
 			wake_up(&s->dma_adc.wait);
 		if (!s->dma_adc.mapped) {
 			if (s->dma_adc.count > (signed)(s->dma_adc.dmasize - ((3 * s->dma_adc.fragsize) >> 1))) {
-				s->enable &= ~CM_CENABLE_RE;
-				outb(s->enable, s->iobase + CODEC_CMI_FUNCTRL0 + 2);
+				pause_adc(s);
 				s->dma_adc.error++;
 			}
 		}
+	    }
 	}
 	/* update DAC pointer */
 	if (s->dma_dac.ready) {
-		hwptr = (s->dma_dac.dmasize - get_dmadac(s)) % s->dma_dac.dmasize;
+		hwptr = get_dmadac(s) % s->dma_dac.dmasize;
 		diff = (s->dma_dac.dmasize + hwptr - s->dma_dac.hwptr) % s->dma_dac.dmasize;
 		s->dma_dac.hwptr = hwptr;
 		s->dma_dac.total_bytes += diff;
@@ -754,8 +1175,7 @@
 		} else {
 			s->dma_dac.count -= diff;
 			if (s->dma_dac.count <= 0) {
-				s->enable &= ~CM_CENABLE_PE;
-				outb(s->enable, s->iobase + CODEC_CMI_FUNCTRL0 + 2);
+				pause_dac(s);
 				s->dma_dac.error++;
 			} else if (s->dma_dac.count <= (signed)s->dma_dac.fragsize && !s->dma_dac.endcleared) {
 				clear_advance(s);
@@ -767,6 +1187,7 @@
 	}
 }
 
+#ifdef CONFIG_SOUND_CMPCI_MIDI
 /* hold spinlock for the following! */
 static void cm_handle_midi(struct cm_state *s)
 {
@@ -796,11 +1217,13 @@
 	if (wake)
 		wake_up(&s->midi.owait);
 }
+#endif
 
 static void cm_interrupt(int irq, void *dev_id, struct pt_regs *regs)
 {
         struct cm_state *s = (struct cm_state *)dev_id;
 	unsigned int intsrc, intstat;
+	unsigned char mask = 0;
 	
 	/* fastpath out, to ease interrupt sharing */
 	intsrc = inl(s->iobase + CODEC_CMI_INT_STATUS);
@@ -810,22 +1233,19 @@
 	intstat = inb(s->iobase + CODEC_CMI_INT_HLDCLR + 2);
 	/* acknowledge interrupt */
 	if (intsrc & CM_INT_CH0)
-	{
-		outb(intstat & ~1, s->iobase + CODEC_CMI_INT_HLDCLR + 2);
-		udelay(10);
-		outb(intstat | 1, s->iobase + CODEC_CMI_INT_HLDCLR + 2);
-	}
+		mask |= 1;
 	if (intsrc & CM_INT_CH1)
-	{
-		outb(intstat & ~2, s->iobase + CODEC_CMI_INT_HLDCLR + 2);
-		udelay(10);
-		outb(intstat | 2, s->iobase + CODEC_CMI_INT_HLDCLR + 2);
-	}
+		mask |= 2;
+	outb(intstat & ~mask, s->iobase + CODEC_CMI_INT_HLDCLR + 2);
+	outb(intstat | mask, s->iobase + CODEC_CMI_INT_HLDCLR + 2);
 	cm_update_ptr(s);
+#ifdef CONFIG_SOUND_CMPCI_MIDI
 	cm_handle_midi(s);
+#endif
 	spin_unlock(&s->lock);
 }
 
+#ifdef CONFIG_SOUND_CMPCI_MIDI
 static void cm_midi_timer(unsigned long data)
 {
 	struct cm_state *s = (struct cm_state *)data;
@@ -837,10 +1257,11 @@
 	s->midi.timer.expires = jiffies+1;
 	add_timer(&s->midi.timer);
 }
+#endif
 
 /* --------------------------------------------------------------------- */
 
-static const char invalid_magic[] = KERN_CRIT "cmpci: invalid magic value\n";
+static const char invalid_magic[] = KERN_CRIT "cm: invalid magic value\n";
 
 #ifdef CONFIG_SOUND_CMPCI	/* support multiple chips */
 #define VALIDATE_STATE(s)
@@ -874,7 +1295,8 @@
 	[SOUND_MIXER_MIC]    = { DSP_MIX_MICVOLIDX,      DSP_MIX_MICVOLIDX,      MT_5MUTEMONO, 0x01, 0x01 },
 	[SOUND_MIXER_SYNTH]  = { DSP_MIX_FMVOLIDX_L,  	 DSP_MIX_FMVOLIDX_R,     MT_5MUTE,     0x40, 0x00 },
 	[SOUND_MIXER_VOLUME] = { DSP_MIX_MASTERVOLIDX_L, DSP_MIX_MASTERVOLIDX_R, MT_5MUTE,     0x00, 0x00 },
-	[SOUND_MIXER_PCM]    = { DSP_MIX_VOICEVOLIDX_L,  DSP_MIX_VOICEVOLIDX_R,  MT_5MUTE,     0x00, 0x00 }
+	[SOUND_MIXER_PCM]    = { DSP_MIX_VOICEVOLIDX_L,  DSP_MIX_VOICEVOLIDX_R,  MT_5MUTE,     0x00, 0x00 },
+	[SOUND_MIXER_SPEAKER]= { DSP_MIX_SPKRVOLIDX,	 DSP_MIX_SPKRVOLIDX,	 MT_5MUTEMONO, 0x01, 0x01 }
 };
 
 #ifdef OSS_DOCUMENTED_MIXER_SEMANTICS
@@ -937,7 +1359,8 @@
 	[SOUND_MIXER_MIC]    = 3,
 	[SOUND_MIXER_SYNTH]  = 4,
 	[SOUND_MIXER_VOLUME] = 5,
-	[SOUND_MIXER_PCM]    = 6
+	[SOUND_MIXER_PCM]    = 6,
+	[SOUND_MIXER_SPEAKER]= 7
 };
 
 #endif /* OSS_DOCUMENTED_MIXER_SEMANTICS */
@@ -983,9 +1406,9 @@
 	}
 	if (cmd == OSS_GETVERSION)
 		return put_user(SOUND_VERSION, (int *)arg);
-	if (_IOC_TYPE(cmd) != 'M' || _SIOC_SIZE(cmd) != sizeof(int))
+	if (_IOC_TYPE(cmd) != 'M' || _IOC_SIZE(cmd) != sizeof(int))
                 return -EINVAL;
-        if (_SIOC_DIR(cmd) == _SIOC_READ) {
+        if (_IOC_DIR(cmd) == _IOC_READ) {
                 switch (_IOC_NR(cmd)) {
                 case SOUND_MIXER_RECSRC: /* Arg contains a bit for each recording source */
 			return put_user(mixer_recmask(s), (int *)arg);
@@ -1033,7 +1456,7 @@
 #endif /* OSS_DOCUMENTED_MIXER_SEMANTICS */
 		}
 	}
-        if (_SIOC_DIR(cmd) != (_SIOC_READ|_SIOC_WRITE)) 
+        if (_IOC_DIR(cmd) != (_IOC_READ|_IOC_WRITE)) 
 		return -EINVAL;
 	s->mix.modcnt++;
 	switch (_IOC_NR(cmd)) {
@@ -1100,7 +1523,7 @@
 			rl = (l < 4 ? 0 : (l - 5) / 3) & 31;
 			rr = (rl >> 2) & 7;
 			wrmixer(s, mixtable[i].left, rl<<3);
-			outb((inb(s->iobase + CODEC_CMI_MIXER2) & ~0x0e) | rr<<1, s->iobase + CODEC_CMI_MIXER2);
+			maskb(s->iobase + CODEC_CMI_MIXER2, ~0x0e, rr<<1);
 			break;
 			
 		case MT_5MUTEMONO:
@@ -1108,7 +1531,7 @@
 			rl = l < 4 ? 0 : (l - 5) / 3;
 			rr = rl >> 2;
  			wrmixer(s, mixtable[i].left, rl<<3);
-			outb((inb(s->iobase + CODEC_CMI_MIXER2) & ~0x0e) | rr<<1, s->iobase + CODEC_CMI_MIXER2);
+			maskb(s->iobase + CODEC_CMI_MIXER2, ~0x0e, rr<<1);
 			break;
 				
 		case MT_5MUTE:
@@ -1117,7 +1540,7 @@
  			wrmixer(s, mixtable[i].left, rl<<3);
 			wrmixer(s, mixtable[i].right, rr<<3);
 			break;
-				
+
 		case MT_6MUTE:
 			if (l < 6)
 				rl = 0x00;
@@ -1187,19 +1610,20 @@
 	release:	cm_release_mixdev,
 };
 
+
 /* --------------------------------------------------------------------- */
 
 static int drain_dac(struct cm_state *s, int nonblock)
 {
-        DECLARE_WAITQUEUE(wait, current);
+	DECLARE_WAITQUEUE(wait, current);
 	unsigned long flags;
 	int count, tmo;
 
 	if (s->dma_dac.mapped || !s->dma_dac.ready)
 		return 0;
+        current->state = TASK_INTERRUPTIBLE;
         add_wait_queue(&s->dma_dac.wait, &wait);
         for (;;) {
-		set_current_state(TASK_INTERRUPTIBLE);
                 spin_lock_irqsave(&s->lock, flags);
 		count = s->dma_dac.count;
                 spin_unlock_irqrestore(&s->lock, flags);
@@ -1212,10 +1636,10 @@
                         current->state = TASK_RUNNING;
                         return -EBUSY;
                 }
-		tmo = (count * HZ) / s->ratedac;
+		tmo = 3 * HZ * (count + s->dma_dac.fragsize) / 2 / s->ratedac;
 		tmo >>= sample_shift[(s->fmt >> CM_CFMT_DACSHIFT) & CM_CFMT_MASK];
-		if (!schedule_timeout(tmo ? : 1) && tmo)
-			printk(KERN_DEBUG "cmpci: dma timed out??\n");
+		if (!schedule_timeout(tmo + 1))
+			printk(KERN_DEBUG "cm: dma timed out??\n");
         }
         remove_wait_queue(&s->dma_dac.wait, &wait);
         current->state = TASK_RUNNING;
@@ -1263,14 +1687,14 @@
 			if (file->f_flags & O_NONBLOCK)
 				return ret ? ret : -EAGAIN;
 			if (!interruptible_sleep_on_timeout(&s->dma_adc.wait, HZ)) {
-				printk(KERN_DEBUG "cmpci: read: chip lockup? dmasz %u fragsz %u count %i hwptr %u swptr %u\n",
+				printk(KERN_DEBUG "cm: read: chip lockup? dmasz %u fragsz %u count %i hwptr %u swptr %u\n",
 				       s->dma_adc.dmasize, s->dma_adc.fragsize, s->dma_adc.count,
 				       s->dma_adc.hwptr, s->dma_adc.swptr);
-				stop_adc(s);
 				spin_lock_irqsave(&s->lock, flags);
-				set_dmaadc(s, virt_to_bus(s->dma_adc.rawbuf), s->dma_adc.dmasamples);
+				stop_adc_unlocked(s);
+				set_dmaadc(s, s->dma_adc.rawphys, s->dma_adc.dmasamples);
 				/* program sample counts */
-				outw(s->dma_adc.fragsamples-1, s->iobase + CODEC_CMI_CH1_FRAME2 + 2);
+				set_countadc(s, s->dma_adc.fragsamples);
 				s->dma_adc.count = s->dma_adc.hwptr = s->dma_adc.swptr = 0;
 				spin_unlock_irqrestore(&s->lock, flags);
 			}
@@ -1284,11 +1708,11 @@
 		spin_lock_irqsave(&s->lock, flags);
 		s->dma_adc.swptr = swptr;
 		s->dma_adc.count -= cnt;
-		spin_unlock_irqrestore(&s->lock, flags);
 		count -= cnt;
 		buffer += cnt;
 		ret += cnt;
-		start_adc(s);
+		start_adc_unlocked(s);
+		spin_unlock_irqrestore(&s->lock, flags);
 	}
 	return ret;
 }
@@ -1310,62 +1734,113 @@
 		return ret;
 	if (!access_ok(VERIFY_READ, buffer, count))
 		return -EFAULT;
+	if (s->status & DO_DUAL_DAC) {
+		if (s->dma_adc.mapped)
+			return -ENXIO;
+		if (!s->dma_adc.ready && (ret = prog_dmabuf(s, 1)))
+			return ret;
+		if (!access_ok(VERIFY_READ, buffer, count))
+			return -EFAULT;
+	}
 	ret = 0;
 #if 0
    spin_lock_irqsave(&s->lock, flags);
    cm_update_ptr(s);
    spin_unlock_irqrestore(&s->lock, flags);
-#endif
+#endif                                                        
 	while (count > 0) {
 		spin_lock_irqsave(&s->lock, flags);
 		if (s->dma_dac.count < 0) {
 			s->dma_dac.count = 0;
 			s->dma_dac.swptr = s->dma_dac.hwptr;
 		}
+		if (s->status & DO_DUAL_DAC) {
+			s->dma_adc.swptr = s->dma_dac.swptr;
+			s->dma_adc.count = s->dma_dac.count;
+			s->dma_adc.endcleared = s->dma_dac.endcleared;
+		}
 		swptr = s->dma_dac.swptr;
 		cnt = s->dma_dac.dmasize-swptr;
-		if (s->dma_dac.count + cnt > s->dma_dac.dmasize)
-			cnt = s->dma_dac.dmasize - s->dma_dac.count;
+		if (s->status & DO_AC3_SW) {
+			if (s->dma_dac.count + 2 * cnt > s->dma_dac.dmasize)
+				cnt = (s->dma_dac.dmasize - s->dma_dac.count) / 2;
+		} else {
+			if (s->dma_dac.count + cnt > s->dma_dac.dmasize)
+				cnt = s->dma_dac.dmasize - s->dma_dac.count;
+		}
 		spin_unlock_irqrestore(&s->lock, flags);
 		if (cnt > count)
 			cnt = count;
+		if ((s->status & DO_DUAL_DAC) && (cnt > count / 2))
+		    cnt = count / 2;
 		if (cnt <= 0) {
 			start_dac(s);
 			if (file->f_flags & O_NONBLOCK)
 				return ret ? ret : -EAGAIN;
 			if (!interruptible_sleep_on_timeout(&s->dma_dac.wait, HZ)) {
-				printk(KERN_DEBUG "cmpci: write: chip lockup? dmasz %u fragsz %u count %i hwptr %u swptr %u\n",
+				printk(KERN_DEBUG "cm: write: chip lockup? dmasz %u fragsz %u count %i hwptr %u swptr %u\n",
 				       s->dma_dac.dmasize, s->dma_dac.fragsize, s->dma_dac.count,
 				       s->dma_dac.hwptr, s->dma_dac.swptr);
-				stop_dac(s);
 				spin_lock_irqsave(&s->lock, flags);
-				set_dmadac(s, virt_to_bus(s->dma_dac.rawbuf), s->dma_dac.dmasamples);
+				stop_dac_unlocked(s);
+				set_dmadac(s, s->dma_dac.rawphys, s->dma_dac.dmasamples);
 				/* program sample counts */
-				outw(s->dma_dac.fragsamples-1, s->iobase + CODEC_CMI_CH0_FRAME2 + 2);
+				set_countdac(s, s->dma_dac.fragsamples);
 				s->dma_dac.count = s->dma_dac.hwptr = s->dma_dac.swptr = 0;
+				if (s->status & DO_DUAL_DAC)  {
+					set_dmadac1(s, s->dma_adc.rawphys, s->dma_adc.dmasamples);
+					s->dma_adc.count = s->dma_adc.hwptr = s->dma_adc.swptr = 0;
+				}
 				spin_unlock_irqrestore(&s->lock, flags);
 			}
 			if (signal_pending(current))
 				return ret ? ret : -ERESTARTSYS;
 			continue;
 		}
-		if (copy_from_user(s->dma_dac.rawbuf + swptr, buffer, cnt))
-			return ret ? ret : -EFAULT;
-		swptr = (swptr + cnt) % s->dma_dac.dmasize;
+		if (s->status & DO_AC3_SW) {
+			// clip exceeded data, caught by 033 and 037
+			if (swptr + 2 * cnt > s->dma_dac.dmasize)
+				cnt = (s->dma_dac.dmasize - swptr) / 2;
+			trans_ac3(s, s->dma_dac.rawbuf + swptr, buffer, cnt);
+			swptr = (swptr + 2 * cnt) % s->dma_dac.dmasize;
+		} else if (s->status & DO_DUAL_DAC) {
+			int	i;
+			unsigned long *src, *dst0, *dst1;
+
+			src = (unsigned long *) buffer;
+			dst0 = (unsigned long *) (s->dma_dac.rawbuf + swptr);
+			dst1 = (unsigned long *) (s->dma_adc.rawbuf + swptr);
+			// copy left/right sample at one time
+			for (i = 0; i <= cnt / 4; i++) {
+				*dst0++ = *src++;
+				*dst1++ = *src++;
+			}
+			swptr = (swptr + cnt) % s->dma_dac.dmasize;
+		} else {
+			if (copy_from_user(s->dma_dac.rawbuf + swptr, buffer, cnt))
+				return ret ? ret : -EFAULT;
+			swptr = (swptr + cnt) % s->dma_dac.dmasize;
+		}
 		spin_lock_irqsave(&s->lock, flags);
 		s->dma_dac.swptr = swptr;
 		s->dma_dac.count += cnt;
+		if (s->status & DO_AC3_SW)
+			s->dma_dac.count += cnt;
 		s->dma_dac.endcleared = 0;
 		spin_unlock_irqrestore(&s->lock, flags);
 		count -= cnt;
 		buffer += cnt;
 		ret += cnt;
+		if (s->status & DO_DUAL_DAC) {
+			count -= cnt;
+			buffer += cnt;
+			ret += cnt;
+		}
 		start_dac(s);
 	}
 	return ret;
 }
 
-/* No kernel lock - fine (we have our own spinlock) */
 static unsigned int cm_poll(struct file *file, struct poll_table_struct *wait)
 {
 	struct cm_state *s = (struct cm_state *)file->private_data;
@@ -1373,17 +1848,10 @@
 	unsigned int mask = 0;
 
 	VALIDATE_STATE(s);
-	if (file->f_mode & FMODE_WRITE) {
-		if (!s->dma_dac.ready && prog_dmabuf(s, 0))
-			return 0;
+	if (file->f_mode & FMODE_WRITE)
 		poll_wait(file, &s->dma_dac.wait, wait);
-	}
-	if (file->f_mode & FMODE_READ) {
-		if (!s->dma_adc.ready && prog_dmabuf(s, 1))
-			return 0;
+	if (file->f_mode & FMODE_READ)
 		poll_wait(file, &s->dma_adc.wait, wait);
-	}
-
 	spin_lock_irqsave(&s->lock, flags);
 	cm_update_ptr(s);
 	if (file->f_mode & FMODE_READ) {
@@ -1413,14 +1881,14 @@
 	VALIDATE_STATE(s);
 	lock_kernel();
 	if (vma->vm_flags & VM_WRITE) {
-		if ((ret = prog_dmabuf(s, 1)) != 0)
+		if ((ret = prog_dmabuf(s, 0)) != 0)
 			goto out;
 		db = &s->dma_dac;
 	} else if (vma->vm_flags & VM_READ) {
-		if ((ret = prog_dmabuf(s, 0)) != 0)
+		if ((ret = prog_dmabuf(s, 1)) != 0)
 			goto out;
 		db = &s->dma_adc;
-	} else 
+	} else
 		goto out;
 	ret = -EINVAL;
 	if (vma->vm_pgoff != 0)
@@ -1428,7 +1896,7 @@
 	size = vma->vm_end - vma->vm_start;
 	if (size > (PAGE_SIZE << db->buforder))
 		goto out;
-	ret = -EAGAIN;
+	ret = -EINVAL;
 	if (remap_page_range(vma->vm_start, virt_to_phys(db->rawbuf), size, vma->vm_page_prot))
 		goto out;
 	db->mapped = 1;
@@ -1463,13 +1931,15 @@
 		return 0;
 
 	case SNDCTL_DSP_GETCAPS:
-		return put_user(DSP_CAP_DUPLEX | DSP_CAP_REALTIME | DSP_CAP_TRIGGER | DSP_CAP_MMAP, (int *)arg);
+		return put_user(DSP_CAP_DUPLEX | DSP_CAP_REALTIME | DSP_CAP_TRIGGER | DSP_CAP_MMAP | DSP_CAP_BIND, (int *)arg);
 		
         case SNDCTL_DSP_RESET:
 		if (file->f_mode & FMODE_WRITE) {
 			stop_dac(s);
 			synchronize_irq();
 			s->dma_dac.swptr = s->dma_dac.hwptr = s->dma_dac.count = s->dma_dac.total_bytes = 0;
+			if (s->status & DO_DUAL_DAC)
+				s->dma_adc.swptr = s->dma_adc.hwptr = s->dma_adc.count = s->dma_adc.total_bytes = 0;
 		}
 		if (file->f_mode & FMODE_READ) {
 			stop_adc(s);
@@ -1479,24 +1949,28 @@
 		return 0;
 
         case SNDCTL_DSP_SPEED:
-                if (get_user(val, (int *)arg))
+		if (get_user(val, (int *)arg))
 			return -EFAULT;
 		if (val >= 0) {
 			if (file->f_mode & FMODE_READ) {
-				stop_adc(s);
+			 	spin_lock_irqsave(&s->lock, flags);
+				stop_adc_unlocked(s);
 				s->dma_adc.ready = 0;
-				set_adc_rate(s, val);
+				set_adc_rate_unlocked(s, val);
+				spin_unlock_irqrestore(&s->lock, flags);
 			}
 			if (file->f_mode & FMODE_WRITE) {
 				stop_dac(s);
 				s->dma_dac.ready = 0;
+				if (s->status & DO_DUAL_DAC)
+					s->dma_adc.ready = 0;
 				set_dac_rate(s, val);
 			}
 		}
 		return put_user((file->f_mode & FMODE_READ) ? s->rateadc : s->ratedac, (int *)arg);
-		
+
         case SNDCTL_DSP_STEREO:
-                if (get_user(val, (int *)arg))
+		if (get_user(val, (int *)arg))
 			return -EFAULT;
 		fmtd = 0;
 		fmtm = ~0;
@@ -1515,12 +1989,19 @@
 				fmtd |= CM_CFMT_STEREO << CM_CFMT_DACSHIFT;
 			else
 				fmtm &= ~(CM_CFMT_STEREO << CM_CFMT_DACSHIFT);
+			if (s->status & DO_DUAL_DAC) {
+				s->dma_adc.ready = 0;
+				if (val)
+					fmtd |= CM_CFMT_STEREO << CM_CFMT_ADCSHIFT;
+				else
+					fmtm &= ~(CM_CFMT_STEREO << CM_CFMT_ADCSHIFT);
+			}
 		}
 		set_fmt(s, fmtm, fmtd);
 		return 0;
 
         case SNDCTL_DSP_CHANNELS:
-                if (get_user(val, (int *)arg))
+		if (get_user(val, (int *)arg))
 			return -EFAULT;
 		if (val != 0) {
 			fmtd = 0;
@@ -1540,14 +2021,26 @@
 					fmtd |= CM_CFMT_STEREO << CM_CFMT_DACSHIFT;
 				else
 					fmtm &= ~(CM_CFMT_STEREO << CM_CFMT_DACSHIFT);
+				if (s->status & DO_DUAL_DAC) {
+					s->dma_adc.ready = 0;
+					if (val >= 2)
+						fmtd |= CM_CFMT_STEREO << CM_CFMT_ADCSHIFT;
+					else
+						fmtm &= ~(CM_CFMT_STEREO << CM_CFMT_ADCSHIFT);
+				}
 			}
 			set_fmt(s, fmtm, fmtd);
-		}
+			if ((s->capability & CAN_MULTI_CH)
+			     && (file->f_mode & FMODE_WRITE)) {
+				val = set_dac_channels(s, val);
+				return put_user(val, (int *)arg);
+			}
+		}            
 		return put_user((s->fmt & ((file->f_mode & FMODE_READ) ? (CM_CFMT_STEREO << CM_CFMT_ADCSHIFT) 
 					   : (CM_CFMT_STEREO << CM_CFMT_DACSHIFT))) ? 2 : 1, (int *)arg);
 		
 	case SNDCTL_DSP_GETFMTS: /* Returns a mask */
-                return put_user(AFMT_S16_LE|AFMT_U8, (int *)arg);
+                return put_user(AFMT_S16_LE|AFMT_U8|AFMT_AC3, (int *)arg);
 		
 	case SNDCTL_DSP_SETFMT: /* Selects ONE fmt*/
 		if (get_user(val, (int *)arg))
@@ -1566,27 +2059,47 @@
 			if (file->f_mode & FMODE_WRITE) {
 				stop_dac(s);
 				s->dma_dac.ready = 0;
-				if (val == AFMT_S16_LE)
+				if (val == AFMT_S16_LE || val == AFMT_AC3)
 					fmtd |= CM_CFMT_16BIT << CM_CFMT_DACSHIFT;
 				else
 					fmtm &= ~(CM_CFMT_16BIT << CM_CFMT_DACSHIFT);
+				if (val == AFMT_AC3) {
+					fmtd |= CM_CFMT_STEREO << CM_CFMT_DACSHIFT;
+					set_ac3(s, s->ratedac);
+				} else
+					set_ac3(s, 0);
+				if (s->status & DO_DUAL_DAC) {
+					s->dma_adc.ready = 0;
+					if (val == AFMT_S16_LE)
+						fmtd |= CM_CFMT_STEREO << CM_CFMT_ADCSHIFT;
+					else
+						fmtm &= ~(CM_CFMT_STEREO << CM_CFMT_ADCSHIFT);
+				}
 			}
 			set_fmt(s, fmtm, fmtd);
 		}
-		return put_user((s->fmt & ((file->f_mode & FMODE_READ) ? (CM_CFMT_16BIT << CM_CFMT_ADCSHIFT) 
+		if (s->status & DO_AC3) return put_user(AFMT_AC3, (int *)arg);
+		return put_user((s->fmt & ((file->f_mode & FMODE_READ) ? (CM_CFMT_16BIT << CM_CFMT_ADCSHIFT)
 					   : (CM_CFMT_16BIT << CM_CFMT_DACSHIFT))) ? AFMT_S16_LE : AFMT_U8, (int *)arg);
-		
+
 	case SNDCTL_DSP_POST:
                 return 0;
 
         case SNDCTL_DSP_GETTRIGGER:
 		val = 0;
-		if (file->f_mode & FMODE_READ && s->enable & CM_CENABLE_RE) 
+		if (s->status & DO_DUAL_DAC) {
+			if (file->f_mode & FMODE_WRITE &&
+			 (s->enable & CM_ENABLE_CH1) &&
+			 (s->enable & CM_ENABLE_CH0))
+				val |= PCM_ENABLE_OUTPUT;
+			return put_user(val, (int *)arg);
+		}
+		if (file->f_mode & FMODE_READ && s->enable & CM_ENABLE_CH0) 
 			val |= PCM_ENABLE_INPUT;
-		if (file->f_mode & FMODE_WRITE && s->enable & CM_CENABLE_PE) 
+		if (file->f_mode & FMODE_WRITE && s->enable & CM_ENABLE_CH1) 
 			val |= PCM_ENABLE_OUTPUT;
 		return put_user(val, (int *)arg);
-		
+
 	case SNDCTL_DSP_SETTRIGGER:
 		if (get_user(val, (int *)arg))
 			return -EFAULT;
@@ -1602,6 +2115,10 @@
 			if (val & PCM_ENABLE_OUTPUT) {
 				if (!s->dma_dac.ready && (ret = prog_dmabuf(s, 0)))
 					return ret;
+				if (s->status & DO_DUAL_DAC) {
+					if (!s->dma_adc.ready && (ret = prog_dmabuf(s, 1)))
+						return ret;
+				}
 				start_dac(s);
 			} else
 				stop_dac(s);
@@ -1611,22 +2128,22 @@
 	case SNDCTL_DSP_GETOSPACE:
 		if (!(file->f_mode & FMODE_WRITE))
 			return -EINVAL;
-		if (!s->dma_dac.ready && (ret = prog_dmabuf(s, 0)))
-			return ret;
+		if (!(s->enable & CM_ENABLE_CH1) && (val = prog_dmabuf(s, 0)) != 0)
+			return val;
 		spin_lock_irqsave(&s->lock, flags);
 		cm_update_ptr(s);
 		abinfo.fragsize = s->dma_dac.fragsize;
                 abinfo.bytes = s->dma_dac.dmasize - s->dma_dac.count;
                 abinfo.fragstotal = s->dma_dac.numfrag;
-                abinfo.fragments = abinfo.bytes >> s->dma_dac.fragshift;      
+                abinfo.fragments = abinfo.bytes >> s->dma_dac.fragshift;
 		spin_unlock_irqrestore(&s->lock, flags);
 		return copy_to_user((void *)arg, &abinfo, sizeof(abinfo)) ? -EFAULT : 0;
 
 	case SNDCTL_DSP_GETISPACE:
 		if (!(file->f_mode & FMODE_READ))
 			return -EINVAL;
-		if (!s->dma_adc.ready && (ret =  prog_dmabuf(s, 1)))
-			return ret;
+		if (!(s->enable & CM_ENABLE_CH0) && (val = prog_dmabuf(s, 1)) != 0)
+			return val;
 		spin_lock_irqsave(&s->lock, flags);
 		cm_update_ptr(s);
 		abinfo.fragsize = s->dma_adc.fragsize;
@@ -1643,8 +2160,6 @@
         case SNDCTL_DSP_GETODELAY:
 		if (!(file->f_mode & FMODE_WRITE))
 			return -EINVAL;
-		if (!s->dma_dac.ready && (ret = prog_dmabuf(s, 0)))
-			return ret;
 		spin_lock_irqsave(&s->lock, flags);
 		cm_update_ptr(s);
                 val = s->dma_dac.count;
@@ -1654,8 +2169,6 @@
         case SNDCTL_DSP_GETIPTR:
 		if (!(file->f_mode & FMODE_READ))
 			return -EINVAL;
-		if (!s->dma_adc.ready && (ret =  prog_dmabuf(s, 1)))
-			return ret;
 		spin_lock_irqsave(&s->lock, flags);
 		cm_update_ptr(s);
                 cinfo.bytes = s->dma_adc.total_bytes;
@@ -1669,8 +2182,6 @@
         case SNDCTL_DSP_GETOPTR:
 		if (!(file->f_mode & FMODE_WRITE))
 			return -EINVAL;
-		if (!s->dma_dac.ready && (ret = prog_dmabuf(s, 0)))
-			return ret;
 		spin_lock_irqsave(&s->lock, flags);
 		cm_update_ptr(s);
                 cinfo.bytes = s->dma_dac.total_bytes;
@@ -1678,6 +2189,10 @@
                 cinfo.ptr = s->dma_dac.hwptr;
 		if (s->dma_dac.mapped)
 			s->dma_dac.count &= s->dma_dac.fragsize-1;
+		if (s->status & DO_DUAL_DAC) {
+			if (s->dma_adc.mapped)
+				s->dma_adc.count &= s->dma_adc.fragsize-1;
+		}
 		spin_unlock_irqrestore(&s->lock, flags);
                 return copy_to_user((void *)arg, &cinfo, sizeof(cinfo));
 
@@ -1685,6 +2200,11 @@
 		if (file->f_mode & FMODE_WRITE) {
 			if ((val = prog_dmabuf(s, 0)))
 				return val;
+			if (s->status & DO_DUAL_DAC) {
+				if ((val = prog_dmabuf(s, 1)))
+					return val;
+				return put_user(2 * s->dma_dac.fragsize, (int *)arg);
+			}
 			return put_user(s->dma_dac.fragsize, (int *)arg);
 		}
 		if ((val = prog_dmabuf(s, 1)))
@@ -1692,7 +2212,7 @@
 		return put_user(s->dma_adc.fragsize, (int *)arg);
 
         case SNDCTL_DSP_SETFRAGMENT:
-                if (get_user(val, (int *)arg))
+		if (get_user(val, (int *)arg))
 			return -EFAULT;
 		if (file->f_mode & FMODE_READ) {
 			s->dma_adc.ossfragshift = val & 0xffff;
@@ -1713,6 +2233,10 @@
 				s->dma_dac.ossfragshift = 15;
 			if (s->dma_dac.ossmaxfrags < 4)
 				s->dma_dac.ossmaxfrags = 4;
+			if (s->status & DO_DUAL_DAC) {
+				s->dma_adc.ossfragshift = s->dma_dac.ossfragshift;
+				s->dma_adc.ossmaxfrags = s->dma_dac.ossmaxfrags;
+			}
 		}
 		return 0;
 
@@ -1720,14 +2244,17 @@
 		if ((file->f_mode & FMODE_READ && s->dma_adc.subdivision) ||
 		    (file->f_mode & FMODE_WRITE && s->dma_dac.subdivision))
 			return -EINVAL;
-                if (get_user(val, (int *)arg))
+		if (get_user(val, (int *)arg))
 			return -EFAULT;
 		if (val != 1 && val != 2 && val != 4)
 			return -EINVAL;
 		if (file->f_mode & FMODE_READ)
 			s->dma_adc.subdivision = val;
-		if (file->f_mode & FMODE_WRITE)
+		if (file->f_mode & FMODE_WRITE) {
 			s->dma_dac.subdivision = val;
+			if (s->status & DO_DUAL_DAC)
+				s->dma_adc.subdivision = val;
+		}
 		return 0;
 
         case SOUND_PCM_READ_RATE:
@@ -1742,7 +2269,63 @@
         case SOUND_PCM_READ_FILTER:
 		return put_user((file->f_mode & FMODE_READ) ? s->rateadc : s->ratedac, (int *)arg);
 
-        case SOUND_PCM_WRITE_FILTER:
+	case SNDCTL_DSP_GETCHANNELMASK:
+		return put_user(DSP_BIND_FRONT|DSP_BIND_SURR|DSP_BIND_CENTER_LFE|DSP_BIND_SPDIF, (int *)arg);
+		
+	case SNDCTL_DSP_BIND_CHANNEL:
+		if (get_user(val, (int *)arg))
+			return -EFAULT;
+		if (val == DSP_BIND_QUERY) {
+			val = DSP_BIND_FRONT;
+			if (s->status & DO_SPDIF_OUT)
+				val |= DSP_BIND_SPDIF;
+			else {
+				if (s->curr_channels == 4)
+					val |= DSP_BIND_SURR;
+				if (s->curr_channels > 4)
+					val |= DSP_BIND_CENTER_LFE;
+			}
+		} else {
+			if (file->f_mode & FMODE_READ) {
+				stop_adc(s);
+				s->dma_adc.ready = 0;
+			}
+			if (file->f_mode & FMODE_WRITE) {
+				stop_dac(s);
+				s->dma_dac.ready = 0;
+				if (val & DSP_BIND_SPDIF) {
+					set_spdifout(s, s->ratedac);
+					set_dac_channels(s, s->fmt & (CM_CFMT_STEREO << CM_CFMT_DACSHIFT) ? 2 : 1);
+					if (!(s->status & DO_SPDIF_OUT))
+						val &= ~DSP_BIND_SPDIF;
+				} else {
+					int channels;
+					int mask;
+
+					mask = val & (DSP_BIND_FRONT|DSP_BIND_SURR|DSP_BIND_CENTER_LFE);
+					switch (mask) {
+					    case DSP_BIND_FRONT:
+						channels = 2;
+						break;
+					    case DSP_BIND_FRONT|DSP_BIND_SURR:
+						channels = 4;
+						break;
+					    case DSP_BIND_FRONT|DSP_BIND_SURR|DSP_BIND_CENTER_LFE:
+						channels = 6;
+						break;
+					    default:
+						channels = s->fmt & (CM_CFMT_STEREO << CM_CFMT_DACSHIFT) ? 2 : 1;
+						break;
+					}
+					set_dac_channels(s, channels);
+				}
+			}
+		}
+		return put_user(val, (int *)arg);
+
+	case SOUND_PCM_WRITE_FILTER:
+	case SNDCTL_DSP_MAPINBUF:
+	case SNDCTL_DSP_MAPOUTBUF:
         case SNDCTL_DSP_SETSYNCRO:
                 return -EINVAL;
 		
@@ -1788,6 +2371,12 @@
 			fmts |= CM_CFMT_16BIT << CM_CFMT_DACSHIFT;
 		s->dma_dac.ossfragshift = s->dma_dac.ossmaxfrags = s->dma_dac.subdivision = 0;
 		set_dac_rate(s, 8000);
+		// clear previous multichannel, spdif, ac3 state
+		set_spdifout(s, 0);
+		if (s->deviceid == PCI_DEVICE_ID_CMEDIA_CM8738) {
+			set_ac3(s, 0);
+			set_dac_channels(s, 1);
+		}
 	}
 	set_fmt(s, fmtm, fmts);
 	s->open_mode |= file->f_mode & (FMODE_READ | FMODE_WRITE);
@@ -1806,11 +2395,23 @@
 	down(&s->open_sem);
 	if (file->f_mode & FMODE_WRITE) {
 		stop_dac(s);
+#ifndef FIXEDDMA
 		dealloc_dmabuf(&s->dma_dac);
+		if (s->status & DO_DUAL_DAC)
+			dealloc_dmabuf(&s->dma_adc);
+#endif
+		if (s->status & DO_MULTI_CH)
+			set_dac_channels(s, 0);
+		if (s->status & DO_AC3)
+			set_ac3(s, 0);
+		if (s->status & DO_SPDIF_OUT)
+			set_spdifout(s, 0);
 	}
 	if (file->f_mode & FMODE_READ) {
 		stop_adc(s);
+#ifndef FIXEDDMA
 		dealloc_dmabuf(&s->dma_adc);
+#endif
 	}
 	s->open_mode &= (~file->f_mode) & (FMODE_READ|FMODE_WRITE);
 	up(&s->open_sem);
@@ -1831,6 +2432,7 @@
 	release:	cm_release,
 };
 
+#ifdef CONFIG_SOUND_CMPCI_MIDI
 /* --------------------------------------------------------------------- */
 
 static ssize_t cm_midi_read(struct file *file, char *buffer, size_t count, loff_t *ppos)
@@ -1847,12 +2449,9 @@
 		return -ESPIPE;
 	if (!access_ok(VERIFY_WRITE, buffer, count))
 		return -EFAULT;
-	if (count == 0)
-		return 0;
 	ret = 0;
 	add_wait_queue(&s->midi.iwait, &wait);
 	while (count > 0) {
-		set_current_state(TASK_INTERRUPTIBLE);
 		spin_lock_irqsave(&s->lock, flags);
 		ptr = s->midi.ird;
 		cnt = MIDIINBUF - ptr;
@@ -1862,14 +2461,15 @@
 		if (cnt > count)
 			cnt = count;
 		if (cnt <= 0) {
-			if (file->f_flags & O_NONBLOCK) 
+			if (file->f_flags & O_NONBLOCK)
 			{
 				if (!ret)
 					ret = -EAGAIN;
 				break;
 			}
+			__set_current_state(TASK_INTERRUPTIBLE);
 			schedule();
-			if (signal_pending(current)) 
+			if (signal_pending(current))
 			{
 				if (!ret)
 					ret = -ERESTARTSYS;
@@ -1877,7 +2477,8 @@
 			}
 			continue;
 		}
-		if (copy_to_user(buffer, s->midi.ibuf + ptr, cnt)) {
+		if (copy_to_user(buffer, s->midi.ibuf + ptr, cnt))
+		{
 			if (!ret)
 				ret = -EFAULT;
 			break;
@@ -1916,7 +2517,6 @@
 	ret = 0;
 	add_wait_queue(&s->midi.owait, &wait);
 	while (count > 0) {
-		set_current_state(TASK_INTERRUPTIBLE);
 		spin_lock_irqsave(&s->lock, flags);
 		ptr = s->midi.owr;
 		cnt = MIDIOUTBUF - ptr;
@@ -1928,11 +2528,13 @@
 		if (cnt > count)
 			cnt = count;
 		if (cnt <= 0) {
-			if (file->f_flags & O_NONBLOCK) {
+			if (file->f_flags & O_NONBLOCK)
+			{
 				if (!ret)
 					ret = -EAGAIN;
 				break;
 			}
+			__set_current_state(TASK_INTERRUPTIBLE);
 			schedule();
 			if (signal_pending(current)) {
 				if (!ret)
@@ -1941,7 +2543,8 @@
 			}
 			continue;
 		}
-		if (copy_from_user(s->midi.obuf + ptr, buffer, cnt)) {
+		if (copy_from_user(s->midi.obuf + ptr, buffer, cnt))
+		{
 			if (!ret)
 				ret = -EFAULT;
 			break;
@@ -2017,7 +2620,7 @@
 		s->midi.ird = s->midi.iwr = s->midi.icnt = 0;
 		s->midi.ord = s->midi.owr = s->midi.ocnt = 0;
 		/* enable MPU-401 */
-		outb(inb(s->iobase + CODEC_CMI_FUNCTRL1) | 4, s->iobase + CODEC_CMI_FUNCTRL1);
+		maskb(s->iobase + CODEC_CMI_FUNCTRL1, ~0, 4);
 		outb(0xff, s->iomidi+1); /* reset command */
 		if (!(inb(s->iomidi+1) & 0x80))
 			inb(s->iomidi);
@@ -2040,23 +2643,24 @@
 	spin_unlock_irqrestore(&s->lock, flags);
 	s->open_mode |= (file->f_mode << FMODE_MIDI_SHIFT) & (FMODE_MIDI_READ | FMODE_MIDI_WRITE);
 	up(&s->open_sem);
+	MOD_INC_USE_COUNT;
 	return 0;
 }
 
 static int cm_midi_release(struct inode *inode, struct file *file)
 {
 	struct cm_state *s = (struct cm_state *)file->private_data;
-        DECLARE_WAITQUEUE(wait, current);
+	DECLARE_WAITQUEUE(wait, current);
 	unsigned long flags;
 	unsigned count, tmo;
 
 	VALIDATE_STATE(s);
-
 	lock_kernel();
+
 	if (file->f_mode & FMODE_WRITE) {
+		__set_current_state(TASK_INTERRUPTIBLE);
 		add_wait_queue(&s->midi.owait, &wait);
 		for (;;) {
-			set_current_state(TASK_INTERRUPTIBLE);
 			spin_lock_irqsave(&s->lock, flags);
 			count = s->midi.ocnt;
 			spin_unlock_irqrestore(&s->lock, flags);
@@ -2067,11 +2671,12 @@
 			if (file->f_flags & O_NONBLOCK) {
 				remove_wait_queue(&s->midi.owait, &wait);
 				set_current_state(TASK_RUNNING);
+				unlock_kernel();
 				return -EBUSY;
 			}
 			tmo = (count * HZ) / 3100;
 			if (!schedule_timeout(tmo ? : 1) && tmo)
-				printk(KERN_DEBUG "cmpci: midi timed out??\n");
+				printk(KERN_DEBUG "cm: midi timed out??\n");
 		}
 		remove_wait_queue(&s->midi.owait, &wait);
 		set_current_state(TASK_RUNNING);
@@ -2085,7 +2690,7 @@
 		if (!(inb(s->iomidi+1) & 0x80))
 			inb(s->iomidi);
 		/* disable MPU-401 */
-		outb(inb(s->iobase + CODEC_CMI_FUNCTRL1) & ~4, s->iobase + CODEC_CMI_FUNCTRL1);
+		maskb(s->iobase + CODEC_CMI_FUNCTRL1, ~4, 0);
 	}
 	spin_unlock_irqrestore(&s->lock, flags);
 	up(&s->open_sem);
@@ -2103,9 +2708,11 @@
 	open:		cm_midi_open,
 	release:	cm_midi_release,
 };
+#endif
 
 /* --------------------------------------------------------------------- */
 
+#ifdef CONFIG_SOUND_CMPCI_FM
 static int cm_dmfm_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
 {
 	static const unsigned char op_offset[18] = {
@@ -2197,10 +2804,8 @@
 		outb(5, s->iosynth+2);
 		outb(arg & 1, s->iosynth+3);
 		return 0;
-
-	default:
-		return -EINVAL;
 	}
+	return -EINVAL;
 }
 
 static int cm_dmfm_open(struct inode *inode, struct file *file)
@@ -2236,6 +2841,7 @@
 	outb(1, s->iosynth+3);  /* enable OPL3 */
 	s->open_mode |= FMODE_DMFM;
 	up(&s->open_sem);
+	MOD_INC_USE_COUNT;
 	return 0;
 }
 
@@ -2267,6 +2873,7 @@
 	open:		cm_dmfm_open,
 	release:	cm_dmfm_release,
 };
+#endif /* CONFIG_SOUND_CMPCI_FM */
 
 /* --------------------------------------------------------------------- */
 
@@ -2285,46 +2892,125 @@
 	int mixch;
 	int vol;
 } initvol[] __initdata = {
-	{ SOUND_MIXER_WRITE_CD, 0x4040 },
-	{ SOUND_MIXER_WRITE_LINE, 0x4040 },
-	{ SOUND_MIXER_WRITE_MIC, 0x4040 },
-	{ SOUND_MIXER_WRITE_SYNTH, 0x4040 },
-	{ SOUND_MIXER_WRITE_VOLUME, 0x4040 },
-	{ SOUND_MIXER_WRITE_PCM, 0x4040 }
+	{ SOUND_MIXER_WRITE_CD, 0x4f4f },
+	{ SOUND_MIXER_WRITE_LINE, 0x4f4f },
+	{ SOUND_MIXER_WRITE_MIC, 0x4f4f },
+	{ SOUND_MIXER_WRITE_SYNTH, 0x4f4f },
+	{ SOUND_MIXER_WRITE_VOLUME, 0x4f4f },
+	{ SOUND_MIXER_WRITE_PCM, 0x4f4f }
 };
 
-#ifdef MODULE
-static int	spdif_loop = 0;
-static int	four_ch = 0;
-static int	rear_out = 0;
-MODULE_PARM(spdif_loop, "i");
-MODULE_PARM(four_ch, "i");
-MODULE_PARM(rear_out, "i");
+/* check chip version and capability */
+static int query_chip(struct cm_state *s)
+{
+	int ChipVersion = -1;
+	unsigned char RegValue;
+
+	// check reg 0Ch, bit 24-31
+	RegValue = inb(s->iobase + CODEC_CMI_INT_HLDCLR + 3);
+	if (RegValue == 0) {
+	    // check reg 08h, bit 24-28
+	    RegValue = inb(s->iobase + CODEC_CMI_CHFORMAT + 3);
+	    RegValue &= 0x1f;
+	    if (RegValue == 0) {
+		ChipVersion = 33;
+		s->max_channels = 4;
+		s->capability |= CAN_AC3_SW;
+		s->capability |= CAN_DUAL_DAC;
+	    } else {
+		ChipVersion = 37;
+		s->max_channels = 4;
+		s->capability |= CAN_AC3_HW;
+		s->capability |= CAN_DUAL_DAC;
+	    }
+	} else {
+	    // check reg 0Ch, bit 26
+	    if (RegValue & (1 << (26-24))) {
+		ChipVersion = 39;
+	    	if (RegValue & (1 << (24-24)))
+		    s->max_channels  = 6;
+	    	else
+		    s->max_channels = 4;
+		s->capability |= CAN_AC3_HW;
+		s->capability |= CAN_DUAL_DAC;
+		s->capability |= CAN_MULTI_CH_HW;
+	    } else {
+		ChipVersion = 55; // 4 or 6 channels
+		s->max_channels  = 6;
+		s->capability |= CAN_AC3_HW;
+		s->capability |= CAN_DUAL_DAC;
+		s->capability |= CAN_MULTI_CH_HW;
+	    }
+	}
+	// still limited to number of speakers
+	if (s->max_channels > s->speakers)
+		s->max_channels = s->speakers;
+	return ChipVersion;
+}
+
+#ifdef CONFIG_SOUND_CMPCI_MIDI
+static	int	mpu_io = CONFIG_SOUND_CMPCI_MPUIO;
 #else
+static	int	mpu_io;
+#endif
+#ifdef CONFIG_SOUND_CMPCI_FM
+static	int	fm_io = CONFIG_SOUND_CMPCI_FMIO;
+#else
+static	int	fm_io;
+#endif
+#ifdef CONFIG_SOUND_CMPCI_SPDIFINVERSE
+static	int	spdif_inverse = 1;
+#else
+static	int	spdif_inverse;
+#endif
 #ifdef CONFIG_SOUND_CMPCI_SPDIFLOOP
-static int	spdif_loop = 1;
+static	int	spdif_loop = 1;
+#else
+static	int	spdif_loop;
+#endif
+#ifdef CONFIG_SOUND_CMPCI_SPEAKERS
+static	int	speakers = CONFIG_SOUND_CMPCI_SPEAKERS;
 #else
-static int	spdif_loop = 0;
+static	int	speakers = 2;
 #endif
-#ifdef CONFIG_SOUND_CMPCI_4CH
-static int	four_ch = 1;
+#ifdef CONFIG_SOUND_CMPCI_LINE_REAR
+static	int	use_line_as_rear = 1;
 #else
-static int	four_ch = 0;
+static	int	use_line_as_rear;
 #endif
-#ifdef CONFIG_SOUND_CMPCI_REAR
-static int	rear_out = 1;
+#ifdef CONFIG_SOUND_CMPCI_LINE_BASS
+static	int	use_line_as_bass = 1;
 #else
-static int	rear_out = 0;
+static	int	use_line_as_bass;
 #endif
+#ifdef CONFIG_SOUND_CMPCI_JOYSTICK
+static	int	joystick = 1;
+#else
+static	int	joystick;
 #endif
+MODULE_PARM(mpu_io, "i");
+MODULE_PARM(fm_io, "i");
+MODULE_PARM(spdif_inverse, "i");
+MODULE_PARM(spdif_loop, "i");
+MODULE_PARM(speakers, "i");
+MODULE_PARM(use_line_as_rear, "i");
+MODULE_PARM(use_line_as_bass, "i");
+MODULE_PARM(joystick, "i");
+MODULE_PARM_DESC(mpu_io, "(0x330, 0x320, 0x310, 0x300) Base of MPU-401, 0 to disable");
+MODULE_PARM_DESC(fm_io, "(0x388, 0x3C8, 0x3E0) Base of OPL3, 0 to disable");
+MODULE_PARM_DESC(spdif_inverse, "(1/0) Invert S/PDIF-in signal");
+MODULE_PARM_DESC(spdif_loop, "(1/0) Route S/PDIF-in to S/PDIF-out directly");
+MODULE_PARM_DESC(speakers, "(2-6) Number of speakers you connect");
+MODULE_PARM_DESC(use_line_as_rear, "(1/0) Use line-in jack as rear-out");
+MODULE_PARM_DESC(use_line_as_bass, "(1/0) Use line-in jack as bass/center");
+MODULE_PARM_DESC(joystick, "(1/0) Enable joystick interface, still need joystick driver");
 
-static int __init init_cmpci(void)
+void initialize_chip(struct pci_dev *pcidev)
 {
 	struct cm_state *s;
-	struct pci_dev *pcidev = NULL;
 	mm_segment_t fs;
-	int i, val, index = 0;
-	
+	int i, val;
+	unsigned char reg_mask = 0;
 	struct {
 		unsigned short	deviceid;
 		char		*devicename;
@@ -2333,33 +3019,21 @@
 		{ PCI_DEVICE_ID_CMEDIA_CM8338A, "CM8338A" },
 		{ PCI_DEVICE_ID_CMEDIA_CM8338B, "CM8338B" },
 		{ PCI_DEVICE_ID_CMEDIA_CM8738,  "CM8738" },
+		{ PCI_DEVICE_ID_CMEDIA_CM8738B, "CM8738B" },
 	};
 	char	*devicename = "unknown";
-
-#ifdef CONFIG_PCI
-	if (!pci_present())   /* No PCI bus in this machine! */
-#endif
-		return -ENODEV;
-	printk(KERN_INFO "cmpci: version v2.41-nomodem time " __TIME__ " " __DATE__ "\n");
-#if 0
-	if (!(wavetable_mem = __get_free_pages(GFP_KERNEL, 20-PAGE_SHIFT)))
-		printk(KERN_INFO "cmpci: cannot allocate 1MB of contiguous nonpageable memory for wavetable data\n");
-#endif
-	while (index < NR_DEVICE && pcidev == NULL && (
- 	       (pcidev = pci_find_device(PCI_VENDOR_ID_CMEDIA, PCI_DEVICE_ID_CMEDIA_CM8338A, pcidev)) ||
-	       (pcidev = pci_find_device(PCI_VENDOR_ID_CMEDIA, PCI_DEVICE_ID_CMEDIA_CM8338B, pcidev)) ||
-	       (pcidev = pci_find_device(PCI_VENDOR_ID_CMEDIA, PCI_DEVICE_ID_CMEDIA_CM8738, pcidev)))) {
+	{
 		if (pci_enable_device(pcidev))
-			continue;
+			return;
 		if (pcidev->irq == 0)
-			continue;
-		if (!(s = kmalloc(sizeof(struct cm_state), GFP_KERNEL))) {
-			printk(KERN_WARNING "cmpci: out of memory\n");
-			continue;
+			return;
+		s = kmalloc(sizeof(*s), GFP_KERNEL);
+		if (!s) {
+			printk(KERN_WARNING "cm: out of memory\n");
+			return;
 		}
 		/* search device name */
-		for (i = 0; i < sizeof(devicetable) / sizeof(devicetable[0]); i++)
-		{
+		for (i = 0; i < sizeof(devicetable) / sizeof(devicetable[0]); i++) {
 			if (devicetable[i].deviceid == pcidev->device)
 			{
 				devicename = devicetable[i].devicename;
@@ -2376,35 +3050,96 @@
 		spin_lock_init(&s->lock);
 		s->magic = CM_MAGIC;
 		s->iobase = pci_resource_start(pcidev, 0);
-		s->iosynth = 0x388;
-		s->iomidi = 0x330;
-		spin_lock_init(&s->lock);
+		s->iosynth = fm_io;
+		s->iomidi = mpu_io;
+		s->status = 0;
+		/* range check */
+		if (speakers < 2)
+			speakers = 2;
+		else if (speakers > 6)
+			speakers = 6;
+		s->speakers = speakers;
 		if (s->iobase == 0)
-			continue;
+			return;
 		s->irq = pcidev->irq;
 
 		if (!request_region(s->iobase, CM_EXTENT_CODEC, "cmpci")) {
-			printk(KERN_ERR "cmpci: io ports %#x-%#x in use\n", s->iobase, s->iobase+CM_EXTENT_CODEC-1);
+			printk(KERN_ERR "cm: io ports %#x-%#x in use\n", s->iobase, s->iobase+CM_EXTENT_CODEC-1);
 			goto err_region5;
 		}
-		if (!request_region(s->iomidi, CM_EXTENT_MIDI, "cmpci Midi")) {
-			printk(KERN_WARNING "cmpci: io ports %#x-%#x in use, midi disabled.\n", s->iomidi, s->iomidi+CM_EXTENT_MIDI-1);
+#ifdef CONFIG_SOUND_CMPCI_MIDI
+		/* disable MPU-401 */
+		maskb(s->iobase + CODEC_CMI_FUNCTRL1, ~0x04, 0);
+		if (s->iomidi) {
+		    if (!request_region(s->iomidi, CM_EXTENT_MIDI, "cmpci Midi")) {
+			printk(KERN_ERR "cm: io ports %#x-%#x in use\n", s->iomidi, s->iomidi+CM_EXTENT_MIDI-1);
 			s->iomidi = 0;
+		    } else {
+		        /* set IO based at 0x330 */
+		        switch (s->iomidi) {
+		 	    case 0x330:
+				reg_mask = 0;
+				break;
+			    case 0x320:
+				reg_mask = 0x20;
+				break;
+			    case 0x310:
+				reg_mask = 0x40;
+				break;
+			    case 0x300:
+				reg_mask = 0x60;
+				break;
+			    default:
+				s->iomidi = 0;
+				break;
+		        }
+		        outb((inb(s->iobase + CODEC_CMI_LEGACY_CTRL + 3) & ~0x60) | reg_mask, s->iobase + CODEC_CMI_LEGACY_CTRL + 3);
+			/* enable MPU-401 */
+			if (s->iomidi) {
+			    maskb(s->iobase + CODEC_CMI_FUNCTRL1, ~0, 0x04);
+			}
+		    }
 		}
-		else
-		{
-			/* set IO based at 0x330 */
-			outb(inb(s->iobase + CODEC_CMI_LEGACY_CTRL + 3) & ~0x60, s->iobase + CODEC_CMI_LEGACY_CTRL + 3);
-		}
-		if (!request_region(s->iosynth, CM_EXTENT_SYNTH, "cmpci FM")) {
-			printk(KERN_WARNING "cmpci: io ports %#x-%#x in use, synth disabled.\n", s->iosynth, s->iosynth+CM_EXTENT_SYNTH-1);
+#endif
+#ifdef CONFIG_SOUND_CMPCI_FM
+		/* disable FM */
+		maskb(s->iobase + CODEC_CMI_MISC_CTRL + 2, ~8, 0);
+		if (s->iosynth) {
+		    if (!request_region(s->iosynth, CM_EXTENT_SYNTH, "cmpci FM")) {
+			printk(KERN_ERR "cm: io ports %#x-%#x in use\n", s->iosynth, s->iosynth+CM_EXTENT_SYNTH-1);
 			s->iosynth = 0;
+		    } else {
+		        /* set IO based at 0x388 */
+		        switch (s->iosynth) {
+		 	    case 0x388:
+				reg_mask = 0;
+				break;
+			    case 0x3C8:
+				reg_mask = 0x01;
+				break;
+			    case 0x3E0:
+				reg_mask = 0x02;
+				break;
+			    case 0x3E8:
+				reg_mask = 0x03;
+				break;
+			    default:
+				s->iosynth = 0;
+				break;
+		        }
+		        maskb(s->iobase + CODEC_CMI_LEGACY_CTRL + 3, ~0x03, reg_mask);
+		        /* enable FM */
+			if (s->iosynth) {
+		            maskb(s->iobase + CODEC_CMI_MISC_CTRL + 2, ~0, 8);
+			}
+		    }
 		}
+#endif
+		/* enable joystick */
+		if (joystick)
+			maskb(s->iobase + CODEC_CMI_FUNCTRL1, ~0, 0x02);
 		else
-		{
-			/* enable FM */
-			outb(inb(s->iobase + CODEC_CMI_MISC_CTRL + 2) | 8, s->iobase + CODEC_CMI_MISC_CTRL);
-		}
+			maskb(s->iobase + CODEC_CMI_FUNCTRL1, ~0x02, 0);
 		/* initialize codec registers */
 		outb(0, s->iobase + CODEC_CMI_INT_HLDCLR + 2);  /* disable ints */
 		outb(0, s->iobase + CODEC_CMI_FUNCTRL0 + 2); /* disable channels */
@@ -2413,21 +3148,25 @@
 
 		/* request irq */
 		if (request_irq(s->irq, cm_interrupt, SA_SHIRQ, "cmpci", s)) {
-			printk(KERN_ERR "cmpci: irq %u in use\n", s->irq);
+			printk(KERN_ERR "cm: irq %u in use\n", s->irq);
 			goto err_irq;
 		}
-		printk(KERN_INFO "cmpci: found %s adapter at io %#06x irq %u\n",
+		printk(KERN_INFO "cm: found %s adapter at io %#06x irq %u\n",
 		       devicename, s->iobase, s->irq);
 		/* register devices */
 		if ((s->dev_audio = register_sound_dsp(&cm_audio_fops, -1)) < 0)
 			goto err_dev1;
 		if ((s->dev_mixer = register_sound_mixer(&cm_mixer_fops, -1)) < 0)
 			goto err_dev2;
-		if (s->iomidi && (s->dev_midi = register_sound_midi(&cm_midi_fops, -1)) < 0)
+#ifdef CONFIG_SOUND_CMPCI_MIDI
+		if ((s->dev_midi = register_sound_midi(&cm_midi_fops, -1)) < 0)
 			goto err_dev3;
-		if (s->iosynth && (s->dev_dmfm = register_sound_special(&cm_dmfm_fops, 15 /* ?? */)) < 0)
+#endif
+#ifdef CONFIG_SOUND_CMPCI_FM
+		if ((s->dev_dmfm = register_sound_special(&cm_dmfm_fops, 15 /* ?? */)) < 0)
 			goto err_dev4;
-		pci_set_master(pcidev);
+#endif
+		pci_set_master(pcidev);	/* enable bus mastering */
 		/* initialize the chips */
 		fs = get_fs();
 		set_fs(KERNEL_DS);
@@ -2440,59 +3179,78 @@
 			val = initvol[i].vol;
 			mixer_ioctl(s, initvol[i].mixch, (unsigned long)&val);
 		}
-		set_fs(fs);
-		if (pcidev->device == PCI_DEVICE_ID_CMEDIA_CM8738)
-		{
+		/* use channel 0 for record, channel 1 for play */
+		maskb(s->iobase + CODEC_CMI_FUNCTRL0, ~2, 1);
+		s->deviceid = pcidev->device;
+		if (pcidev->device == PCI_DEVICE_ID_CMEDIA_CM8738) {
+			/* chip version and hw capability check */
+			s->chip_version = query_chip(s);
+			printk(KERN_INFO "chip version = 0%d\n", s->chip_version);
+			/* seet SPDIF-in inverse before enable SPDIF loop */
+			if (spdif_inverse) {
+				/* turn on spdif-in inverse */
+				maskb(s->iobase + CODEC_CMI_CHFORMAT + 2, ~0, 1);
+				printk(KERN_INFO "cm: Inverse SPDIF-in\n");
+			} else {
+				/* turn off spdif-ininverse */
+				maskb(s->iobase + CODEC_CMI_CHFORMAT + 2, ~1, 0);
+			}
+
 			/* enable SPDIF loop */
-			if (spdif_loop)
-			{
+			if (spdif_loop) {
+				s->status |= DO_SPDIF_LOOP;
 				/* turn on spdif-in to spdif-out */
-				outb(inb(s->iobase + CODEC_CMI_FUNCTRL1) | 0x80, s->iobase + CODEC_CMI_FUNCTRL1);
-				printk(KERN_INFO "cmpci: Enable SPDIF loop\n");
+				maskb(s->iobase + CODEC_CMI_FUNCTRL1, ~0, 0x80);
+				printk(KERN_INFO "cm: Enable SPDIF loop\n");
+			} else {
+				s->status &= ~DO_SPDIF_LOOP;
+				/* turn off spdif-in to spdif-out */
+				maskb(s->iobase + CODEC_CMI_FUNCTRL1, ~0x80, 0);
 			}
-			else
-				outb(inb(s->iobase + CODEC_CMI_FUNCTRL1) & ~0x80, s->iobase + CODEC_CMI_FUNCTRL1);
-			/* enable 4 channels mode */
-			if (four_ch)
-			{
-				/* 4 channel mode (analog duplicate) */
-				outb(inb(s->iobase + CODEC_CMI_MISC_CTRL + 3) | 0x04, s->iobase + CODEC_CMI_MISC_CTRL + 3);
-				printk(KERN_INFO "cmpci: Enable 4 channels mode\n");
-				/* has separate rear-out jack ? */
-				if (rear_out)
-				{
-					/* has separate rear out jack */
-					outb(inb(s->iobase + CODEC_CMI_MIXER1) & ~0x20, s->iobase + CODEC_CMI_MIXER1);
-				}
-				else
-				{
-					outb(inb(s->iobase + CODEC_CMI_MIXER1) | 0x20, s->iobase + CODEC_CMI_MIXER1);
-					printk(KERN_INFO "cmpci: line-in routed as rear-out\n");
-				}
+			if (use_line_as_rear) {
+				s->capability |= CAN_LINE_AS_REAR;
+				s->status |= DO_LINE_AS_REAR;
+				maskb(s->iobase + CODEC_CMI_MIXER1, ~0, 0x20);
+			} else
+				maskb(s->iobase + CODEC_CMI_MIXER1, ~0x20, 0);
+			if (s->chip_version >= 39) {
+				if (use_line_as_bass) {
+					s->capability |= CAN_LINE_AS_BASS;
+					s->status |= DO_LINE_AS_BASS;
+					maskb(s->iobase + CODEC_CMI_LEGACY_CTRL + 1, ~0, 0x60);
+				} else
+					maskb(s->iobase + CODEC_CMI_LEGACY_CTRL + 1, ~0x60, 0);
 			}
-			else
-				outb(inb(s->iobase + CODEC_CMI_MISC_CTRL + 3) & ~0x04, s->iobase + CODEC_CMI_MISC_CTRL + 3);
+		} else {
+			/* 8338 will fall here */
+			s->max_channels = 2;
 		}
 		/* queue it for later freeing */
 		s->next = devs;
 		devs = s;
-		index++;
-		continue;
+		return;
 
+#ifdef CONFIG_SOUND_CMPCI_FM
+		unregister_sound_special(s->dev_dmfm);
 	err_dev4:
+#endif
+#ifdef CONFIG_SOUND_CMPCI_MIDI
 		unregister_sound_midi(s->dev_midi);
 	err_dev3:
+#endif
 		unregister_sound_mixer(s->dev_mixer);
 	err_dev2:
 		unregister_sound_dsp(s->dev_audio);
 	err_dev1:
-		printk(KERN_ERR "cmpci: cannot register misc device\n");
+		printk(KERN_ERR "cm: cannot register misc device\n");
 		free_irq(s->irq, s);
 	err_irq:
-		if(s->iosynth)
-			release_region(s->iosynth, CM_EXTENT_SYNTH);
-		if(s->iomidi)
-			release_region(s->iomidi, CM_EXTENT_MIDI);
+#ifdef CONFIG_SOUND_CMPCI_FM
+		if (s->iosynth) release_region(s->iosynth, CM_EXTENT_SYNTH);
+#endif
+#ifdef CONFIG_SOUND_CMPCI_MIDI
+		if (s->iomidi) release_region(s->iomidi, CM_EXTENT_MIDI);
+#endif
 		release_region(s->iobase, CM_EXTENT_CODEC);
 	err_region5:
 		kfree(s);
@@ -2500,15 +3258,47 @@
 	if (!devs) {
 		if (wavetable_mem)
 			free_pages(wavetable_mem, 20-PAGE_SHIFT);
+		return;
+	}
+	return;
+}
+
+static int __init init_cmpci(void)
+{
+	struct pci_dev *pcidev = NULL;
+	int index = 0;
+
+#ifdef CONFIG_PCI
+	if (!pci_present())   /* No PCI bus in this machine! */
+#endif
 		return -ENODEV;
+	printk(KERN_INFO "cm: version $Revision: 5.64 $ time " __TIME__ " " __DATE__ "\n");
+#if 0
+	if (!(wavetable_mem = __get_free_pages(GFP_KERNEL, 20-PAGE_SHIFT)))
+		printk(KERN_INFO "cm: cannot allocate 1MB of contiguous nonpageable memory for wavetable data\n");
+#endif
+	while (index < NR_DEVICE && (
+	       (pcidev = pci_find_device(PCI_VENDOR_ID_CMEDIA, PCI_DEVICE_ID_CMEDIA_CM8738, pcidev)))) { 
+		initialize_chip(pcidev);
+		index++;
+	}
+	while (index < NR_DEVICE && (
+ 	       (pcidev = pci_find_device(PCI_VENDOR_ID_CMEDIA, PCI_DEVICE_ID_CMEDIA_CM8338A, pcidev)))) {
+		initialize_chip(pcidev);
+		index++;
+	}
+	while (index < NR_DEVICE && (
+	       (pcidev = pci_find_device(PCI_VENDOR_ID_CMEDIA, PCI_DEVICE_ID_CMEDIA_CM8338B, pcidev)))) {
+		initialize_chip(pcidev);
+		index++;
 	}
 	return 0;
 }
 
 /* --------------------------------------------------------------------- */
 
-MODULE_AUTHOR("ChenLi Tien, cltien@home.com");
-MODULE_DESCRIPTION("CMPCI Audio Driver");
+MODULE_AUTHOR("ChenLi Tien, cltien@cmedia.com.tw");
+MODULE_DESCRIPTION("CM8x38 Audio Driver");
 
 static void __exit cleanup_cmpci(void)
 {
@@ -2520,28 +3310,34 @@
 		synchronize_irq();
 		outb(0, s->iobase + CODEC_CMI_FUNCTRL0 + 2); /* disable channels */
 		free_irq(s->irq, s);
+#ifdef FIXEDDMA
+    		dealloc_dmabuf(&s->dma_dac);
+    		dealloc_dmabuf(&s->dma_adc);
+#endif
 
 		/* reset mixer */
 		wrmixer(s, DSP_MIX_DATARESETIDX, 0);
 
 		release_region(s->iobase, CM_EXTENT_CODEC);
-		if(s->iomidi)
-		{
-			release_region(s->iomidi, CM_EXTENT_MIDI);
-			unregister_sound_midi(s->dev_midi);
-		}
-		if(s->iosynth)
-		{
-			release_region(s->iosynth, CM_EXTENT_SYNTH);
-			unregister_sound_special(s->dev_dmfm);
-		}
+#ifdef CONFIG_SOUND_CMPCI_MIDI
+		if (s->iomidi) release_region(s->iomidi, CM_EXTENT_MIDI);
+#endif
+#ifdef CONFIG_SOUND_CMPCI_FM
+		if (s->iosynth) release_region(s->iosynth, CM_EXTENT_SYNTH);
+#endif
 		unregister_sound_dsp(s->dev_audio);
 		unregister_sound_mixer(s->dev_mixer);
+#ifdef CONFIG_SOUND_CMPCI_MIDI
+		unregister_sound_midi(s->dev_midi);
+#endif
+#ifdef CONFIG_SOUND_CMPCI_FM
+		unregister_sound_special(s->dev_dmfm);
+#endif
 		kfree(s);
 	}
 	if (wavetable_mem)
 		free_pages(wavetable_mem, 20-PAGE_SHIFT);
-	printk(KERN_INFO "cmpci: unloading\n");
+	printk(KERN_INFO "cm: unloading\n");
 }
 
 module_init(init_cmpci);
diff -urN linux-2.4.6-pre5/drivers/sound/cs4281/cs4281m.c linux/drivers/sound/cs4281/cs4281m.c
--- linux-2.4.6-pre5/drivers/sound/cs4281/cs4281m.c	Mon Dec  3 22:49:02 2001
+++ linux/drivers/sound/cs4281/cs4281m.c	Mon Dec  3 22:49:12 2001
@@ -658,7 +658,7 @@
 	       card->pBA0 + BA0_ACCTL);
 
 	// Wait for the write to occur.
-	for (count = 0; count < 10; count++) {
+	for (count = 0; count < 100; count++) {
 		// First, we want to wait for a short time.
 		udelay(25);
 		// Now, check to see if the write has completed.
@@ -4463,9 +4463,9 @@
 	unregister_sound_midi(s->dev_midi);
 	iounmap(s->pBA1);
 	iounmap(s->pBA0);
-	kfree(s);
 	pci_set_drvdata(pci_dev,NULL);
 	list_del(&s->list);
+	kfree(s);
 	CS_DBGOUT(CS_INIT | CS_FUNCTION, 2, printk(KERN_INFO
 		 "cs4281: cs4281_remove()-: remove successful\n"));
 }
diff -urN linux-2.4.6-pre5/drivers/sound/cs46xx.c linux/drivers/sound/cs46xx.c
--- linux-2.4.6-pre5/drivers/sound/cs46xx.c	Mon Dec  3 22:49:02 2001
+++ linux/drivers/sound/cs46xx.c	Mon Dec  3 22:49:12 2001
@@ -50,6 +50,7 @@
  *	20010409-tw	add hercules game theatre XP amp code.
  *	20010420-tw	cleanup powerdown/up code.
  *	20010521-tw	eliminate pops, and fixes for powerdown.
+ *	20010525-tw	added fixes for thinkpads with powerdown logic.
  *
  *	Status:
  *	Playback/Capture supported from 8k-48k.
@@ -179,7 +180,7 @@
 MODULE_PARM(hercules_egpio_disable, "i");
 static unsigned long initdelay=700;  /* PM delay in millisecs */
 MODULE_PARM(initdelay, "i");
-static unsigned long powerdown=1;  /* turn on/off powerdown processing in driver */
+static unsigned long powerdown=-1;  /* turn on/off powerdown processing in driver */
 MODULE_PARM(powerdown, "i");
 #define DMABUF_DEFAULTORDER 3
 static unsigned long defaultorder=DMABUF_DEFAULTORDER;
@@ -190,6 +191,14 @@
 static int thinkpad;
 MODULE_PARM(thinkpad, "i");
 
+/*
+* set the powerdown module parm to 0 to disable all 
+* powerdown. also set thinkpad to 1 to disable powerdown, 
+* but also to enable the clkrun functionality.
+*/
+static unsigned cs_powerdown=1;
+static unsigned cs_laptop_wait=1;
+
 /* An instance of the 4610 channel */
 struct cs_channel 
 {
@@ -199,7 +208,7 @@
 };
 
 #define CS46XX_MAJOR_VERSION "1"
-#define CS46XX_MINOR_VERSION "27"
+#define CS46XX_MINOR_VERSION "28"
 
 #ifdef __ia64__
 #define CS46XX_ARCH	     	"64"	//architecture key
@@ -284,6 +293,8 @@
 		int ossmaxfrags;
 		unsigned subdivision;
 	} dmabuf;
+	/* Guard against mmap/write/read races */
+	struct semaphore sem;
 };
 
 struct cs_card {
@@ -370,8 +381,10 @@
 static loff_t cs_llseek(struct file *file, loff_t offset, int origin);
 static int cs_hardware_init(struct cs_card *card);
 static int cs46xx_powerup(struct cs_card *card, unsigned int type);
-static int cs461x_powerdown(struct cs_card *card, unsigned int type);
+static int cs461x_powerdown(struct cs_card *card, unsigned int type, int suspendflag);
 static void cs461x_clear_serial_FIFOs(struct cs_card *card, int type);
+static void cs46xx_suspend_tbl(struct pci_dev *pcidev);
+static void cs46xx_resume_tbl(struct pci_dev *pcidev);
 
 static inline unsigned ld2(unsigned int x)
 {
@@ -688,7 +701,7 @@
 {
 	struct ac97_codec *dev=card->ac97_codec[0];
 
-	CS_DBGOUT(CS_FUNCTION, 2, printk("cs46xx: cs_mute()+ %s\n",
+	CS_DBGOUT(CS_FUNCTION, 2, printk(KERN_INFO "cs46xx: cs_mute()+ %s\n",
 		(state == CS_TRUE) ? "Muting" : "UnMuting") );
 
 	if(state == CS_TRUE)
@@ -717,7 +730,7 @@
 		cs_ac97_set(dev, (u8)BA0_AC97_MASTER_VOLUME_MONO, card->pm.u32AC97_master_volume_mono);
 		cs_ac97_set(dev, (u8)BA0_AC97_PCM_OUT_VOLUME, card->pm.u32AC97_pcm_out_volume);
 	}
-	CS_DBGOUT(CS_FUNCTION, 2, printk("cs46xx: cs_mute()-\n"));
+	CS_DBGOUT(CS_FUNCTION, 2, printk(KERN_INFO "cs46xx: cs_mute()-\n"));
 }
 
 /* set playback sample rate */
@@ -1250,7 +1263,7 @@
 	dmabuf->SGok = 0;
 }
 
-static int prog_dmabuf(struct cs_state *state)
+static int __prog_dmabuf(struct cs_state *state)
 {
         struct dmabuf *dmabuf = &state->dmabuf;
         unsigned long flags;
@@ -1431,6 +1444,17 @@
 	return 1;
 }
 
+static int prog_dmabuf(struct cs_state *state)
+{
+	int ret;
+	
+	down(&state->sem);
+	ret = __prog_dmabuf(state);
+	up(&state->sem);
+	
+	return ret;
+}
+
 static void cs_clear_tail(struct cs_state *state)
 {
 }
@@ -2089,11 +2113,12 @@
 		return -ESPIPE;
 	if (dmabuf->mapped)
 		return -ENXIO;
-	if (!dmabuf->ready && (ret = prog_dmabuf(state)))
-		return ret;
 	if (!access_ok(VERIFY_WRITE, buffer, count))
 		return -EFAULT;
-	ret = 0;
+	
+	down(&state->sem);
+	if (!dmabuf->ready && (ret = __prog_dmabuf(state)))
+		goto out;
 
 	add_wait_queue(&state->dmabuf.wait, &wait);
 	while (count > 0) {
@@ -2101,8 +2126,8 @@
 		{
 			schedule();
 			if (signal_pending(current)) {
-				ret = ret ? ret : -ERESTARTSYS;
-				break;
+				if(!ret) ret = -ERESTARTSYS;
+				goto out;
 			}
 		}
 		spin_lock_irqsave(&state->card->lock, flags);
@@ -2122,12 +2147,20 @@
 			start_adc(state);
 			if (file->f_flags & O_NONBLOCK) {
 				if (!ret) ret = -EAGAIN;
-				break;
+				goto out;
  			}
+			up(&state->sem);
 			schedule();
 			if (signal_pending(current)) {
-				ret = ret ? ret : -ERESTARTSYS;
-				break;
+				if(!ret) ret = -ERESTARTSYS;
+				goto out;
+			}
+			down(&state->sem);
+			if (dmabuf->mapped) 
+			{
+				if(!ret)
+					ret = -ENXIO;
+				goto out;
 			}
  			continue;
 		}
@@ -2142,7 +2175,7 @@
 			(void *)((unsigned)dmabuf->rawbuf + swptr), cnt, &copied))
 		{
 			if (!ret) ret = -EFAULT;
-			break;
+			goto out;
 		}
                 swptr = (swptr + cnt) % dmabuf->dmasize;
                 spin_lock_irqsave(&card->lock, flags);
@@ -2154,6 +2187,8 @@
                 ret += copied;
                 start_adc(state);
 	}
+out:
+	up(&state->sem);
 	remove_wait_queue(&state->dmabuf.wait, &wait);
 	set_current_state(TASK_RUNNING);
 	CS_DBGOUT(CS_WAVE_READ | CS_FUNCTION, 4, 
@@ -2183,12 +2218,21 @@
 
 	if (ppos != &file->f_pos)
 		return -ESPIPE;
+
+	down(&state->sem);
 	if (dmabuf->mapped)
-		return -ENXIO;
-	if (!dmabuf->ready && (ret = prog_dmabuf(state)))
-		return ret;
+	{
+		ret = -ENXIO;
+		goto out;
+	}
+
+	if (!dmabuf->ready && (ret = __prog_dmabuf(state)))
+		goto out;
 	if (!access_ok(VERIFY_READ, buffer, count))
-		return -EFAULT;
+	{
+	ret = -EFAULT;
+	goto out;
+	}
 	add_wait_queue(&state->dmabuf.wait, &wait);
 	ret = 0;
 /*
@@ -2200,8 +2244,8 @@
 		{
 			schedule();
 			if (signal_pending(current)) {
-				ret = ret ? ret : -ERESTARTSYS;
-				break;
+				if(!ret) ret = -ERESTARTSYS;
+				goto out;
 			}
 		}
 		spin_lock_irqsave(&state->card->lock, flags);
@@ -2234,18 +2278,26 @@
 			start_dac(state);
 			if (file->f_flags & O_NONBLOCK) {
 				if (!ret) ret = -EAGAIN;
-				break;
+				goto out;
  			}
+			up(&state->sem);
 			schedule();
  			if (signal_pending(current)) {
-				ret = ret ? ret : -ERESTARTSYS;
-				break;
+				if(!ret) ret = -ERESTARTSYS;
+				goto out;
  			}
+			down(&state->sem);
+			if (dmabuf->mapped)
+			{
+				if(!ret)
+					ret = -ENXIO;
+				goto out;
+			}
  			continue;
  		}
 		if (copy_from_user(dmabuf->rawbuf + swptr, buffer, cnt)) {
 			if (!ret) ret = -EFAULT;
-			return ret;
+			goto out;
 		}
 		spin_lock_irqsave(&state->card->lock, flags);
 		swptr = (swptr + cnt) % dmabuf->dmasize;
@@ -2265,6 +2317,8 @@
 		ret += cnt;
 		start_dac(state);
 	}
+out:
+	up(&state->sem);
 	remove_wait_queue(&state->dmabuf.wait, &wait);
 	set_current_state(TASK_RUNNING);
 
@@ -2352,9 +2406,9 @@
 	struct cs_card *card = (struct cs_card *)file->private_data;
 	struct cs_state *state;
 	struct dmabuf *dmabuf;
-	int ret;
+	int ret = 0;
 	unsigned long size;
-	
+
 	CS_DBGOUT(CS_FUNCTION | CS_PARMS, 2, printk("cs46xx: cs_mmap()+ file=0x%x %s %s\n", 
 		(unsigned)file, vma->vm_flags & VM_WRITE ? "VM_WRITE" : "",
 		vma->vm_flags & VM_READ ? "VM_READ" : "") );
@@ -2393,24 +2447,39 @@
  */
 	state = card->states[1];  
 	if(!(unsigned)state)
-		return -EINVAL;
+	{
+		ret = -EINVAL;
+		goto out;
+	}
 
+	down(&state->sem);	
 	dmabuf = &state->dmabuf;
 	if (cs4x_pgoff(vma) != 0)
-		return -EINVAL;
+	{
+		ret = -EINVAL;
+		goto out;
+	}
 	size = vma->vm_end - vma->vm_start;
 
 	CS_DBGOUT(CS_PARMS, 2, printk("cs46xx: cs_mmap(): size=%d\n",(unsigned)size) );
 
 	if (size > (PAGE_SIZE << dmabuf->buforder))
-		return -EINVAL;
+	{
+		ret = -EINVAL;
+		goto out;
+	}
 	if (remap_page_range(vma->vm_start, virt_to_phys(dmabuf->rawbuf),
 			     size, vma->vm_page_prot))
-		return -EAGAIN;
+	{
+		ret = -EAGAIN;
+		goto out;
+	}
 	dmabuf->mapped = 1;
 
 	CS_DBGOUT(CS_FUNCTION, 2, printk("cs46xx: cs_mmap()-\n") );
-	return 0;
+out:
+	up(&state->sem);
+	return ret;	
 }
 
 static int cs_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
@@ -3146,6 +3215,7 @@
 			if (state == NULL)
 				return -ENOMEM;
 			memset(state, 0, sizeof(struct cs_state));
+			init_MUTEX(&state->sem);
 			dmabuf = &state->dmabuf;
 			dmabuf->pbuf = (void *)get_free_page(GFP_KERNEL | GFP_DMA);
 			if(dmabuf->pbuf==NULL)
@@ -3217,6 +3287,7 @@
 			if (state == NULL)
 				return -ENOMEM;
 			memset(state, 0, sizeof(struct cs_state));
+			init_MUTEX(&state->sem);
 			dmabuf = &state->dmabuf;
 			dmabuf->pbuf = (void *)get_free_page(GFP_KERNEL | GFP_DMA);
 			if(dmabuf->pbuf==NULL)
@@ -3281,7 +3352,6 @@
 		if((ret = prog_dmabuf(state)))
 			return ret;
 	}
-
 	CS_DBGOUT(CS_OPEN | CS_FUNCTION, 2, printk("cs46xx: cs_open()- 0\n") );
 	return 0;
 }
@@ -3321,11 +3391,10 @@
 			state->card->states[state->virt] = NULL;
 			state->open_mode &= (~file->f_mode) & (FMODE_READ|FMODE_WRITE);
 
-			if( (tmp = cs461x_powerdown(card, CS_POWER_DAC )) )
+			if( (tmp = cs461x_powerdown(card, CS_POWER_DAC, CS_FALSE )) )
 			{
 				CS_DBGOUT(CS_ERROR, 1, printk(KERN_INFO 
 					"cs46xx: cs_release_mixdev() powerdown DAC failure (0x%x)\n",tmp) );
-				return -EIO;
 			}
 
 			/* Now turn off external AMP if needed */
@@ -3355,11 +3424,10 @@
 			state->card->states[state->virt] = NULL;
 			state->open_mode &= (~file->f_mode) & (FMODE_READ|FMODE_WRITE);
 
-			if( (tmp = cs461x_powerdown(card, CS_POWER_ADC )) )
+			if( (tmp = cs461x_powerdown(card, CS_POWER_ADC, CS_FALSE )) )
 			{
 				CS_DBGOUT(CS_ERROR, 1, printk(KERN_INFO 
 					"cs46xx: cs_release_mixdev() powerdown ADC failure (0x%x)\n",tmp) );
-				return -EIO;
 			}
 
 			/* Now turn off external AMP if needed */
@@ -3419,8 +3487,8 @@
 void cs46xx_ac97_suspend(struct cs_card *card)
 {
 	int Count,i;
-	unsigned int tmp;
 	struct ac97_codec *dev=card->ac97_codec[0];
+	unsigned int tmp;
 
 	CS_DBGOUT(CS_PM, 9, printk("cs46xx: cs46xx_ac97_suspend()+\n"));
 
@@ -3445,7 +3513,6 @@
 * Save the ac97 volume registers as well as the current powerdown state.
 * Now, mute the all the outputs (master, headphone, and mono), as well
 * as the PCM volume, in preparation for powering down the entire part.
-*/ 
 	card->pm.u32AC97_master_volume = (u32)cs_ac97_get( dev, 
 			(u8)BA0_AC97_MASTER_VOLUME); 
 	card->pm.u32AC97_headphone_volume = (u32)cs_ac97_get(dev, 
@@ -3454,22 +3521,27 @@
 			(u8)BA0_AC97_MASTER_VOLUME_MONO); 
 	card->pm.u32AC97_pcm_out_volume = (u32)cs_ac97_get(dev, 
 			(u8)BA0_AC97_PCM_OUT_VOLUME);
-		
+*/ 
+/*
+* mute the outputs
+*/
 	cs_ac97_set(dev, (u8)BA0_AC97_MASTER_VOLUME, 0x8000);
 	cs_ac97_set(dev, (u8)BA0_AC97_HEADPHONE_VOLUME, 0x8000);
 	cs_ac97_set(dev, (u8)BA0_AC97_MASTER_VOLUME_MONO, 0x8000);
 	cs_ac97_set(dev, (u8)BA0_AC97_PCM_OUT_VOLUME, 0x8000);
 
+/*
+* save the registers that cause pops
+*/
 	card->pm.u32AC97_powerdown = (u32)cs_ac97_get(dev, (u8)AC97_POWER_CONTROL); 
 	card->pm.u32AC97_general_purpose = (u32)cs_ac97_get(dev, (u8)BA0_AC97_GENERAL_PURPOSE); 
-
 /*
 * And power down everything on the AC97 codec.
 * well, for now, only power down the DAC/ADC and MIXER VREFON components. 
 * trouble with removing VREF.
 */
 	if( (tmp = cs461x_powerdown(card, CS_POWER_DAC | CS_POWER_ADC |
-			CS_POWER_MIXVON )) )
+			CS_POWER_MIXVON, CS_TRUE )) )
 	{
 		CS_DBGOUT(CS_ERROR | CS_INIT, 1, printk(KERN_INFO 
 			"cs46xx: cs46xx_ac97_suspend() failure (0x%x)\n",tmp) );
@@ -3502,17 +3574,12 @@
 */
 	cs_ac97_set(dev, (u8)BA0_AC97_GENERAL_PURPOSE, 
 		(u16)card->pm.u32AC97_general_purpose);
-
-	cs_ac97_set(dev, (u8)AC97_POWER_CONTROL, 
-		(u16)card->pm.u32AC97_powerdown);
-	mdelay(10);
-
 /*
 * Now, while the outputs are still muted, restore the state of power
 * on the AC97 part.
 */
 	cs_ac97_set(dev, (u8)BA0_AC97_POWERDOWN, (u16)card->pm.u32AC97_powerdown);
-	mdelay(5);
+	mdelay(5 * cs_laptop_wait);
 /*
 * Restore just the first set of registers, from register number
 * 0x02 to the register number that ulHighestRegToRestore specifies.
@@ -3544,7 +3611,7 @@
 		dmabuf->ready = 0;
 		resync_dma_ptrs(card->states[1]);
 		cs_set_divisor(dmabuf);
-		if(prog_dmabuf(card->states[1]))
+		if(__prog_dmabuf(card->states[1]))
 		{
 			CS_DBGOUT(CS_PM | CS_ERROR, 1, 
 				printk("cs46xx: cs46xx_restart_part()- (-1) prog_dmabuf() dac error\n"));
@@ -3558,7 +3625,7 @@
 		dmabuf->ready = 0;
 		resync_dma_ptrs(card->states[0]);
 		cs_set_divisor(dmabuf);
-		if(prog_dmabuf(card->states[0]))
+		if(__prog_dmabuf(card->states[0]))
 		{
 			CS_DBGOUT(CS_PM | CS_ERROR, 1, 
 				printk("cs46xx: cs46xx_restart_part()- (-1) prog_dmabuf() adc error\n"));
@@ -3704,7 +3771,7 @@
 		{
 			CS_DBGOUT(CS_PM | CS_ERROR, 4, printk(
 				"cs46xx: cs46xx_resume()- ERROR in cs_hardware_init()\n"));
-			mdelay(10);
+			mdelay(10 * cs_laptop_wait);
 			cs461x_reset(card);
 			continue;
 		}
@@ -3789,12 +3856,13 @@
 	if(!(card->pm.flags & CS46XX_PM_IDLE))
 		loopcnt = 2000;
 	else
-		loopcnt = 500;
+		loopcnt = 500 * cs_laptop_wait;
+ 	loopcnt *= cs_laptop_wait;
 	for (count = 0; count < loopcnt; count++) {
 		/*
 		 *  First, we want to wait for a short time.
 	 	 */
-		udelay(10);
+		udelay(10 * cs_laptop_wait);
 		/*
 		 *  Now, check to see if the read has completed.
 		 *  ACCTL = 460h, DCV should be reset by now and 460h = 17h
@@ -3819,7 +3887,8 @@
 	if(!(card->pm.flags & CS46XX_PM_IDLE))
 		loopcnt = 2000;
 	else
-		loopcnt = 100;
+		loopcnt = 1000;
+ 	loopcnt *= cs_laptop_wait;
 	for (count = 0; count < loopcnt; count++) {
 		/*
 		 *  Read the AC97 status register.
@@ -3828,16 +3897,16 @@
 		 */
 		if (cs461x_peekBA0(card, BA0_ACSTS) & ACSTS_VSTS)
 			break;
-		udelay(10);
+		udelay(10 * cs_laptop_wait);
 	}
 	
 	/*
 	 *  Make sure we got valid status.
 	 */
 	if (!( (tmp=cs461x_peekBA0(card, BA0_ACSTS)) & ACSTS_VSTS)) {
-		CS_DBGOUT(CS_ERROR, 1, printk(KERN_WARNING 
-			"cs46xx: AC'97 read problem (ACSTS_VSTS), reg = 0x%x val=0x%x \n", reg, tmp));
-		CS_DBGOUT(CS_ERROR, 9, printk(KERN_WARNING "returning 0xffff\n"));
+		CS_DBGOUT(CS_ERROR, 2, printk(KERN_WARNING 
+			"cs46xx: AC'97 read problem (ACSTS_VSTS), reg = 0x%x val=0x%x 0xffff \n", 
+				reg, tmp));
 		return 0xffff;
 	}
 
@@ -3849,7 +3918,7 @@
 		"cs46xx: cs_ac97_get() reg = 0x%x, val = 0x%x, BA0_ACCAD = 0x%x\n", 
 			reg, cs461x_peekBA0(card, BA0_ACSDA),
 			cs461x_peekBA0(card, BA0_ACCAD)));
-	return (cs461x_peekBA0(card, BA0_ACSDA));
+	return(cs461x_peekBA0(card, BA0_ACSDA));
 }
 
 static void cs_ac97_set(struct ac97_codec *dev, u8 reg, u16 val)
@@ -3893,7 +3962,7 @@
 		/*
 		 *  First, we want to wait for a short time.
 		 */
-		udelay(10);
+		udelay(10 * cs_laptop_wait);
 		/*
 		 *  Now, check to see if the write has completed.
 		 *  ACCTL = 460h, DCV should be reset by now and 460h = 07h
@@ -4032,24 +4101,28 @@
 		return -ENODEV;
 	}
 match:
-	card->active_ctrl(card, -1);
-	card->amplifier_ctrl(card, -1);
 	MOD_DEC_USE_COUNT;
 	if(!CS_DEC_AND_TEST(&card->mixer_use_cnt))
 	{
 		CS_DBGOUT(CS_FUNCTION | CS_RELEASE, 4,
 			  printk(KERN_INFO "cs46xx: cs_release_mixdev()- no powerdown, usecnt>0\n"));
+		card->active_ctrl(card, -1);
+		card->amplifier_ctrl(card, -1);
 		return 0;
 	}
 /*
 * ok, no outstanding mixer opens, so powerdown.
 */
-	if( (tmp = cs461x_powerdown(card, CS_POWER_MIXVON )) )
+	if( (tmp = cs461x_powerdown(card, CS_POWER_MIXVON, CS_FALSE )) )
 	{
 		CS_DBGOUT(CS_ERROR | CS_INIT, 1, printk(KERN_INFO 
 			"cs46xx: cs_release_mixdev() powerdown MIXVON failure (0x%x)\n",tmp) );
+		card->active_ctrl(card, -1);
+		card->amplifier_ctrl(card, -1);
 		return -EIO;
 	}
+	card->active_ctrl(card, -1);
+	card->amplifier_ctrl(card, -1);
 	CS_DBGOUT(CS_FUNCTION | CS_RELEASE, 4,
 		  printk(KERN_INFO "cs46xx: cs_release_mixdev()- 0\n"));
 	return 0;
@@ -4341,14 +4414,14 @@
 }
 
 
-static int cs461x_powerdown(struct cs_card *card, unsigned int type)
+static int cs461x_powerdown(struct cs_card *card, unsigned int type, int suspendflag)
 {
 	int count;
-	unsigned int tmp=0;
+	unsigned int tmp=0,muted=0;
 
 	CS_DBGOUT(CS_FUNCTION, 4, printk(KERN_INFO 
 		"cs46xx: cs461x_powerdown()+ type=0x%x\n",type));
-	if(!powerdown)
+	if(!cs_powerdown && !suspendflag)
 	{
 		CS_DBGOUT(CS_FUNCTION, 8, printk(KERN_INFO 
 			"cs46xx: cs461x_powerdown() DISABLED exiting\n"));
@@ -4380,8 +4453,6 @@
 	type &= ~CS_POWER_MIXVON;
 	type &= ~CS_POWER_MIXVOFF;
 
-	cs_mute(card, CS_TRUE);
-
 	/*
 	 *  Power down indicated areas.
 	 */
@@ -4396,6 +4467,11 @@
 		tmp = cs_ac97_get(card->ac97_codec[0], AC97_POWER_CONTROL);
 		if (tmp & CS_AC97_POWER_CONTROL_MIXVOFF_ON)
 		{
+			if(!muted)
+			{
+				cs_mute(card, CS_TRUE);
+				muted=1;
+			}
 			tmp |= CS_AC97_POWER_CONTROL_MIXVOFF;
 			cs_ac97_set(card->ac97_codec[0], AC97_POWER_CONTROL, tmp );
 			/*
@@ -4439,6 +4515,11 @@
 		tmp = cs_ac97_get(card->ac97_codec[0], AC97_POWER_CONTROL);
 		if (tmp & CS_AC97_POWER_CONTROL_MIXVON_ON)
 		{
+			if(!muted)
+			{
+				cs_mute(card, CS_TRUE);
+				muted=1;
+			}
 			tmp |= CS_AC97_POWER_CONTROL_MIXVON;
 			cs_ac97_set(card->ac97_codec[0], AC97_POWER_CONTROL, tmp );
 			/*
@@ -4480,6 +4561,11 @@
 		tmp = cs_ac97_get(card->ac97_codec[0], AC97_POWER_CONTROL);
 		if (tmp & CS_AC97_POWER_CONTROL_ADC_ON)
 		{
+			if(!muted)
+			{
+				cs_mute(card, CS_TRUE);
+				muted=1;
+			}
 			tmp |= CS_AC97_POWER_CONTROL_ADC;
 			cs_ac97_set(card->ac97_codec[0], AC97_POWER_CONTROL, tmp );
 
@@ -4524,6 +4610,11 @@
 		tmp = cs_ac97_get(card->ac97_codec[0], AC97_POWER_CONTROL);
 		if (tmp & CS_AC97_POWER_CONTROL_DAC_ON)
 		{
+			if(!muted)
+			{
+				cs_mute(card, CS_TRUE);
+				muted=1;
+			}
 			tmp |= CS_AC97_POWER_CONTROL_DAC;
 			cs_ac97_set(card->ac97_codec[0], AC97_POWER_CONTROL, tmp );
 			/*
@@ -4557,7 +4648,8 @@
 		}
 	}
 	tmp = cs_ac97_get(card->ac97_codec[0], AC97_POWER_CONTROL);
-	cs_mute(card, CS_FALSE);
+	if(muted)
+		cs_mute(card, CS_FALSE);
 	CS_DBGOUT(CS_FUNCTION, 4, printk(KERN_INFO 
 		"cs46xx: cs461x_powerdown()- 0 tmp=0x%x\n",tmp));
 	return 0;
@@ -4566,7 +4658,7 @@
 static int cs46xx_powerup(struct cs_card *card, unsigned int type)
 {
 	int count;
-	unsigned int tmp=0;
+	unsigned int tmp=0,muted=0;
 
 	CS_DBGOUT(CS_FUNCTION, 8, printk(KERN_INFO 
 		"cs46xx: cs46xx_powerup()+ type=0x%x\n",type));
@@ -4578,7 +4670,6 @@
 	if(type & (CS_POWER_DAC | CS_POWER_ADC))
 		type |= CS_POWER_MIXVON | CS_POWER_MIXVOFF;
 
-	cs_mute(card, CS_TRUE);
 	/*
 	 *  Power up indicated areas.
 	 */
@@ -4593,6 +4684,11 @@
 		tmp = cs_ac97_get(card->ac97_codec[0], AC97_POWER_CONTROL);
 		if (!(tmp & CS_AC97_POWER_CONTROL_MIXVOFF_ON))
 		{
+			if(!muted)
+			{
+				cs_mute(card, CS_TRUE);
+				muted=1;
+			}
 			tmp &= ~CS_AC97_POWER_CONTROL_MIXVOFF;
 			cs_ac97_set(card->ac97_codec[0], AC97_POWER_CONTROL, tmp );
 			/*
@@ -4636,6 +4732,11 @@
 		tmp = cs_ac97_get(card->ac97_codec[0], AC97_POWER_CONTROL);
 		if (!(tmp & CS_AC97_POWER_CONTROL_MIXVON_ON))
 		{
+			if(!muted)
+			{
+				cs_mute(card, CS_TRUE);
+				muted=1;
+			}
 			tmp &= ~CS_AC97_POWER_CONTROL_MIXVON;
 			cs_ac97_set(card->ac97_codec[0], AC97_POWER_CONTROL, tmp );
 			/*
@@ -4677,6 +4778,11 @@
 		tmp = cs_ac97_get(card->ac97_codec[0], AC97_POWER_CONTROL);
 		if (!(tmp & CS_AC97_POWER_CONTROL_ADC_ON))
 		{
+			if(!muted)
+			{
+				cs_mute(card, CS_TRUE);
+				muted=1;
+			}
 			tmp &= ~CS_AC97_POWER_CONTROL_ADC;
 			cs_ac97_set(card->ac97_codec[0], AC97_POWER_CONTROL, tmp );
 
@@ -4721,6 +4827,11 @@
 		tmp = cs_ac97_get(card->ac97_codec[0], AC97_POWER_CONTROL);
 		if (!(tmp & CS_AC97_POWER_CONTROL_DAC_ON))
 		{
+			if(!muted)
+			{
+				cs_mute(card, CS_TRUE);
+				muted=1;
+			}
 			tmp &= ~CS_AC97_POWER_CONTROL_DAC;
 			cs_ac97_set(card->ac97_codec[0], AC97_POWER_CONTROL, tmp );
 			/*
@@ -4754,7 +4865,8 @@
 		}
 	}
 	tmp = cs_ac97_get(card->ac97_codec[0], AC97_POWER_CONTROL);
-	cs_mute(card, CS_FALSE);
+	if(muted)
+		cs_mute(card, CS_FALSE);
 	CS_DBGOUT(CS_FUNCTION, 4, printk(KERN_INFO 
 		"cs46xx: cs46xx_powerup()- 0 tmp=0x%x\n",tmp));
 	return 0;
@@ -4843,7 +4955,7 @@
 	 *  generating bit clock (so we don't try to start the PLL without an
 	 *  input clock).
 	 */
-	mdelay(5);		/* 1 should be enough ?? (and pigs might fly) */
+	mdelay(5 * cs_laptop_wait);		/* 1 should be enough ?? (and pigs might fly) */
 
 	/*
 	 *  Set the serial port timing configuration, so that
@@ -4876,7 +4988,7 @@
 	/*
          *  Wait until the PLL has stabilized.
 	 */
-	mdelay(5);		/* Again 1 should be enough ?? */
+	mdelay(5 * cs_laptop_wait);		/* Again 1 should be enough ?? */
 
 	/*
 	 *  Turn on clocking of the core so that we can setup the serial ports.
@@ -4903,7 +5015,7 @@
 	cs461x_pokeBA0(card, BA0_SERMC1, SERMC1_PTC_AC97 | SERMC1_MSPE);
 
 
-	mdelay(5);		/* Shouldnt be needed ?? */
+	mdelay(5 * cs_laptop_wait);		/* Shouldnt be needed ?? */
 	
 /*
 * If we are resuming under 2.2.x then we can not schedule a timeout.
@@ -4930,7 +5042,7 @@
 	{
 		for (count = 0; count < 100; count++) {
 		// First, we want to wait for a short time.
-			udelay(25);
+			udelay(25 * cs_laptop_wait);
 
 			if (cs461x_peekBA0(card, BA0_ACSTS) & ACSTS_CRDY)
 				break;
@@ -4978,7 +5090,7 @@
 	{
 		for (count = 0; count < 100; count++) {
 		// First, we want to wait for a short time.
-			udelay(25);
+			udelay(25 * cs_laptop_wait);
 
 			if ((cs461x_peekBA0(card, BA0_ACISV) & (ACISV_ISV3 | ACISV_ISV4)) == (ACISV_ISV3 | ACISV_ISV4))
 				break;
@@ -5068,7 +5180,7 @@
 	 */
 	if(card->pm.flags & CS46XX_PM_IDLE)
 	{
-		if(!powerdown)
+		if(!cs_powerdown)
 		{
 			if( (tmp = cs46xx_powerup(card, CS_POWER_DAC | CS_POWER_ADC |
 					CS_POWER_MIXVON )) )
@@ -5081,7 +5193,7 @@
 		else
 		{
 			if( (tmp = cs461x_powerdown(card, CS_POWER_DAC | CS_POWER_ADC |
-					CS_POWER_MIXVON )) )
+					CS_POWER_MIXVON, CS_FALSE )) )
 			{
 				CS_DBGOUT(CS_ERROR | CS_INIT, 1, printk(KERN_INFO 
 					"cs46xx: cs461x_powerdown() failure (0x%x)\n",tmp) );
@@ -5148,6 +5260,7 @@
 	CS_DBGOUT(CS_FUNCTION | CS_INIT, 2,
 		  printk(KERN_INFO "cs46xx: probe()+\n"));
 
+	dma_mask = 0xffffffff;	/* this enables playback and recording */
 	if (pci_enable_device(pci_dev)) {
 		CS_DBGOUT(CS_INIT | CS_ERROR, 1, printk(KERN_ERR
 			 "cs46xx: pci_enable_device() failed\n"));
@@ -5169,8 +5282,6 @@
 		      "cs46xx: probe() architecture does not support 32bit PCI busmaster DMA\n"));
 		return -1;
 	}
-	dma_mask = 0xffffffff;	/* this enables playback and recording */
-
 	pci_read_config_word(pci_dev, PCI_SUBSYSTEM_VENDOR_ID, &ss_vendor);
 	pci_read_config_word(pci_dev, PCI_SUBSYSTEM_ID, &ss_card);
 
@@ -5239,7 +5350,31 @@
 		printk(KERN_INFO "cs46xx: Activating CLKRUN hack for Thinkpad.\n");
 		card->active_ctrl = clkrun_hack;
 	}
-	
+/*
+* The thinkpads don't work well without runtime updating on their kernel 
+* delay values (or any laptop with variable CPU speeds really).
+* so, just to be safe set the init delay to 2100.  Eliminates
+* failures on T21 Thinkpads.  remove this code when the udelay
+* and mdelay kernel code is replaced by a pm timer, or the delays
+* work well for battery and/or AC power both.
+*/
+	if(card->active_ctrl == clkrun_hack)
+	{
+		initdelay = 2100;
+		cs_laptop_wait = 5;
+	}
+	if((card->active_ctrl == clkrun_hack) && !(powerdown == 1))
+	{
+/*
+* for some currently unknown reason, powering down the DAC and ADC component
+* blocks on thinkpads causes some funky behavior... distoorrrtion and ac97 
+* codec access problems.  probably the serial clock becomes unsynced. 
+* added code to sync the chips back up, but only helped about 70% the time.
+*/
+		cs_powerdown = 0;
+	}
+	if(powerdown == 0)
+		cs_powerdown = 0;
 	card->active_ctrl(card, 1);
 
 	/* claim our iospace and irq */
@@ -5290,7 +5425,7 @@
 					unregister_sound_mixer(card->ac97_codec[j]->dev_mixer);
 					kfree (card->ac97_codec[j]);
 				}
-			mdelay(10);
+			mdelay(10 * cs_laptop_wait);
 			continue;
 		}
 		break;
@@ -5413,7 +5548,7 @@
 	 *  them.
 	 */
 	if( (tmp = cs461x_powerdown(card, CS_POWER_DAC | CS_POWER_ADC |
-			CS_POWER_MIXVON )) )
+			CS_POWER_MIXVON, CS_TRUE )) )
 	{
 		CS_DBGOUT(CS_ERROR | CS_INIT, 1, printk(KERN_INFO 
 			"cs46xx: cs461x_powerdown() failure (0x%x)\n",tmp) );
@@ -5553,21 +5688,22 @@
 	return 0;
 }
 
-static void cs46xx_suspend_tbl(struct pci_dev *pcidev)
+#if CS46XX_ACPI_SUPPORT
+static int cs46xx_suspend_tbl(struct pci_dev *pcidev, u32 state)
 {
 	struct cs_card *s = PCI_GET_DRIVER_DATA(pcidev);
 	CS_DBGOUT(CS_PM | CS_FUNCTION, 2, 
 		printk(KERN_INFO "cs46xx: cs46xx_suspend_tbl request\n"));
 	cs46xx_suspend(s);
-	return;
+	return 0;
 }
 
-static void cs46xx_resume_tbl(struct pci_dev *pcidev)
+static int cs46xx_resume_tbl(struct pci_dev *pcidev)
 {
 	struct cs_card *s = PCI_GET_DRIVER_DATA(pcidev);
 	CS_DBGOUT(CS_PM | CS_FUNCTION, 2, 
 		printk(KERN_INFO "cs46xx: cs46xx_resume_tbl request\n"));
 	cs46xx_resume(s);
-	return;
+	return 0;
 }
-
+#endif
diff -urN linux-2.4.6-pre5/drivers/sound/cs46xxpm-24.h linux/drivers/sound/cs46xxpm-24.h
--- linux-2.4.6-pre5/drivers/sound/cs46xxpm-24.h	Wed Apr 11 19:02:38 2001
+++ linux/drivers/sound/cs46xxpm-24.h	Mon Dec  3 22:49:12 2001
@@ -36,8 +36,8 @@
 * for now (12/22/00) only enable the pm_register PM support.
 * allow these table entries to be null.
 */
-static void cs46xx_suspend_tbl(struct pci_dev *pcidev);
-static void cs46xx_resume_tbl(struct pci_dev *pcidev);
+static int cs46xx_suspend_tbl(struct pci_dev *pcidev, u32 state);
+static int cs46xx_resume_tbl(struct pci_dev *pcidev);
 #define cs_pm_register(a, b, c)  0
 #define cs_pm_unregister_all(a) 
 #define CS46XX_SUSPEND_TBL cs46xx_suspend_tbl
diff -urN linux-2.4.6-pre5/drivers/sound/maestro3.c linux/drivers/sound/maestro3.c
--- linux-2.4.6-pre5/drivers/sound/maestro3.c	Sat Apr 21 10:36:30 2001
+++ linux/drivers/sound/maestro3.c	Mon Dec  3 22:49:12 2001
@@ -371,7 +371,7 @@
  * I'm not very good at laying out functions in a file :)
  */
 static int m3_notifier(struct notifier_block *nb, unsigned long event, void *buf);
-static void m3_suspend(struct pci_dev *pci_dev);
+static int m3_suspend(struct pci_dev *pci_dev, u32 state);
 static void check_suspend(struct m3_card *card);
 
 struct notifier_block m3_reboot_nb = {m3_notifier, NULL, 0};
@@ -2771,12 +2771,12 @@
 
     for(card = devs; card != NULL; card = card->next) {
         if(!card->in_suspend)
-            m3_suspend(card->pcidev); /* XXX legal? */
+            m3_suspend(card->pcidev, 3); /* XXX legal? */
     }
     return 0;
 }
 
-static void m3_suspend(struct pci_dev *pci_dev)
+static int m3_suspend(struct pci_dev *pci_dev, u32 state)
 {
     unsigned long flags;
     int i;
@@ -2823,9 +2823,11 @@
     card->in_suspend = 1;
 
     restore_flags(flags);
+
+    return 0;
 }
 
-static void m3_resume(struct pci_dev *pci_dev)
+static int m3_resume(struct pci_dev *pci_dev)
 {
     unsigned long flags;
     int index;
@@ -2904,6 +2906,8 @@
      * when we suspended
      */
     wake_up(&card->suspend_queue);
+
+    return 0;
 }
 
 MODULE_AUTHOR("Zach Brown <zab@zabbo.net>");
diff -urN linux-2.4.6-pre5/drivers/sound/sb_card.c linux/drivers/sound/sb_card.c
--- linux-2.4.6-pre5/drivers/sound/sb_card.c	Tue May 22 10:23:16 2001
+++ linux/drivers/sound/sb_card.c	Mon Dec  3 22:49:12 2001
@@ -298,6 +298,11 @@
 		ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0031),
 		0,0,0,0,
 		0,1,1,-1},
+	{"Sound Blaster 16", 
+		ISAPNP_VENDOR('C','T','L'), ISAPNP_DEVICE(0x00ed), 
+		ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0041),
+		0,0,0,0,
+		0,1,1,-1},
 	{"Sound Blaster Vibra16S", 
 		ISAPNP_VENDOR('C','T','L'), ISAPNP_DEVICE(0x0051), 
 		ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0001),
@@ -518,6 +523,9 @@
 
 	{	ISAPNP_VENDOR('C','T','L'), ISAPNP_DEVICE(0x002b), 
 		ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0031), 0 },
+
+	{	ISAPNP_VENDOR('C','T','L'), ISAPNP_DEVICE(0x00ed), 
+		ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0041), 0 },
 
 	{	ISAPNP_VENDOR('C','T','L'), ISAPNP_DEVICE(0x0051), 
 		ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0001), 0 },
diff -urN linux-2.4.6-pre5/drivers/sound/wavfront.c linux/drivers/sound/wavfront.c
--- linux-2.4.6-pre5/drivers/sound/wavfront.c	Thu May 24 15:14:08 2001
+++ linux/drivers/sound/wavfront.c	Mon Dec  3 22:49:12 2001
@@ -2045,19 +2045,17 @@
 
 	switch (cmd) {
 	case SNDCTL_SYNTH_INFO:
-		memcpy (&((char *) arg)[0], &wavefront_info,
-			sizeof (wavefront_info));
+		if(copy_to_user(&((char *) arg)[0], &wavefront_info,
+			sizeof (wavefront_info)))
+			return -EFAULT;
 		return 0;
-		break;
 
 	case SNDCTL_SEQ_RESETSAMPLES:
-		printk (KERN_WARNING LOGNAME "driver cannot reset samples.\n");
+//		printk (KERN_WARNING LOGNAME "driver cannot reset samples.\n");
 		return 0; /* don't force an error */
-		break;
 
 	case SNDCTL_SEQ_PERCMODE:
 		return 0; /* don't force an error */
-		break;
 
 	case SNDCTL_SYNTH_MEMAVL:
 		if ((dev.freemem = wavefront_freemem ()) < 0) {
@@ -2069,10 +2067,11 @@
 		break;
 
 	case SNDCTL_SYNTH_CONTROL:
-		copy_from_user (&wc, arg, sizeof (wc));
-
-		if ((err = wavefront_synth_control (cmd, &wc)) == 0) {
-			copy_to_user (arg, &wc, sizeof (wc));
+		if(copy_from_user (&wc, arg, sizeof (wc)))
+			err = -EFAULT;
+		else if ((err = wavefront_synth_control (cmd, &wc)) == 0) {
+			if(copy_to_user (arg, &wc, sizeof (wc)))
+				err = -EFAULT;
 		}
 
 		return err;
diff -urN linux-2.4.6-pre5/drivers/sound/wf_midi.c linux/drivers/sound/wf_midi.c
--- linux-2.4.6-pre5/drivers/sound/wf_midi.c	Mon Dec  3 22:49:02 2001
+++ linux/drivers/sound/wf_midi.c	Mon Dec  3 22:49:12 2001
@@ -591,19 +591,17 @@
 	switch (cmd) {
 
 	case SNDCTL_SYNTH_INFO:
-		copy_to_user (&((char *) arg)[0],
+		if(copy_to_user (&((char *) arg)[0],
 			      &wf_mpu_synth_info[index],
-			      sizeof (struct synth_info));
-	
+			      sizeof (struct synth_info)))
+			return -EFAULT;
 		return 0;
-		break;
 	
 	case SNDCTL_SYNTH_MEMAVL:
 		return 0x7fffffff;
-		break;
 	
 	default:
-		return -(EINVAL);
+		return -EINVAL;
 	}
 }
 
diff -urN linux-2.4.6-pre5/drivers/telephony/ixj.c linux/drivers/telephony/ixj.c
--- linux-2.4.6-pre5/drivers/telephony/ixj.c	Mon Dec  3 22:49:02 2001
+++ linux/drivers/telephony/ixj.c	Mon Dec  3 22:49:12 2001
@@ -4480,9 +4480,15 @@
 	if (lcp == NULL)
 		return -ENOMEM;
 	if (copy_from_user(lcp, (char *) cp, sizeof(IXJ_FILTER_CADENCE)))
+	{
+		kfree(lcp);
 		return -EFAULT;
+	}
 	if (lcp->filter >= 4)
+	{
+		kfree(lcp);
 		return -1;
+	}
 	j->cadence_f[lcp->filter].state = 0;
 	j->cadence_f[lcp->filter].enable = lcp->enable;
 	j->filter_en[lcp->filter] = j->cadence_f[lcp->filter].en_filter = lcp->en_filter;
@@ -4647,13 +4653,18 @@
 	}
 }
 
-static int capabilities_check(IXJ *j, struct phone_capability *pcreq)
+static int capabilities_check(IXJ *j, struct phone_capability *u_pcreq)
 {
 	int cnt;
 	int retval = 0;
+	struct phone_capability pcreq;
+	
+	if(copy_from_user(&pcreq, u_pcreq, sizeof(struct phone_capability)))
+		return -EFAULT;
+		
 	for (cnt = 0; cnt < j->caps; cnt++) {
-		if (pcreq->captype == j->caplist[cnt].captype
-		    && pcreq->cap == j->caplist[cnt].cap) {
+		if (pcreq.captype == j->caplist[cnt].captype
+		    && pcreq.cap == j->caplist[cnt].cap) {
 			retval = 1;
 			break;
 		}
@@ -4704,7 +4715,8 @@
 			return -EFAULT;
 		break;
 	case PHONE_RING_CADENCE:
-		j->ring_cadence = arg;
+		if(get_user(j->ring_cadence, (int *)arg))
+			return -EFAULT;
 		break;
 	case IXJCTL_CIDCW:
 		if(arg) {
diff -urN linux-2.4.6-pre5/drivers/usb/Config.in linux/drivers/usb/Config.in
--- linux-2.4.6-pre5/drivers/usb/Config.in	Mon Dec  3 22:49:02 2001
+++ linux/drivers/usb/Config.in	Mon Dec  3 22:49:12 2001
@@ -59,6 +59,7 @@
    dep_tristate '  USB IBM (Xirlink) C-it Camera support' CONFIG_USB_IBMCAM $CONFIG_USB $CONFIG_VIDEO_DEV
    dep_tristate '  USB OV511 Camera support' CONFIG_USB_OV511 $CONFIG_USB $CONFIG_VIDEO_DEV
    dep_tristate '  USB Philips Cameras' CONFIG_USB_PWC $CONFIG_USB $CONFIG_VIDEO_DEV
+   dep_tristate '  USB SE401 Camera support' CONFIG_USB_SE401 $CONFIG_USB $CONFIG_VIDEO_DEV
    dep_tristate '  D-Link USB FM radio support (EXPERIMENTAL)' CONFIG_USB_DSBR $CONFIG_USB $CONFIG_VIDEO_DEV $CONFIG_EXPERIMENTAL
    dep_tristate '  DABUSB driver' CONFIG_USB_DABUSB $CONFIG_USB
 
diff -urN linux-2.4.6-pre5/drivers/usb/Makefile linux/drivers/usb/Makefile
--- linux-2.4.6-pre5/drivers/usb/Makefile	Mon Dec  3 22:49:02 2001
+++ linux/drivers/usb/Makefile	Mon Dec  3 22:49:12 2001
@@ -62,6 +62,7 @@
 obj-$(CONFIG_USB_DABUSB)	+= dabusb.o
 obj-$(CONFIG_USB_PLUSB)		+= plusb.o
 obj-$(CONFIG_USB_OV511)		+= ov511.o
+obj-$(CONFIG_USB_SE401)		+= se401.o
 obj-$(CONFIG_USB_PEGASUS)	+= pegasus.o
 obj-$(CONFIG_USB_CATC)		+= catc.o
 obj-$(CONFIG_USB_RIO500)	+= rio500.o
diff -urN linux-2.4.6-pre5/drivers/usb/pegasus.c linux/drivers/usb/pegasus.c
--- linux-2.4.6-pre5/drivers/usb/pegasus.c	Mon Dec  3 22:49:02 2001
+++ linux/drivers/usb/pegasus.c	Mon Dec  3 22:49:12 2001
@@ -53,8 +53,8 @@
 /*
  * Version Information
  */
-#define DRIVER_VERSION "v0.4.18 2001/03/18 (C) 1999-2000"
-#define DRIVER_AUTHOR "Petko Manolov <petkan@dce.bg>"
+#define DRIVER_VERSION "v0.4.19 2001/06/07 (C) 1999-2001"
+#define DRIVER_AUTHOR "Petko Manolov <pmanolov@lnxw.com>"
 #define DRIVER_DESC "ADMtek AN986 Pegasus USB Ethernet driver"
 
 #define	PEGASUS_USE_INTR
@@ -117,8 +117,7 @@
 			warn( __FUNCTION__ " status %d", urb->status);
 	}
 	pegasus->flags &= ~ETH_REGS_CHANGED;
-	if ( pegasus->flags & CTRL_URB_SLEEP ) {
-		pegasus->flags &= ~CTRL_URB_SLEEP;
+	if ( waitqueue_active(&pegasus->ctrl_wait) ) {
 		wake_up_interruptible( &pegasus->ctrl_wait );
 	}
 }
@@ -137,10 +136,9 @@
 	}
 	memcpy(buffer,data,size);
 	
-	while ( pegasus->flags & ETH_REGS_CHANGED ) {
-		pegasus->flags |= CTRL_URB_SLEEP;
+	while ( pegasus->flags & ETH_REGS_CHANGED )
 		interruptible_sleep_on( &pegasus->ctrl_wait );
-	}
+
 	pegasus->dr.requesttype = PEGASUS_REQT_READ;
 	pegasus->dr.request = PEGASUS_REQ_GET_REGS;
 	pegasus->dr.value = cpu_to_le16 (0);
@@ -155,7 +153,6 @@
 
 	add_wait_queue( &pegasus->ctrl_wait, &wait );
 	set_current_state( TASK_INTERRUPTIBLE );
-	pegasus->flags |= CTRL_URB_SLEEP;
 
 	if ( (ret = usb_submit_urb( &pegasus->ctrl_urb )) ) {
 		err( __FUNCTION__ " BAD CTRLs %d", ret);
@@ -163,11 +160,12 @@
 	}
 
 	schedule();
-	remove_wait_queue( &pegasus->ctrl_wait, &wait );
 out:
+	remove_wait_queue( &pegasus->ctrl_wait, &wait );
 	memcpy(data,buffer,size);
 	kfree(buffer);
-	return	ret;
+
+	return ret;
 }
 
 
@@ -184,10 +182,9 @@
 	}
 	memcpy(buffer, data, size);
 
-	while ( pegasus->flags & ETH_REGS_CHANGED ) {
-		pegasus->flags |= CTRL_URB_SLEEP ;
+	while ( pegasus->flags & ETH_REGS_CHANGED )
 		interruptible_sleep_on( &pegasus->ctrl_wait );
-	}
+
 	pegasus->dr.requesttype = PEGASUS_REQT_WRITE;
 	pegasus->dr.request = PEGASUS_REQ_SET_REGS;
 	pegasus->dr.value = cpu_to_le16 (0);
@@ -202,19 +199,18 @@
 			  
 	add_wait_queue( &pegasus->ctrl_wait, &wait );
 	set_current_state( TASK_INTERRUPTIBLE );
-	pegasus->flags |= CTRL_URB_SLEEP;
 
 	if ( (ret = usb_submit_urb( &pegasus->ctrl_urb )) ) {
 		err( __FUNCTION__ " BAD CTRL %d", ret);
-		kfree(buffer);
-		return	ret;
+		goto out;
 	}
-
+	
 	schedule();
+out:
 	remove_wait_queue( &pegasus->ctrl_wait, &wait );
-
 	kfree(buffer);
-	return	ret;
+	
+	return ret;
 }
 
 
@@ -232,10 +228,9 @@
 	}
 	memcpy(buffer, &data, 1);
 
-	while ( pegasus->flags & ETH_REGS_CHANGED ) {
-		pegasus->flags |= CTRL_URB_SLEEP;
+	while ( pegasus->flags & ETH_REGS_CHANGED )
 		interruptible_sleep_on( &pegasus->ctrl_wait );
-	}
+
 	pegasus->dr.requesttype = PEGASUS_REQT_WRITE;
 	pegasus->dr.request = PEGASUS_REQ_SET_REG;
 	pegasus->dr.value = cpu_to_le16p( &dat);
@@ -250,19 +245,18 @@
 
 	add_wait_queue( &pegasus->ctrl_wait, &wait );
 	set_current_state( TASK_INTERRUPTIBLE );
-	pegasus->flags |= CTRL_URB_SLEEP;
 
 	if ( (ret = usb_submit_urb( &pegasus->ctrl_urb )) ) {
 		err( __FUNCTION__ " BAD CTRL %d", ret);
-		kfree(buffer);
-		return	ret;
+		goto out;
 	}
 
 	schedule();
+out:
 	remove_wait_queue( &pegasus->ctrl_wait, &wait );
-
 	kfree(buffer);
-	return	ret;
+
+	return ret;
 }
 
 
@@ -451,7 +445,7 @@
 		return 1;
 
 	if ( usb_dev_id[pegasus->dev_index].vendor == VENDOR_LINKSYS ||
-	     usb_dev_id[pegasus->dev_index].vendor == VENDOR_DLINK1 ) {
+	     usb_dev_id[pegasus->dev_index].vendor == VENDOR_DLINK ) {
 		__u16	auxmode;
 
 		read_mii_word( pegasus, 0, 0x1b, &auxmode );
@@ -797,7 +791,6 @@
 	} else {
 		pegasus->eth_regs[EthCtrl0] &= ~RX_MULTICAST;
 		pegasus->eth_regs[EthCtrl2] &= ~RX_PROMISCUOUS;
-		info("%s: set Rx mode", net->name);
 	}
 
 	pegasus->flags |= ETH_REGS_CHANGE;
diff -urN linux-2.4.6-pre5/drivers/usb/pegasus.h linux/drivers/usb/pegasus.h
--- linux-2.4.6-pre5/drivers/usb/pegasus.h	Mon May 21 17:04:24 2001
+++ linux/drivers/usb/pegasus.h	Mon Dec  3 22:49:12 2001
@@ -128,30 +128,51 @@
 };
 
 #define	VENDOR_3COM		0x0506
-#define VENDOR_ACCTON           0x083a
-#define VENDOR_ADMTEK           0x07a6
-#define VENDOR_BILLIONTON       0x08dd
-#define VENDOR_COREGA           0x07aa
-#define VENDOR_DLINK1           0x2001
-#define VENDOR_DLINK2           0x07b8
-#define VENDOR_IODATA           0x04bb
-#define VENDOR_LANEED           0x056e
-#define VENDOR_LINKSYS          0x066b
-#define VENDOR_MELCO            0x0411
-#define VENDOR_SMARTBRIDGES	0x08d1
-#define VENDOR_SMC              0x0707
-#define VENDOR_SOHOWARE         0x15e8
+#define	VENDOR_ABOCOM		0x07b8
+#define	VENDOR_ACCTON		0x083a
+#define	VENDOR_ADMTEK		0x07a6
+#define	VENDOR_BILLIONTON	0x08dd
+#define	VENDOR_COREGA		0x07aa
+#define	VENDOR_DLINK		0x2001
+#define	VENDOR_ELSA		0x05cc
+#define	VENDOR_IODATA		0x04bb
+#define	VENDOR_LANEED		0x056e
+#define	VENDOR_LINKSYS		0x066b
+#define	VENDOR_MELCO		0x0411
+#define	VENDOR_SMARTBRIDGES	0x08d1
+#define	VENDOR_SMC		0x0707
+#define	VENDOR_SOHOWARE		0x15e8
 
 #else	/* PEGASUS_DEV */
 
 PEGASUS_DEV( "3Com USB Ethernet 3C460B", VENDOR_3COM, 0x4601,
 		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,
+		DEFAULT_GPIO_RESET | HAS_HOME_PNA )
+PEGASUS_DEV( "USB HPNA/Ethernet", VENDOR_ABOCOM, 0x4004,
+		DEFAULT_GPIO_RESET | HAS_HOME_PNA )
+PEGASUS_DEV( "USB HPNA/Ethernet", VENDOR_ABOCOM, 0x4007,
+		DEFAULT_GPIO_RESET | HAS_HOME_PNA )
+PEGASUS_DEV( "USB 10/100 Fast Ethernet", VENDOR_ABOCOM, 0x4102,
+		DEFAULT_GPIO_RESET | PEGASUS_II )
+PEGASUS_DEV( "USB 10/100 Fast Ethernet", VENDOR_ABOCOM, 0x4002,
+		DEFAULT_GPIO_RESET )
+PEGASUS_DEV( "USB 10/100 Fast Ethernet", VENDOR_ABOCOM, 0x400b,
+		DEFAULT_GPIO_RESET | PEGASUS_II )
+PEGASUS_DEV( "USB 10/100 Fast Ethernet", VENDOR_ABOCOM, 0x400c,
+		DEFAULT_GPIO_RESET | PEGASUS_II )
+PEGASUS_DEV( "USB 10/100 Fast Ethernet", VENDOR_ABOCOM, 0xabc1,
+		DEFAULT_GPIO_RESET )
+PEGASUS_DEV( "USB 10/100 Fast Ethernet", VENDOR_ABOCOM, 0x200c,
+		DEFAULT_GPIO_RESET | PEGASUS_II ) 	
 PEGASUS_DEV( "Accton USB 10/100 Ethernet Adapter", VENDOR_ACCTON, 0x1046,
 		DEFAULT_GPIO_RESET )
 PEGASUS_DEV( "ADMtek ADM8511 \"Pegasus II\" USB Ethernet",
 		VENDOR_ADMTEK, 0x8511,
 		DEFAULT_GPIO_RESET | PEGASUS_II )
-PEGASUS_DEV( "ADMtek AN986 \"Pegasus\" USB Ethernet (eval board)",
+PEGASUS_DEV( "ADMtek AN986 \"Pegasus\" USB Ethernet (eval. board)",
 		VENDOR_ADMTEK, 0x0986,
 		DEFAULT_GPIO_RESET | HAS_HOME_PNA )
 PEGASUS_DEV( "Billionton USB-100", VENDOR_BILLIONTON, 0x0986,
@@ -164,24 +185,32 @@
 		DEFAULT_GPIO_RESET | PEGASUS_II )
 PEGASUS_DEV( "Corega FEter USB-TX", VENDOR_COREGA, 0x0004,
 		DEFAULT_GPIO_RESET )
-PEGASUS_DEV( "D-Link DSB-650TX", VENDOR_DLINK1, 0x4001,
+PEGASUS_DEV( "D-Link DSB-650TX", VENDOR_DLINK, 0x4001,
 		LINKSYS_GPIO_RESET )
-PEGASUS_DEV( "D-Link DSB-650TX", VENDOR_DLINK1, 0x4002,
+PEGASUS_DEV( "D-Link DSB-650TX", VENDOR_DLINK, 0x4002,
 		LINKSYS_GPIO_RESET )
-PEGASUS_DEV( "D-Link DSB-650TX(PNA)", VENDOR_DLINK1, 0x4003,
+PEGASUS_DEV( "D-Link DSB-650TX", VENDOR_DLINK, 0x4102,
+		LINKSYS_GPIO_RESET | PEGASUS_II )
+PEGASUS_DEV( "D-Link DSB-650TX", VENDOR_DLINK, 0x400b,
+		LINKSYS_GPIO_RESET | PEGASUS_II )
+PEGASUS_DEV( "D-Link DSB-650TX", VENDOR_DLINK, 0x200c,
+		LINKSYS_GPIO_RESET | PEGASUS_II )
+PEGASUS_DEV( "D-Link DSB-650TX(PNA)", VENDOR_DLINK, 0x4003,
 		DEFAULT_GPIO_RESET | HAS_HOME_PNA )
-PEGASUS_DEV( "D-Link DSB-650", VENDOR_DLINK1, 0xabc1,
+PEGASUS_DEV( "D-Link DSB-650", VENDOR_DLINK, 0xabc1,
 		DEFAULT_GPIO_RESET )
-PEGASUS_DEV( "D-Link DU-E10", VENDOR_DLINK2, 0xabc1,
+PEGASUS_DEV( "Elsa Micolink USB2Ethernet", VENDOR_ELSA, 0x3000,
 		DEFAULT_GPIO_RESET )
-PEGASUS_DEV( "D-Link DU-E100", VENDOR_DLINK2, 0x4002,
-		DEFAULT_GPIO_RESET )
-PEGASUS_DEV( "FiberLine USB", VENDOR_DLINK2, 0x4102,
-		DEFAULT_GPIO_RESET | PEGASUS_II )
 PEGASUS_DEV( "IO DATA USB ET/TX", VENDOR_IODATA, 0x0904,
 		DEFAULT_GPIO_RESET )
 PEGASUS_DEV( "LANEED USB Ethernet LD-USB/TX", VENDOR_LANEED, 0x4002,
 		DEFAULT_GPIO_RESET )
+PEGASUS_DEV( "LANEED USB Ethernet LD-USB/TX", VENDOR_LANEED, 0x400b,
+		DEFAULT_GPIO_RESET | PEGASUS_II )
+PEGASUS_DEV( "LANEED USB Ethernet LD-USB/T", VENDOR_LANEED, 0xabc1,
+		DEFAULT_GPIO_RESET )
+PEGASUS_DEV( "LANEED USB Ethernet LD-USB/TX", VENDOR_LANEED, 0x200c,
+		DEFAULT_GPIO_RESET | PEGASUS_II )
 PEGASUS_DEV( "Linksys USB10TX", VENDOR_LINKSYS, 0x2202,
 		LINKSYS_GPIO_RESET )
 PEGASUS_DEV( "Linksys USB100TX", VENDOR_LINKSYS, 0x2203,
@@ -190,8 +219,16 @@
 		LINKSYS_GPIO_RESET | HAS_HOME_PNA )
 PEGASUS_DEV( "Linksys USB Ethernet Adapter", VENDOR_LINKSYS, 0x2206,
 		LINKSYS_GPIO_RESET )
+PEGASUS_DEV( "Linksys USB USB10TX", VENDOR_LINKSYS, 0x400b,
+		LINKSYS_GPIO_RESET | PEGASUS_II )
+PEGASUS_DEV( "Linksys USB10TX", VENDOR_LINKSYS, 0x200c,
+		LINKSYS_GPIO_RESET | PEGASUS_II )	
 PEGASUS_DEV( "MELCO/BUFFALO LUA-TX", VENDOR_MELCO, 0x0001,
 		DEFAULT_GPIO_RESET )
+PEGASUS_DEV( "MELCO/BUFFALO LUA-TX", VENDOR_MELCO, 0x0005,
+		DEFAULT_GPIO_RESET )
+PEGASUS_DEV( "MELCO/BUFFALO LUA2-TX", VENDOR_MELCO, 0x0009,
+		DEFAULT_GPIO_RESET | PEGASUS_II )
 PEGASUS_DEV( "smartNIC 2 PnP Adapter", VENDOR_SMARTBRIDGES, 0x0003,
 		DEFAULT_GPIO_RESET | PEGASUS_II )
 PEGASUS_DEV( "SMC 202 USB Ethernet", VENDOR_SMC, 0x0200,
diff -urN linux-2.4.6-pre5/drivers/usb/se401.c linux/drivers/usb/se401.c
--- linux-2.4.6-pre5/drivers/usb/se401.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/usb/se401.c	Mon Dec  3 22:49:12 2001
@@ -0,0 +1,1675 @@
+/*
+ * Endpoints (formerly known as AOX) se401 USB Camera Driver
+ *
+ * Copyright (c) 2000 Jeroen B. Vreeken (pe1rxq@amsat.org)
+ *
+ * Still somewhat based on the Linux ov511 driver.
+ * 
+ * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *
+ * Thanks to Endpoints Inc. (www.endpoints.com) for making documentation on
+ * their chipset available and supporting me while writing this driver.
+ * 	- Jeroen Vreeken
+ */
+
+static const char version[] = "0.22";
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/version.h>
+#include <linux/init.h>
+#include <linux/fs.h>
+#include <linux/vmalloc.h>
+#include <linux/slab.h>
+#include <linux/proc_fs.h>
+#include <linux/pagemap.h>
+#include <linux/usb.h>
+#include <asm/io.h>
+#include <asm/semaphore.h>
+#include <linux/wrapper.h>
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 3, 0)
+#define virt_to_page(arg)	MAP_NR(arg)
+#define vmalloc_32		vmalloc
+#endif
+
+#include "se401.h"
+
+static int flickerless=0;
+
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 3, 0)
+static __devinitdata struct usb_device_id device_table [] = {
+	{ USB_DEVICE(0x03e8, 0x0004) },/* Endpoints/Aox SE401 */
+	{ USB_DEVICE(0x0471, 0x030b) },/* Philips PCVC665K */
+	{ USB_DEVICE(0x047d, 0x5001) },/* Kensington 67014 */
+	{ USB_DEVICE(0x047d, 0x5002) },/* Kensington 6701(5/7) */
+	{ USB_DEVICE(0x047d, 0x5003) },/* Kensington 67016 */
+	{ }
+};
+
+MODULE_DEVICE_TABLE(usb, device_table);
+#endif
+
+static int video_nr = -1;
+
+MODULE_AUTHOR("Jeroen Vreeken <pe1rxq@amsat.org>");
+MODULE_DESCRIPTION("SE401 USB Camera Driver");
+MODULE_PARM(flickerless, "i");
+MODULE_PARM_DESC(flickerless, "Net frequency to adjust exposure time to (0/50/60)");
+EXPORT_NO_SYMBOLS;
+
+
+static struct usb_driver se401_driver;
+
+
+/**********************************************************************
+ *
+ * Memory management
+ *
+ * This is a shameless copy from the USB-cpia driver (linux kernel
+ * version 2.3.29 or so, I have no idea what this code actually does ;).
+ * Actually it seems to be a copy of a shameless copy of the bttv-driver.
+ * Or that is a copy of a shameless copy of ... (To the powers: is there
+ * no generic kernel-function to do this sort of stuff?)
+ *
+ * Yes, it was a shameless copy from the bttv-driver. IIRC, Alan says
+ * there will be one, but apparentely not yet -jerdfelt
+ *
+ * So I copied it again for the ov511 driver -claudio
+ *
+ * Same for the se401 driver -Jeroen
+ **********************************************************************/
+
+/* Given PGD from the address space's page table, return the kernel
+ * virtual mapping of the physical memory mapped at ADR.
+ */
+static inline unsigned long uvirt_to_kva(pgd_t *pgd, unsigned long adr)
+{
+	unsigned long ret = 0UL;
+	pmd_t *pmd;
+	pte_t *ptep, pte;
+
+	if (!pgd_none(*pgd)) {
+		pmd = pmd_offset(pgd, adr);
+		if (!pmd_none(*pmd)) {
+			ptep = pte_offset(pmd, adr);
+			pte = *ptep;
+			if (pte_present(pte)) {
+				ret = (unsigned long) page_address(pte_page(pte));
+				ret |= (adr & (PAGE_SIZE - 1));
+			}
+		}
+	}
+
+	return ret;
+}
+
+/* Here we want the physical address of the memory.
+ * This is used when initializing the contents of the
+ * area and marking the pages as reserved.
+ */
+static inline unsigned long kvirt_to_pa(unsigned long adr)
+{
+	unsigned long va, kva, ret;
+
+	va = VMALLOC_VMADDR(adr);
+	kva = uvirt_to_kva(pgd_offset_k(va), va);
+	ret = __pa(kva);
+	return ret;
+}
+
+static void *rvmalloc(unsigned long size)
+{
+	void *mem;
+	unsigned long adr, page;
+
+	/* Round it off to PAGE_SIZE */
+	size += (PAGE_SIZE - 1);
+	size &= ~(PAGE_SIZE - 1);
+
+	mem = vmalloc_32(size);
+	if (!mem)
+		return NULL;
+
+	memset(mem, 0, size); /* Clear the ram out, no junk to the user */
+	adr = (unsigned long) mem;
+	while (size > 0) {
+		page = kvirt_to_pa(adr);
+		mem_map_reserve(virt_to_page(__va(page)));
+		adr += PAGE_SIZE;
+		if (size > PAGE_SIZE)
+			size -= PAGE_SIZE;
+		else
+			size = 0;
+	}
+
+	return mem;
+}
+
+static void rvfree(void *mem, unsigned long size)
+{
+	unsigned long adr, page;
+
+	if (!mem)
+		return;
+
+	size += (PAGE_SIZE - 1);
+	size &= ~(PAGE_SIZE - 1);
+
+	adr=(unsigned long) mem;
+	while (size > 0) {
+		page = kvirt_to_pa(adr);
+		mem_map_unreserve(virt_to_page(__va(page)));
+		adr += PAGE_SIZE;
+		if (size > PAGE_SIZE)
+			size -= PAGE_SIZE;
+		else
+			size = 0;
+	}
+	vfree(mem);
+}
+
+
+
+/****************************************************************************
+ *
+ * /proc interface
+ *
+ ***************************************************************************/
+
+#if defined(CONFIG_PROC_FS) && defined(CONFIG_VIDEO_PROC_FS)
+
+static struct proc_dir_entry *se401_proc_entry = NULL;
+extern struct proc_dir_entry *video_proc_entry;
+
+#define YES_NO(x) ((x) ? "yes" : "no")
+
+static int se401_read_proc(char *page, char **start, off_t off, int count,
+			   int *eof, void *data)
+{
+	char *out = page;
+	int i, len;
+	struct usb_se401 *se401 = data;
+	
+	/* Stay under PAGE_SIZE or else bla bla bla.... */
+
+	out+=sprintf(out, "driver_version  : %s\n", version);
+	out+=sprintf(out, "model           : %s\n", se401->camera_name);
+	out+=sprintf(out, "in use          : %s\n", YES_NO (se401->user));
+	out+=sprintf(out, "streaming       : %s\n", YES_NO (se401->streaming));
+	out+=sprintf(out, "button state    : %s\n", YES_NO (se401->button));
+	out+=sprintf(out, "button pressed  : %s\n", YES_NO (se401->buttonpressed));
+	out+=sprintf(out, "num_frames      : %d\n", SE401_NUMFRAMES);
+
+	out+=sprintf(out, "Sizes           :");
+	for (i=0; i<se401->sizes; i++) {
+		out+=sprintf(out, " %dx%d", se401->width[i],
+		    se401->height[i]);
+	}
+	out+=sprintf(out, "\n");
+	
+	out+=sprintf(out, "Frames total    : %d\n", se401->readcount);
+	out+=sprintf(out, "Frames read     : %d\n", se401->framecount);
+	out+=sprintf(out, "Packets dropped : %d\n", se401->dropped);
+	out+=sprintf(out, "Decoding Errors : %d\n", se401->error);
+
+	len = out - page;
+	len -= off;
+	if (len < count) {
+		*eof = 1;
+			if (len <= 0) return 0;
+	} else
+		len = count;
+
+	*start = page + off;
+	
+	return len;	
+}
+
+static int se401_write_proc(struct file *file, const char *buffer, 
+			    unsigned long count, void *data)
+{
+	return -EINVAL;
+}
+
+static void create_proc_se401_cam (struct usb_se401 *se401)
+{
+	char name[7];
+	struct proc_dir_entry *ent;
+
+	if (!se401_proc_entry || !se401)
+		return;
+
+	sprintf (name, "video%d", se401->vdev.minor);
+
+	ent = create_proc_entry(name, S_IFREG | S_IRUGO | S_IWUSR,
+				se401_proc_entry);
+
+	if (!ent)
+		return;
+
+	ent->data = se401;
+	ent->read_proc = se401_read_proc;
+	ent->write_proc = se401_write_proc;
+	se401->proc_entry = ent;
+}
+
+static void destroy_proc_se401_cam (struct usb_se401 *se401)
+{
+	/* One to much, just to be sure :) */
+	char name[9];
+
+	if (!se401 || !se401->proc_entry)
+		return;
+	
+	sprintf(name, "video%d", se401->vdev.minor);
+	remove_proc_entry(name, se401_proc_entry);
+	se401->proc_entry = NULL;
+}
+
+static void proc_se401_create (void)
+{
+	if (video_proc_entry == NULL) {
+		err("/proc/video/ doesn't exist");
+		return;
+	}
+
+	se401_proc_entry=create_proc_entry("se401", S_IFDIR, video_proc_entry);
+
+	if (se401_proc_entry)
+		se401_proc_entry->owner = THIS_MODULE;
+	else
+		err("Unable to initialize /proc/video/se401");
+}
+
+static void proc_se401_destroy(void)
+{
+	if (se401_proc_entry == NULL)
+		return;
+
+	remove_proc_entry("se401", video_proc_entry);
+}
+#endif /* CONFIG_PROC_FS && CONFIG_VIDEO_PROC_FS */
+
+
+/****************************************************************************
+ *
+ * se401 register read/write functions
+ *
+ ***************************************************************************/
+
+static int se401_sndctrl(int set, struct usb_se401 *se401, unsigned short req,
+			 unsigned short value, unsigned char *cp, int size)
+{
+	return usb_control_msg (
+                se401->dev,
+                set ? usb_sndctrlpipe(se401->dev, 0) : usb_rcvctrlpipe(se401->dev, 0),
+                req,
+                (set ? USB_DIR_OUT : USB_DIR_IN) | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+                value,
+                0,
+                cp,
+                size,
+                HZ
+        );
+}
+
+static int se401_set_feature(struct usb_se401 *se401, unsigned short selector,
+			     unsigned short param)
+{
+	/* specs say that the selector (address) should go in the value field
+	   and the param in index, but in the logs of the windows driver they do
+	   this the other way around...
+	 */
+	return usb_control_msg (
+		se401->dev,
+		usb_sndctrlpipe(se401->dev, 0),
+		SE401_REQ_SET_EXT_FEATURE,
+		USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+		param,
+		selector,
+                NULL,
+                0,
+                HZ
+        );
+}
+
+static unsigned short se401_get_feature(struct usb_se401 *se401, 
+				        unsigned short selector)
+{
+	/* For 'set' the selecetor should be in index, not sure if the spec is
+	   wrong here to....
+	 */
+	unsigned char cp[2];
+        usb_control_msg (
+                se401->dev,
+                usb_rcvctrlpipe(se401->dev, 0),
+                SE401_REQ_GET_EXT_FEATURE,
+                USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+        	0,
+                selector,
+                cp,
+                2,
+                HZ
+        );
+	return cp[0]+cp[1]*256;
+}
+
+/****************************************************************************
+ *
+ * Camera control
+ *
+ ***************************************************************************/
+
+
+static int se401_send_pict(struct usb_se401 *se401)
+{
+	se401_set_feature(se401, HV7131_REG_TITL, se401->expose_l);/* integration time low */
+	se401_set_feature(se401, HV7131_REG_TITM, se401->expose_m);/* integration time mid */
+	se401_set_feature(se401, HV7131_REG_TITU, se401->expose_h);/* integration time mid */
+	se401_set_feature(se401, HV7131_REG_ARLV, se401->resetlevel);/* reset level value */
+	se401_set_feature(se401, HV7131_REG_ARCG, se401->rgain);/* red color gain */
+	se401_set_feature(se401, HV7131_REG_AGCG, se401->ggain);/* green color gain */
+	se401_set_feature(se401, HV7131_REG_ABCG, se401->bgain);/* blue color gain */
+	    	
+	return 0;
+}
+
+static void se401_set_exposure(struct usb_se401 *se401, int brightness)
+{
+	int integration=brightness<<5;
+	
+	if (flickerless==50) {
+		integration=integration-integration%106667;
+	}
+	if (flickerless==60) {
+		integration=integration-integration%88889;
+	}
+	se401->brightness=integration>>5;
+	se401->expose_h=(integration>>16)&0xff;
+	se401->expose_m=(integration>>8)&0xff;
+	se401->expose_l=integration&0xff;
+}
+
+static int se401_get_pict(struct usb_se401 *se401, struct video_picture *p)
+{
+	p->brightness=se401->brightness;
+	if (se401->enhance) {
+		p->whiteness=32768;
+	} else {
+		p->whiteness=0;
+	}
+	p->colour=65535;
+	p->contrast=65535;
+	p->hue=se401->rgain<<10;
+	p->palette=se401->palette;
+	p->depth=3; /* rgb24 */
+	return 0;
+}
+
+
+static int se401_set_pict(struct usb_se401 *se401, struct video_picture *p)
+{
+	if (p->palette != VIDEO_PALETTE_RGB24)
+		return 1;
+	se401->palette=p->palette;
+	if (p->hue!=se401->hue) {
+		se401->rgain= p->hue>>10;
+		se401->bgain= 0x40-(p->hue>>10);
+		se401->hue=p->hue;
+	}
+	if (p->brightness!=se401->brightness) {
+		se401_set_exposure(se401, p->brightness);
+	}
+	if (p->whiteness>=32768) {
+		se401->enhance=1;
+	} else {
+		se401->enhance=0;
+	}
+	se401_send_pict(se401);
+	se401_send_pict(se401);
+	return 0;
+}
+
+/*
+	Hyundai have some really nice docs about this and other sensor related
+	stuff on their homepage: www.hei.co.kr
+*/
+static void se401_auto_resetlevel(struct usb_se401 *se401)
+{
+	unsigned int ahrc, alrc;
+	int oldreset=se401->resetlevel;
+
+	/* For some reason this normally read-only register doesn't get reset
+	   to zero after reading them just once...
+	 */
+	se401_get_feature(se401, HV7131_REG_HIREFNOH); 
+	se401_get_feature(se401, HV7131_REG_HIREFNOL);
+	se401_get_feature(se401, HV7131_REG_LOREFNOH);
+	se401_get_feature(se401, HV7131_REG_LOREFNOL);
+	ahrc=256*se401_get_feature(se401, HV7131_REG_HIREFNOH) + 
+	    se401_get_feature(se401, HV7131_REG_HIREFNOL);
+	alrc=256*se401_get_feature(se401, HV7131_REG_LOREFNOH) +
+	    se401_get_feature(se401, HV7131_REG_LOREFNOL);
+
+	/* Not an exact science, but it seems to work pretty well... */
+	if (alrc > 10) {
+		while (alrc>=10 && se401->resetlevel < 63) {
+			se401->resetlevel++;
+			alrc /=2;
+		}
+	} else if (ahrc > 20) {
+		while (ahrc>=20 && se401->resetlevel > 0) {
+			se401->resetlevel--;
+			ahrc /=2;
+		}
+	}
+	if (se401->resetlevel!=oldreset)
+		se401_set_feature(se401, HV7131_REG_ARLV, se401->resetlevel);
+
+	return;
+}
+
+/* irq handler for snapshot button */
+static void se401_button_irq(struct urb *urb)
+{
+	struct usb_se401 *se401=urb->context;
+	
+	if (!urb) {
+		info("ohoh: null urb");
+		return;
+	}
+	if (!se401->dev) {
+		info("ohoh: device vapourished");
+		return;
+	}
+	
+	if (urb->actual_length >=2 && !urb->status) {
+		if (se401->button)
+			se401->buttonpressed=1;
+	}
+}
+
+static void se401_video_irq(struct urb *urb)
+{
+	struct usb_se401 *se401=urb->context;
+	int length=urb->actual_length;
+
+	/* ohoh... */
+	if (!se401->streaming) {
+		return;
+	}
+	if (!urb) {
+		info ("ohoh: null urb");
+		return;
+	}
+	if (!se401->dev) {
+		info ("ohoh: device vapourished");
+		return;
+	}
+
+	/* 0 sized packets happen if we are to fast, but sometimes the camera
+	   keeps sending them forever...
+	 */
+	if (length && !urb->status) {
+		se401->nullpackets=0;
+		switch(se401->scratch[se401->scratch_next].state) {
+			case BUFFER_READY:
+			case BUFFER_BUSY: {
+				se401->dropped++;
+				break;
+			}
+			case BUFFER_UNUSED: {
+				memcpy(se401->scratch[se401->scratch_next].data, (unsigned char *)urb->transfer_buffer, length);
+				se401->scratch[se401->scratch_next].state=BUFFER_READY;
+				se401->scratch[se401->scratch_next].offset=se401->bayeroffset;
+				se401->scratch[se401->scratch_next].length=length;
+				if (waitqueue_active(&se401->wq)) {
+					wake_up_interruptible(&se401->wq);
+				}
+				se401->scratch_overflow=0;
+				se401->scratch_next++;
+				if (se401->scratch_next>=SE401_NUMSCRATCH)
+					se401->scratch_next=0;;
+				break;
+			}
+		}
+		se401->bayeroffset+=length;
+		if (se401->bayeroffset>=se401->cheight*se401->cwidth) {
+			se401->bayeroffset=0;
+		}
+	} else {
+		se401->nullpackets++;
+		if (se401->nullpackets > SE401_MAX_NULLPACKETS) {
+			if (waitqueue_active(&se401->wq)) {
+				wake_up_interruptible(&se401->wq);
+			}		
+		}
+	}
+
+	/* Resubmit urb for new data */
+	urb->status=0;
+	urb->dev=se401->dev;
+	if(usb_submit_urb(urb))
+		info("urb burned down");
+	return;
+}
+
+static void se401_send_size(struct usb_se401 *se401, int width, int height)
+{
+	int i=0;
+	int mode=0x03; /* No compression */
+	int sendheight=height;
+	int sendwidth=width;
+
+	/* JangGu compression can only be used with the camera supported sizes,
+	   but bayer seems to work with any size that fits on the sensor.
+	   We check if we can use compression with the current size with either
+	   4 or 16 times subcapturing, if not we use uncompressed bayer data
+	   but this will result in cutouts of the maximum size....
+	 */
+	while (i<se401->sizes && !(se401->width[i]==width && se401->height[i]==height))
+		i++;
+	while (i<se401->sizes) {
+		if (se401->width[i]==width*2 && se401->height[i]==height*2) {
+			sendheight=se401->height[i];
+			sendwidth=se401->width[i];
+			mode=0x40;
+		}
+		if (se401->width[i]==width*4 && se401->height[i]==height*4) {
+			sendheight=se401->height[i];
+			sendwidth=se401->width[i];
+			mode=0x42;
+		}
+		i++;
+	}
+
+	se401_sndctrl(1, se401, SE401_REQ_SET_WIDTH, sendwidth, NULL, 0);
+	se401_sndctrl(1, se401, SE401_REQ_SET_HEIGHT, sendheight, NULL, 0);
+	se401_set_feature(se401, SE401_OPERATINGMODE, mode);
+
+	if (mode==0x03) {
+		se401->format=FMT_BAYER;
+	} else {
+		se401->format=FMT_JANGGU;
+	}
+
+	return;
+}
+
+/*
+	In this function se401_send_pict is called several times,
+	for some reason (depending on the state of the sensor and the phase of
+	the moon :) doing this only in either place doesn't always work...
+*/
+static int se401_start_stream(struct usb_se401 *se401)
+{
+	urb_t *urb;
+	int err=0, i;
+	se401->streaming=1;
+
+        se401_sndctrl(1, se401, SE401_REQ_CAMERA_POWER, 1, NULL, 0);
+        se401_sndctrl(1, se401, SE401_REQ_LED_CONTROL, 1, NULL, 0);
+
+	/* Set picture settings */
+	se401_set_feature(se401, HV7131_REG_MODE_B, 0x05);/*windowed + pix intg */
+	se401_send_pict(se401);
+
+	se401_send_size(se401, se401->cwidth, se401->cheight);
+
+	se401_sndctrl(1, se401, SE401_REQ_START_CONTINUOUS_CAPTURE, 0, NULL, 0);
+
+	/* Do some memory allocation */
+	for (i=0; i<SE401_NUMFRAMES; i++) {
+		se401->frame[i].data=se401->fbuf + i * se401->maxframesize;
+		se401->frame[i].curpix=0;
+	}
+	for (i=0; i<SE401_NUMSBUF; i++) {
+		se401->sbuf[i].data=kmalloc(SE401_PACKETSIZE, GFP_KERNEL);
+	}
+
+	se401->bayeroffset=0;
+	se401->scratch_next=0;
+	se401->scratch_use=0;
+	se401->scratch_overflow=0;
+	for (i=0; i<SE401_NUMSCRATCH; i++) {
+		se401->scratch[i].data=kmalloc(SE401_PACKETSIZE, GFP_KERNEL);
+		se401->scratch[i].state=BUFFER_UNUSED;
+	}
+
+	for (i=0; i<SE401_NUMSBUF; i++) {
+		urb=usb_alloc_urb(0);
+		if(!urb)
+			return ENOMEM;
+
+		FILL_BULK_URB(urb, se401->dev,
+			usb_rcvbulkpipe(se401->dev, SE401_VIDEO_ENDPOINT),
+			se401->sbuf[i].data, SE401_PACKETSIZE,
+			se401_video_irq,
+			se401);
+		urb->transfer_flags |= USB_QUEUE_BULK;
+
+		se401->urb[i]=urb;
+
+		err=usb_submit_urb(se401->urb[i]);
+		if(err)
+			err("urb burned down");
+	}
+
+	se401->framecount=0;
+
+	return 0;
+}
+
+static int se401_stop_stream(struct usb_se401 *se401)
+{
+	int i;
+
+	if (!se401->streaming || !se401->dev)
+		return 1;
+
+	se401->streaming=0;
+
+	se401_sndctrl(1, se401, SE401_REQ_STOP_CONTINUOUS_CAPTURE, 0, NULL, 0);
+
+	se401_sndctrl(1, se401, SE401_REQ_LED_CONTROL, 0, NULL, 0);
+	se401_sndctrl(1, se401, SE401_REQ_CAMERA_POWER, 0, NULL, 0);
+
+	for (i=0; i<SE401_NUMSBUF; i++) if (se401->urb[i]) {
+		se401->urb[i]->next=NULL;
+		usb_unlink_urb(se401->urb[i]);
+		usb_free_urb(se401->urb[i]);
+		se401->urb[i]=NULL;
+		kfree(se401->sbuf[i].data);
+	}
+	for (i=0; i<SE401_NUMSCRATCH; i++) {
+		kfree(se401->scratch[i].data);
+		se401->scratch[i].data=NULL;
+	}
+
+	return 0;
+}
+
+static int se401_set_size(struct usb_se401 *se401, int width, int height)
+{
+	int wasstreaming=se401->streaming;
+	/* Check to see if we need to change */
+	if (se401->cwidth==width && se401->cheight==height)
+		return 0;
+
+	/* Check for a valid mode */
+	if (!width || !height)
+		return 1;
+	if ((width & 1) || (height & 1))
+		return 1;
+	if (width>se401->width[se401->sizes-1])
+		return 1;
+	if (height>se401->height[se401->sizes-1])
+		return 1;
+
+	/* Stop a current stream and start it again at the new size */
+	if (wasstreaming)
+		se401_stop_stream(se401);
+	se401->cwidth=width;
+	se401->cheight=height;
+	if (wasstreaming)
+		se401_start_stream(se401);
+	return 0;
+}
+
+
+/****************************************************************************
+ *
+ * Video Decoding
+ *
+ ***************************************************************************/
+
+/*
+	This shouldn't really be done in a v4l driver....
+	But it does make the image look a lot more usable.
+	Basicly it lifts the dark pixels more than the light pixels.
+*/
+static inline void enhance_picture(unsigned char *frame, int len)
+{
+	while (len--) {
+		*frame++=(((*frame^255)*(*frame^255))/255)^255;
+	}
+}
+
+static inline void decode_JangGu_integrate(struct usb_se401 *se401, int data)
+{
+	struct se401_frame *frame=&se401->frame[se401->curframe];
+	int linelength=se401->cwidth*3;
+
+	if (frame->curlinepix >= linelength) {
+		frame->curlinepix=0;
+		frame->curline+=linelength;
+	}
+
+	/* First three are absolute, all others relative.
+	 * Format is rgb from right to left (mirrorred image), 
+	 * we flip it to get bgr from left to right. */
+	if (frame->curlinepix < 3) {
+		*(frame->curline-frame->curlinepix)=1+data*4;
+	} else {
+		*(frame->curline-frame->curlinepix)=
+		    *(frame->curline-frame->curlinepix+3)+data*4;
+	}
+	frame->curlinepix++;
+}
+
+static inline void decode_JangGu_vlc (struct usb_se401 *se401, unsigned char *data, int bit_exp, int packetlength)
+{
+	int pos=0;
+	int vlc_cod=0;
+	int vlc_size=0;
+	int vlc_data=0;
+	int bit_cur;
+	int bit;
+	data+=4;
+	while (pos < packetlength) {
+		bit_cur=8;
+		while (bit_cur && bit_exp) {
+			bit=((*data)>>(bit_cur-1))&1;
+			if (!vlc_cod) {
+				if (bit) {
+					vlc_size++;
+				} else {
+					if (!vlc_size) {
+						decode_JangGu_integrate(se401, 0);
+					} else {
+						vlc_cod=2;
+						vlc_data=0;
+					}
+				}
+			} else {
+				if (vlc_cod==2) {
+					if (!bit) vlc_data=-(1<<vlc_size)+1;
+					vlc_cod--;
+				}
+				vlc_size--;
+				vlc_data+=bit<<vlc_size;
+				if (!vlc_size) {
+					decode_JangGu_integrate(se401, vlc_data);
+					vlc_cod=0;
+				}
+			}
+			bit_cur--;
+			bit_exp--;
+		}
+		pos++;
+		data++;
+	}
+}
+
+static inline void decode_JangGu (struct usb_se401 *se401, struct se401_scratch *buffer)
+{
+	unsigned char *data=buffer->data;
+	int len=buffer->length;
+	int bit_exp=0, pix_exp=0, frameinfo=0, packetlength=0, size;
+	int datapos=0;
+
+	/* New image? */
+	if (!se401->frame[se401->curframe].curpix) {
+		se401->frame[se401->curframe].curlinepix=0;
+		se401->frame[se401->curframe].curline=
+		    se401->frame[se401->curframe].data+
+		    se401->cwidth*3-1;
+		if (se401->frame[se401->curframe].grabstate==FRAME_READY)
+			se401->frame[se401->curframe].grabstate=FRAME_GRABBING;
+		se401->vlcdatapos=0;
+	}
+	while (datapos < len) {
+		size=1024-se401->vlcdatapos;
+		if (size+datapos > len)
+			size=len-datapos;
+		memcpy(se401->vlcdata+se401->vlcdatapos, data+datapos, size);
+		se401->vlcdatapos+=size;
+		packetlength=0;
+		if (se401->vlcdatapos >= 4) {
+			bit_exp=se401->vlcdata[3]+(se401->vlcdata[2]<<8);
+			pix_exp=se401->vlcdata[1]+((se401->vlcdata[0]&0x3f)<<8);
+			frameinfo=se401->vlcdata[0]&0xc0;
+			packetlength=((bit_exp+47)>>4)<<1;
+			if (packetlength > 1024) {
+				se401->vlcdatapos=0;
+				datapos=len;
+				packetlength=0;
+				se401->error++;
+				se401->frame[se401->curframe].curpix=0;
+			}
+		}
+		if (packetlength && se401->vlcdatapos >= packetlength) {
+			decode_JangGu_vlc(se401, se401->vlcdata, bit_exp, packetlength);
+			se401->frame[se401->curframe].curpix+=pix_exp*3;
+			datapos+=size-(se401->vlcdatapos-packetlength);
+			se401->vlcdatapos=0;
+			if (se401->frame[se401->curframe].curpix>=se401->cwidth*se401->cheight*3) {
+				if (se401->frame[se401->curframe].curpix==se401->cwidth*se401->cheight*3) {
+					if (se401->frame[se401->curframe].grabstate==FRAME_GRABBING) {
+						se401->frame[se401->curframe].grabstate=FRAME_DONE;
+						se401->framecount++;
+						se401->readcount++;
+					}
+					if (se401->frame[(se401->curframe+1)&(SE401_NUMFRAMES-1)].grabstate==FRAME_READY) {
+						se401->curframe=(se401->curframe+1) & (SE401_NUMFRAMES-1);
+					}
+				} else {
+					se401->error++;
+				}
+				se401->frame[se401->curframe].curpix=0;
+				datapos=len;
+			}
+		} else {
+			datapos+=size;
+		}
+	}
+}
+
+static inline void decode_bayer (struct usb_se401 *se401, struct se401_scratch *buffer)
+{
+	unsigned char *data=buffer->data;
+	int len=buffer->length;
+	int offset=buffer->offset;
+	int datasize=se401->cwidth*se401->cheight;
+	struct se401_frame *frame=&se401->frame[se401->curframe];
+
+	unsigned char *framedata=frame->data, *curline, *nextline;
+	int width=se401->cwidth;
+	int blineoffset=0, bline;
+	int linelength=width*3, i;
+	
+
+	if (frame->curpix==0) {
+		if (frame->grabstate==FRAME_READY) {
+			frame->grabstate=FRAME_GRABBING;
+		}
+		frame->curline=framedata+linelength;
+		frame->curlinepix=0;
+	}
+
+	if (offset!=frame->curpix) {
+		/* Regard frame as lost :( */
+		frame->curpix=0;
+		se401->error++;
+		return;
+	}
+
+	/* Check if we have to much data */
+	if (frame->curpix+len > datasize) {
+		len=datasize-frame->curpix;
+	}
+	if (se401->cheight%4)
+		blineoffset=1;
+	bline=frame->curpix/se401->cwidth+blineoffset;
+
+	curline=frame->curline;
+	nextline=curline+linelength;
+	if (nextline >= framedata+datasize*3)
+		nextline=curline;
+	while (len) {
+		if (frame->curlinepix>=width) {
+			frame->curlinepix-=width;
+			bline=frame->curpix/width+blineoffset;
+			curline+=linelength*2;
+			nextline+=linelength*2;
+			if (curline >= framedata+datasize*3) {
+				frame->curlinepix++;
+				curline-=3;
+				nextline-=3;
+				len--;
+				data++;
+				frame->curpix++;
+			}
+			if (nextline >= framedata+datasize*3)
+				nextline=curline;
+		}
+		if ((bline&1)) {
+			if ((frame->curlinepix&1)) {
+				*(curline+2)=*data;
+				*(curline-1)=*data;
+				*(nextline+2)=*data;
+				*(nextline-1)=*data;
+			} else {
+				*(curline+1)=
+					(*(curline+1)+*data)/2;
+				*(curline-2)=
+					(*(curline-2)+*data)/2;
+				*(nextline+1)=*data;
+				*(nextline-2)=*data;
+			}
+		} else {
+			if ((frame->curlinepix&1)) {
+				*(curline+1)=
+					(*(curline+1)+*data)/2;
+				*(curline-2)=
+					(*(curline-2)+*data)/2;
+				*(nextline+1)=*data;
+				*(nextline-2)=*data;
+			} else {
+				*curline=*data;
+				*(curline-3)=*data;
+				*nextline=*data;
+				*(nextline-3)=*data;
+			}
+		}
+		frame->curlinepix++;
+		curline-=3;
+		nextline-=3;
+		len--;
+		data++;
+		frame->curpix++;
+	}
+	frame->curline=curline;
+
+	if (frame->curpix>=datasize) {
+		/* Fix the top line */
+		framedata+=linelength;
+		for (i=0; i<linelength; i++) {
+			*--framedata=*(framedata+linelength);
+		}
+		/* Fix the left side (green is already present) */
+		for (i=0; i<se401->cheight; i++) {
+			*framedata=*(framedata+3);
+			*(framedata+1)=*(framedata+4);
+			*(framedata+2)=*(framedata+5);
+			framedata+=linelength;
+		}
+		frame->curpix=0;
+		frame->grabstate=FRAME_DONE;
+		se401->framecount++;
+		se401->readcount++;
+		if (se401->frame[(se401->curframe+1)&(SE401_NUMFRAMES-1)].grabstate==FRAME_READY) {
+			se401->curframe=(se401->curframe+1) & (SE401_NUMFRAMES-1);
+		}
+	}
+}
+
+static int se401_newframe(struct usb_se401 *se401, int framenr)
+{
+	DECLARE_WAITQUEUE(wait, current);
+	int errors=0;
+
+	while (se401->streaming &&
+	    (se401->frame[framenr].grabstate==FRAME_READY ||
+	     se401->frame[framenr].grabstate==FRAME_GRABBING) ) {
+		if(!se401->frame[framenr].curpix) {
+			errors++;
+		}
+		wait_interruptible(
+		    se401->scratch[se401->scratch_use].state!=BUFFER_READY,
+		    &se401->wq,
+		    &wait
+		);
+		if (se401->nullpackets > SE401_MAX_NULLPACKETS) {
+			se401->nullpackets=0;
+			info("to many null length packets, restarting capture");
+			se401_stop_stream(se401);
+			se401_start_stream(se401);			
+		} else {
+			if (se401->scratch[se401->scratch_use].state!=BUFFER_READY) {
+				se401->frame[framenr].grabstate=FRAME_ERROR;
+				return -EIO;
+			}
+			se401->scratch[se401->scratch_use].state=BUFFER_BUSY;
+			if (se401->format==FMT_JANGGU) {
+				decode_JangGu(se401, &se401->scratch[se401->scratch_use]);
+			} else {
+				decode_bayer(se401, &se401->scratch[se401->scratch_use]);
+			}
+			se401->scratch[se401->scratch_use].state=BUFFER_UNUSED;
+			se401->scratch_use++;
+			if (se401->scratch_use>=SE401_NUMSCRATCH)
+				se401->scratch_use=0;
+			if (errors > SE401_MAX_ERRORS) {
+				errors=0;
+				info("to much errors, restarting capture");
+				se401_stop_stream(se401);
+				se401_start_stream(se401);
+			}
+		}
+	}
+	
+	if (se401->frame[framenr].grabstate==FRAME_DONE) 
+		if (se401->enhance)
+			enhance_picture(se401->frame[framenr].data, se401->cheight*se401->cwidth*3);
+	return 0;
+}
+
+
+/****************************************************************************
+ *
+ * Video4Linux
+ *
+ ***************************************************************************/
+
+
+static int se401_open(struct video_device *dev, int flags)
+{
+	struct usb_se401 *se401 = (struct usb_se401 *)dev;
+	int err = 0;
+
+	MOD_INC_USE_COUNT;
+	down(&se401->lock);
+
+	se401->fbuf=rvmalloc(se401->maxframesize * SE401_NUMFRAMES);
+	if(!se401->fbuf) err=-ENOMEM;
+
+        if (err) {
+		MOD_DEC_USE_COUNT;
+		up(&se401->lock);
+	        return err;
+	}
+	
+	se401->user=1;
+
+	up(&se401->lock);
+	
+	return 0;
+}
+
+static void se401_close(struct video_device *dev)
+{
+        struct usb_se401 *se401 = (struct usb_se401 *)dev;
+	int i;
+
+	down(&se401->lock);
+
+	for (i=0; i<SE401_NUMFRAMES; i++)
+		se401->frame[i].grabstate=FRAME_UNUSED;
+	if (se401->streaming)
+		se401_stop_stream(se401);
+
+	rvfree(se401->fbuf, se401->maxframesize * SE401_NUMFRAMES);
+	se401->user=0;
+	up(&se401->lock);
+
+        if (!se401->dev) {
+                video_unregister_device(&se401->vdev);
+		kfree(se401->width);
+		kfree(se401->height);
+                kfree(se401);
+                se401 = NULL;
+		info("device unregistered");
+	}
+
+        MOD_DEC_USE_COUNT;
+}
+
+static int se401_init_done(struct video_device *dev)
+{
+#if defined(CONFIG_PROC_FS) && defined(CONFIG_VIDEO_PROC_FS)
+        create_proc_se401_cam((struct usb_se401 *)dev);
+#endif
+
+        return 0;
+}
+
+static long se401_write(struct video_device *dev, const char *buf, unsigned long
+ count, int noblock)
+{
+        return -EINVAL;
+}
+
+static int se401_ioctl(struct video_device *vdev, unsigned int cmd, void *arg)
+{
+        struct usb_se401 *se401 = (struct usb_se401 *)vdev;
+
+        if (!se401->dev)
+                return -EIO;
+
+        switch (cmd) {
+	case VIDIOCGCAP:
+	{
+		struct video_capability b;
+		strcpy(b.name, se401->camera_name);
+		b.type = VID_TYPE_CAPTURE;
+		b.channels = 1;
+		b.audios = 0;
+		b.maxwidth = se401->width[se401->sizes-1];
+		b.maxheight = se401->height[se401->sizes-1];
+		b.minwidth = se401->width[0];
+		b.minheight = se401->height[0];
+
+		if (copy_to_user(arg, &b, sizeof(b)))
+			return -EFAULT;
+
+		return 0;
+	}
+	case VIDIOCGCHAN:
+	{
+		struct video_channel v;
+
+		if (copy_from_user(&v, arg, sizeof(v)))
+			return -EFAULT;
+		if (v.channel != 0)
+			return -EINVAL;
+
+		v.flags = 0;
+		v.tuners = 0;
+		v.type = VIDEO_TYPE_CAMERA;
+		strcpy(v.name, "Camera");
+
+		if (copy_to_user(arg, &v, sizeof(v)))
+			return -EFAULT;
+
+		return 0;
+	}
+	case VIDIOCSCHAN:
+	{
+		int v;
+
+		if (copy_from_user(&v, arg, sizeof(v)))
+			return -EFAULT;
+
+		if (v != 0)
+			return -EINVAL;
+
+		return 0;
+	}
+        case VIDIOCGPICT:
+        {
+		struct video_picture p;
+
+		se401_get_pict(se401, &p);
+
+		if (copy_to_user(arg, &p, sizeof(p)))
+			return -EFAULT;
+		return 0;
+	}
+	case VIDIOCSPICT:
+	{
+		struct video_picture p;
+
+		if (copy_from_user(&p, arg, sizeof(p)))
+			return -EFAULT;
+
+		if (se401_set_pict(se401, &p))
+			return -EINVAL;
+		return 0;
+	}
+	case VIDIOCSWIN:
+	{
+		struct video_window vw;
+
+		if (copy_from_user(&vw, arg, sizeof(vw)))
+			return -EFAULT;
+		if (vw.flags)
+			return -EINVAL;
+		if (vw.clipcount)
+			return -EINVAL;
+		if (se401_set_size(se401, vw.width, vw.height))
+			return -EINVAL;
+		
+		return 0;
+        }
+	case VIDIOCGWIN:
+	{
+		struct video_window vw;
+
+		vw.x = 0;               /* FIXME */
+		vw.y = 0;
+		vw.chromakey = 0;
+		vw.flags = 0;
+		vw.clipcount = 0;
+		vw.width = se401->cwidth;
+		vw.height = se401->cheight;
+
+		if (copy_to_user(arg, &vw, sizeof(vw)))
+			return -EFAULT;
+
+		return 0;
+	}
+	case VIDIOCGMBUF:
+	{
+		struct video_mbuf vm;
+		int i;
+
+		memset(&vm, 0, sizeof(vm));
+		vm.size = SE401_NUMFRAMES * se401->maxframesize;
+		vm.frames = SE401_NUMFRAMES;
+		for (i=0; i<SE401_NUMFRAMES; i++)
+			vm.offsets[i] = se401->maxframesize * i;
+
+		if (copy_to_user((void *)arg, (void *)&vm, sizeof(vm)))
+		return -EFAULT;
+
+		return 0;
+	}
+	case VIDIOCMCAPTURE:
+	{
+		struct video_mmap vm;
+
+		if (copy_from_user(&vm, arg, sizeof(vm)))
+		return -EFAULT;
+		if (vm.format != VIDEO_PALETTE_RGB24)
+			return -EINVAL;
+		if (vm.frame >= SE401_NUMFRAMES)
+			return -EINVAL;
+		if (se401->frame[vm.frame].grabstate != FRAME_UNUSED)
+			return -EBUSY;
+
+		/* Is this according to the v4l spec??? */
+		if (se401_set_size(se401, vm.width, vm.height))
+			return -EINVAL;
+		se401->frame[vm.frame].grabstate=FRAME_READY;
+
+		if (!se401->streaming)
+			se401_start_stream(se401);
+
+		/* Set the picture properties */
+		if (se401->framecount==0)
+			se401_send_pict(se401);
+		/* Calibrate the reset level after a few frames. */
+		if (se401->framecount%20==1)
+			se401_auto_resetlevel(se401);
+
+		return 0;
+	}
+	case VIDIOCSYNC:
+	{
+		int frame, ret=0;
+
+		if (copy_from_user((void *)&frame, arg, sizeof(int)))
+			return -EFAULT;
+
+		ret=se401_newframe(se401, frame);
+		se401->frame[frame].grabstate=FRAME_UNUSED;
+		return ret;
+	}
+	case VIDIOCGFBUF:
+	{
+		struct video_buffer vb;
+
+		memset(&vb, 0, sizeof(vb));
+		vb.base = NULL; /* frame buffer not supported, not used */
+
+		if (copy_to_user((void *)arg, (void *)&vb, sizeof(vb)))
+			return -EFAULT;
+
+		return 0;
+	}
+	case VIDIOCKEY:
+		return 0;
+	case VIDIOCCAPTURE:
+		return -EINVAL;
+	case VIDIOCSFBUF:
+		return -EINVAL;
+	case VIDIOCGTUNER:
+	case VIDIOCSTUNER:
+		return -EINVAL;
+	case VIDIOCGFREQ:
+	case VIDIOCSFREQ:
+		return -EINVAL;
+	case VIDIOCGAUDIO:
+	case VIDIOCSAUDIO:
+		return -EINVAL;
+        default:
+                return -ENOIOCTLCMD;
+        } /* end switch */
+
+        return 0;
+}
+
+static long se401_read(struct video_device *dev, char *buf, unsigned long count,
+ int noblock)
+{
+	int realcount=count, ret=0;
+	struct usb_se401 *se401 = (struct usb_se401 *)dev;
+
+
+	if (se401->dev == NULL)
+		return -EIO;
+	if (realcount > se401->cwidth*se401->cheight*3)
+		realcount=se401->cwidth*se401->cheight*3;
+
+	/* Shouldn't happen: */
+	if (se401->frame[0].grabstate==FRAME_GRABBING)
+		return -EBUSY;
+	se401->frame[0].grabstate=FRAME_READY;
+	se401->frame[1].grabstate=FRAME_UNUSED;
+	se401->curframe=0;
+
+	if (!se401->streaming)
+		se401_start_stream(se401);
+
+	/* Set the picture properties */
+	if (se401->framecount==0)
+		se401_send_pict(se401);
+	/* Calibrate the reset level after a few frames. */
+	if (se401->framecount%20==1)
+		se401_auto_resetlevel(se401);
+
+	ret=se401_newframe(se401, 0);
+
+	if (!ret) {
+		copy_to_user(buf, se401->frame[0].data, realcount);
+	} else {
+		realcount=ret;
+	}
+	se401->frame[0].grabstate=FRAME_UNUSED;
+
+	return realcount;
+}
+
+static int se401_mmap(struct video_device *dev, const char *adr,
+        unsigned long size)
+{
+	struct usb_se401 *se401 = (struct usb_se401 *)dev;
+	unsigned long start = (unsigned long)adr;
+	unsigned long page, pos;
+
+	down(&se401->lock);
+	
+	if (se401->dev == NULL) {
+		up(&se401->lock);
+		return -EIO;
+	}
+	if (size > (((SE401_NUMFRAMES * se401->maxframesize) + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1))) {
+		up(&se401->lock);
+		return -EINVAL;
+	}
+	pos = (unsigned long)se401->fbuf;
+	while (size > 0) {
+		page = kvirt_to_pa(pos);
+		if (remap_page_range(start, page, PAGE_SIZE, PAGE_SHARED)) {
+			up(&se401->lock);
+			return -EAGAIN;
+		}
+		start += PAGE_SIZE;
+		pos += PAGE_SIZE;
+		if (size > PAGE_SIZE)
+			size -= PAGE_SIZE;
+		else
+			size = 0;
+	}
+	up(&se401->lock);
+
+        return 0;
+}
+
+static struct video_device se401_template = {
+        name:           "se401 USB camera",
+        type:           VID_TYPE_CAPTURE,
+        hardware:       VID_HARDWARE_SE401,
+        open:           se401_open,
+        close:          se401_close,
+        read:           se401_read,
+        write:          se401_write,
+        ioctl:          se401_ioctl,
+        mmap:           se401_mmap,
+        initialize:     se401_init_done,
+};
+
+
+
+/***************************/
+static int se401_init(struct usb_se401 *se401)
+{
+        int i=0, rc;
+        unsigned char cp[0x40];
+	char temp[200];
+
+	/* led on */
+        se401_sndctrl(1, se401, SE401_REQ_LED_CONTROL, 1, NULL, 0);
+
+	/* get camera descriptor */
+	rc=se401_sndctrl(0, se401, SE401_REQ_GET_CAMERA_DESCRIPTOR, 0, cp, sizeof(cp));
+	if (cp[1]!=0x41) {
+		err("Wrong descriptor type");
+		return 1;
+	}
+	sprintf (temp, "ExtraFeatures: %d", cp[3]);
+
+	se401->sizes=cp[4]+cp[5]*256;
+	se401->width=kmalloc(se401->sizes*sizeof(int), GFP_KERNEL);
+	se401->height=kmalloc(se401->sizes*sizeof(int), GFP_KERNEL);
+	for (i=0; i<se401->sizes; i++) {
+		    se401->width[i]=cp[6+i*4+0]+cp[6+i*4+1]*256;
+		    se401->height[i]=cp[6+i*4+2]+cp[6+i*4+3]*256;
+	}
+	sprintf (temp, "%s Sizes:", temp);
+	for (i=0; i<se401->sizes; i++) {
+		sprintf(temp, "%s %dx%d", temp, se401->width[i], se401->height[i]);
+	}
+	info("%s", temp);
+	se401->maxframesize=se401->width[se401->sizes-1]*se401->height[se401->sizes-1]*3;
+
+	rc=se401_sndctrl(0, se401, SE401_REQ_GET_WIDTH, 0, cp, sizeof(cp));
+	se401->cwidth=cp[0]+cp[1]*256;
+	rc=se401_sndctrl(0, se401, SE401_REQ_GET_HEIGHT, 0, cp, sizeof(cp));
+	se401->cheight=cp[0]+cp[1]*256;
+
+	if (!cp[2] && SE401_FORMAT_BAYER) {
+		err("Bayer format not supported!");
+		return 1;
+	}
+	/* set output mode (BAYER) */
+        se401_sndctrl(1, se401, SE401_REQ_SET_OUTPUT_MODE, SE401_FORMAT_BAYER, NULL, 0);
+
+	rc=se401_sndctrl(0, se401, SE401_REQ_GET_BRT, 0, cp, sizeof(cp));
+	se401->brightness=cp[0]+cp[1]*256;
+	/* some default values */
+	se401->resetlevel=0x2d;
+	se401->rgain=0x20;
+	se401->ggain=0x20;
+	se401->bgain=0x20;
+	se401_set_exposure(se401, 20000);
+	se401->palette=VIDEO_PALETTE_RGB24;
+	se401->enhance=1;
+	se401->dropped=0;
+	se401->error=0;
+	se401->framecount=0;
+	se401->readcount=0;
+
+	/* Start interrupt transfers for snapshot button */
+	se401->inturb=usb_alloc_urb(0);
+	if (!se401->inturb) {
+		info("Allocation of inturb failed");
+		return 1;
+	}
+	FILL_INT_URB(se401->inturb, se401->dev,
+	    usb_rcvintpipe(se401->dev, SE401_BUTTON_ENDPOINT),
+	    &se401->button, sizeof(se401->button),
+	    se401_button_irq,
+	    se401,
+	    HZ/10
+	);
+	if (usb_submit_urb(se401->inturb)) {
+		info("int urb burned down");
+		return 1;
+	}
+	
+        /* Flash the led */
+        se401_sndctrl(1, se401, SE401_REQ_CAMERA_POWER, 1, NULL, 0);
+        se401_sndctrl(1, se401, SE401_REQ_LED_CONTROL, 1, NULL, 0);
+        se401_sndctrl(1, se401, SE401_REQ_CAMERA_POWER, 0, NULL, 0);
+	se401_sndctrl(1, se401, SE401_REQ_LED_CONTROL, 0, NULL, 0);
+
+        return 0;
+}
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 3, 0)
+static void* se401_probe(struct usb_device *dev, unsigned int ifnum)
+#else
+static void* __devinit se401_probe(struct usb_device *dev, unsigned int ifnum,
+	const struct usb_device_id *id)
+#endif
+{
+        struct usb_interface_descriptor *interface;
+        struct usb_se401 *se401;
+        char *camera_name=NULL;
+
+        /* We don't handle multi-config cameras */
+        if (dev->descriptor.bNumConfigurations != 1)
+                return NULL;
+
+        interface = &dev->actconfig->interface[ifnum].altsetting[0];
+
+        /* Is it an se401? */
+        if (dev->descriptor.idVendor == 0x03e8 &&
+            dev->descriptor.idProduct == 0x0004) {
+                camera_name="Endpoints/Aox SE401";
+        } else if (dev->descriptor.idVendor == 0x0471 &&
+            dev->descriptor.idProduct == 0x030b) {
+                camera_name="Philips PCVC665K";
+        } else if (dev->descriptor.idVendor == 0x047d &&
+	    dev->descriptor.idProduct == 0x5001) {
+		camera_name="Kensington VideoCAM 67014";
+        } else if (dev->descriptor.idVendor == 0x047d &&
+	    dev->descriptor.idProduct == 0x5002) {
+		camera_name="Kensington VideoCAM 6701(5/7)";
+        } else if (dev->descriptor.idVendor == 0x047d &&
+	    dev->descriptor.idProduct == 0x5003) {
+		camera_name="Kensington VideoCAM 67016";
+	} else
+		return NULL;
+
+        /* Checking vendor/product should be enough, but what the hell */
+        if (interface->bInterfaceClass != 0x00)
+                return NULL;
+        if (interface->bInterfaceSubClass != 0x00)
+                return NULL;
+
+        /* We found one */
+        info("SE401 camera found: %s", camera_name);
+
+        if ((se401 = kmalloc(sizeof(*se401), GFP_KERNEL)) == NULL) {
+                err("couldn't kmalloc se401 struct");
+                return NULL;
+        }
+
+        memset(se401, 0, sizeof(*se401));
+
+        se401->dev = dev;
+        se401->iface = interface->bInterfaceNumber;
+        se401->camera_name = camera_name;
+
+	info("firmware version: %02x", dev->descriptor.bcdDevice & 255);
+
+        if (se401_init(se401))
+		return NULL;
+	memcpy(&se401->vdev, &se401_template, sizeof(se401_template));
+	memcpy(se401->vdev.name, se401->camera_name, strlen(se401->camera_name));
+	if (video_register_device(&se401->vdev, VFL_TYPE_GRABBER, video_nr) == -1) {
+		err("video_register_device failed");
+		return NULL;
+	}
+	info("registered new video device: video%d", se401->vdev.minor);
+
+	init_waitqueue_head(&se401->wq);
+	init_MUTEX(&se401->lock);
+
+        return se401;
+}
+
+static void se401_disconnect(struct usb_device *dev, void *ptr)
+{
+	int i;
+	struct usb_se401 *se401 = (struct usb_se401 *) ptr;
+
+	/* We don't want people trying to open up the device */
+	if (!se401->user)
+              video_unregister_device(&se401->vdev);
+
+        usb_driver_release_interface(&se401_driver,
+                &se401->dev->actconfig->interface[se401->iface]);
+
+        se401->dev = NULL;
+        se401->frame[0].grabstate = FRAME_ERROR;
+        se401->frame[1].grabstate = FRAME_ERROR;
+
+	se401->streaming = 0;
+
+	if (waitqueue_active(&se401->wq))
+                wake_up_interruptible(&se401->wq);
+
+	for (i=0; i<SE401_NUMSBUF; i++) if (se401->urb[i]) {
+		se401->urb[i]->next = NULL;
+		usb_unlink_urb(se401->urb[i]);
+		usb_free_urb(se401->urb[i]);
+		se401->urb[i] = NULL;
+		kfree(se401->sbuf[i].data);
+	}
+	for (i=0; i<SE401_NUMSCRATCH; i++) if (se401->scratch[i].data) {
+		kfree(se401->scratch[i].data);
+	}
+	if (se401->inturb) {
+		usb_unlink_urb(se401->inturb);
+		usb_free_urb(se401->inturb);
+	}
+        info("%s disconnected", se401->camera_name);
+
+#if defined(CONFIG_PROC_FS) && defined(CONFIG_VIDEO_PROC_FS)
+	destroy_proc_se401_cam(se401);
+#endif
+
+        /* Free the memory */
+        if (!se401->user) {
+		kfree(se401->width);
+		kfree(se401->height);
+                kfree(se401);
+                se401 = NULL;
+        }
+}
+
+
+static struct usb_driver se401_driver = {
+        name:		"se401",
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 3, 0)
+        id_table:	device_table,
+#endif
+	probe:		se401_probe,
+        disconnect:	se401_disconnect
+};
+
+
+
+/****************************************************************************
+ *
+ *  Module routines
+ *
+ ***************************************************************************/
+
+static int __init usb_se401_init(void)
+{
+#if defined(CONFIG_PROC_FS) && defined(CONFIG_VIDEO_PROC_FS)
+	proc_se401_create();
+#endif
+
+	info("SE401 usb camera driver version %s registering", version);
+	if (flickerless)
+		if (flickerless!=50 && flickerless!=60) {
+			info("Invallid flickerless value, use 0, 50 or 60.");
+			return -1;
+	}
+	if (usb_register(&se401_driver) < 0)
+		return -1;
+	return 0;
+}
+
+static void __exit usb_se401_exit(void)
+{
+	usb_deregister(&se401_driver);
+	info("SE401 driver deregistered");
+
+#if defined(CONFIG_PROC_FS) && defined(CONFIG_VIDEO_PROC_FS)
+	proc_se401_destroy();
+#endif
+}
+
+module_init(usb_se401_init);
+module_exit(usb_se401_exit);
diff -urN linux-2.4.6-pre5/drivers/usb/se401.h linux/drivers/usb/se401.h
--- linux-2.4.6-pre5/drivers/usb/se401.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/usb/se401.h	Mon Dec  3 22:49:12 2001
@@ -0,0 +1,234 @@
+
+#ifndef __LINUX_se401_H
+#define __LINUX_se401_H
+
+#include <asm/uaccess.h>
+#include <linux/videodev.h>
+#include <linux/smp_lock.h>
+
+#define se401_DEBUG	/* Turn on debug messages */
+
+#ifdef se401_DEBUG
+#  define PDEBUG(level, fmt, args...) \
+if (debug >= level) info("[" __PRETTY_FUNCTION__ ":%d] " fmt, __LINE__ , ## args)
+#else
+#  define PDEBUG(level, fmt, args...) do {} while(0)
+#endif
+
+/* An almost drop-in replacement for sleep_on_interruptible */
+#define wait_interruptible(test, queue, wait) \
+{ \
+	add_wait_queue(queue, wait); \
+	set_current_state(TASK_INTERRUPTIBLE); \
+	if (test) \
+		schedule(); \
+	remove_wait_queue(queue, wait); \
+	set_current_state(TASK_RUNNING); \
+	if (signal_pending(current)) \
+		break; \
+}
+
+#define SE401_REQ_GET_CAMERA_DESCRIPTOR		0x06
+#define SE401_REQ_START_CONTINUOUS_CAPTURE	0x41
+#define SE401_REQ_STOP_CONTINUOUS_CAPTURE	0x42
+#define SE401_REQ_CAPTURE_FRAME			0x43
+#define SE401_REQ_GET_BRT			0x44
+#define SE401_REQ_SET_BRT			0x45
+#define SE401_REQ_GET_WIDTH			0x4c
+#define SE401_REQ_SET_WIDTH			0x4d
+#define SE401_REQ_GET_HEIGHT			0x4e
+#define SE401_REQ_SET_HEIGHT			0x4f
+#define SE401_REQ_GET_OUTPUT_MODE		0x50
+#define SE401_REQ_SET_OUTPUT_MODE		0x51
+#define SE401_REQ_GET_EXT_FEATURE		0x52
+#define SE401_REQ_SET_EXT_FEATURE		0x53
+#define SE401_REQ_CAMERA_POWER			0x56
+#define SE401_REQ_LED_CONTROL			0x57
+#define SE401_REQ_BIOS				0xff
+
+#define SE401_BIOS_READ				0x07
+
+#define SE401_FORMAT_BAYER	0x40
+
+/* Hyundai hv7131b registers
+   7121 and 7141 should be the same (haven't really checked...) */
+/* Mode registers: */
+#define HV7131_REG_MODE_A		0x00
+#define HV7131_REG_MODE_B		0x01
+#define HV7131_REG_MODE_C		0x02
+/* Frame registers: */
+#define HV7131_REG_FRSU		0x10
+#define HV7131_REG_FRSL		0x11
+#define HV7131_REG_FCSU		0x12
+#define HV7131_REG_FCSL		0x13
+#define HV7131_REG_FWHU		0x14
+#define HV7131_REG_FWHL		0x15
+#define HV7131_REG_FWWU		0x16
+#define HV7131_REG_FWWL		0x17
+/* Timing registers: */
+#define HV7131_REG_THBU		0x20
+#define HV7131_REG_THBL		0x21
+#define HV7131_REG_TVBU		0x22
+#define HV7131_REG_TVBL		0x23
+#define HV7131_REG_TITU		0x25
+#define HV7131_REG_TITM		0x26
+#define HV7131_REG_TITL		0x27
+#define HV7131_REG_TMCD		0x28
+/* Adjust Registers: */
+#define HV7131_REG_ARLV		0x30
+#define HV7131_REG_ARCG		0x31
+#define HV7131_REG_AGCG		0x32
+#define HV7131_REG_ABCG		0x33
+#define HV7131_REG_APBV		0x34
+#define HV7131_REG_ASLP		0x54
+/* Offset Registers: */
+#define HV7131_REG_OFSR		0x50
+#define HV7131_REG_OFSG		0x51
+#define HV7131_REG_OFSB		0x52
+/* REset level statistics registers: */
+#define HV7131_REG_LOREFNOH	0x57
+#define HV7131_REG_LOREFNOL	0x58
+#define HV7131_REG_HIREFNOH	0x59
+#define HV7131_REG_HIREFNOL	0x5a
+
+/* se401 registers */
+#define SE401_OPERATINGMODE	0x2000
+
+
+/* size of usb transfers */
+#define SE401_PACKETSIZE	4096
+/* number of queued bulk transfers to use, should be about 8 */
+#define SE401_NUMSBUF		1
+/* read the usb specs for this one :) */
+#define SE401_VIDEO_ENDPOINT	1
+#define SE401_BUTTON_ENDPOINT	2
+/* number of frames supported by the v4l part */
+#define SE401_NUMFRAMES		2
+/* scratch buffers for passing data to the decoders */
+#define SE401_NUMSCRATCH	32
+/* maximum amount of data in a JangGu packet */
+#define SE401_VLCDATALEN	1024
+/* number of nul sized packets to receive before kicking the camera */
+#define SE401_MAX_NULLPACKETS	4000
+/* number of decoding errors before kicking the camera */
+#define SE401_MAX_ERRORS	200
+
+struct usb_device;
+
+struct se401_sbuf {
+	unsigned char *data;
+};
+
+enum {
+	FRAME_UNUSED,		/* Unused (no MCAPTURE) */
+	FRAME_READY,		/* Ready to start grabbing */
+	FRAME_GRABBING,		/* In the process of being grabbed into */
+	FRAME_DONE,		/* Finished grabbing, but not been synced yet */
+	FRAME_ERROR,		/* Something bad happened while processing */
+};
+
+enum {
+	FMT_BAYER,
+	FMT_JANGGU,
+};
+
+enum {
+	BUFFER_UNUSED,
+	BUFFER_READY,
+	BUFFER_BUSY,
+	BUFFER_DONE,
+};
+
+struct se401_scratch {
+	unsigned char *data;
+	volatile int state;
+	int offset;
+	int length;
+};
+
+struct se401_frame {
+	unsigned char *data;		/* Frame buffer */
+
+	volatile int grabstate;	/* State of grabbing */
+
+	unsigned char *curline;
+	int curlinepix;
+	int curpix;
+};
+
+struct usb_se401 {
+	struct video_device vdev;
+
+	/* Device structure */
+	struct usb_device *dev;
+
+	unsigned char iface;
+
+	char *camera_name;
+
+	int change;
+	int brightness;
+	int hue;
+	int rgain;
+	int ggain;
+	int bgain;
+	int expose_h;
+	int expose_m;
+	int expose_l;
+	int resetlevel;
+	
+	int enhance;
+
+	int format;
+	int sizes;
+	int *width;
+	int *height;
+	int cwidth;		/* current width */
+	int cheight;		/* current height */
+	int palette;
+	int maxframesize;
+	int cframesize;		/* current framesize */
+
+	struct semaphore lock;
+	int user;		/* user count for exclusive use */
+
+	int streaming;		/* Are we streaming video? */
+
+	char *fbuf;		/* Videodev buffer area */
+
+	urb_t *urb[SE401_NUMSBUF];
+	urb_t *inturb;
+	
+	int button;
+	int buttonpressed;
+
+	int curframe;		/* Current receiving frame */
+	struct se401_frame frame[SE401_NUMFRAMES];	
+	int readcount;
+	int framecount;
+	int error;
+	int dropped;
+
+	int scratch_next;
+	int scratch_use;
+	int scratch_overflow;
+	struct se401_scratch scratch[SE401_NUMSCRATCH];
+
+	/* Decoder specific data: */
+	unsigned char vlcdata[SE401_VLCDATALEN];
+	int vlcdatapos;
+	int bayeroffset;
+
+	struct se401_sbuf sbuf[SE401_NUMSBUF];
+
+	wait_queue_head_t wq;	/* Processes waiting */
+
+	/* proc interface */
+	struct proc_dir_entry *proc_entry;	/* /proc/se401/videoX */
+
+	int nullpackets;
+};
+
+
+#endif
+
diff -urN linux-2.4.6-pre5/drivers/usb/serial/Config.in linux/drivers/usb/serial/Config.in
--- linux-2.4.6-pre5/drivers/usb/serial/Config.in	Fri Apr  6 15:51:50 2001
+++ linux/drivers/usb/serial/Config.in	Mon Dec  3 22:49:12 2001
@@ -28,6 +28,8 @@
      bool '    USB Keyspan USA-49W Firmware' CONFIG_USB_SERIAL_KEYSPAN_USA49W
   fi
   dep_tristate '  USB MCT Single Port Serial Driver (EXPERIMENTAL)' CONFIG_USB_SERIAL_MCT_U232 $CONFIG_USB_SERIAL $CONFIG_EXPERIMENTAL
+  dep_tristate '  USB Prolific 2303 Single Port Serial Driver (EXPERIMENTAL)' CONFIG_USB_SERIAL_PL2303 $CONFIG_USB_SERIAL $CONFIG_EXPERIMENTAL
+  dep_tristate '  USB REINER SCT cyberJack pinpad/e-com chipcard reader (EXPERIMENTAL)' CONFIG_USB_SERIAL_CYBERJACK $CONFIG_USB_SERIAL $CONFIG_EXPERIMENTAL
   dep_tristate '  USB ZyXEL omni.net LCD Plus Driver (EXPERIMENTAL)' CONFIG_USB_SERIAL_OMNINET $CONFIG_USB_SERIAL $CONFIG_EXPERIMENTAL
 fi
 
diff -urN linux-2.4.6-pre5/drivers/usb/serial/Makefile linux/drivers/usb/serial/Makefile
--- linux-2.4.6-pre5/drivers/usb/serial/Makefile	Mon Mar 19 17:21:54 2001
+++ linux/drivers/usb/serial/Makefile	Mon Dec  3 22:49:12 2001
@@ -18,6 +18,8 @@
 obj-$(CONFIG_USB_SERIAL_EMPEG)			+= empeg.o
 obj-$(CONFIG_USB_SERIAL_MCT_U232)		+= mct_u232.o
 obj-$(CONFIG_USB_SERIAL_EDGEPORT)		+= io_edgeport.o
+obj-$(CONFIG_USB_SERIAL_PL2303)			+= pl2303.o
+obj-$(CONFIG_USB_SERIAL_CYBERJACK)		+= cyberjack.o
  
 # Objects that export symbols.
 export-objs	:= usbserial.o
diff -urN linux-2.4.6-pre5/drivers/usb/serial/cyberjack.c linux/drivers/usb/serial/cyberjack.c
--- linux-2.4.6-pre5/drivers/usb/serial/cyberjack.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/usb/serial/cyberjack.c	Mon Dec  3 22:49:12 2001
@@ -0,0 +1,520 @@
+/*
+ *  REINER SCT cyberJack pinpad/e-com USB Chipcard Reader Driver
+ *
+ *  Copyright (C) 2001  REINER SCT
+ *  Author: Matthias Bruestle
+ *
+ *  Contact: linux-usb@sii.li (see MAINTAINERS)
+ *
+ *  This program is largely derived from work by the linux-usb group
+ *  and associated source files.  Please see the usb/serial files for
+ *  individual credits and copyrights.
+ *
+ *  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.
+ *
+ *  Thanks to Greg Kroah-Hartman (greg@kroah.com) for his help and
+ *  patience.
+ *
+ *  In case of problems, please write to the contact e-mail address
+ *  mentioned above.
+ */
+
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/signal.h>
+#include <linux/errno.h>
+#include <linux/poll.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/fcntl.h>
+#include <linux/tty.h>
+#include <linux/tty_driver.h>
+#include <linux/tty_flip.h>
+#include <linux/module.h>
+#include <linux/spinlock.h>
+#include <linux/usb.h>
+
+#ifdef CONFIG_USB_SERIAL_DEBUG
+	static int debug = 1;
+#else
+	static int debug;
+#endif
+
+#include "usb-serial.h"
+
+/*
+ * Version Information
+ */
+#define DRIVER_VERSION "v1.0"
+#define DRIVER_AUTHOR "Matthias Bruestle"
+#define DRIVER_DESC "REINER SCT cyberJack pinpad/e-com USB Chipcard Reader Driver"
+
+
+#define CYBERJACK_VENDOR_ID	0x0C4B
+#define CYBERJACK_PRODUCT_ID	0x0100
+
+/* Function prototypes */
+static int cyberjack_startup (struct usb_serial *serial);
+static void cyberjack_shutdown (struct usb_serial *serial);
+static int  cyberjack_open (struct usb_serial_port *port, struct file *filp);
+static void cyberjack_close (struct usb_serial_port *port, struct file *filp);
+static int cyberjack_write (struct usb_serial_port *port, int from_user,
+	const unsigned char *buf, int count);
+static void cyberjack_read_int_callback( struct urb *urb );
+static void cyberjack_read_bulk_callback (struct urb *urb);
+static void cyberjack_write_bulk_callback (struct urb *urb);
+
+static __devinitdata struct usb_device_id id_table [] = {
+	{ USB_DEVICE(CYBERJACK_VENDOR_ID, CYBERJACK_PRODUCT_ID) },
+	{ }			/* Terminating entry */
+};
+
+MODULE_DEVICE_TABLE (usb, id_table);
+
+struct usb_serial_device_type cyberjack_device = {
+	name:			"Reiner SCT Cyberjack USB card reader",
+	id_table:		id_table,
+	needs_interrupt_in:	MUST_HAVE,
+	needs_bulk_in:		MUST_HAVE,
+	needs_bulk_out:		MUST_HAVE,
+	num_interrupt_in:	1,
+	num_bulk_in:		1,
+	num_bulk_out:		1,
+	num_ports:		1,
+	startup:		cyberjack_startup,
+	shutdown:		cyberjack_shutdown,
+	open:			cyberjack_open,
+	close:			cyberjack_close,
+	write:			cyberjack_write,
+	read_int_callback:	cyberjack_read_int_callback,
+	read_bulk_callback:	cyberjack_read_bulk_callback,
+	write_bulk_callback:	cyberjack_write_bulk_callback,
+};
+
+struct cyberjack_private {
+	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 */
+};
+
+/* do some startup allocations not currently performed by usb_serial_probe() */
+static int cyberjack_startup (struct usb_serial *serial)
+{
+	struct cyberjack_private *priv;
+
+	dbg (__FUNCTION__);
+
+	/* allocate the private data structure */
+	serial->port->private = kmalloc(sizeof(struct cyberjack_private), GFP_KERNEL);
+	if (!serial->port->private)
+		return (-1); /* error */
+
+	/* set initial values */
+	priv = (struct cyberjack_private *)serial->port->private;
+	priv->rdtodo = 0;
+	priv->wrfilled = 0;
+	priv->wrsent = 0;
+
+	init_waitqueue_head(&serial->port->write_wait);
+
+	return( 0 );
+}
+
+static void cyberjack_shutdown (struct usb_serial *serial)
+{
+	int i;
+	
+	dbg (__FUNCTION__);
+
+	/* stop reads and writes on all ports */
+	for (i=0; i < serial->num_ports; ++i) {
+		while (serial->port[i].open_count > 0) {
+			cyberjack_close (&serial->port[i], NULL);
+		}
+		/* My special items, the standard routines free my urbs */
+		if (serial->port[i].private)
+			kfree(serial->port[i].private);
+	}
+}
+	
+static int  cyberjack_open (struct usb_serial_port *port, struct file *filp)
+{
+	struct cyberjack_private *priv;
+	int result = 0;
+
+	if (port_paranoia_check (port, __FUNCTION__))
+		return -ENODEV;
+
+	MOD_INC_USE_COUNT;
+
+	dbg(__FUNCTION__ " - port %d", port->number);
+
+	down (&port->sem);
+
+	++port->open_count;
+
+	if (!port->active) {
+		port->active = 1;
+		/* force low_latency on so that our tty_push actually forces
+		 * the data through, otherwise it is scheduled, and with high
+		 * data rates (like with OHCI) data can get lost.
+		 */
+		port->tty->low_latency = 1;
+
+		priv = (struct cyberjack_private *)port->private;
+		priv->rdtodo = 0;
+		priv->wrfilled = 0;
+		priv->wrsent = 0;
+
+		/* shutdown any bulk reads that might be going on */
+		usb_unlink_urb (port->write_urb);
+		usb_unlink_urb (port->read_urb);
+		usb_unlink_urb (port->interrupt_in_urb);
+
+		port->interrupt_in_urb->dev = port->serial->dev;
+		result = usb_submit_urb(port->interrupt_in_urb);
+		if (result)
+			err(" usb_submit_urb(read int) failed");
+		dbg(__FUNCTION__ " - usb_submit_urb(int urb)");
+	}
+
+	up (&port->sem);
+
+	return result;
+}
+
+static void cyberjack_close (struct usb_serial_port *port, struct file *filp)
+{
+	dbg(__FUNCTION__ " - port %d", port->number);
+
+	down (&port->sem);
+
+	--port->open_count;
+
+	if (port->open_count <= 0) {
+		/* shutdown any bulk reads that might be going on */
+		usb_unlink_urb (port->write_urb);
+		usb_unlink_urb (port->read_urb);
+		usb_unlink_urb (port->interrupt_in_urb);
+
+		port->active = 0;
+		port->open_count = 0;
+	}
+
+	up (&port->sem);
+	MOD_DEC_USE_COUNT;
+}
+
+static int cyberjack_write (struct usb_serial_port *port, int from_user, const unsigned char *buf, int count)
+{
+	struct usb_serial *serial = port->serial;
+	struct cyberjack_private *priv = (struct cyberjack_private *)port->private;
+	int result;
+	int wrexpected;
+
+	dbg(__FUNCTION__ " - port %d", port->number);
+	dbg(__FUNCTION__ " - from_user %d", from_user);
+
+	if (count == 0) {
+		dbg(__FUNCTION__ " - write request of 0 bytes");
+		return (0);
+	}
+
+	if (port->write_urb->status == -EINPROGRESS) {
+		dbg (__FUNCTION__ " - already writing");
+		return (0);
+	}
+
+	down (&port->sem);
+
+	if( (count+priv->wrfilled)>sizeof(priv->wrbuf) ) {
+		/* To much data  for buffer. Reset buffer. */
+		priv->wrfilled=0;
+		return (0);
+	}
+
+	/* Copy data */
+	if (from_user) {
+		copy_from_user(priv->wrbuf+priv->wrfilled, buf, count);
+	} else {
+		memcpy (priv->wrbuf+priv->wrfilled, buf, count);
+	}  
+	usb_serial_debug_data (__FILE__, __FUNCTION__, count,
+		priv->wrbuf+priv->wrfilled);
+	priv->wrfilled += count;
+
+	if( priv->wrfilled >= 3 ) {
+		wrexpected = ((int)priv->wrbuf[2]<<8)+priv->wrbuf[1]+3;
+		dbg(__FUNCTION__ " - expected data: %d", wrexpected);
+	} else {
+		wrexpected = sizeof(priv->wrbuf);
+	}
+
+	if( priv->wrfilled >= wrexpected ) {
+		/* We have enough data to begin transmission */
+		int length;
+
+		dbg(__FUNCTION__ " - transmitting data (frame 1)");
+		length = (wrexpected > port->bulk_out_size) ? port->bulk_out_size : wrexpected;
+
+		memcpy (port->write_urb->transfer_buffer, priv->wrbuf, length );
+		priv->wrsent=length;
+
+		/* set up our urb */
+		FILL_BULK_URB(port->write_urb, serial->dev, 
+			      usb_sndbulkpipe(serial->dev, port->bulk_out_endpointAddress),
+			      port->write_urb->transfer_buffer, length,
+			      ((serial->type->write_bulk_callback) ? 
+			       serial->type->write_bulk_callback : 
+			       cyberjack_write_bulk_callback), 
+			      port);
+
+		/* send the data out the bulk port */
+		result = usb_submit_urb(port->write_urb);
+		if (result) {
+			err(__FUNCTION__ " - failed submitting write urb, error %d", result);
+			/* Throw away data. No better idea what to do with it. */
+			priv->wrfilled=0;
+			priv->wrsent=0;
+			up (&port->sem);
+			return 0;
+		}
+
+		dbg(__FUNCTION__ " - priv->wrsent=%d",priv->wrsent);
+		dbg(__FUNCTION__ " - priv->wrfilled=%d",priv->wrfilled);
+
+		if( priv->wrsent>=priv->wrfilled ) {
+			dbg(__FUNCTION__ " - buffer cleaned");
+			memset( priv->wrbuf, 0, sizeof(priv->wrbuf) );
+			priv->wrfilled=0;
+			priv->wrsent=0;
+		}
+	}
+
+	up (&port->sem);
+	return (count);
+} 
+
+static void cyberjack_read_int_callback( struct urb *urb )
+{
+	struct usb_serial_port *port = (struct usb_serial_port *)urb->context;
+	struct cyberjack_private *priv = (struct cyberjack_private *)port->private;
+	struct usb_serial *serial;
+	unsigned char *data = urb->transfer_buffer;
+
+	dbg(__FUNCTION__ " - port %d", port->number);
+
+	/* the urb might have been killed. */
+	if (urb->status)
+		return;
+
+	if (port_paranoia_check (port, "cyberjack_read_interrupt")) return;
+
+	serial = port->serial;
+	if (serial_paranoia_check (serial, "cyberjack_read_interrupt")) return;
+
+	usb_serial_debug_data (__FILE__, __FUNCTION__, urb->actual_length, data);
+
+	/* React only to interrupts signaling a bulk_in transfer */
+	if( (urb->actual_length==4) && (data[0]==0x01) ) {
+		short old_rdtodo = priv->rdtodo;
+		int result;
+
+		/* This is a announcement of comming bulk_ins. */
+		unsigned short size = ((unsigned short)data[3]<<8)+data[2]+3;
+
+		if( (size>259) || (size==0) ) {
+			dbg( "Bad announced bulk_in data length: %d", size );
+			/* Dunno what is most reliable to do here. */
+			/* return; */
+		}
+
+		if( (old_rdtodo+size)<(old_rdtodo) ) {
+			dbg( "To many bulk_in urbs to do." );
+			return;
+		}
+
+		/* "+=" is probably more fault tollerant than "=" */
+		priv->rdtodo += size;
+
+		dbg(__FUNCTION__ " - rdtodo: %d", priv->rdtodo);
+
+		if( !old_rdtodo ) {
+			port->read_urb->dev = port->serial->dev;
+			result = usb_submit_urb(port->read_urb);
+			if( result )
+				err(__FUNCTION__ " - failed resubmitting read urb, error %d", result);
+			dbg(__FUNCTION__ " - usb_submit_urb(read urb)");
+		}
+	}
+}
+
+static void cyberjack_read_bulk_callback (struct urb *urb)
+{
+	struct usb_serial_port *port = (struct usb_serial_port *)urb->context;
+	struct cyberjack_private *priv = (struct cyberjack_private *)port->private;
+	struct usb_serial *serial = get_usb_serial (port, __FUNCTION__);
+	struct tty_struct *tty;
+	unsigned char *data = urb->transfer_buffer;
+	int i;
+	int result;
+
+	dbg(__FUNCTION__ " - port %d", port->number);
+	
+	if (!serial) {
+		dbg(__FUNCTION__ " - bad serial pointer, exiting");
+		return;
+	}
+
+	if (urb->status) {
+		usb_serial_debug_data (__FILE__, __FUNCTION__, urb->actual_length, urb->transfer_buffer);
+		dbg(__FUNCTION__ " - nonzero read bulk status received: %d", urb->status);
+		return;
+	}
+
+	usb_serial_debug_data (__FILE__, __FUNCTION__, urb->actual_length, data);
+
+	tty = port->tty;
+	if (urb->actual_length) {
+		for (i = 0; i < urb->actual_length ; ++i) {
+			/* if we insert more than TTY_FLIPBUF_SIZE characters, we drop them. */
+			if(tty->flip.count >= TTY_FLIPBUF_SIZE) {
+				tty_flip_buffer_push(tty);
+			}
+			/* this doesn't actually push the data through unless tty->low_latency is set */
+			tty_insert_flip_char(tty, data[i], 0);
+		}
+	  	tty_flip_buffer_push(tty);
+	}
+
+	/* Reduce urbs to do by one. */
+	priv->rdtodo-=urb->actual_length;
+	/* Just to be sure */
+	if( priv->rdtodo<0 ) priv->rdtodo=0;
+
+	dbg(__FUNCTION__ " - rdtodo: %d", priv->rdtodo);
+
+	/* Continue to read if we have still urbs to do. */
+	if( priv->rdtodo /* || (urb->actual_length==port->bulk_in_endpointAddress)*/ ) {
+		port->read_urb->dev = port->serial->dev;
+		result = usb_submit_urb(port->read_urb);
+		if (result)
+			err(__FUNCTION__ " - failed resubmitting read urb, error %d", result);
+		dbg(__FUNCTION__ " - usb_submit_urb(read urb)");
+	}
+}
+
+static void cyberjack_write_bulk_callback (struct urb *urb)
+{
+	struct usb_serial_port *port = (struct usb_serial_port *)urb->context;
+	struct cyberjack_private *priv = (struct cyberjack_private *)port->private;
+	struct usb_serial *serial = get_usb_serial (port, __FUNCTION__);
+
+	dbg(__FUNCTION__ " - port %d", port->number);
+	
+	if (!serial) {
+		dbg(__FUNCTION__ " - bad serial pointer, exiting");
+		return;
+	}
+
+	if (urb->status) {
+		dbg(__FUNCTION__ " - nonzero write bulk status received: %d", urb->status);
+		return;
+	}
+
+	/* only do something if we have more data to send */
+	if( priv->wrfilled ) {
+		int length, blksize, result;
+
+		if (port->write_urb->status == -EINPROGRESS) {
+			dbg (__FUNCTION__ " - already writing");
+			return;
+		}
+
+		down (&port->sem);
+
+		dbg(__FUNCTION__ " - transmitting data (frame n)");
+
+		length = ((priv->wrfilled - priv->wrsent) > port->bulk_out_size) ?
+			port->bulk_out_size : (priv->wrfilled - priv->wrsent);
+
+		memcpy (port->write_urb->transfer_buffer, priv->wrbuf + priv->wrsent,
+			length );
+		priv->wrsent+=length;
+
+		/* set up our urb */
+		FILL_BULK_URB(port->write_urb, serial->dev, 
+			      usb_sndbulkpipe(serial->dev, port->bulk_out_endpointAddress),
+			      port->write_urb->transfer_buffer, length,
+			      ((serial->type->write_bulk_callback) ? 
+			       serial->type->write_bulk_callback : 
+			       cyberjack_write_bulk_callback), 
+			      port);
+
+		/* send the data out the bulk port */
+		result = usb_submit_urb(port->write_urb);
+		if (result) {
+			err(__FUNCTION__ " - failed submitting write urb, error %d", result);
+			/* Throw away data. No better idea what to do with it. */
+			priv->wrfilled=0;
+			priv->wrsent=0;
+			up (&port->sem);
+			queue_task(&port->tqueue, &tq_immediate);
+			mark_bh(IMMEDIATE_BH);
+			return;
+		}
+
+		dbg(__FUNCTION__ " - priv->wrsent=%d",priv->wrsent);
+		dbg(__FUNCTION__ " - priv->wrfilled=%d",priv->wrfilled);
+
+		blksize = ((int)priv->wrbuf[2]<<8)+priv->wrbuf[1]+3;
+
+		if( (priv->wrsent>=priv->wrfilled) || (priv->wrsent>=blksize) ) {
+			dbg(__FUNCTION__ " - buffer cleaned");
+			memset( priv->wrbuf, 0, sizeof(priv->wrbuf) );
+			priv->wrfilled=0;
+			priv->wrsent=0;
+		}
+
+		up (&port->sem);
+		queue_task(&port->tqueue, &tq_immediate);
+		mark_bh(IMMEDIATE_BH);
+		return;
+	}
+
+	queue_task(&port->tqueue, &tq_immediate);
+	mark_bh(IMMEDIATE_BH);
+	
+	return;
+}
+
+static int __init cyberjack_init (void)
+{
+	usb_serial_register (&cyberjack_device);
+
+	info(DRIVER_VERSION " " DRIVER_AUTHOR);
+	info(DRIVER_DESC);
+
+	return 0;
+}
+
+static void __exit cyberjack_exit (void)
+{
+	usb_serial_deregister (&cyberjack_device);
+}
+
+module_init(cyberjack_init);
+module_exit(cyberjack_exit);
+
+MODULE_AUTHOR( DRIVER_AUTHOR );
+MODULE_DESCRIPTION( DRIVER_DESC );
+
+MODULE_PARM(debug, "i");
+MODULE_PARM_DESC(debug, "Debug enabled or not");
+
diff -urN linux-2.4.6-pre5/drivers/usb/serial/pl2303.c linux/drivers/usb/serial/pl2303.c
--- linux-2.4.6-pre5/drivers/usb/serial/pl2303.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/usb/serial/pl2303.c	Mon Dec  3 22:49:12 2001
@@ -0,0 +1,844 @@
+/*
+ * Prolific PL2303 USB to serial adaptor driver
+ *
+ * Copyright (C) 2001 Greg Kroah-Hartman (greg@kroah.com)
+ *
+ * Original driver for 2.2.x by anonymous
+ *
+ *	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.
+ *
+ * See Documentation/usb/usb-serial.txt for more information on using this driver
+ *
+ * 2001_Jun_06 gkh
+ *	finished porting to 2.4 format.
+ * 
+ */
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/signal.h>
+#include <linux/errno.h>
+#include <linux/poll.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/fcntl.h>
+#include <linux/tty.h>
+#include <linux/tty_driver.h>
+#include <linux/tty_flip.h>
+#include <linux/serial.h>
+#include <linux/module.h>
+#include <linux/spinlock.h>
+#include <linux/usb.h>
+
+#ifdef CONFIG_USB_SERIAL_DEBUG
+	static int debug = 1;
+#else
+	static int debug;
+#endif
+
+#include "usb-serial.h"
+#include "pl2303.h"
+
+/*
+ * Version Information
+ */
+#define DRIVER_VERSION "v0.5"
+#define DRIVER_DESC "Prolific PL2303 USB to serial adaptor driver"
+
+
+#ifndef MIN
+#define MIN(a,b)        ((a) < (b) ? (a) : (b))
+#endif
+
+
+#define	PL2303_LOCK(port,flags)					\
+		do {						\
+		spin_lock_irqsave(&((struct pl2303_private *)(port->private))->lock, flags);	\
+		} while (0)
+
+#define	PL2303_UNLOCK(port,flags)				\
+		do {						\
+		spin_unlock_irqrestore(&((struct pl2303_private *)(port->private))->lock, flags);	\
+		} while (0)
+
+
+
+static __devinitdata struct usb_device_id id_table [] = {
+	{ USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID) },
+	{ USB_DEVICE(ATEN_VENDOR_ID, ATEN_PRODUCT_ID) },
+	{ }					/* Terminating entry */
+};
+
+MODULE_DEVICE_TABLE (usb, id_table);
+
+struct pl2303_private {
+	spinlock_t	lock;
+	unsigned char	*xmit_buf;
+	int		xmit_head;
+	int		xmit_tail;
+	int		xmit_cnt;
+};
+
+/* function prototypes for a PL2303 serial converter */
+static int pl2303_startup (struct usb_serial *serial);
+static int pl2303_open (struct usb_serial_port *port, struct file *filp);
+static void pl2303_close (struct usb_serial_port *port, struct file *filp);
+static void pl2303_set_termios (struct usb_serial_port *port,
+				struct termios *old);
+static int pl2303_ioctl (struct usb_serial_port *port, struct file *file,
+			 unsigned int cmd, unsigned long arg);
+static void pl2303_throttle (struct usb_serial_port *port);
+static void pl2303_unthrottle (struct usb_serial_port *port);
+static void pl2303_read_int_callback (struct urb *urb);
+static void pl2303_read_bulk_callback (struct urb *urb);
+static void pl2303_write_bulk_callback (struct urb *urb);
+static int pl2303_write (struct usb_serial_port *port, int from_user,
+			 const unsigned char *buf, int count);
+static int pl2303_write_room(struct usb_serial_port *port);
+static int pl2303_chars_in_buffer(struct usb_serial_port *port);
+static void pl2303_break_ctl(struct usb_serial_port *port,int break_state);
+static void start_xmit (struct usb_serial_port *port);
+
+
+/* All of the device info needed for the PL2303 SIO serial converter */
+static struct usb_serial_device_type pl2303_device = {
+	name:			"PL-2303",
+	id_table:		id_table,
+	needs_interrupt_in:	DONT_CARE,		/* this device must have an interrupt in endpoint */
+	needs_bulk_in:		MUST_HAVE,		/* this device must have a bulk in endpoint */
+	needs_bulk_out:		MUST_HAVE,		/* this device must have a bulk out endpoint */
+	num_interrupt_in:	NUM_DONT_CARE,
+	num_bulk_in:		1,
+	num_bulk_out:		1,
+	num_ports:		1,
+	open:			pl2303_open,
+	close:			pl2303_close,
+	throttle:		pl2303_throttle,
+	unthrottle:		pl2303_unthrottle,
+	write:			pl2303_write,
+	ioctl:			pl2303_ioctl,
+	write_room:		pl2303_write_room,
+	chars_in_buffer:	pl2303_chars_in_buffer,
+	break_ctl:		pl2303_break_ctl,
+	set_termios:		pl2303_set_termios,
+	read_bulk_callback:	pl2303_read_bulk_callback,
+	read_int_callback:	pl2303_read_int_callback,
+	write_bulk_callback:	pl2303_write_bulk_callback,
+	startup:		pl2303_startup,
+};
+
+
+#define WDR_TIMEOUT (HZ * 5 )   /* default urb timeout */
+
+static unsigned char *tmp_buf;
+static DECLARE_MUTEX (tmp_buf_sem);
+
+
+
+static int
+pl2303_write (struct usb_serial_port *port, int from_user,
+	      const unsigned char *buf, int count)
+{				/* pl2303_write */
+	struct pl2303_private *info = (struct pl2303_private *)port->private;
+	unsigned long flags;
+	int c,ret=0;
+	struct tty_struct *tty=port->tty;
+
+	dbg ("pl2303_write port %d, %d bytes", port->number, count);
+
+	if (!info) {
+		return -ENODEV;
+	}
+
+	if (!tty || !info->xmit_buf || !tmp_buf) {
+		return 0;
+	}
+
+
+	PL2303_LOCK(port,flags);
+
+
+	if (from_user) {
+		down(&tmp_buf_sem);
+		while (1) {
+			c = MIN(count, MIN(SERIAL_XMIT_SIZE - info->xmit_cnt - 1,
+					   SERIAL_XMIT_SIZE - info->xmit_head));
+			if (c <= 0)
+				break;
+
+			c -= copy_from_user(tmp_buf, buf, c);
+			if (!c) {
+				if (!ret) {
+					ret = -EFAULT;
+				}
+				break;
+			}
+			c = MIN(c, MIN(SERIAL_XMIT_SIZE - info->xmit_cnt - 1,
+				       SERIAL_XMIT_SIZE - info->xmit_head));
+			memcpy(info->xmit_buf + info->xmit_head, tmp_buf, c);
+			info->xmit_head = ((info->xmit_head + c) & (SERIAL_XMIT_SIZE-1));
+			info->xmit_cnt += c;
+			buf += c;
+			count -= c;
+			ret += c;
+		}
+		up(&tmp_buf_sem);
+	} else {
+		while (1) {
+			c = MIN(count, MIN(SERIAL_XMIT_SIZE - info->xmit_cnt - 1, 
+					   SERIAL_XMIT_SIZE - info->xmit_head));
+			if (c <= 0) {
+				break;
+			}
+			memcpy(info->xmit_buf + info->xmit_head, buf, c);
+			info->xmit_head = (info->xmit_head + c) & (SERIAL_XMIT_SIZE-1);
+			info->xmit_cnt += c;
+			buf += c;
+			count -= c;
+			ret += c;
+		}
+	}
+	PL2303_UNLOCK(port, flags);
+
+	if (info->xmit_cnt && !tty->stopped && !tty->hw_stopped) {
+		start_xmit(port);
+	}
+	return ret;
+}
+
+static int pl2303_write_room(struct usb_serial_port *port)
+{
+	struct pl2303_private *info = (struct pl2303_private *)port->private;
+	int     ret;
+
+	if (!info)
+		return 0;
+
+	ret = SERIAL_XMIT_SIZE - info->xmit_cnt - 1;
+	if (ret < 0)
+		ret = 0;
+	return ret;
+}
+
+static int pl2303_chars_in_buffer(struct usb_serial_port *port)
+{
+	struct pl2303_private *info = (struct pl2303_private *)port->private;
+
+	if (!info)
+		return 0;
+
+	return info->xmit_cnt;
+}
+
+static void pl2303_throttle(struct usb_serial_port *port)
+{
+#if 0
+	//struct usb_serial *serial = port->serial;
+	struct tty_struct *tty=port->tty;
+	unsigned long flags;
+
+
+	char    buf[64];
+
+	dbg("throttle %s: %d....", tty_name(tty, buf),
+	    tty->ldisc.chars_in_buffer(tty));
+
+//FIXME FIXME FIXME	
+	if (I_IXOFF(tty))
+		rs_send_xchar(tty, STOP_CHAR(tty));
+
+	PL2303_LOCK(port,flags);
+	//Should remove read request if one is present
+	PL2303_UNLOCK(port,flags);
+#endif
+}
+
+static void pl2303_unthrottle(struct usb_serial_port *port)
+{
+#if 0
+	//struct usb_serial *serial = port->serial;
+	struct tty_struct *tty=port->tty;
+	unsigned long flags;
+
+
+	char    buf[64];
+
+	dbg("unthrottle %s: %d....", tty_name(tty, buf),
+	    tty->ldisc.chars_in_buffer(tty));
+
+	//FIXME FIXME FIXME FIXME FIXME
+	if (I_IXOFF(tty)) {
+		if (info->x_char)
+			info->x_char = 0;
+		else
+			rs_send_xchar(tty, START_CHAR(tty));
+	}
+
+	PL2303_LOCK(port,flags);
+	//Should add read request if one is not present
+	PL2303_UNLOCK(fport,flags);
+#endif
+}
+
+
+static void
+pl2303_set_termios (struct usb_serial_port *port, struct termios *old_termios)
+{				/* pl2303_set_termios */
+	struct usb_serial *serial = port->serial;
+	unsigned int cflag = port->tty->termios->c_cflag;
+	unsigned char buf[7] = { 0, 0, 0, 0, 0, 0, 0};
+	int baud;
+	int i;
+
+
+	dbg ("pl2303_set_termios port %d", port->number);
+
+
+	i = usb_control_msg (serial->dev, usb_rcvctrlpipe (serial->dev, 0),
+			     0x21, 0xa1, 0, 0, buf, 7, 100);
+
+	dbg ("0xa1:0x21:0:0  %d - %x %x %x %x %x %x %x", i,
+	     buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6]);
+
+
+	i = usb_control_msg (serial->dev, usb_sndctrlpipe (serial->dev, 0),
+			     1, 0x40, 0, 1, NULL, 0, 100);
+
+	dbg ("0x40:1:0:1  %d", i);
+
+
+
+	if (cflag & CSIZE) {
+		switch (cflag & CSIZE) {
+			case CS6:
+				buf[6] = 6;
+				dbg ("Setting CS6");
+				break;
+			case CS7:
+				buf[6] = 7;
+				dbg ("Setting CS7");
+				break;
+			case CS8:
+				buf[6] = 8;
+				dbg ("Setting CS8");
+				break;
+			default:
+				err ("CSIZE was set but not CS6-CS8");
+		}
+	}
+
+	baud = 0;
+	switch (cflag & CBAUD) {
+		case B0:
+			err ("Can't do B0 yet");  //FIXME
+			break;
+		case B300:
+			baud = 300;
+			break;
+		case B600:
+			baud = 600;
+			break;
+		case B1200:
+			baud = 1200;
+			break;
+		case B2400:
+			baud = 2400;
+			break;
+		case B4800:
+			baud = 4800;
+			break;
+		case B9600:
+			baud = 9600;
+			break;
+		case B19200:
+			baud = 19200;
+			break;
+		case B38400:
+			baud = 38400;
+			break;
+		case B57600:
+			baud = 57600;
+			break;
+		case B115200:
+			baud = 115200;
+			break;
+		default:
+			dbg ("pl2303 driver does not support the baudrate requested (fix it)");
+			break;
+	}
+
+	if (baud) {
+		buf[0] = baud & 0xff;
+		buf[1] = (baud >> 8) & 0xff;
+		buf[2] = (baud >> 16) & 0xff;
+		buf[3] = (baud >> 24) & 0xff;
+	}
+
+
+	/* For reference buf[4]=1 is 1.5 stop bits */
+
+	if (cflag & CSTOPB) {
+		buf[4] = 2;
+	}
+
+
+	if (cflag & PARENB) {
+		/* For reference buf[5]=3 is mark parity */
+		/* For reference buf[5]=4 is space parity */
+		if (cflag & PARODD) {
+			buf[5] = 1;
+		} else {
+			buf[5] = 2;
+		}
+	}
+
+	i = usb_control_msg (serial->dev, usb_sndctrlpipe (serial->dev, 0),
+			     0x20, 0x21, 0, 0, buf, 7, 100);
+
+	dbg ("0x21:0x20:0:0  %d", i);
+
+	i = usb_control_msg (serial->dev, usb_sndctrlpipe (serial->dev, 0),
+			     0x22, 0x21, 1, 0, NULL, 0, 100);
+
+	dbg ("0x21:0x22:1:0  %d", i);
+
+	i = usb_control_msg (serial->dev, usb_sndctrlpipe (serial->dev, 0),
+			     0x22, 0x21, 3, 0, NULL, 0, 100);
+
+	dbg ("0x21:0x22:3:0  %d", i);
+
+	buf[0] = buf[1] = buf[2] = buf[3] = buf[4] = buf[5] = buf[6] = 0;
+
+	i = usb_control_msg (serial->dev, usb_rcvctrlpipe (serial->dev, 0),
+			     0x21, 0xa1, 0, 0, buf, 7, 100);
+
+	dbg ("0xa1:0x21:0:0  %d - %x %x %x %x %x %x %x", i,
+	     buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6]);
+
+	if (cflag & CRTSCTS) {
+
+		i = usb_control_msg (serial->dev, usb_sndctrlpipe (serial->dev, 0),
+				     0x01, 0x40, 0x0, 0x41, NULL, 0, 100);
+
+		dbg ("0x40:0x1:0x0:0x41  %d", i);
+
+	}
+
+
+	return;
+}       
+
+
+static int
+pl2303_open (struct usb_serial_port *port, struct file *filp)
+{				/* pl2303_open */
+	struct termios tmp_termios;
+	struct usb_serial *serial = port->serial;
+	unsigned char buf[10];
+	int i;
+
+	dbg ("pl2303_open port %d", port->number);
+
+	port->active++;
+
+#define FISH(a,b,c,d) \
+	i=usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev,0), \
+		    b, a,c  , d, buf, 1, 100); \
+	dbg("0x%x:0x%x:0x%x:0x%x  %d - %x",a,b,c,d,i,buf[0]);
+
+#define SOUP(a,b,c,d) \
+	i=usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev,0), \
+		    b, a,c  , d, NULL, 0, 100); \
+	dbg("0x%x:0x%x:0x%x:0x%x  %d",a,b,c,d,i);
+
+
+	FISH (0xc0, 1, 0x8484, 0);
+	SOUP (0x40, 1, 0x0404, 0);
+	FISH (0xc0, 1, 0x8484, 0);
+	FISH (0xc0, 1, 0x8383, 0);
+	FISH (0xc0, 1, 0x8484, 0);
+	SOUP (0x40, 1, 0x0404, 1);
+	FISH (0xc0, 1, 0x8484, 0);
+	FISH (0xc0, 1, 0x8383, 0);
+	SOUP (0x40, 1, 0, 1);
+	SOUP (0x40, 1, 1, 0xc0);
+	SOUP (0x40, 1, 2, 4);
+
+	/* Setup termios */
+
+	if (port->active == 1) {
+		*(port->tty->termios) = tty_std_termios;
+		port->tty->termios->c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL;
+	}
+
+
+	pl2303_set_termios (port, &tmp_termios);
+
+	//FIXME: need to assert RTS and DTR if CRTSCTS off
+
+
+	if (port->active == 1) {
+		struct pl2303_private *info;
+		unsigned long flags,page;
+		int i;
+
+		info = (struct pl2303_private *)kmalloc (sizeof(struct pl2303_private), GFP_KERNEL);
+		if (info == NULL) {
+			err(__FUNCTION__ " - out of memory");
+			pl2303_close (port, NULL);
+			return -ENOMEM;
+		}
+		spin_lock_init(&info->lock);
+		port->private = info;
+
+
+		page = get_free_page(GFP_KERNEL);
+		if (!page) {
+			pl2303_close (port, NULL);
+			return -ENOMEM;
+		}
+
+		PL2303_LOCK(port,flags);
+
+		info->xmit_cnt = info->xmit_head = info->xmit_tail = 0;
+
+		if (tmp_buf)
+			free_page(page);
+		else
+			tmp_buf	= (unsigned char *) page;
+
+		PL2303_UNLOCK(port,flags);
+
+		page = get_free_page(GFP_KERNEL);
+		if (!page) {
+			pl2303_close (port, NULL);
+			return -ENOMEM;
+		}
+
+		PL2303_LOCK(port,flags);
+
+		if (info->xmit_buf)
+			free_page(page);
+		else
+			info->xmit_buf=(unsigned char *) page;
+
+		PL2303_UNLOCK(port,flags);
+
+
+		if ((i = usb_submit_urb (port->read_urb))) {
+			err ("usb_submit_urb(read bulk 1) failed");
+			dbg ("i=%d", i);
+			pl2303_close (port, NULL);
+			return -EPROTO;
+
+		}
+
+		if ((i = usb_submit_urb (port->interrupt_in_urb))) {
+			err ("usb_submit_urb(interrupt ink) failed");
+			dbg ("i=%d", i);
+			pl2303_close (port, NULL);
+
+			return -EPROTO;
+		}
+	}
+
+	return(0);
+}				/* pl2303_open */
+
+
+static void
+pl2303_close (struct usb_serial_port *port, struct file *filp)
+{				/* pl2303_close */
+	struct pl2303_private *info;
+	unsigned int c_cflag = port->tty->termios->c_cflag;
+	unsigned long flags;
+
+	dbg ("pl2303_close port %d", port->number);
+
+	/* shutdown our bulk reads and writes */
+	if (port->active == 1) {
+
+		if (c_cflag & HUPCL) {
+			//FIXME: Do drop DTR
+			//FIXME: Do drop RTS
+		}
+
+		usb_unlink_urb (port->write_urb);
+		usb_unlink_urb (port->read_urb);
+		usb_unlink_urb (port->interrupt_in_urb);
+
+		info = (struct pl2303_private *)port->private;
+		if (info) {
+			PL2303_LOCK(port,flags);
+			if (info->xmit_buf) {
+				unsigned char * temp;
+				temp = info->xmit_buf;
+				info->xmit_buf = 0;
+				free_page((unsigned long) temp);
+			}
+			PL2303_UNLOCK(port,flags);
+		}
+
+		//FIXME: tmp_buf memory leak
+
+
+	}
+	port->active--;
+}				/* pl2303_close */
+
+
+/* do some startup allocations not currently performed by usb_serial_probe() */
+static int
+pl2303_startup (struct usb_serial *serial)
+{
+	return(0);
+}
+
+
+static int
+pl2303_ioctl (struct usb_serial_port *port, struct file *file,
+	      unsigned int cmd, unsigned long arg)
+{
+// struct usb_serial *serial = port->serial;
+// __u16 urb_value=0; /* Will hold the new flags */
+// char buf[1];
+// int  ret, mask;
+
+
+	dbg ("pl2303_sio ioctl 0x%04x", cmd);
+
+	/* Based on code from acm.c and others */
+	switch (cmd) {
+		
+		case TIOCMGET:
+			dbg ("TIOCMGET");
+
+
+			return put_user (0, (unsigned long *) arg);
+			break;
+		case TIOCMBIS:
+		case TIOCMBIC:
+		case TIOCMSET:
+			return 0;
+
+		default:
+			/* This is not an error - turns out the higher layers will do 
+			 *  some ioctls itself (see comment above)
+			 */
+			dbg ("pl2303_sio ioctl arg not supported - it was 0x%04x", cmd);
+			return(-ENOIOCTLCMD);
+			break;
+	}
+	dbg ("pl2303_ioctl returning 0");
+
+	return 0;
+}				/* pl2303_ioctl */
+
+
+static void pl2303_break_ctl(struct usb_serial_port *port,int break_state)
+{
+//FIXME
+}
+
+
+static void
+pl2303_read_int_callback (struct urb *urb)
+{
+	struct usb_serial_port *port = (struct usb_serial_port *) urb->context;
+	struct usb_serial *serial = get_usb_serial (port, "pl2303_read_int_callback");
+	//unsigned char *data = urb->transfer_buffer;
+	//int i;
+
+//ints auto restart...
+
+	if (!serial) {
+		return;
+	}
+
+	if (urb->status) {
+		urb->status = 0;
+		return;
+	}
+
+
+#if 0
+//FIXME need to update state of terminal lines variable
+	if (urb->actual_length) {
+		printk (KERN_DEBUG __FILE__ ": INT data read - length = %d, data = ",
+			urb->actual_length);
+		for (i = 0; i < urb->actual_length; ++i) {
+			printk ("%.2x ", data[i]);
+		}
+		printk ("\n");
+	}
+#endif
+
+	return;
+}
+
+static void
+pl2303_read_bulk_callback (struct urb *urb)
+{
+	struct usb_serial_port *port = (struct usb_serial_port *) urb->context;
+	struct usb_serial *serial = get_usb_serial (port, "pl2303_read_bulk_callback");
+	struct tty_struct *tty;
+	unsigned char *data = urb->transfer_buffer;
+	int i;
+
+	if (!serial) {
+		return;
+	}
+
+// PL2303 mysteriously fails with -EPROTO reschedule the read
+	if (urb->status) {
+		urb->status = 0;
+		if (usb_submit_urb (urb))
+			dbg ("failed resubmitting read bulk urb");
+		return;
+	}
+
+	if (debug) {
+		if (urb->actual_length) {
+			printk (KERN_DEBUG __FILE__ ": BULK data read - length = %d, data = ",
+				urb->actual_length);
+			for (i = 0; i < urb->actual_length; ++i) {
+				printk ("%.2x ", data[i]);
+			}
+			printk ("\n");
+		}
+	}
+
+	tty = port->tty;
+	if (urb->actual_length) {
+		for (i = 0; i < urb->actual_length; ++i) {
+			if (tty->flip.count >= TTY_FLIPBUF_SIZE) {
+				dbg ("ARGH ------------ Flip buffer overrun...");
+
+				break;
+			}
+			tty_insert_flip_char (tty, data[i], 0);
+		}
+		tty_flip_buffer_push (tty);
+	}
+
+
+	/* Schedule the next read*/
+	if (usb_submit_urb (urb))
+		dbg ("failed submitting read bulk urb");
+
+	return;
+}
+
+
+
+static void
+pl2303_write_bulk_callback (struct urb *urb)
+{
+	struct usb_serial_port *port = (struct usb_serial_port *) urb->context;
+	struct usb_serial *serial;
+	struct tty_struct *tty = port->tty;
+
+	dbg ("pl2303_write_bulk_callback");
+
+
+	if (port_paranoia_check (port, "pl2303_write_bulk_callback")) {
+		return;
+	}
+
+	serial = port->serial;
+	if (serial_paranoia_check (serial, "pl2303_write_bulk_callback")) {
+		return;
+	}
+
+
+	if (urb->status) {
+		dbg ("Overflow in write");
+		dbg ("nonzero write bulk status received: %d", urb->status);
+		//need to resubmit frame;
+
+		port->write_urb->transfer_buffer_length = 1;
+
+		//Resubmit ourselves
+
+		if (usb_submit_urb (port->write_urb))
+			err ("usb_submit_urb(write bulk) failed");
+
+		return;
+	}
+
+	wake_up_interruptible (&port->write_wait);
+
+	if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && tty->ldisc.write_wakeup)
+		(tty->ldisc.write_wakeup) (tty);
+
+	wake_up_interruptible (&tty->write_wait);
+
+	start_xmit(port);
+
+	return;
+}
+
+
+
+static void
+start_xmit (struct usb_serial_port *port)
+{
+	struct usb_serial *serial;
+	struct pl2303_private *info;
+	unsigned long flags;
+
+	serial = port->serial;
+	info = (struct pl2303_private *)port->private;
+
+	if (info) {
+		PL2303_LOCK(port,flags);
+
+		if (port->write_urb->status != -EINPROGRESS) {
+			if (info->xmit_tail != info->xmit_head) {
+
+				memcpy (port->write_urb->transfer_buffer, &info->xmit_buf[info->xmit_tail],1);
+				info->xmit_cnt--;
+				info->xmit_tail = (info->xmit_tail + 1) & (SERIAL_XMIT_SIZE - 1);
+
+
+				port->write_urb->transfer_buffer_length = 1;
+
+
+				if (usb_submit_urb (port->write_urb))
+					err ("usb_submit_urb(write bulk) failed");
+
+
+			}
+		}
+
+		PL2303_UNLOCK(port,flags);
+	}
+}
+
+
+static int __init pl2303_init (void)
+{
+	usb_serial_register (&pl2303_device);
+	info(DRIVER_VERSION " : " DRIVER_DESC);
+	return 0;
+}
+
+
+static void __exit pl2303_exit (void)
+{
+	usb_serial_deregister (&pl2303_device);
+}
+
+
+module_init(pl2303_init);
+module_exit(pl2303_exit);
+
+MODULE_DESCRIPTION(DRIVER_DESC);
+
+MODULE_PARM(debug, "i");
+MODULE_PARM_DESC(debug, "Debug enabled or not");
+
diff -urN linux-2.4.6-pre5/drivers/usb/usb-ohci.c linux/drivers/usb/usb-ohci.c
--- linux-2.4.6-pre5/drivers/usb/usb-ohci.c	Mon Dec  3 22:49:02 2001
+++ linux/drivers/usb/usb-ohci.c	Mon Dec  3 22:49:12 2001
@@ -2585,15 +2585,15 @@
 
 /*-------------------------------------------------------------------------*/
 
-static void
-ohci_pci_suspend (struct pci_dev *dev)
+static int
+ohci_pci_suspend (struct pci_dev *dev, u32 state)
 {
 	ohci_t		*ohci = (ohci_t *) dev->driver_data;
 
 	if ((ohci->hc_control & OHCI_CTRL_HCFS) != OHCI_USB_OPER) {
 		dbg ("can't suspend usb-%s (state is %s)", dev->slot_name,
 			hcfs2string (ohci->hc_control & OHCI_CTRL_HCFS));
-		return;
+		return -EIO;
 	}
 
 	/* act as if usb suspend can always be used */
@@ -2605,11 +2605,13 @@
 	ohci->hc_control = OHCI_USB_SUSPEND;
 	writel (ohci->hc_control, &ohci->regs->control);
 	wait_ms (10);
+
+	return 0;
 }
 
 /*-------------------------------------------------------------------------*/
 
-static void
+static int
 ohci_pci_resume (struct pci_dev *dev)
 {
 	ohci_t		*ohci = (ohci_t *) dev->driver_data;
@@ -2620,7 +2622,7 @@
 	if (atomic_read (&ohci->resume_count) != 1) {
 		err ("concurrent PCI resumes for usb-%s", dev->slot_name);
 		atomic_dec (&ohci->resume_count);
-		return;
+		return -EBUSY;
 	}
 
 	/* did we suspend, or were we powered off? */
@@ -2653,7 +2655,7 @@
 		if (temp != OHCI_USB_RESUME) {
 			err ("controller usb-%s won't resume", dev->slot_name);
 			ohci->disabled = 1;
-			return;
+			return -EIO;
 		}
 
 		ohci->disabled = 0;
@@ -2676,6 +2678,8 @@
 
 	/* controller is operational, extra resumes are harmless */
 	atomic_dec (&ohci->resume_count);
+
+	return 0;
 }
 
 #endif	/* CONFIG_PM */
diff -urN linux-2.4.6-pre5/drivers/usb/usb-uhci.c linux/drivers/usb/usb-uhci.c
--- linux-2.4.6-pre5/drivers/usb/usb-uhci.c	Mon Dec  3 22:49:02 2001
+++ linux/drivers/usb/usb-uhci.c	Mon Dec  3 22:49:12 2001
@@ -2897,16 +2897,18 @@
 }
 
 #ifdef CONFIG_PM
-_static void
-uhci_pci_suspend (struct pci_dev *dev)
+_static int
+uhci_pci_suspend (struct pci_dev *dev, u32 state)
 {
 	reset_hc((uhci_t *) dev->driver_data);
+	return 0;
 }
 
-_static void
+_static int
 uhci_pci_resume (struct pci_dev *dev)
 {
 	start_hc((uhci_t *) dev->driver_data);
+	return 0;
 }
 #endif
 
diff -urN linux-2.4.6-pre5/drivers/video/cyber2000fb.c linux/drivers/video/cyber2000fb.c
--- linux-2.4.6-pre5/drivers/video/cyber2000fb.c	Fri Feb  9 11:30:23 2001
+++ linux/drivers/video/cyber2000fb.c	Mon Dec  3 22:49:12 2001
@@ -1612,14 +1612,15 @@
 	}
 }
 
-static void cyberpro_suspend(struct pci_dev *dev)
+static int cyberpro_suspend(struct pci_dev *dev, u32 state)
 {
+	return 0;
 }
 
 /*
  * Re-initialise the CyberPro hardware
  */
-static void cyberpro_resume(struct pci_dev *dev)
+static int cyberpro_resume(struct pci_dev *dev)
 {
 	struct cfb_info *cfb = (struct cfb_info *)dev->driver_data;
 
@@ -1633,6 +1634,8 @@
 		cfb->fb.var.activate = FB_ACTIVATE_NOW;
 		cyber2000fb_set_var(&cfb->fb.var, -1, &cfb->fb);
 	}
+
+	return 0;
 }
 
 static struct pci_device_id cyberpro_pci_table[] __devinitdata = {
diff -urN linux-2.4.6-pre5/drivers/video/imsttfb.c linux/drivers/video/imsttfb.c
--- linux-2.4.6-pre5/drivers/video/imsttfb.c	Wed Apr 18 11:49:12 2001
+++ linux/drivers/video/imsttfb.c	Mon Dec  3 22:49:12 2001
@@ -6,6 +6,7 @@
  *  With additional hacking by Jeffrey Kuskin (jsk@mojave.stanford.edu)
  *  Modified by Danilo Beuche 1998
  *  Some register values added by Damien Doligez, INRIA Rocquencourt
+ *  Various cleanups by Paul Mundt (lethal@chaoticdreams.org)
  *
  *  This file was written by Ryan Nielsen (ran@krazynet.com)
  *  Most of the frame buffer device stuff was copied from atyfb.c
@@ -378,6 +379,7 @@
 #define CURSOR_DRAW_DELAY	2
 
 static int currcon = 0;
+static int inverse = 0;
 static char fontname[40] __initdata = { 0 };
 static char curblink __initdata = 1;
 static char noaccel __initdata = 0;
@@ -1235,7 +1237,6 @@
 {
 	struct fb_info_imstt *p = (struct fb_info_imstt *)info;
 	u_int bpp = fb_display[currcon].var.bits_per_pixel;
-	u_int i;
 
 	if (regno > 255)
 		return 1;
@@ -1413,7 +1414,7 @@
 	disp->type_aux = p->fix.type_aux;
 	disp->line_length = disp->var.xres * (disp->var.bits_per_pixel >> 3);
 	disp->can_soft_blank = 1;
-	disp->inverse = 0;
+	disp->inverse = inverse;
 	disp->ypanstep = 1;
 	disp->ywrapstep = 0;
 	if (accel) {
@@ -1887,7 +1888,6 @@
 	struct pci_dev *pdev = NULL;
 	struct fb_info_imstt *p;
 	unsigned long addr, size;
-	__u16 cmd;
 
 	while ((pdev = pci_find_device(PCI_VENDOR_ID_IMS, PCI_ANY_ID, pdev))) {
 		if ((pdev->class >> 16) != PCI_BASE_CLASS_DISPLAY)
@@ -1963,6 +1963,9 @@
 			curblink = 0;
 		} else if (!strncmp(this_opt, "noaccel", 7)) {
 			noaccel = 1;
+		} else if (!strncmp(this_opt, "inverse", 7)) {
+			inverse = 1;
+			fb_invert_cmaps();
 		}
 #if defined(CONFIG_PPC)
 		else if (!strncmp(this_opt, "vmode:", 6)) {
@@ -1994,16 +1997,8 @@
 }
 
 #else /* MODULE */
-
-int __init
-init_module (void)
-{
-
-	return imsttfb_init();
-}
-
-void
-cleanup_module (void)
+static void __exit
+imsttfb_exit(void)
 {
 	struct fb_info_imstt *p;
 	__u32 i;
@@ -2012,13 +2007,18 @@
 		p = fb_info_imstt_p[i];
 		if (!p)
 			continue;
+		unregister_framebuffer(&p->info);
 		iounmap(p->cmap_regs);
 		iounmap(p->dc_regs);
 		iounmap(p->frame_buffer);
-		kfree(p);
 		release_mem_region(p->frame_buffer_phys, p->board_size);
+		kfree(p);
 	}
 }
 
 #include "macmodes.c"
+
+module_init(imsttfb_init);
+module_exit(imsttfb_exit);
 #endif /* MODULE */
+
diff -urN linux-2.4.6-pre5/drivers/video/macmodes.c linux/drivers/video/macmodes.c
--- linux-2.4.6-pre5/drivers/video/macmodes.c	Fri Mar  2 18:38:39 2001
+++ linux/drivers/video/macmodes.c	Mon Dec  3 22:49:12 2001
@@ -94,7 +94,15 @@
 	/* 1280x1024, 75 Hz, Non-Interlaced (135.00 MHz dotclock) */
 	"mac20", 75, 1280, 1024, 7408, 232, 64, 38, 1, 112, 3,
 	FB_SYNC_HOR_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED
-    },
+    }, {
+	/* 1152x768, 60 Hz, Titanium PowerBook */
+	"mac21", 60, 1152, 768, 15386, 158, 26, 29, 3, 136, 6,
+	FB_SYNC_HOR_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED
+    }, {
+	/* 1600x1024, 60 Hz, Non-Interlaced (112.27 MHz dotclock) */
+	"mac22", 60, 1600, 1024, 8908, 88, 104, 1, 10, 16, 1,
+	FB_SYNC_HOR_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED
+    }
 
 #if 0
     /* Anyone who has timings for these? */
@@ -154,12 +162,16 @@
     { VMODE_1024_768_75V, &mac_modedb[9] },
     { VMODE_1024_768_70, &mac_modedb[8] },
     { VMODE_1024_768_60, &mac_modedb[7] },
+    /* 1152x768 */
+    { VMODE_1152_768_60, &mac_modedb[14] },
     /* 1152x870 */
     { VMODE_1152_870_75, &mac_modedb[11] },
     /* 1280x960 */
     { VMODE_1280_960_75, &mac_modedb[12] },
     /* 1280x1024 */
     { VMODE_1280_1024_75, &mac_modedb[13] },
+    /* 1600x1024 */
+    { VMODE_1600_1024_60, &mac_modedb[15] },
     { -1, NULL }
 };
 
@@ -191,6 +203,7 @@
     { 0x730, VMODE_768_576_50I },	/* PAL (Alternate) */
     { 0x73a, VMODE_1152_870_75 },	/* 3rd party 19" */
     { 0x73f, VMODE_640_480_67 },	/* no sense lines connected at all */
+    { 0xBEEF, VMODE_1600_1024_60 },	/* 22" Apple Cinema Display */
     { -1,    VMODE_640_480_60 },	/* catch-all, must be last */
 };
 
diff -urN linux-2.4.6-pre5/drivers/video/matrox/matroxfb_DAC1064.c linux/drivers/video/matrox/matroxfb_DAC1064.c
--- linux-2.4.6-pre5/drivers/video/matrox/matroxfb_DAC1064.c	Wed Apr 11 19:21:35 2001
+++ linux/drivers/video/matrox/matroxfb_DAC1064.c	Mon Dec  3 22:49:12 2001
@@ -4,7 +4,7 @@
  *
  * (c) 1998-2001 Petr Vandrovec <vandrove@vc.cvut.cz>
  *
- * Version: 1.52 2001/02/02
+ * Version: 1.53 2001/06/18
  *
  * See matroxfb_base.c for contributors.
  *
@@ -33,12 +33,14 @@
 #define DAC1064_OPT_RESERVED	0x10
 
 static void matroxfb_DAC1064_flashcursor(unsigned long ptr) {
+	unsigned long flags;
+
 #define minfo ((struct matrox_fb_info*)ptr)
-	matroxfb_DAC_lock();
+	matroxfb_DAC_lock_irqsave(flags);
 	outDAC1064(PMINFO M1064_XCURCTRL, inDAC1064(PMINFO M1064_XCURCTRL) ^ M1064_XCURCTRL_DIS ^ M1064_XCURCTRL_XGA);
 	ACCESS_FBINFO(cursor.timer.expires) = jiffies + HZ/2;
 	add_timer(&ACCESS_FBINFO(cursor.timer));
-	matroxfb_DAC_unlock();
+	matroxfb_DAC_unlock_irqrestore(flags);
 #undef minfo
 }
 
@@ -719,7 +721,8 @@
 	ACCESS_FBINFO(capable.vxres) = vxres_g100;
 	ACCESS_FBINFO(features.accel.has_cacheflush) = 1;
 	ACCESS_FBINFO(cursor.timer.function) = matroxfb_DAC1064_flashcursor;
-	ACCESS_FBINFO(capable.plnwt) = ACCESS_FBINFO(devflags.accelerator) != FB_ACCEL_MATROX_MGAG100;
+	ACCESS_FBINFO(capable.plnwt) = ACCESS_FBINFO(devflags.accelerator) == FB_ACCEL_MATROX_MGAG100
+			? ACCESS_FBINFO(devflags.sgram) : 1;
 
 	ACCESS_FBINFO(primout) = &m1064;
 
diff -urN linux-2.4.6-pre5/drivers/video/matrox/matroxfb_Ti3026.c linux/drivers/video/matrox/matroxfb_Ti3026.c
--- linux-2.4.6-pre5/drivers/video/matrox/matroxfb_Ti3026.c	Thu Aug 10 12:34:31 2000
+++ linux/drivers/video/matrox/matroxfb_Ti3026.c	Mon Dec  3 22:49:12 2001
@@ -279,12 +279,14 @@
   0x00, 0x00, TVP3026_XCURCTRL_DIS };
 
 static void matroxfb_ti3026_flashcursor(unsigned long ptr) {
+	unsigned long flags;
+
 #define minfo ((struct matrox_fb_info*)ptr)
-	matroxfb_DAC_lock();
+	matroxfb_DAC_lock_irqsave(flags);
 	outTi3026(PMINFO TVP3026_XCURCTRL, inTi3026(PMINFO TVP3026_XCURCTRL) ^ TVP3026_XCURCTRL_DIS ^ TVP3026_XCURCTRL_XGA);
 	ACCESS_FBINFO(cursor.timer.expires) = jiffies + HZ/2;
 	add_timer(&ACCESS_FBINFO(cursor.timer));
-	matroxfb_DAC_unlock();
+	matroxfb_DAC_unlock_irqrestore(flags);
 #undef minfo
 }
 
diff -urN linux-2.4.6-pre5/drivers/video/matrox/matroxfb_accel.c linux/drivers/video/matrox/matroxfb_accel.c
--- linux-2.4.6-pre5/drivers/video/matrox/matroxfb_accel.c	Thu Aug 10 12:34:31 2000
+++ linux/drivers/video/matrox/matroxfb_accel.c	Mon Dec  3 22:49:12 2001
@@ -2,9 +2,9 @@
  *
  * Hardware accelerated Matrox Millennium I, II, Mystique, G100, G200 and G400
  *
- * (c) 1998,1999,2000 Petr Vandrovec <vandrove@vc.cvut.cz>
+ * (c) 1998-2001 Petr Vandrovec <vandrove@vc.cvut.cz>
  *
- * Version: 1.50 2000/08/10
+ * Version: 1.51 2001/06/18
  *
  * MTRR stuff: 1998 Tom Rini <trini@kernel.crashing.org>
  *
@@ -129,6 +129,10 @@
 	mga_outl(M_YDSTORG, curr_ydstorg(MINFO));
 	if (ACCESS_FBINFO(capable.plnwt))
 		mga_outl(M_PLNWT, -1);
+	if (ACCESS_FBINFO(capable.srcorg)) {
+		mga_outl(M_SRCORG, 0);
+		mga_outl(M_DSTORG, 0);
+	}
 	mga_outl(M_OPMODE, mopmode);
 	mga_outl(M_CXBNDRY, 0xFFFF0000);
 	mga_outl(M_YTOP, 0);
diff -urN linux-2.4.6-pre5/drivers/video/matrox/matroxfb_base.c linux/drivers/video/matrox/matroxfb_base.c
--- linux-2.4.6-pre5/drivers/video/matrox/matroxfb_base.c	Mon Dec  3 22:49:02 2001
+++ linux/drivers/video/matrox/matroxfb_base.c	Mon Dec  3 22:49:12 2001
@@ -4,7 +4,7 @@
  *
  * (c) 1998-2001 Petr Vandrovec <vandrove@vc.cvut.cz>
  *
- * Version: 1.52 2001/02/02
+ * Version: 1.53 2001/06/18
  *
  * MTRR stuff: 1998 Tom Rini <trini@kernel.crashing.org>
  *
@@ -72,6 +72,9 @@
  *               "Ken Aaker" <kdaaker@rchland.vnet.ibm.com>
  *                     memtype extension (needed for GXT130P RS/6000 adapter)
  *
+ *               "Uns Lider" <unslider@miranda.org>
+ *                     G100 PLNWT fixes
+ *
  * (following author is not in any relation with this code, but his code
  *  is included in this driver)
  *
@@ -1409,7 +1412,7 @@
 
 #define DEVF_VIDEO64BIT		0x0001
 #define	DEVF_SWAPS		0x0002
-/* #define DEVF_recycled	0x0004 */
+#define DEVF_SRCORG		0x0004
 /* #define DEVF_recycled	0x0008 */
 #define DEVF_CROSS4MB		0x0010
 #define DEVF_TEXT4B		0x0020
@@ -1424,12 +1427,12 @@
 #define DEVF_G450DAC		0x4000
 
 #define DEVF_GCORE	(DEVF_VIDEO64BIT | DEVF_SWAPS | DEVF_CROSS4MB | DEVF_DDC_8_2)
-#define DEVF_G2CORE	(DEVF_GCORE | DEVF_ANY_VXRES | DEVF_MAVEN_CAPABLE | DEVF_PANELLINK_CAPABLE)
+#define DEVF_G2CORE	(DEVF_GCORE | DEVF_ANY_VXRES | DEVF_MAVEN_CAPABLE | DEVF_PANELLINK_CAPABLE | DEVF_SRCORG)
 #define DEVF_G100	(DEVF_GCORE) /* no doc, no vxres... */
 #define DEVF_G200	(DEVF_G2CORE)
 #define DEVF_G400	(DEVF_G2CORE | DEVF_SUPPORT32MB | DEVF_TEXT16B | DEVF_CRTC2)
 /* if you'll find how to drive DFP... */
-#define DEVF_G450	(DEVF_GCORE | DEVF_ANY_VXRES | DEVF_SUPPORT32MB | DEVF_TEXT16B | DEVF_CRTC2 | DEVF_G450DAC)
+#define DEVF_G450	(DEVF_GCORE | DEVF_ANY_VXRES | DEVF_SUPPORT32MB | DEVF_TEXT16B | DEVF_CRTC2 | DEVF_G450DAC | DEVF_SRCORG)
 
 static struct board {
 	unsigned short vendor, device, rev, svid, sid;
@@ -1556,7 +1559,7 @@
 		DEVF_G200,
 		230000,
 		&vbG200,
-		"unknown G200 (AGP)"},
+		"G200 (AGP)"},
 	{PCI_VENDOR_ID_MATROX,	PCI_DEVICE_ID_MATROX_G400_AGP,	0x80,
 		PCI_SS_VENDOR_ID_MATROX,	PCI_SS_ID_MATROX_MILLENNIUM_G400_MAX_AGP,
 		DEVF_G400,
@@ -1568,13 +1571,13 @@
 		DEVF_G400,
 		300000,
 		&vbG400,
-		"unknown G400 (AGP)"},
+		"G400 (AGP)"},
 	{PCI_VENDOR_ID_MATROX,	PCI_DEVICE_ID_MATROX_G400_AGP,	0xFF,
 		0,			0,
 		DEVF_G450,
 		500000,		/* ??? vco goes up to 900MHz... */
 		&vbG400,
-		"unknown G450 (AGP)"},
+		"G450 (AGP)"},
 #endif
 	{0,			0,				0xFF,
 		0,			0,
@@ -1611,6 +1614,7 @@
 
 	printk(KERN_INFO "matroxfb: Matrox %s detected\n", b->name);
 	ACCESS_FBINFO(capable.plnwt) = 1;
+	ACCESS_FBINFO(capable.srcorg) = b->flags & DEVF_SRCORG;
 	ACCESS_FBINFO(devflags.video64bits) = b->flags & DEVF_VIDEO64BIT;
 	if (b->flags & DEVF_TEXT4B) {
 		ACCESS_FBINFO(devflags.vgastep) = 4;
@@ -2483,7 +2487,7 @@
 	return 0;
 }
 
-static int initialized __initdata = 0;
+static int __initdata initialized = 0;
 
 int __init matroxfb_init(void)
 {
@@ -2495,6 +2499,7 @@
 		initialized = 1;
 		matrox_init();
 	}
+	hotplug = 1;
 	/* never return failure, user can hotplug matrox later... */
 	return 0;
 }
@@ -2526,7 +2531,7 @@
 MODULE_PARM(mtrr, "i");
 MODULE_PARM_DESC(mtrr, "This speeds up video memory accesses (0=disabled or 1) (default=1)");
 MODULE_PARM(sgram, "i");
-MODULE_PARM_DESC(sgram, "Indicates that G200/G400 has SGRAM memory (0=SDRAM, 1=SGRAM) (default=0)");
+MODULE_PARM_DESC(sgram, "Indicates that G100/G200/G400 has SGRAM memory (0=SDRAM, 1=SGRAM) (default=0)");
 MODULE_PARM(inv24, "i");
 MODULE_PARM_DESC(inv24, "Inverts clock polarity for 24bpp and loop frequency > 100MHz (default=do not invert polarity)");
 MODULE_PARM(inverse, "i");
diff -urN linux-2.4.6-pre5/drivers/video/matrox/matroxfb_base.h linux/drivers/video/matrox/matroxfb_base.h
--- linux-2.4.6-pre5/drivers/video/matrox/matroxfb_base.h	Fri Feb  9 11:30:23 2001
+++ linux/drivers/video/matrox/matroxfb_base.h	Mon Dec  3 22:49:12 2001
@@ -492,6 +492,7 @@
 		int		cross4MB;
 		int		text;
 		int		plnwt;
+		int		srcorg;
 			      } capable;
 	struct {
 		unsigned int	size;
@@ -738,6 +739,7 @@
 
 /* G200 only */
 #define M_SRCORG	0x2CB4
+#define M_DSTORG	0x2CB8
 
 #define M_RAMDAC_BASE	0x3C00
 
diff -urN linux-2.4.6-pre5/drivers/video/matrox/matroxfb_g450.c linux/drivers/video/matrox/matroxfb_g450.c
--- linux-2.4.6-pre5/drivers/video/matrox/matroxfb_g450.c	Fri Dec 29 14:07:23 2000
+++ linux/drivers/video/matrox/matroxfb_g450.c	Mon Dec  3 22:49:12 2001
@@ -6,17 +6,20 @@
 
 static int matroxfb_g450_get_reg(WPMINFO int reg) {
 	int val;
+	unsigned long flags;
 
-	matroxfb_DAC_lock();
+	matroxfb_DAC_lock_irqsave(flags);
 	val = matroxfb_DAC_in(PMINFO reg);
-	matroxfb_DAC_unlock();
+	matroxfb_DAC_unlock_irqrestore(flags);
 	return val;
 }
 
 static int matroxfb_g450_set_reg(WPMINFO int reg, int val) {
-	matroxfb_DAC_lock();
+	unsigned long flags;
+
+	matroxfb_DAC_lock_irqsave(flags);
 	matroxfb_DAC_out(PMINFO reg, val);
-	matroxfb_DAC_unlock();
+	matroxfb_DAC_unlock_irqrestore(flags);
 	return 0;
 }
 
diff -urN linux-2.4.6-pre5/drivers/video/mdacon.c linux/drivers/video/mdacon.c
--- linux-2.4.6-pre5/drivers/video/mdacon.c	Fri Feb  9 11:30:23 2001
+++ linux/drivers/video/mdacon.c	Mon Dec  3 22:49:12 2001
@@ -21,6 +21,9 @@
  *  This file is subject to the terms and conditions of the GNU General Public
  *  License.  See the file COPYING in the main directory of this archive for
  *  more details.
+ *
+ *  Changelog:
+ *  Paul G. (03/2001) Fix mdacon= boot prompt to use __setup().
  */
 
 #include <linux/types.h>
@@ -129,6 +132,7 @@
 	spin_unlock_irqrestore(&mda_lock, flags);
 }
 
+#ifdef TEST_MDA_B
 static int test_mda_b(unsigned char val, unsigned char reg)
 {
 	unsigned long flags;
@@ -143,6 +147,7 @@
 	spin_unlock_irqrestore(&mda_lock, flags);
 	return val;
 }
+#endif
 
 static inline void mda_set_origin(unsigned int location)
 {
@@ -182,20 +187,27 @@
 
 
 #ifndef MODULE
-void __init mdacon_setup(char *str, int *ints)
+static int __init mdacon_setup(char *str)
 {
 	/* command line format: mdacon=<first>,<last> */
 
+	int ints[3];
+
+	str = get_options(str, ARRAY_SIZE(ints), ints);
+
 	if (ints[0] < 2)
-		return;
+		return 0;
 
 	if (ints[1] < 1 || ints[1] > MAX_NR_CONSOLES || 
 	    ints[2] < 1 || ints[2] > MAX_NR_CONSOLES)
-		return;
+		return 0;
 
-	mda_first_vc = ints[1]-1;
-	mda_last_vc  = ints[2]-1;
+	mda_first_vc = ints[1];
+	mda_last_vc  = ints[2];
+	return 1;
 }
+
+__setup("mdacon=", mdacon_setup);
 #endif
 
 static int __init mda_detect(void)
@@ -237,17 +249,19 @@
 	 * memory location, so now we do an I/O port test.
 	 */
 
+#ifdef TEST_MDA_B
 	/* Edward: These two mess `tests' mess up my cursor on bootup */
 
 	/* cursor low register */
-	/* if (! test_mda_b(0x66, 0x0f)) {
+	if (! test_mda_b(0x66, 0x0f)) {
 		return 0;
-	} */
+	}
 
 	/* cursor low register */
-	/* if (! test_mda_b(0x99, 0x0f)) {
+	if (! test_mda_b(0x99, 0x0f)) {
 		return 0;
-	} */
+	}
+#endif
 
 	/* See if the card is a Hercules, by checking whether the vsync
 	 * bit of the status register is changing.  This test lasts for
diff -urN linux-2.4.6-pre5/fs/freevxfs/vxfs_bmap.c linux/fs/freevxfs/vxfs_bmap.c
--- linux-2.4.6-pre5/fs/freevxfs/vxfs_bmap.c	Thu May 24 15:00:59 2001
+++ linux/fs/freevxfs/vxfs_bmap.c	Mon Dec  3 22:49:12 2001
@@ -27,7 +27,7 @@
  * SUCH DAMAGE.
  */
 
-#ident "$Id: vxfs_bmap.c,v 1.20 2001/04/25 18:11:23 hch Exp hch $"
+#ident "$Id: vxfs_bmap.c,v 1.22 2001/05/26 22:41:23 hch Exp hch $"
 
 /*
  * Veritas filesystem driver - filesystem to disk block mapping.
@@ -70,7 +70,7 @@
 	struct super_block		*sbp = ip->i_sb;
 	kdev_t				dev = ip->i_dev;
 	u_long				bsize = sbp->s_blocksize;
-	u_long				size = 0;
+	long				size = 0;
 	int				i;
 
 	for (i = 0; i < VXFS_NDADDR; i++) {
@@ -135,7 +135,7 @@
 
 	for (i = 0; i < size * VXFS_TYPED_PER_BLOCK(ip->i_sb); i++) {
 		struct vxfs_typed	*typ;
-		u_int64_t		off;
+		int64_t			off;
 
 		bp = bread(ip->i_dev,
 				indir + (i / VXFS_TYPED_PER_BLOCK(ip->i_sb)),
@@ -166,10 +166,12 @@
 			goto out;
 		case VXFS_TYPED_INDIRECT_DEV4:
 		case VXFS_TYPED_DATA_DEV4: {
-			struct vxfs_typed_dev4	*typ4 = (struct vxfs_typed_dev4 *)typ;
+			struct vxfs_typed_dev4	*typ4 =
+				(struct vxfs_typed_dev4 *)typ;
+
 			printk(KERN_INFO "\n\nTYPED_DEV4 detected!\n");
-			printk(KERN_INFO "block: %Ld\tsize: %Ld\tdev: %d\n",
-			       (long long)typ4->vd4_block, (long long)typ4->vd4_size, typ4->vd4_dev);
+			printk(KERN_INFO "block: %Lu\tsize: %Ld\tdev: %d\n",
+				typ4->vd4_block, typ4->vd4_size, typ4->vd4_dev);
 			goto fail;
 		}
 		default:
@@ -205,7 +207,7 @@
 
 	for (i = 0; i < VXFS_NTYPED; i++) {
 		struct vxfs_typed	*typ = vip->vii_org.typed + i;
-		u_int64_t		off = (typ->vt_hdr & VXFS_TYPED_OFFSETMASK);
+		int64_t			off = (typ->vt_hdr & VXFS_TYPED_OFFSETMASK);
 
 #ifdef DIAGNOSTIC
 		vxfs_typdump(typ);
@@ -225,10 +227,12 @@
 			break;
 		case VXFS_TYPED_INDIRECT_DEV4:
 		case VXFS_TYPED_DATA_DEV4: {
-			struct vxfs_typed_dev4	*typ4 = (struct vxfs_typed_dev4 *)typ;
+			struct vxfs_typed_dev4	*typ4 =
+				(struct vxfs_typed_dev4 *)typ;
+
 			printk(KERN_INFO "\n\nTYPED_DEV4 detected!\n");
-			printk(KERN_INFO "block: %Ld\tsize: %Ld\tdev: %d\n",
-			       (long long)typ4->vd4_block, (long long)typ4->vd4_size, typ4->vd4_dev);
+			printk(KERN_INFO "block: %Lu\tsize: %Ld\tdev: %d\n",
+				typ4->vd4_block, typ4->vd4_size, typ4->vd4_dev);
 			return 0;
 		}
 		default:
diff -urN linux-2.4.6-pre5/fs/freevxfs/vxfs_fshead.h linux/fs/freevxfs/vxfs_fshead.h
--- linux-2.4.6-pre5/fs/freevxfs/vxfs_fshead.h	Mon May 21 12:31:06 2001
+++ linux/fs/freevxfs/vxfs_fshead.h	Mon Dec  3 22:49:12 2001
@@ -30,7 +30,7 @@
 #ifndef _VXFS_FSHEAD_H_
 #define _VXFS_FSHEAD_H_
 
-#ident "$Id: vxfs_fshead.h,v 1.6 2001/04/25 18:11:23 hch Exp hch $"
+#ident "$Id: vxfs_fshead.h,v 1.7 2001/05/23 17:27:39 hch Exp hch $"
 
 /*
  * Veritas filesystem driver - fileset header structures.
@@ -61,8 +61,8 @@
 
 	/*
 	 * Slightly more fields follow, but they
-	 *  a) are not of any interested for us, and
-	 *  b) differ much in different vxfs versions/ports
+	 *  a) are not of any interest for us, and
+	 *  b) differ a lot in different vxfs versions/ports
 	 */
 };
 
diff -urN linux-2.4.6-pre5/fs/freevxfs/vxfs_inode.c linux/fs/freevxfs/vxfs_inode.c
--- linux-2.4.6-pre5/fs/freevxfs/vxfs_inode.c	Mon May 21 12:31:06 2001
+++ linux/fs/freevxfs/vxfs_inode.c	Mon Dec  3 22:49:12 2001
@@ -27,7 +27,7 @@
  * SUCH DAMAGE.
  */
 
-#ident "$Id: vxfs_inode.c,v 1.34 2001/05/21 15:33:08 hch Exp hch $"
+#ident "$Id: vxfs_inode.c,v 1.36 2001/05/26 22:28:02 hch Exp hch $"
 
 /*
  * Veritas filesystem driver - inode routines.
@@ -47,6 +47,7 @@
 extern struct inode_operations vxfs_immed_symlink_iops;
 
 static struct file_operations vxfs_file_operations = {
+	.llseek =		generic_file_llseek,
 	.read =			generic_file_read,
 	.mmap =			generic_file_mmap,
 };
@@ -91,7 +92,7 @@
  *  Returns the matching VxFS inode on success, else a NULL pointer.
  *
  * NOTE:
- *  While __vxfs_iget uses that pagecache this function uses the
+ *  While __vxfs_iget uses the pagecache vxfs_blkiget uses the
  *  buffercache.  This function should not be used outside the
  *  read_super() method, othwerwise the data may be incoherent.
  */
@@ -138,7 +139,7 @@
  *  Returns the matching VxFS inode on success, else a NULL pointer.
  */
 static struct vxfs_inode_info *
-__vxfs_iget(struct super_block *sbp, ino_t ino, struct inode *ilistp)
+__vxfs_iget(ino_t ino, struct inode *ilistp)
 {
 	struct page			*pp;
 	u_long				offset;
@@ -184,7 +185,7 @@
 struct vxfs_inode_info *
 vxfs_stiget(struct super_block *sbp, ino_t ino)
 {
-        return __vxfs_iget(sbp, ino, VXFS_SBI(sbp)->vsi_stilist);
+        return __vxfs_iget(ino, VXFS_SBI(sbp)->vsi_stilist);
 }
 
 /**
@@ -288,7 +289,7 @@
 	struct address_space_operations	*aops;
 	ino_t				ino = ip->i_ino;
 
-	if (!(vip = __vxfs_iget(sbp, ino, VXFS_SBI(sbp)->vsi_ilist)))
+	if (!(vip = __vxfs_iget(ino, VXFS_SBI(sbp)->vsi_ilist)))
 		return;
 
 	vxfs_iinit(ip, vip);
diff -urN linux-2.4.6-pre5/fs/freevxfs/vxfs_inode.h linux/fs/freevxfs/vxfs_inode.h
--- linux-2.4.6-pre5/fs/freevxfs/vxfs_inode.h	Mon May 21 12:31:06 2001
+++ linux/fs/freevxfs/vxfs_inode.h	Mon Dec  3 22:49:12 2001
@@ -30,7 +30,7 @@
 #ifndef _VXFS_INODE_H_
 #define _VXFS_INODE_H_
 
-#ident "$Id: vxfs_inode.h,v 1.14 2001/04/25 18:11:23 hch Exp hch $"
+#ident "$Id: vxfs_inode.h,v 1.15 2001/05/26 22:41:23 hch Exp hch $"
 
 /*
  * Veritas filesystem driver - inode structure.
@@ -77,7 +77,7 @@
 	vx_daddr_t		ve4_indir[VXFS_NIADDR];	/* Indirect extents */
 	struct direct {					/* Direct extents */
 		vx_daddr_t	extent;			/* Extent number */
-		u_int32_t	size;			/* Size of extent */
+		int32_t		size;			/* Size of extent */
 	} ve4_direct[VXFS_NDADDR];
 };
 
diff -urN linux-2.4.6-pre5/fs/freevxfs/vxfs_lookup.c linux/fs/freevxfs/vxfs_lookup.c
--- linux-2.4.6-pre5/fs/freevxfs/vxfs_lookup.c	Mon May 21 12:31:06 2001
+++ linux/fs/freevxfs/vxfs_lookup.c	Mon Dec  3 22:49:12 2001
@@ -27,7 +27,7 @@
  * SUCH DAMAGE.
  */
 
-#ident "$Id: vxfs_lookup.c,v 1.17 2001/05/21 15:23:53 hch Exp hch $"
+#ident "$Id: vxfs_lookup.c,v 1.19 2001/05/30 19:50:20 hch Exp hch $"
 
 /*
  * Veritas filesystem driver - lookup and other directory related code.
@@ -240,9 +240,8 @@
 	struct inode		*ip = fp->f_dentry->d_inode;
 	struct super_block	*sbp = ip->i_sb;
 	u_long			bsize = sbp->s_blocksize;
-	u_long			page, npages, block, nblocks, offset;
+	u_long			page, npages, block, pblocks, nblocks, offset;
 	loff_t			pos;
-	int			pblocks;
 
 	switch ((long)fp->f_pos) {
 	case 0:
@@ -262,14 +261,14 @@
 	if (pos > VXFS_DIRROUND(ip->i_size))
 		return 0;
 
-	page = pos >> PAGE_CACHE_SHIFT;
-	offset = pos & ~PAGE_CACHE_MASK;
-	block = pos >> sbp->s_blocksize_bits;
-
 	npages = dir_pages(ip);
 	nblocks = dir_blocks(ip);
 	pblocks = VXFS_BLOCK_PER_PAGE(sbp);
 
+	page = pos >> PAGE_CACHE_SHIFT;
+	offset = pos & ~PAGE_CACHE_MASK;
+	block = (u_long)(pos >> sbp->s_blocksize_bits) % pblocks;
+
 	for (; page < npages; page++, block = 0) {
 		caddr_t			kaddr;
 		struct page		*pp;
@@ -310,6 +309,7 @@
 					goto done;
 				}
 			}
+			offset = 0;
 		}
 		vxfs_put_page(pp);
 		offset = 0;
diff -urN linux-2.4.6-pre5/fs/freevxfs/vxfs_super.c linux/fs/freevxfs/vxfs_super.c
--- linux-2.4.6-pre5/fs/freevxfs/vxfs_super.c	Mon May 21 12:31:06 2001
+++ linux/fs/freevxfs/vxfs_super.c	Mon Dec  3 22:49:12 2001
@@ -27,7 +27,7 @@
  * SUCH DAMAGE.
  */
 
-#ident "$Id: vxfs_super.c,v 1.24 2001/05/20 15:21:14 hch Exp hch $"
+#ident "$Id: vxfs_super.c,v 1.25 2001/05/25 18:25:55 hch Exp hch $"
 
 /*
  * Veritas filesystem driver - superblock related routines.
@@ -168,18 +168,18 @@
 	bp = bread(dev, 1, bsize);
 	if (!bp) {
 		printk(KERN_WARNING "vxfs: unable to read disk superblock\n");
-		return NULL;
+		goto out;
 	}
 
 	rsbp = (struct vxfs_sb *)bp->b_data;
 	if (rsbp->vs_magic != VXFS_SUPER_MAGIC) {
 		printk(KERN_NOTICE "vxfs: WRONG superblock magic\n");
-		return NULL;
+		goto out;
 	}
 
 	if (rsbp->vs_version < 2 || rsbp->vs_version > 4) {
 		printk(KERN_NOTICE "vxfs: unsupported VxFS version (%d)\n", rsbp->vs_version);
-		return NULL;
+		goto out;
 	}
 
 #ifdef DIAGNOSTIC
@@ -210,12 +210,12 @@
 	default:
 		printk(KERN_WARNING "vxfs: unsupported blocksise: %d\n",
 				rsbp->vs_bsize);
-		return NULL;
+		goto out;
 	}
 
 	if (vxfs_read_olt(sbp, bsize)) {
 		printk(KERN_WARNING "vxfs: unable to read olt\n");
-		return NULL;
+		goto out;
 	}
 
 	if (vxfs_read_fshead(sbp)) {
@@ -228,6 +228,8 @@
 		return (sbp);
 	
 	printk(KERN_WARNING "vxfs: unable to get root dentry.\n");
+out:
+	kfree(infp);
 	return NULL;
 }
 
diff -urN linux-2.4.6-pre5/fs/jffs/inode-v23.c linux/fs/jffs/inode-v23.c
--- linux-2.4.6-pre5/fs/jffs/inode-v23.c	Sun May 20 11:35:00 2001
+++ linux/fs/jffs/inode-v23.c	Mon Dec  3 22:49:12 2001
@@ -16,6 +16,7 @@
  * Ported to Linux 2.3.x and MTD:
  * Copyright (C) 2000  Alexander Larsson (alex@cendio.se), Cendio Systems AB
  *
+ * Copyright 2000, 2001  Red Hat, Inc.
  */
 
 /* inode.c -- Contains the code that is called from the VFS.  */
@@ -1719,9 +1720,6 @@
 static int __init
 init_jffs_fs(void)
 {
-	printk("JFFS version "
-	       JFFS_VERSION_STRING
-	       ", (C) 1999, 2000  Axis Communications AB\n");
 	return register_filesystem(&jffs_fs_type);
 }
 
diff -urN linux-2.4.6-pre5/fs/nls/Config.in linux/fs/nls/Config.in
--- linux-2.4.6-pre5/fs/nls/Config.in	Sat May 19 17:47:55 2001
+++ linux/fs/nls/Config.in	Mon Dec  3 22:49:12 2001
@@ -29,7 +29,7 @@
   tristate 'Codepage 852 (Central/Eastern Europe)' CONFIG_NLS_CODEPAGE_852
   tristate 'Codepage 855 (Cyrillic)'               CONFIG_NLS_CODEPAGE_855
   tristate 'Codepage 857 (Turkish)'                CONFIG_NLS_CODEPAGE_857
-  tristate 'Codepage 860 (Portugese)'              CONFIG_NLS_CODEPAGE_860
+  tristate 'Codepage 860 (Portuguese)'             CONFIG_NLS_CODEPAGE_860
   tristate 'Codepage 861 (Icelandic)'              CONFIG_NLS_CODEPAGE_861
   tristate 'Codepage 862 (Hebrew)'                 CONFIG_NLS_CODEPAGE_862
   tristate 'Codepage 863 (Canadian French)'        CONFIG_NLS_CODEPAGE_863
@@ -43,7 +43,7 @@
   tristate 'Korean charset (CP949, EUC-KR)'        CONFIG_NLS_CODEPAGE_949
   tristate 'Thai charset (CP874, TIS-620)'         CONFIG_NLS_CODEPAGE_874
   tristate 'Hebrew charsets (ISO-8859-8, CP1255)'  CONFIG_NLS_ISO8859_8
-  tristate 'Windows CP1251 (Bulgarian, Belarussian)' CONFIG_NLS_CODEPAGE_1251
+  tristate 'Windows CP1251 (Bulgarian, Belarusian)' CONFIG_NLS_CODEPAGE_1251
   tristate 'NLS ISO 8859-1  (Latin 1; Western European Languages)' CONFIG_NLS_ISO8859_1
   tristate 'NLS ISO 8859-2  (Latin 2; Slavic/Central European Languages)' CONFIG_NLS_ISO8859_2
   tristate 'NLS ISO 8859-3  (Latin 3; Esperanto, Galician, Maltese, Turkish)' CONFIG_NLS_ISO8859_3
@@ -56,7 +56,7 @@
   tristate 'NLS ISO 8859-14 (Latin 8; Celtic)'      CONFIG_NLS_ISO8859_14
   tristate 'NLS ISO 8859-15 (Latin 9; Western European Languages with Euro)' CONFIG_NLS_ISO8859_15
   tristate 'NLS KOI8-R (Russian)'                   CONFIG_NLS_KOI8_R
-  tristate 'NLS KOI8-U/RU (Ukrainian, Belarussian)' CONFIG_NLS_KOI8_U
+  tristate 'NLS KOI8-U/RU (Ukrainian, Belarusian)' CONFIG_NLS_KOI8_U
   tristate 'NLS UTF8'                               CONFIG_NLS_UTF8
   endmenu
 fi
diff -urN linux-2.4.6-pre5/fs/proc/base.c linux/fs/proc/base.c
--- linux-2.4.6-pre5/fs/proc/base.c	Mon Dec  3 22:49:02 2001
+++ linux/fs/proc/base.c	Mon Dec  3 22:49:12 2001
@@ -312,6 +312,13 @@
 #define MAY_PTRACE(p) \
 (p==current||(p->p_pptr==current&&(p->ptrace & PT_PTRACED)&&p->state==TASK_STOPPED))
 
+
+static int mem_open(struct inode* inode, struct file* file)
+{
+	file->private_data = (void*)(current->self_exec_id);
+	return 0;
+}
+
 static ssize_t mem_read(struct file * file, char * buf,
 			size_t count, loff_t *ppos)
 {
@@ -319,6 +326,8 @@
 	char *page;
 	unsigned long src = *ppos;
 	int copied = 0;
+	struct mm_struct *mm;
+
 
 	if (!MAY_PTRACE(task))
 		return -ESRCH;
@@ -327,6 +336,18 @@
 	if (!page)
 		return -ENOMEM;
 
+	task_lock(task);
+	mm = task->mm;
+	if (mm)
+		atomic_inc(&mm->mm_users);
+	task_unlock(task);
+
+	if (file->private_data != (void*)(current->self_exec_id) ) {
+		mmput(mm);
+		return -EIO;
+	}
+		
+
 	while (count > 0) {
 		int this_len, retval;
 
@@ -347,6 +368,7 @@
 		count -= retval;
 	}
 	*ppos = src;
+	mmput(mm);
 	free_page((unsigned long) page);
 	return copied;
 }
@@ -398,6 +420,7 @@
 static struct file_operations proc_mem_operations = {
 	read:		mem_read,
 	write:		mem_write,
+	open:		mem_open,
 };
 
 static struct inode_operations proc_mem_inode_operations = {
diff -urN linux-2.4.6-pre5/fs/proc/generic.c linux/fs/proc/generic.c
--- linux-2.4.6-pre5/fs/proc/generic.c	Fri May 25 17:56:44 2001
+++ linux/fs/proc/generic.c	Mon Dec  3 22:49:12 2001
@@ -192,13 +192,22 @@
 
 static unsigned char proc_alloc_map[PROC_NDYNAMIC / 8];
 
+spinlock_t proc_alloc_map_lock = SPIN_LOCK_UNLOCKED;
+
 static int make_inode_number(void)
 {
-	int i = find_first_zero_bit((void *) proc_alloc_map, PROC_NDYNAMIC);
-	if (i<0 || i>=PROC_NDYNAMIC) 
-		return -1;
+	int i;
+	spin_lock(&proc_alloc_map_lock);
+	i = find_first_zero_bit((void *) proc_alloc_map, PROC_NDYNAMIC);
+	if (i<0 || i>=PROC_NDYNAMIC) {
+		i = -1;
+		goto out;
+	}
 	set_bit(i, (void *) proc_alloc_map);
-	return PROC_DYNAMIC_FIRST + i;
+	i += PROC_DYNAMIC_FIRST;
+out:
+	spin_unlock(&proc_alloc_map_lock);
+	return i;
 }
 
 static int proc_readlink(struct dentry *dentry, char *buffer, int buflen)
diff -urN linux-2.4.6-pre5/fs/select.c linux/fs/select.c
--- linux-2.4.6-pre5/fs/select.c	Wed May 16 10:31:27 2001
+++ linux/fs/select.c	Mon Dec  3 22:49:12 2001
@@ -260,7 +260,7 @@
 	fd_set_bits fds;
 	char *bits;
 	long timeout;
-	int ret, size;
+	int ret, size, max_fdset;
 
 	timeout = MAX_SCHEDULE_TIMEOUT;
 	if (tvp) {
@@ -285,8 +285,10 @@
 	if (n < 0)
 		goto out_nofds;
 
-	if (n > current->files->max_fdset)
-		n = current->files->max_fdset;
+	/* max_fdset can increase, so grab it once to avoid race */
+	max_fdset = current->files->max_fdset;
+	if (n > max_fdset)
+		n = max_fdset;
 
 	/*
 	 * We need 6 bitmaps (in/out/ex for both incoming and outgoing),
diff -urN linux-2.4.6-pre5/include/asm-arm/bitops.h linux/include/asm-arm/bitops.h
--- linux-2.4.6-pre5/include/asm-arm/bitops.h	Mon Nov 27 17:07:59 2000
+++ linux/include/asm-arm/bitops.h	Mon Dec  3 22:49:12 2001
@@ -24,12 +24,62 @@
  * Function prototypes to keep gcc -Wall happy.
  */
 extern void set_bit(int nr, volatile void * addr);
+
+static inline void __set_bit(int nr, volatile void *addr)
+{
+	((unsigned char *) addr)[nr >> 3] |= (1U << (nr & 7));
+}
+
 extern void clear_bit(int nr, volatile void * addr);
+
+static inline void __clear_bit(int nr, volatile void *addr)
+{
+	((unsigned char *) addr)[nr >> 3] &= ~(1U << (nr & 7));
+}
+
 extern void change_bit(int nr, volatile void * addr);
 
+static inline void __change_bit(int nr, volatile void *addr)
+{
+	((unsigned char *) addr)[nr >> 3] ^= (1U << (nr & 7));
+}
+
 extern int test_and_set_bit(int nr, volatile void * addr);
+
+static inline int __test_and_set_bit(int nr, volatile void *addr)
+{
+	unsigned int mask = 1 << (nr & 7);
+	unsigned int oldval;
+
+	oldval = ((unsigned char *) addr)[nr >> 3];
+	((unsigned char *) addr)[nr >> 3] = oldval | mask;
+	return oldval & mask;
+}
+
 extern int test_and_clear_bit(int nr, volatile void * addr);
+
+static inline int __test_and_clear_bit(int nr, volatile void *addr)
+{
+	unsigned int mask = 1 << (nr & 7);
+	unsigned int oldval;
+
+	oldval = ((unsigned char *) addr)[nr >> 3];
+	((unsigned char *) addr)[nr >> 3] = oldval & ~mask;
+	return oldval & mask;
+}
+
 extern int test_and_change_bit(int nr, volatile void * addr);
+
+static inline int __test_and_change_bit(int nr, volatile void *addr)
+{
+	unsigned int mask = 1 << (nr & 7);
+	unsigned int oldval;
+
+	oldval = ((unsigned char *) addr)[nr >> 3];
+	((unsigned char *) addr)[nr >> 3] = oldval ^ mask;
+	return oldval & mask;
+}
+
 extern int find_first_zero_bit(void * addr, unsigned size);
 extern int find_next_zero_bit(void * addr, int size, int offset);
 
diff -urN linux-2.4.6-pre5/include/asm-arm/io.h linux/include/asm-arm/io.h
--- linux-2.4.6-pre5/include/asm-arm/io.h	Thu Apr 12 12:20:31 2001
+++ linux/include/asm-arm/io.h	Mon Dec  3 22:49:12 2001
@@ -119,7 +119,7 @@
  * is in pci.h
  */
 extern void *consistent_alloc(int gfp, size_t size, dma_addr_t *handle);
-extern void consistent_free(void *vaddr);
+extern void consistent_free(void *vaddr, size_t size, dma_addr_t handle);
 extern void consistent_sync(void *vaddr, size_t size, int rw);
 
 #define __raw_writeb(v,a)		__arch_putb(v,a)
diff -urN linux-2.4.6-pre5/include/asm-arm/pci.h linux/include/asm-arm/pci.h
--- linux-2.4.6-pre5/include/asm-arm/pci.h	Wed May 16 10:31:27 2001
+++ linux/include/asm-arm/pci.h	Mon Dec  3 22:49:12 2001
@@ -41,7 +41,7 @@
 pci_free_consistent(struct pci_dev *hwdev, size_t size, void *vaddr,
 		    dma_addr_t dma_handle)
 {
-	consistent_free(vaddr);
+	consistent_free(vaddr, size, dma_handle);
 }
 
 /* Map a single buffer of the indicated size for DMA in streaming mode.
diff -urN linux-2.4.6-pre5/include/asm-arm/proc-armo/system.h linux/include/asm-arm/proc-armo/system.h
--- linux-2.4.6-pre5/include/asm-arm/proc-armo/system.h	Mon Sep 18 15:15:24 2000
+++ linux/include/asm-arm/proc-armo/system.h	Mon Dec  3 22:49:12 2001
@@ -12,6 +12,8 @@
 
 #include <asm/proc-fns.h>
 
+#define vectors_base()	(0)
+
 extern __inline__ unsigned long __xchg(unsigned long x, volatile void *ptr, int size)
 {
 	extern void __bad_xchg(volatile void *, int);
diff -urN linux-2.4.6-pre5/include/asm-arm/proc-armv/system.h linux/include/asm-arm/proc-armv/system.h
--- linux-2.4.6-pre5/include/asm-arm/proc-armv/system.h	Mon Nov 27 17:07:59 2000
+++ linux/include/asm-arm/proc-armv/system.h	Mon Dec  3 22:49:12 2001
@@ -17,8 +17,30 @@
 	"mcr	p15, 0, %0, c1, c0	@ set CR"	\
 	: : "r" (x))
 
+#define CR_M	(1 << 0)	/* MMU enable				*/
+#define CR_A	(1 << 1)	/* Alignment abort enable		*/
+#define CR_C	(1 << 2)	/* Dcache enable			*/
+#define CR_W	(1 << 3)	/* Write buffer enable			*/
+#define CR_P	(1 << 4)	/* 32-bit exception handler		*/
+#define CR_D	(1 << 5)	/* 32-bit data address range		*/
+#define CR_L	(1 << 6)	/* Implementation defined		*/
+#define CD_B	(1 << 7)	/* Big endian				*/
+#define CR_S	(1 << 8)	/* System MMU protection		*/
+#define CD_R	(1 << 9)	/* ROM MMU protection			*/
+#define CR_F	(1 << 10)	/* Implementation defined		*/
+#define CR_Z	(1 << 11)	/* Implementation defined		*/
+#define CR_I	(1 << 12)	/* Icache enable			*/
+#define CR_V	(1 << 13)	/* Vectors relocated to 0xffff0000	*/
+#define CR_RR	(1 << 14)	/* Round Robin cache replacement	*/
+
 extern unsigned long cr_no_alignment;	/* defined in entry-armv.S */
 extern unsigned long cr_alignment;	/* defined in entry-armv.S */
+
+#ifdef __ARM_ARCH_4__
+#define vectors_base()	((cr_alignment & CR_V) ? 0xffff0000 : 0)
+#else
+#define vectors_base()	(0)
+#endif
 
 /*
  * A couple of speedups for the ARM
diff -urN linux-2.4.6-pre5/include/asm-arm/xor.h linux/include/asm-arm/xor.h
--- linux-2.4.6-pre5/include/asm-arm/xor.h	Thu Apr 12 12:20:31 2001
+++ linux/include/asm-arm/xor.h	Mon Dec  3 22:49:12 2001
@@ -7,290 +7,7 @@
  * it under the terms of the GNU General Public License version 2 as
  * published by the Free Software Foundation.
  */
-
-/*
- *  linux/include/asm-arm/xor.h
- *
- *  Copyright (C) 2001 Russell King
- *
- * 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.
- */
-
-/*
- *  linux/include/asm-arm/xor.h
- *
- *  Copyright (C) 2001 Russell King
- *
- * 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 <asm-generic/xor.h>
-
-#define __XOR(a1, a2) a1 ^= a2
-
-#define GET_BLOCK_2(dst) \
-	__asm__("ldmia	%0, {%1, %2}" \
-		: "=r" (dst), "=r" (a1), "=r" (a2) \
-		: "0" (dst))
-
-#define GET_BLOCK_4(dst) \
-	__asm__("ldmia	%0, {%1, %2, %3, %4}" \
-		: "=r" (dst), "=r" (a1), "=r" (a2), "=r" (a3), "=r" (a4) \
-		: "0" (dst))
-
-#define XOR_BLOCK_2(src) \
-	__asm__("ldmia	%0!, {%1, %2}" \
-		: "=r" (src), "=r" (b1), "=r" (b2) \
-		: "0" (src)); \
-	__XOR(a1, b1); __XOR(a2, b2);
-
-#define XOR_BLOCK_4(src) \
-	__asm__("ldmia	%0!, {%1, %2, %3, %4}" \
-		: "=r" (src), "=r" (b1), "=r" (b2), "=r" (b3), "=r" (b4) \
-		: "0" (src)); \
-	__XOR(a1, b1); __XOR(a2, b2); __XOR(a3, b3); __XOR(a4, b4)
-
-#define PUT_BLOCK_2(dst) \
-	__asm__ __volatile__("stmia	%0!, {%2, %3}" \
-		: "=r" (dst) \
-		: "0" (dst), "r" (a1), "r" (a2))
-
-#define PUT_BLOCK_4(dst) \
-	__asm__ __volatile__("stmia	%0!, {%2, %3, %4, %5}" \
-		: "=r" (dst) \
-		: "0" (dst), "r" (a1), "r" (a2), "r" (a3), "r" (a4))
-
-static void
-xor_arm4regs_2(unsigned long bytes, unsigned long *p1, unsigned long *p2)
-{
-	unsigned int lines = bytes / sizeof(unsigned long) / 4;
-	register unsigned int a1 __asm__("r4");
-	register unsigned int a2 __asm__("r5");
-	register unsigned int a3 __asm__("r6");
-	register unsigned int a4 __asm__("r7");
-	register unsigned int b1 __asm__("r8");
-	register unsigned int b2 __asm__("r9");
-	register unsigned int b3 __asm__("ip");
-	register unsigned int b4 __asm__("lr");
-
-	do {
-		GET_BLOCK_4(p1);
-		XOR_BLOCK_4(p2);
-		PUT_BLOCK_4(p1);
-	} while (--lines);
-}
-
-static void
-xor_arm4regs_3(unsigned long bytes, unsigned long *p1, unsigned long *p2,
-		unsigned long *p3)
-{
-	unsigned int lines = bytes / sizeof(unsigned long) / 4;
-	register unsigned int a1 __asm__("r4");
-	register unsigned int a2 __asm__("r5");
-	register unsigned int a3 __asm__("r6");
-	register unsigned int a4 __asm__("r7");
-	register unsigned int b1 __asm__("r8");
-	register unsigned int b2 __asm__("r9");
-	register unsigned int b3 __asm__("ip");
-	register unsigned int b4 __asm__("lr");
-
-	do {
-		GET_BLOCK_4(p1);
-		XOR_BLOCK_4(p2);
-		XOR_BLOCK_4(p3);
-		PUT_BLOCK_4(p1);
-	} while (--lines);
-}
-
-static void
-xor_arm4regs_4(unsigned long bytes, unsigned long *p1, unsigned long *p2,
-		unsigned long *p3, unsigned long *p4)
-{
-	unsigned int lines = bytes / sizeof(unsigned long) / 2;
-	register unsigned int a1 __asm__("r8");
-	register unsigned int a2 __asm__("r9");
-	register unsigned int b1 __asm__("ip");
-	register unsigned int b2 __asm__("lr");
-
-	do {
-		GET_BLOCK_2(p1);
-		XOR_BLOCK_2(p2);
-		XOR_BLOCK_2(p3);
-		XOR_BLOCK_2(p4);
-		PUT_BLOCK_2(p1);
-	} while (--lines);
-}
-
-static void
-xor_arm4regs_5(unsigned long bytes, unsigned long *p1, unsigned long *p2,
-		unsigned long *p3, unsigned long *p4, unsigned long *p5)
-{
-	unsigned int lines = bytes / sizeof(unsigned long) / 2;
-	register unsigned int a1 __asm__("r8");
-	register unsigned int a2 __asm__("r9");
-	register unsigned int b1 __asm__("ip");
-	register unsigned int b2 __asm__("lr");
-
-	do {
-		GET_BLOCK_2(p1);
-		XOR_BLOCK_2(p2);
-		XOR_BLOCK_2(p3);
-		XOR_BLOCK_2(p4);
-		XOR_BLOCK_2(p5);
-		PUT_BLOCK_2(p1);
-	} while (--lines);
-}
-
-static struct xor_block_template xor_block_arm4regs = {
-	name:	"arm4regs",
-	do_2:	xor_arm4regs_2,
-	do_3:	xor_arm4regs_3,
-	do_4:	xor_arm4regs_4,
-	do_5:	xor_arm4regs_5,
-};
-
-#undef XOR_TRY_TEMPLATES
-#define XOR_TRY_TEMPLATES			\
-	do {					\
-		xor_speed(&xor_block_arm4regs);	\
-		xor_speed(&xor_block_8regs);	\
-		xor_speed(&xor_block_32regs);	\
-	} while (0)
-
-#define __XOR(a1, a2) a1 ^= a2
-
-#define GET_BLOCK_2(dst) \
-	__asm__("ldmia	%0, {%1, %2}" \
-		: "=r" (dst), "=r" (a1), "=r" (a2) \
-		: "0" (dst))
-
-#define GET_BLOCK_4(dst) \
-	__asm__("ldmia	%0, {%1, %2, %3, %4}" \
-		: "=r" (dst), "=r" (a1), "=r" (a2), "=r" (a3), "=r" (a4) \
-		: "0" (dst))
-
-#define XOR_BLOCK_2(src) \
-	__asm__("ldmia	%0!, {%1, %2}" \
-		: "=r" (src), "=r" (b1), "=r" (b2) \
-		: "0" (src)); \
-	__XOR(a1, b1); __XOR(a2, b2);
-
-#define XOR_BLOCK_4(src) \
-	__asm__("ldmia	%0!, {%1, %2, %3, %4}" \
-		: "=r" (src), "=r" (b1), "=r" (b2), "=r" (b3), "=r" (b4) \
-		: "0" (src)); \
-	__XOR(a1, b1); __XOR(a2, b2); __XOR(a3, b3); __XOR(a4, b4)
-
-#define PUT_BLOCK_2(dst) \
-	__asm__ __volatile__("stmia	%0!, {%2, %3}" \
-		: "=r" (dst) \
-		: "0" (dst), "r" (a1), "r" (a2))
-
-#define PUT_BLOCK_4(dst) \
-	__asm__ __volatile__("stmia	%0!, {%2, %3, %4, %5}" \
-		: "=r" (dst) \
-		: "0" (dst), "r" (a1), "r" (a2), "r" (a3), "r" (a4))
-
-static void
-xor_arm4regs_2(unsigned long bytes, unsigned long *p1, unsigned long *p2)
-{
-	unsigned int lines = bytes / sizeof(unsigned long) / 4;
-	register unsigned int a1 __asm__("r4");
-	register unsigned int a2 __asm__("r5");
-	register unsigned int a3 __asm__("r6");
-	register unsigned int a4 __asm__("r7");
-	register unsigned int b1 __asm__("r8");
-	register unsigned int b2 __asm__("r9");
-	register unsigned int b3 __asm__("ip");
-	register unsigned int b4 __asm__("lr");
-
-	do {
-		GET_BLOCK_4(p1);
-		XOR_BLOCK_4(p2);
-		PUT_BLOCK_4(p1);
-	} while (--lines);
-}
-
-static void
-xor_arm4regs_3(unsigned long bytes, unsigned long *p1, unsigned long *p2,
-		unsigned long *p3)
-{
-	unsigned int lines = bytes / sizeof(unsigned long) / 4;
-	register unsigned int a1 __asm__("r4");
-	register unsigned int a2 __asm__("r5");
-	register unsigned int a3 __asm__("r6");
-	register unsigned int a4 __asm__("r7");
-	register unsigned int b1 __asm__("r8");
-	register unsigned int b2 __asm__("r9");
-	register unsigned int b3 __asm__("ip");
-	register unsigned int b4 __asm__("lr");
-
-	do {
-		GET_BLOCK_4(p1);
-		XOR_BLOCK_4(p2);
-		XOR_BLOCK_4(p3);
-		PUT_BLOCK_4(p1);
-	} while (--lines);
-}
-
-static void
-xor_arm4regs_4(unsigned long bytes, unsigned long *p1, unsigned long *p2,
-		unsigned long *p3, unsigned long *p4)
-{
-	unsigned int lines = bytes / sizeof(unsigned long) / 2;
-	register unsigned int a1 __asm__("r8");
-	register unsigned int a2 __asm__("r9");
-	register unsigned int b1 __asm__("ip");
-	register unsigned int b2 __asm__("lr");
-
-	do {
-		GET_BLOCK_2(p1);
-		XOR_BLOCK_2(p2);
-		XOR_BLOCK_2(p3);
-		XOR_BLOCK_2(p4);
-		PUT_BLOCK_2(p1);
-	} while (--lines);
-}
-
-static void
-xor_arm4regs_5(unsigned long bytes, unsigned long *p1, unsigned long *p2,
-		unsigned long *p3, unsigned long *p4, unsigned long *p5)
-{
-	unsigned int lines = bytes / sizeof(unsigned long) / 2;
-	register unsigned int a1 __asm__("r8");
-	register unsigned int a2 __asm__("r9");
-	register unsigned int b1 __asm__("ip");
-	register unsigned int b2 __asm__("lr");
-
-	do {
-		GET_BLOCK_2(p1);
-		XOR_BLOCK_2(p2);
-		XOR_BLOCK_2(p3);
-		XOR_BLOCK_2(p4);
-		XOR_BLOCK_2(p5);
-		PUT_BLOCK_2(p1);
-	} while (--lines);
-}
-
-static struct xor_block_template xor_block_arm4regs = {
-	name:	"arm4regs",
-	do_2:	xor_arm4regs_2,
-	do_3:	xor_arm4regs_3,
-	do_4:	xor_arm4regs_4,
-	do_5:	xor_arm4regs_5,
-};
-
-#undef XOR_TRY_TEMPLATES
-#define XOR_TRY_TEMPLATES			\
-	do {					\
-		xor_speed(&xor_block_arm4regs);	\
-		xor_speed(&xor_block_8regs);	\
-		xor_speed(&xor_block_32regs);	\
-	} while (0)
 
 #define __XOR(a1, a2) a1 ^= a2
 
diff -urN linux-2.4.6-pre5/include/asm-sh/bigsur.h linux/include/asm-sh/bigsur.h
--- linux-2.4.6-pre5/include/asm-sh/bigsur.h	Wed Dec 31 16:00:00 1969
+++ linux/include/asm-sh/bigsur.h	Mon Dec  3 22:49:12 2001
@@ -0,0 +1,80 @@
+/*
+ *
+ * Hitachi Big Sur Eval Board support
+ *
+ * Dustin McIntire (dustin@sensoria.com)
+ *
+ * May be copied or modified under the terms of the GNU General Public
+ * License.  See linux/COPYING for more information.
+ *
+ * Derived from Hitachi SH7751 reference manual
+ * 
+ */
+
+#ifndef _ASM_BIGSUR_H_
+#define _ASM_BIGSUR_H_
+
+#include <asm/irq.h>
+#include <asm/hd64465.h>
+
+/* 7751 Internal IRQ's used by external CPLD controller */
+#define BIGSUR_IRQ_LOW	0
+#define BIGSUR_IRQ_NUM  14         /* External CPLD level 1 IRQs */
+#define BIGSUR_IRQ_HIGH (BIGSUR_IRQ_LOW + BIGSUR_IRQ_NUM)
+#define BIGSUR_2NDLVL_IRQ_LOW   (HD64465_IRQ_BASE+HD64465_IRQ_NUM)  
+#define BIGSUR_2NDLVL_IRQ_NUM   32 /* Level 2 IRQs = 4 regs * 8 bits */
+#define BIGSUR_2NDLVL_IRQ_HIGH  (BIGSUR_2NDLVL_IRQ_LOW + \
+                                 BIGSUR_2NDLVL_IRQ_NUM)
+
+/* PCI interrupt base number (A_INTA-A_INTD) */
+#define BIGSUR_SH7751_PCI_IRQ_BASE  (BIGSUR_2NDLVL_IRQ_LOW+10)  
+
+/* CPLD registers and external chip addresses */
+#define BIGSUR_HD64464_ADDR	0xB2000000
+#define BIGSUR_DGDR	0xB1FFFE00
+#define BIGSUR_BIDR	0xB1FFFD00
+#define BIGSUR_CSLR	0xB1FFFC00
+#define BIGSUR_SW1R	0xB1FFFB00
+#define BIGSUR_DBGR	0xB1FFFA00
+#define BIGSUR_BDTR	0xB1FFF900
+#define BIGSUR_BDRR	0xB1FFF800
+#define BIGSUR_PPR1	0xB1FFF700
+#define BIGSUR_PPR2	0xB1FFF600
+#define BIGSUR_IDE2	0xB1FFF500
+#define BIGSUR_IDE3	0xB1FFF400
+#define BIGSUR_SPCR	0xB1FFF300
+#define BIGSUR_ETHR	0xB1FE0000
+#define BIGSUR_PPDR	0xB1FDFF00
+#define BIGSUR_ICTL	0xB1FDFE00
+#define BIGSUR_ICMD	0xB1FDFD00
+#define BIGSUR_DMA0	0xB1FDFC00
+#define BIGSUR_DMA1	0xB1FDFB00
+#define BIGSUR_IRQ0	0xB1FDFA00
+#define BIGSUR_IRQ1	0xB1FDF900
+#define BIGSUR_IRQ2	0xB1FDF800
+#define BIGSUR_IRQ3	0xB1FDF700
+#define BIGSUR_IMR0	0xB1FDF600
+#define BIGSUR_IMR1	0xB1FDF500
+#define BIGSUR_IMR2	0xB1FDF400
+#define BIGSUR_IMR3	0xB1FDF300
+#define BIGSUR_IRLMR0	0xB1FDF200
+#define BIGSUR_IRLMR1	0xB1FDF100
+#define BIGSUR_V320USC_ADDR  0xB1000000
+#define BIGSUR_HD64465_ADDR  0xB0000000
+#define BIGSUR_INTERNAL_BASE 0xB0000000
+
+/* SMC ethernet card parameters */
+#define BIGSUR_ETHER_IOPORT		0x220
+
+/* IDE register paramters */
+#define BIGSUR_IDECMD_IOPORT	0x1f0
+#define BIGSUR_IDECTL_IOPORT	0x1f8
+
+/* LED bit position in BIGSUR_CSLR */
+#define BIGSUR_LED  (1<<4)
+
+/* PCI: default LOCAL memory window sizes (seen from PCI bus) */
+#define BIGSUR_LSR0_SIZE    (64*(1<<20)) //64MB
+#define BIGSUR_LSR1_SIZE    (64*(1<<20)) //64MB
+
+#endif /* _ASM_BIGSUR_H_ */
diff -urN linux-2.4.6-pre5/include/asm-sh/bitops.h linux/include/asm-sh/bitops.h
--- linux-2.4.6-pre5/include/asm-sh/bitops.h	Mon Oct  2 11:57:34 2000
+++ linux/include/asm-sh/bitops.h	Mon Dec  3 22:49:12 2001
@@ -19,6 +19,16 @@
 	restore_flags(flags);
 }
 
+static __inline__ void __set_bit(int nr, volatile void * addr)
+{
+	int	mask;
+	volatile unsigned int *a = addr;
+
+	a += nr >> 5;
+	mask = 1 << (nr & 0x1f);
+	*a |= mask;
+}
+
 /*
  * clear_bit() doesn't provide any barrier for the compiler.
  */
@@ -37,6 +47,16 @@
 	restore_flags(flags);
 }
 
+static __inline__ void __clear_bit(int nr, volatile void * addr)
+{
+	int	mask;
+	volatile unsigned int *a = addr;
+
+	a += nr >> 5;
+	mask = 1 << (nr & 0x1f);
+	*a &= ~mask;
+}
+
 static __inline__ void change_bit(int nr, volatile void * addr)
 {
 	int	mask;
@@ -50,6 +70,16 @@
 	restore_flags(flags);
 }
 
+static __inline__ void __change_bit(int nr, volatile void * addr)
+{
+	int	mask;
+	volatile unsigned int *a = addr;
+
+	a += nr >> 5;
+	mask = 1 << (nr & 0x1f);
+	*a ^= mask;
+}
+
 static __inline__ int test_and_set_bit(int nr, volatile void * addr)
 {
 	int	mask, retval;
@@ -66,6 +96,19 @@
 	return retval;
 }
 
+static __inline__ int __test_and_set_bit(int nr, volatile void * addr)
+{
+	int	mask, retval;
+	volatile unsigned int *a = addr;
+
+	a += nr >> 5;
+	mask = 1 << (nr & 0x1f);
+	retval = (mask & *a) != 0;
+	*a |= mask;
+
+	return retval;
+}
+
 static __inline__ int test_and_clear_bit(int nr, volatile void * addr)
 {
 	int	mask, retval;
@@ -82,6 +125,19 @@
 	return retval;
 }
 
+static __inline__ int __test_and_clear_bit(int nr, volatile void * addr)
+{
+	int	mask, retval;
+	volatile unsigned int *a = addr;
+
+	a += nr >> 5;
+	mask = 1 << (nr & 0x1f);
+	retval = (mask & *a) != 0;
+	*a &= ~mask;
+
+	return retval;
+}
+
 static __inline__ int test_and_change_bit(int nr, volatile void * addr)
 {
 	int	mask, retval;
@@ -98,6 +154,18 @@
 	return retval;
 }
 
+static __inline__ int __test_and_change_bit(int nr, volatile void * addr)
+{
+	int	mask, retval;
+	volatile unsigned int *a = addr;
+
+	a += nr >> 5;
+	mask = 1 << (nr & 0x1f);
+	retval = (mask & *a) != 0;
+	*a ^= mask;
+
+	return retval;
+}
 
 static __inline__ int test_bit(int nr, const volatile void *addr)
 {
@@ -156,6 +224,23 @@
 
 #define find_first_zero_bit(addr, size) \
         find_next_zero_bit((addr), (size), 0)
+
+/*
+ * ffs: find first bit set. This is defined the same way as
+ * the libc and compiler builtin ffs routines, therefore
+ * differs in spirit from the above ffz (man ffs).
+ */
+
+#define ffs(x) generic_ffs(x)
+
+/*
+ * hweightN: returns the hamming weight (i.e. the number
+ * of bits set) of a N-bit word
+ */
+
+#define hweight32(x) generic_hweight32(x)
+#define hweight16(x) generic_hweight16(x)
+#define hweight8(x) generic_hweight8(x)
 
 #ifdef __LITTLE_ENDIAN__
 #define ext2_set_bit(nr, addr) test_and_set_bit((nr), (addr))
diff -urN linux-2.4.6-pre5/include/asm-sh/bugs.h linux/include/asm-sh/bugs.h
--- linux-2.4.6-pre5/include/asm-sh/bugs.h	Wed Apr 11 21:24:52 2001
+++ linux/include/asm-sh/bugs.h	Mon Dec  3 22:49:12 2001
@@ -32,7 +32,7 @@
 		break;
 	case CPU_SH7750:
 		*p++ = '4';
-		printk("CPU: SH7750\n");
+		printk("CPU: SH7750/SH7751\n");
 		break;
 	case CPU_ST40STB1:
 		*p++ = '4';
diff -urN linux-2.4.6-pre5/include/asm-sh/dc_sysasic.h linux/include/asm-sh/dc_sysasic.h
--- linux-2.4.6-pre5/include/asm-sh/dc_sysasic.h	Wed Dec 31 16:00:00 1969
+++ linux/include/asm-sh/dc_sysasic.h	Mon Dec  3 22:49:12 2001
@@ -0,0 +1,35 @@
+/* include/asm-sh/dc_sysasic.h
+ *
+ * Definitions for the Dreamcast System ASIC and related peripherals.
+ *
+ * Copyright (c) 2001 M. R. Brown <mrbrown@linuxdc.org>
+ *
+ * This file is part of the LinuxDC project (www.linuxdc.org)
+ *
+ * Released under the terms of the GNU GPL v2.0.
+ *
+ */
+
+#include <asm/irq.h>
+
+/* Hardware events -
+
+   Each of these events correspond to a bit within the Event Mask Registers/
+   Event Status Registers.  Because of the virtual IRQ numbering scheme, a
+   base offset must be used when calculating the virtual IRQ that each event
+   takes.
+*/
+
+#define HW_EVENT_IRQ_BASE  OFFCHIP_IRQ_BASE /* 48 */
+
+/* IRQ 13 */
+#define HW_EVENT_VSYNC     (HW_EVENT_IRQ_BASE +  5) /* VSync */
+#define HW_EVENT_MAPLE_DMA (HW_EVENT_IRQ_BASE + 12) /* Maple DMA complete */
+#define HW_EVENT_GDROM_DMA (HW_EVENT_IRQ_BASE + 14) /* GD-ROM DMA complete */
+
+/* IRQ 11 */
+#define HW_EVENT_GDROM_CMD (HW_EVENT_IRQ_BASE + 32) /* GD-ROM cmd. complete */
+#define HW_EVENT_AICA_SYS  (HW_EVENT_IRQ_BASE + 33) /* AICA-related */
+#define HW_EVENT_EXTERNAL  (HW_EVENT_IRQ_BASE + 35) /* Ext. (expansion) */
+
+#define HW_EVENT_IRQ_MAX (HW_EVENT_IRQ_BASE + 95)
diff -urN linux-2.4.6-pre5/include/asm-sh/hardirq.h linux/include/asm-sh/hardirq.h
--- linux-2.4.6-pre5/include/asm-sh/hardirq.h	Fri Aug  4 16:15:37 2000
+++ linux/include/asm-sh/hardirq.h	Mon Dec  3 22:49:12 2001
@@ -6,8 +6,7 @@
 
 /* entry.S is sensitive to the offsets of these fields */
 typedef struct {
-	unsigned int __softirq_active;
-	unsigned int __softirq_mask;
+	unsigned int __softirq_pending;
 	unsigned int __local_irq_count;
 	unsigned int __local_bh_count;
 	unsigned int __syscall_count;
diff -urN linux-2.4.6-pre5/include/asm-sh/hd64465_gpio.h linux/include/asm-sh/hd64465_gpio.h
--- linux-2.4.6-pre5/include/asm-sh/hd64465_gpio.h	Sun May 20 12:11:39 2001
+++ linux/include/asm-sh/hd64465_gpio.h	Mon Dec  3 22:49:12 2001
@@ -1,7 +1,7 @@
 #ifndef _ASM_SH_HD64465_GPIO_
 #define _ASM_SH_HD64465_GPIO_ 1
 /*
- * $Id: hd64465_gpio.h,v 1.1 2001/01/02 15:35:22 mjd Exp $
+ * $Id: hd64465_gpio.h,v 1.2 2001/05/24 00:14:13 gniibe Exp $
  *
  * Hitachi HD64465 companion chip: General Purpose IO pins support.
  * This layer enables other device drivers to configure GPIO
diff -urN linux-2.4.6-pre5/include/asm-sh/io.h linux/include/asm-sh/io.h
--- linux-2.4.6-pre5/include/asm-sh/io.h	Wed Apr 11 21:24:52 2001
+++ linux/include/asm-sh/io.h	Mon Dec  3 22:49:12 2001
@@ -109,10 +109,10 @@
 
 # if defined(CONFIG_SH_HP600)
 #  include <asm/io_hd64461.h>
-# elif defined(CONFIG_SH_7750_OVERDRIVE)
-#  include <asm/io_od.h>
-# elif defined(CONFIG_SH_SOLUTION_ENGINE)
+# elif (defined(CONFIG_SH_SOLUTION_ENGINE) || defined(CONFIG_SH_7751_SOLUTION_ENGINE))
 #  include <asm/io_se.h>
+# elif defined(CONFIG_SH_SH2000)
+#  include <asm/io_sh2000.h>
 # elif defined(CONFIG_SH_DMIDA) || \
        defined(CONFIG_SH_STB1_HARP) || \
        defined(CONFIG_SH_STB1_OVERDRIVE)
@@ -123,6 +123,8 @@
 #  include <asm/io_dc.h>
 # elif defined(CONFIG_SH_CAT68701)
 #  include <asm/io_cat68701.h>
+# elif defined(CONFIG_SH_BIGSUR)
+#  include <asm/io_bigsur.h>
 # elif defined(CONFIG_SH_UNKNOWN)
 #  include <asm/io_unknown.h>
 # else
diff -urN linux-2.4.6-pre5/include/asm-sh/io_bigsur.h linux/include/asm-sh/io_bigsur.h
--- linux-2.4.6-pre5/include/asm-sh/io_bigsur.h	Wed Dec 31 16:00:00 1969
+++ linux/include/asm-sh/io_bigsur.h	Mon Dec  3 22:49:12 2001
@@ -0,0 +1,89 @@
+/*
+ * include/asm-sh/io_bigsur.h
+ *
+ * By Dustin McIntire (dustin@sensoria.com) (c)2001
+ * Derived from io_hd64465.h, which bore the message:
+ * By Greg Banks <gbanks@pocketpenguins.com>
+ * (c) 2000 PocketPenguins Inc. 
+ * and from io_hd64461.h, which bore the message:
+ * Copyright 2000 Stuart Menefy (stuart.menefy@st.com)
+ *
+ * May be copied or modified under the terms of the GNU General Public
+ * License.  See linux/COPYING for more information.
+ *
+ * IO functions for a Hitachi Big Sur Evaluation Board.
+ */
+
+#ifndef _ASM_SH_IO_BIGSUR_H
+#define _ASM_SH_IO_BIGSUR_H
+
+#include <linux/types.h>
+#include <asm/io_generic.h>
+
+extern unsigned char bigsur_inb(unsigned long port);
+extern unsigned short bigsur_inw(unsigned long port);
+extern unsigned int bigsur_inl(unsigned long port);
+
+extern void bigsur_outb(unsigned char value, unsigned long port);
+extern void bigsur_outw(unsigned short value, unsigned long port);
+extern void bigsur_outl(unsigned int value, unsigned long port);
+
+extern unsigned char bigsur_inb_p(unsigned long port);
+extern void bigsur_outb_p(unsigned char value, unsigned long port);
+
+extern void bigsur_insb(unsigned long port, void *addr, unsigned long count);
+extern void bigsur_insw(unsigned long port, void *addr, unsigned long count);
+extern void bigsur_insl(unsigned long port, void *addr, unsigned long count);
+extern void bigsur_outsb(unsigned long port, const void *addr, unsigned long count);
+extern void bigsur_outsw(unsigned long port, const void *addr, unsigned long count);
+extern void bigsur_outsl(unsigned long port, const void *addr, unsigned long count);
+extern unsigned long bigsur_isa_port2addr(unsigned long offset);
+extern int bigsur_irq_demux(int irq);
+extern void bigsur_init_pci(void);
+/* Provision for generic secondary demux step -- used by PCMCIA code */
+extern void bigsur_register_irq_demux(int irq,
+		int (*demux)(int irq, void *dev), void *dev);
+extern void bigsur_unregister_irq_demux(int irq);
+/* Set this variable to 1 to see port traffic */
+extern int bigsur_io_debug;
+/* Map a range of ports to a range of kernel virtual memory. */
+extern void bigsur_port_map(u32 baseport, u32 nports, u32 addr, u8 shift);
+extern void bigsur_port_unmap(u32 baseport, u32 nports);
+
+#endif /* _ASM_SH_IO_BIGSUR_H */
+
+#ifdef __WANT_IO_DEF
+
+# define __inb			bigsur_inb
+# define __inw			bigsur_inw
+# define __inl			bigsur_inl
+# define __outb			bigsur_outb
+# define __outw			bigsur_outw
+# define __outl			bigsur_outl
+
+# define __inb_p		bigsur_inb_p
+# define __inw_p		bigsur_inw
+# define __inl_p		bigsur_inl
+# define __outb_p		bigsur_outb_p
+# define __outw_p		bigsur_outw
+# define __outl_p		bigsur_outl
+
+# define __insb			bigsur_insb
+# define __insw			bigsur_insw
+# define __insl			bigsur_insl
+# define __outsb		bigsur_outsb
+# define __outsw		bigsur_outsw
+# define __outsl		bigsur_outsl
+
+# define __readb		generic_readb
+# define __readw		generic_readw
+# define __readl		generic_readl
+# define __writeb		generic_writeb
+# define __writew		generic_writew
+# define __writel		generic_writel
+
+# define __isa_port2addr	bigsur_isa_port2addr
+# define __ioremap		generic_ioremap
+# define __iounmap		generic_iounmap
+
+#endif
diff -urN linux-2.4.6-pre5/include/asm-sh/io_od.h linux/include/asm-sh/io_od.h
--- linux-2.4.6-pre5/include/asm-sh/io_od.h	Wed Apr 11 21:24:52 2001
+++ linux/include/asm-sh/io_od.h	Wed Dec 31 16:00:00 1969
@@ -1,77 +0,0 @@
-/*
- * include/asm-sh/io_od.h
- *
- * Copyright 2000 Stuart Menefy (stuart.menefy@st.com)
- *
- * May be copied or modified under the terms of the GNU General Public
- * License.  See linux/COPYING for more information.
- *
- * IO functions for an STMicroelectronics Overdrive
- */
-
-#ifndef _ASM_SH_IO_OD_H
-#define _ASM_SH_IO_OD_H
-
-#include <asm/io_generic.h>
-
-extern unsigned char od_inb(unsigned long port);
-extern unsigned short od_inw(unsigned long port);
-extern unsigned int od_inl(unsigned long port);
-
-extern void od_outb(unsigned char value, unsigned long port);
-extern void od_outw(unsigned short value, unsigned long port);
-extern void od_outl(unsigned int value, unsigned long port);
-
-extern unsigned char od_inb_p(unsigned long port);
-extern unsigned short od_inw_p(unsigned long port);
-extern unsigned int od_inl_p(unsigned long port);
-extern void od_outb_p(unsigned char value, unsigned long port);
-extern void od_outw_p(unsigned short value, unsigned long port);
-extern void od_outl_p(unsigned int value, unsigned long port);
-
-extern void od_insb(unsigned long port, void *addr, unsigned long count);
-extern void od_insw(unsigned long port, void *addr, unsigned long count);
-extern void od_insl(unsigned long port, void *addr, unsigned long count);
-extern void od_outsb(unsigned long port, const void *addr, unsigned long count);
-extern void od_outsw(unsigned long port, const void *addr, unsigned long count);
-extern void od_outsl(unsigned long port, const void *addr, unsigned long count);
-
-extern unsigned long od_isa_port2addr(unsigned long offset);
-
-#ifdef __WANT_IO_DEF
-
-# define __inb			od_inb
-# define __inw			od_inw
-# define __inl			od_inl
-# define __outb			od_outb
-# define __outw			od_outw
-# define __outl			od_outl
-
-# define __inb_p		od_inb_p
-# define __inw_p		od_inw_p
-# define __inl_p		od_inl_p
-# define __outb_p		od_outb_p
-# define __outw_p		od_outw_p
-# define __outl_p		od_outl_p
-
-# define __insb			od_insb
-# define __insw			od_insw
-# define __insl			od_insl
-# define __outsb		od_outsb
-# define __outsw		od_outsw
-# define __outsl		od_outsl
-
-# define __readb		generic_readb
-# define __readw		generic_readw
-# define __readl		generic_readl
-# define __writeb		generic_writeb
-# define __writew		generic_writew
-# define __writel		generic_writel
-
-# define __isa_port2addr	od_isa_port2addr
-# define __ioremap		generic_ioremap
-# define __iounmap		generic_iounmap
-
-#endif
-
-#endif /* _ASM_SH_IO_OD_H */
diff -urN linux-2.4.6-pre5/include/asm-sh/io_sh2000.h linux/include/asm-sh/io_sh2000.h
--- linux-2.4.6-pre5/include/asm-sh/io_sh2000.h	Wed Dec 31 16:00:00 1969
+++ linux/include/asm-sh/io_sh2000.h	Mon Dec  3 22:49:12 2001
@@ -0,0 +1,56 @@
+/*
+ * include/asm-sh/io_sh2000.h
+ *
+ * Copyright 2000 Stuart Menefy (stuart.menefy@st.com)
+ *           2001 SUGIOKA Toshinobu (sugioka@itonet.co.jp)
+ *
+ * May be copied or modified under the terms of the GNU General Public
+ * License.  See linux/COPYING for more information.
+ *
+ * IO functions for use when we don't know what machine we are on
+ */
+
+#ifndef _ASM_SH_IO_SH2000_H
+#define _ASM_SH_IO_SH2000_H
+
+#include <asm/io_generic.h>
+
+unsigned long sh2000_isa_port2addr(unsigned long offset);
+
+#ifdef __WANT_IO_DEF
+
+# define __inb			generic_inb
+# define __inw			generic_inw
+# define __inl			generic_inl
+# define __outb			generic_outb
+# define __outw			generic_outw
+# define __outl			generic_outl
+
+# define __inb_p		generic_inb_p
+# define __inw_p		generic_inw
+# define __inl_p		generic_inl
+# define __outb_p		generic_outb_p
+# define __outw_p		generic_outw
+# define __outl_p		generic_outl
+
+# define __insb			generic_insb
+# define __insw			generic_insw
+# define __insl			generic_insl
+# define __outsb		generic_outsb
+# define __outsw		generic_outsw
+# define __outsl		generic_outsl
+
+# define __readb		generic_readb
+# define __readw		generic_readw
+# define __readl		generic_readl
+# define __writeb		generic_writeb
+# define __writew		generic_writew
+# define __writel		generic_writel
+
+# define __isa_port2addr	sh2000_isa_port2addr
+# define __ioremap		generic_ioremap
+# define __iounmap		generic_iounmap
+
+#endif
+
+#endif /* _ASM_SH_IO_SH2000_H */
diff -urN linux-2.4.6-pre5/include/asm-sh/irq.h linux/include/asm-sh/irq.h
--- linux-2.4.6-pre5/include/asm-sh/irq.h	Wed Apr 11 21:24:52 2001
+++ linux/include/asm-sh/irq.h	Mon Dec  3 22:49:12 2001
@@ -43,7 +43,8 @@
 #define DMA_PRIORITY	7
 
 #if defined (CONFIG_CPU_SUBTYPE_SH7707) || defined (CONFIG_CPU_SUBTYPE_SH7708) || \
-    defined (CONFIG_CPU_SUBTYPE_SH7709) || defined (CONFIG_CPU_SUBTYPE_SH7750)
+    defined (CONFIG_CPU_SUBTYPE_SH7709) || defined (CONFIG_CPU_SUBTYPE_SH7750) || \
+    defined (CONFIG_CPU_SUBTYPE_SH7751)
 #define SCI_ERI_IRQ	23
 #define SCI_RXI_IRQ	24
 #define SCI_TXI_IRQ	25
@@ -68,7 +69,8 @@
 #define IRDA_IPR_ADDR	INTC_IPRE
 #define IRDA_IPR_POS	2
 #define IRDA_PRIORITY	3
-#elif defined(CONFIG_CPU_SUBTYPE_SH7750) || defined(CONFIG_CPU_SUBTYPE_ST40STB1)
+#elif defined(CONFIG_CPU_SUBTYPE_SH7750) || defined(CONFIG_CPU_SUBTYPE_SH7751) || \
+      defined(CONFIG_CPU_SUBTYPE_ST40STB1)
 #define SCIF_ERI_IRQ	40
 #define SCIF_RXI_IRQ	41
 #define SCIF_BRI_IRQ	42
@@ -95,7 +97,7 @@
 
 /* 1. ONCHIP_NR_IRQS */
 #ifdef CONFIG_SH_GENERIC
-# define ONCHIP_NR_IRQS 89
+# define ONCHIP_NR_IRQS 144
 #else
 # if defined(CONFIG_CPU_SUBTYPE_SH7707)
 #  define ONCHIP_NR_IRQS 64
@@ -107,8 +109,10 @@
 #  define PINT_NR_IRQS   16
 # elif defined(CONFIG_CPU_SUBTYPE_SH7750)
 #  define ONCHIP_NR_IRQS 48	// Actually 44
+# elif defined(CONFIG_CPU_SUBTYPE_SH7751)
+#  define ONCHIP_NR_IRQS 72
 # elif defined(CONFIG_CPU_SUBTYPE_ST40STB1)
-#  define ONCHIP_NR_IRQS 89
+#  define ONCHIP_NR_IRQS 144
 # endif
 #endif
 
@@ -131,10 +135,14 @@
 #else
 # if defined(CONFIG_HD64461)
 #  define OFFCHIP_NR_IRQS 16
+# elif defined (CONFIG_SH_BIGSUR) /* must be before CONFIG_HD64465 */
+#  define OFFCHIP_NR_IRQS 48
 # elif defined(CONFIG_HD64465)
 #  define OFFCHIP_NR_IRQS 16
 # elif defined (CONFIG_SH_EC3104)
 #  define OFFCHIP_NR_IRQS 16
+# elif defined (CONFIG_SH_DREAMCAST)
+#  define OFFCHIP_NR_IRQS 96
 # else
 #  define OFFCHIP_NR_IRQS 0
 # endif
@@ -240,6 +248,16 @@
 #define __irq_demux(irq) irq
 #endif /* CONFIG_CPU_SUBTYPE_SH7707 || CONFIG_CPU_SUBTYPE_SH7709 */
 
+#if defined(CONFIG_CPU_SUBTYPE_SH7750) || defined(CONFIG_CPU_SUBTYPE_SH7751) || \
+    defined(CONFIG_CPU_SUBTYPE_ST40STB1)
+#define INTC_ICR        0xffd00000
+#define INTC_ICR_NMIL	(1<<15)
+#define INTC_ICR_MAI	(1<<14)
+#define INTC_ICR_NMIB	(1<<9)
+#define INTC_ICR_NMIE	(1<<8)
+#define INTC_ICR_IRLM	(1<<7)
+#endif
+
 #ifdef CONFIG_CPU_SUBTYPE_ST40STB1
 #define INTC2_FIRST_IRQ 64
 #define NR_INTC2_IRQS 25
@@ -266,6 +284,11 @@
 	return __irq_demux(irq);
 }
 
+#elif defined(CONFIG_SH_BIGSUR)
+
+extern int bigsur_irq_demux(int irq);
+#define irq_demux(irq) bigsur_irq_demux(irq)
+
 #elif defined(CONFIG_HD64461)
 
 extern int hd64461_irq_demux(int irq);
@@ -285,6 +308,11 @@
 
 extern int cat68701_irq_demux(int irq);
 #define irq_demux cat68701_irq_demux
+
+#elif defined(CONFIG_SH_DREAMCAST)
+
+extern int systemasic_irq_demux(int irq);
+#define irq_demux systemasic_irq_demux
 
 #else
 
diff -urN linux-2.4.6-pre5/include/asm-sh/machvec.h linux/include/asm-sh/machvec.h
--- linux-2.4.6-pre5/include/asm-sh/machvec.h	Wed Apr 11 21:24:52 2001
+++ linux/include/asm-sh/machvec.h	Mon Dec  3 22:49:12 2001
@@ -72,8 +72,10 @@
 	unsigned int mv_hw_hp680 : 1;
 	unsigned int mv_hw_hp690 : 1;
 	unsigned int mv_hw_hd64461 : 1;
+	unsigned int mv_hw_sh2000 : 1;
 	unsigned int mv_hw_hd64465 : 1;
 	unsigned int mv_hw_dreamcast : 1;
+	unsigned int mv_hw_bigsur : 1;
 };
 
 extern struct sh_machine_vector sh_mv;
@@ -87,9 +89,12 @@
 #define MACH_HP690	(sh_mv.mv_hw_hp690)
 #define MACH_HD64461	(sh_mv.mv_hw_hd64461)
 #define MACH_HD64465	(sh_mv.mv_hw_hd64465)
+#define MACH_SH2000	(sh_mv.mv_hw_sh2000)
 #define MACH_DREAMCAST	(sh_mv.mv_hw_dreamcast)
+#define MACH_BIGSUR	(sh_mv.mv_hw_bigsur)
 #else
-# ifdef CONFIG_SH_SOLUTION_ENGINE
+# if defined(CONFIG_SH_SOLUTION_ENGINE) || \
+     defined(CONFIG_SH_7751_SOLUTION_ENGINE)
 #  define MACH_SE		1
 # else
 #  define MACH_SE		0
@@ -114,6 +119,7 @@
 # else
 #  define MACH_HP690		0
 # endif
+# endif
 # ifdef CONFIG_HD64461
 #  define MACH_HD64461		1
 # else
@@ -124,6 +130,11 @@
 # else
 #  define MACH_HD64465		0
 # endif
+# ifdef CONFIG_SH_SH2000
+#  define MACH_SH2000		1
+# else
+#  define MACH_SH2000		0
+# endif
 # ifdef CONFIG_SH_EC3104
 #  define MACH_EC3104		1
 # else
@@ -134,6 +145,10 @@
 # else
 #  define MACH_DREAMCAST	0
 # endif
+# ifdef CONFIG_SH_BIGSUR
+#  define MACH_BIGSUR		1
+# else
+#  define MACH_BIGSUR		0
 #endif
 
 #endif /* _ASM_SH_MACHVEC_H */
diff -urN linux-2.4.6-pre5/include/asm-sh/mc146818rtc.h linux/include/asm-sh/mc146818rtc.h
--- linux-2.4.6-pre5/include/asm-sh/mc146818rtc.h	Wed Dec 31 16:00:00 1969
+++ linux/include/asm-sh/mc146818rtc.h	Mon Dec  3 22:49:12 2001
@@ -0,0 +1,159 @@
+/*
+ * Machine dependent access functions for RTC registers.
+ */
+#ifndef _ASM_MC146818RTC_H
+#define _ASM_MC146818RTC_H
+
+#include <asm/rtc.h>
+
+#define RTC_ALWAYS_BCD	1
+
+/* FIXME:RTC Interrupt feature is not implemented yet. */
+#undef  RTC_IRQ
+#define RTC_IRQ		0
+
+#if defined(__sh3__)
+#define RTC_PORT(n)		(R64CNT+(n)*2)
+#define CMOS_READ(addr)		__CMOS_READ(addr,b)
+#define CMOS_WRITE(val,addr)	__CMOS_WRITE(val,addr,b)
+
+#elif defined(__SH4__)
+#define RTC_PORT(n)		(R64CNT+(n)*4)
+#define CMOS_READ(addr)		__CMOS_READ(addr,w)
+#define CMOS_WRITE(val,addr)	__CMOS_WRITE(val,addr,w)
+#endif
+
+#define __CMOS_READ(addr, s) ({						\
+	unsigned char val=0, rcr1, rcr2, r64cnt, retry;			\
+	switch(addr) {							\
+		case RTC_SECONDS:					\
+			val = ctrl_inb(RSECCNT);			\
+			break;						\
+		case RTC_SECONDS_ALARM:					\
+			val = ctrl_inb(RSECAR);				\
+			break;						\
+		case RTC_MINUTES:					\
+			val = ctrl_inb(RMINCNT);			\
+			break;						\
+		case RTC_MINUTES_ALARM:					\
+			val = ctrl_inb(RMINAR);				\
+			break;						\
+		case RTC_HOURS:						\
+			val = ctrl_inb(RHRCNT);				\
+			break;						\
+		case RTC_HOURS_ALARM:					\
+			val = ctrl_inb(RHRAR);				\
+			break;						\
+		case RTC_DAY_OF_WEEK:					\
+			val = ctrl_inb(RWKCNT);				\
+			break;						\
+		case RTC_DAY_OF_MONTH:					\
+			val = ctrl_inb(RDAYCNT);			\
+			break;						\
+		case RTC_MONTH:						\
+			val = ctrl_inb(RMONCNT);			\
+			break;						\
+		case RTC_YEAR:						\
+			val = ctrl_in##s(RYRCNT);			\
+			break;						\
+		case RTC_REG_A: /* RTC_FREQ_SELECT */			\
+			rcr2 = ctrl_inb(RCR2);				\
+			val = (rcr2 & RCR2_PESMASK) >> 4;		\
+			rcr1 = ctrl_inb(RCR1);				\
+			rcr1 = (rcr1 & (RCR1_CIE | RCR1_AIE)) | RCR1_AF;\
+			retry = 0;					\
+			do {						\
+				ctrl_outb(rcr1, RCR1); /* clear CF */	\
+				r64cnt = ctrl_inb(R64CNT);		\
+			} while((ctrl_inb(RCR1) & RCR1_CF) && retry++ < 1000);\
+			r64cnt ^= RTC_BIT_INVERTED;			\
+			if(r64cnt == 0x7f || r64cnt == 0)		\
+				val |= RTC_UIP;				\
+			break;						\
+		case RTC_REG_B:	/* RTC_CONTROL */			\
+			rcr1 = ctrl_inb(RCR1);				\
+			rcr2 = ctrl_inb(RCR2);				\
+			if(rcr1 & RCR1_CIE)	val |= RTC_UIE;		\
+			if(rcr1 & RCR1_AIE)	val |= RTC_AIE;		\
+			if(rcr2 & RCR2_PESMASK)	val |= RTC_PIE;		\
+			if(!(rcr2 & RCR2_START))val |= RTC_SET;		\
+			val |= RTC_24H;					\
+			break;						\
+		case RTC_REG_C:	/* RTC_INTR_FLAGS */			\
+			rcr1 = ctrl_inb(RCR1);				\
+			rcr1 &= ~(RCR1_CF | RCR1_AF);			\
+			ctrl_outb(rcr1, RCR1);				\
+			rcr2 = ctrl_inb(RCR2);				\
+			rcr2 &= ~RCR2_PEF;				\
+			ctrl_outb(rcr2, RCR2);				\
+			break;						\
+		case RTC_REG_D:	/* RTC_VALID */				\
+			/* Always valid ... */				\
+			val = RTC_VRT;					\
+			break;						\
+		default:						\
+			break;						\
+	}								\
+	val;								\
+})
+
+#define __CMOS_WRITE(val, addr, s) ({					\
+	unsigned char rcr1,rcr2;					\
+	switch(addr) {							\
+		case RTC_SECONDS:					\
+			ctrl_outb(val, RSECCNT);			\
+			break;						\
+		case RTC_SECONDS_ALARM:					\
+			ctrl_outb(val, RSECAR);				\
+			break;						\
+		case RTC_MINUTES:					\
+			ctrl_outb(val, RMINCNT);			\
+			break;						\
+		case RTC_MINUTES_ALARM:					\
+			ctrl_outb(val, RMINAR);				\
+			break;						\
+		case RTC_HOURS:						\
+			ctrl_outb(val, RHRCNT);				\
+			break;						\
+		case RTC_HOURS_ALARM:					\
+			ctrl_outb(val, RHRAR);				\
+			break;						\
+		case RTC_DAY_OF_WEEK:					\
+			ctrl_outb(val, RWKCNT);				\
+			break;						\
+		case RTC_DAY_OF_MONTH:					\
+			ctrl_outb(val, RDAYCNT);			\
+			break;						\
+		case RTC_MONTH:						\
+			ctrl_outb(val, RMONCNT);			\
+			break;						\
+		case RTC_YEAR:						\
+			ctrl_out##s((ctrl_in##s(RYRCNT) & 0xff00) | (val & 0xff), RYRCNT);\
+			break;						\
+		case RTC_REG_A: /* RTC_FREQ_SELECT */			\
+			rcr2 = ctrl_inb(RCR2);				\
+			if((val & RTC_DIV_CTL) == RTC_DIV_RESET2)	\
+				rcr2 |= RCR2_RESET;			\
+			ctrl_outb(rcr2, RCR2);				\
+			break;						\
+		case RTC_REG_B:	/* RTC_CONTROL */			\
+			rcr1 = (ctrl_inb(RCR1) & 0x99) | RCR1_AF;	\
+			if(val & RTC_AIE) rcr1 |= RCR1_AIE;		\
+			else              rcr1 &= ~RCR1_AIE;		\
+			if(val & RTC_UIE) rcr1 |= RCR1_CIE;		\
+			else              rcr1 &= ~RCR1_CIE;		\
+			ctrl_outb(rcr1, RCR1);				\
+			rcr2 = ctrl_inb(RCR2);				\
+			if(val & RTC_SET) rcr2 &= ~RCR2_START;		\
+			else              rcr2 |= RCR2_START;		\
+			ctrl_outb(rcr2, RCR2);				\
+			break;						\
+		case RTC_REG_C:	/* RTC_INTR_FLAGS */			\
+			break;						\
+		case RTC_REG_D:	/* RTC_VALID */				\
+			break;						\
+		default:						\
+			break;						\
+	}								\
+})
+#endif /* _ASM_MC146818RTC_H */
diff -urN linux-2.4.6-pre5/include/asm-sh/pci-sh7751.h linux/include/asm-sh/pci-sh7751.h
--- linux-2.4.6-pre5/include/asm-sh/pci-sh7751.h	Wed Dec 31 16:00:00 1969
+++ linux/include/asm-sh/pci-sh7751.h	Mon Dec  3 22:49:12 2001
@@ -0,0 +1,281 @@
+/*
+ *	Low-Level PCI Support for SH7751 targets
+ *
+ *  Dustin McIntire (dustin@sensoria.com) (c) 2001
+ *	
+ *  May be copied or modified under the terms of the GNU General Public
+ *  License.  See linux/COPYING for more information.
+ *
+ */
+
+#ifndef _PCI_SH7751_H_
+#define _PCI_SH7751_H_
+
+#include <linux/pci.h>
+
+/* set debug level 4=verbose...1=terse */
+//#define DEBUG_PCI 3
+#undef DEBUG_PCI
+
+#ifdef DEBUG_PCI
+#define PCIDBG(n, x...) { if(DEBUG_PCI>=n) printk(x); }
+#else
+#define PCIDBG(n, x...)
+#endif
+
+/* startup values */
+#define PCI_PROBE_BIOS 1
+#define PCI_PROBE_CONF1 2
+#define PCI_PROBE_CONF2 4
+#define PCI_NO_SORT 0x100
+#define PCI_BIOS_SORT 0x200
+#define PCI_NO_CHECKS 0x400
+#define PCI_ASSIGN_ROMS 0x1000
+#define PCI_BIOS_IRQ_SCAN 0x2000
+
+/* Platform Specific Values */
+#define SH7751_VENDOR_ID             0x1054
+#define SH7751_DEVICE_ID             0x3505
+
+/* SH7751 Specific Values */
+#define SH7751_PCI_CONFIG_BASE	     0xFD000000  /* Config space base addr */
+#define SH7751_PCI_CONFIG_SIZE       0x1000000   /* Config space size */
+#define SH7751_PCI_MEMORY_BASE	     0xFD000000  /* Memory space base addr */
+#define SH7751_PCI_MEM_SIZE          0x01000000  /* Size of Memory window */
+#define SH7751_PCI_IO_BASE           0xFE240000  /* IO space base address */
+#define SH7751_PCI_IO_SIZE           0x40000     /* Size of IO window */
+
+#define SH7751_PCIREG_BASE           0xFE200000  /* PCI regs base address */
+#define PCI_REG(n)                  (SH7751_PCIREG_BASE+ n)
+
+#define SH7751_PCICONF0            0x0           /* PCI Config Reg 0 */
+  #define SH7751_PCICONF0_DEVID      0xFFFF0000  /* Device ID */
+  #define SH7751_PCICONF0_VNDID      0x0000FFFF  /* Vendor ID */
+#define SH7751_PCICONF1            0x4           /* PCI Config Reg 1 */
+  #define SH7751_PCICONF1_DPE        0x80000000  /* Data Parity Error */
+  #define SH7751_PCICONF1_SSE        0x40000000  /* System Error Status */
+  #define SH7751_PCICONF1_RMA        0x20000000  /* Master Abort */
+  #define SH7751_PCICONF1_RTA        0x10000000  /* Target Abort Rx Status */
+  #define SH7751_PCICONF1_STA        0x08000000  /* Target Abort Exec Status */
+  #define SH7751_PCICONF1_DEV        0x06000000  /* Timing Status */
+  #define SH7751_PCICONF1_DPD        0x01000000  /* Data Parity Status */
+  #define SH7751_PCICONF1_FBBC       0x00800000  /* Back 2 Back Status */
+  #define SH7751_PCICONF1_UDF        0x00400000  /* User Defined Status */
+  #define SH7751_PCICONF1_66M        0x00200000  /* 66Mhz Operation Status */
+  #define SH7751_PCICONF1_PM         0x00100000  /* Power Management Status */
+  #define SH7751_PCICONF1_PBBE       0x00000200  /* Back 2 Back Control */
+  #define SH7751_PCICONF1_SER        0x00000100  /* SERR Output Control */
+  #define SH7751_PCICONF1_WCC        0x00000080  /* Wait Cycle Control */
+  #define SH7751_PCICONF1_PER        0x00000040  /* Parity Error Response */
+  #define SH7751_PCICONF1_VPS        0x00000020  /* VGA Pallet Snoop */
+  #define SH7751_PCICONF1_MWIE       0x00000010  /* Memory Write+Invalidate */
+  #define SH7751_PCICONF1_SPC        0x00000008  /* Special Cycle Control */
+  #define SH7751_PCICONF1_BUM        0x00000004  /* Bus Master Control */
+  #define SH7751_PCICONF1_MES        0x00000002  /* Memory Space Control */
+  #define SH7751_PCICONF1_IOS        0x00000001  /* I/O Space Control */
+#define SH7751_PCICONF2            0x8           /* PCI Config Reg 2 */
+  #define SH7751_PCICONF2_BCC        0xFF000000  /* Base Class Code */
+  #define SH7751_PCICONF2_SCC        0x00FF0000  /* Sub-Class Code */
+  #define SH7751_PCICONF2_RLPI       0x0000FF00  /* Programming Interface */
+  #define SH7751_PCICONF2_REV        0x000000FF  /* Revision ID */
+#define SH7751_PCICONF3            0xC           /* PCI Config Reg 3 */ 
+  #define SH7751_PCICONF3_BIST7      0x80000000  /* Bist Supported */
+  #define SH7751_PCICONF3_BIST6      0x40000000  /* Bist Executing */
+  #define SH7751_PCICONF3_BIST3_0    0x0F000000  /* Bist Passed */
+  #define SH7751_PCICONF3_HD7        0x00800000  /* Single Funtion device */
+  #define SH7751_PCICONF3_HD6_0      0x007F0000  /* Configuration Layout */
+  #define SH7751_PCICONF3_LAT        0x0000FF00  /* Latency Timer */
+  #define SH7751_PCICONF3_CLS        0x000000FF  /* Cache Line Size */
+#define SH7751_PCICONF4            0x10          /* PCI Config Reg 4 */
+  #define SH7751_PCICONF4_BASE       0xFFFFFFFC  /* I/O Space Base Addr */
+  #define SH7751_PCICONF4_ASI        0x00000001  /* Address Space Type */
+#define SH7751_PCICONF5            0x14          /* PCI Config Reg 5 */
+  #define SH7751_PCICONF5_BASE       0xFFFFFFF0  /* Mem Space Base Addr */
+  #define SH7751_PCICONF5_LAP        0x00000008  /* Prefetch Enabled */
+  #define SH7751_PCICONF5_LAT        0x00000006  /* Local Memory type */
+  #define SH7751_PCICONF5_ASI        0x00000001  /* Address Space Type */  
+#define SH7751_PCICONF6            0x18          /* PCI Config Reg 6 */
+  #define SH7751_PCICONF6_BASE       0xFFFFFFF0  /* Mem Space Base Addr */
+  #define SH7751_PCICONF6_LAP        0x00000008  /* Prefetch Enabled */
+  #define SH7751_PCICONF6_LAT        0x00000006  /* Local Memory type */
+  #define SH7751_PCICONF6_ASI        0x00000001  /* Address Space Type */  
+/* PCICONF7 - PCICONF10 are undefined */
+#define SH7751_PCICONF11           0x2C          /* PCI Config Reg 11 */
+  #define SH7751_PCICONF11_SSID      0xFFFF0000  /* Subsystem ID */
+  #define SH7751_PCICONF11_SVID      0x0000FFFF  /* Subsystem Vendor ID */
+/* PCICONF12 is undefined */
+#define SH7751_PCICONF13           0x34          /* PCI Config Reg 13 */
+  #define SH7751_PCICONF13_CPTR      0x000000FF  /* PM function pointer */
+/* PCICONF14 is undefined */
+#define SH7751_PCICONF15           0x3C          /* PCI Config Reg 15 */
+  #define SH7751_PCICONF15_IPIN      0x000000FF  /* Interrupt Pin */
+#define SH7751_PCICONF16           0x40          /* PCI Config Reg 16 */
+  #define SH7751_PCICONF16_PMES      0xF8000000  /* PME Support */
+  #define SH7751_PCICONF16_D2S       0x04000000  /* D2 Support */
+  #define SH7751_PCICONF16_D1S       0x02000000  /* D1 Support */
+  #define SH7751_PCICONF16_DSI       0x00200000  /* Bit Device Init. */
+  #define SH7751_PCICONF16_PMCK      0x00080000  /* Clock for PME req. */
+  #define SH7751_PCICONF16_VER       0x00070000  /* PM Version */
+  #define SH7751_PCICONF16_NIP       0x0000FF00  /* Next Item Pointer */
+  #define SH7751_PCICONF16_CID       0x000000FF  /* Capability Identifier */
+#define SH7751_PCICONF17           0x44          /* PCI Config Reg 17 */
+  #define SH7751_PCICONF17_DATA      0xFF000000  /* Data field for PM */
+  #define SH7751_PCICONF17_PMES      0x00800000  /* PME Status */
+  #define SH7751_PCICONF17_DSCL      0x00600000  /* Data Scaling Value */
+  #define SH7751_PCICONF17_DSEL      0x001E0000  /* Data Select */
+  #define SH7751_PCICONF17_PMEN      0x00010000  /* PME Enable */
+  #define SH7751_PCICONF17_PWST      0x00000003  /* Power State */
+/* SH7715 Internal PCI Registers */
+#define SH7751_PCICR               0x100         /* PCI Control Register */
+  #define SH7751_PCICR_PREFIX        0xA5000000  /* CR prefix for write */
+  #define SH7751_PCICR_TRSB          0x00000200  /* Target Read Single */
+  #define SH7751_PCICR_BSWP          0x00000100  /* Target Byte Swap */
+  #define SH7751_PCICR_PLUP          0x00000080  /* Enable PCI Pullup */
+  #define SH7751_PCICR_ARBM          0x00000040  /* PCI Arbitration Mode */
+  #define SH7751_PCICR_MD            0x00000030  /* MD9 and MD10 status */
+  #define SH7751_PCICR_SERR          0x00000008  /* SERR output assert */
+  #define SH7751_PCICR_INTA          0x00000004  /* INTA output assert */
+  #define SH7751_PCICR_PRST          0x00000002  /* PCI Reset Assert */
+  #define SH7751_PCICR_CFIN          0x00000001  /* Central Fun. Init Done */
+#define SH7751_PCILSR0             0x104         /* PCI Local Space Register0 */
+#define SH7751_PCILSR1             0x108         /* PCI Local Space Register1 */
+#define SH7751_PCILAR0             0x10C         /* PCI Local Address Register1 */
+#define SH7751_PCILAR1             0x110         /* PCI Local Address Register1 */
+#define SH7751_PCIINT              0x114         /* PCI Interrupt Register */
+  #define SH7751_PCIINT_MLCK         0x00008000  /* Master Lock Error */
+  #define SH7751_PCIINT_TABT         0x00004000  /* Target Abort Error */
+  #define SH7751_PCIINT_TRET         0x00000200  /* Target Retry Error */
+  #define SH7751_PCIINT_MFDE         0x00000100  /* Master Func. Disable Error */
+  #define SH7751_PCIINT_PRTY         0x00000080  /* Address Parity Error */
+  #define SH7751_PCIINT_SERR         0x00000040  /* SERR Detection Error */
+  #define SH7751_PCIINT_TWDP         0x00000020  /* Tgt. Write Parity Error */
+  #define SH7751_PCIINT_TRDP         0x00000010  /* Tgt. Read Parity Error Det. */
+  #define SH7751_PCIINT_MTABT        0x00000008  /* Master-Tgt. Abort Error */
+  #define SH7751_PCIINT_MMABT        0x00000004  /* Master-Master Abort Error */
+  #define SH7751_PCIINT_MWPD         0x00000002  /* Master Write PERR Detect */
+  #define SH7751_PCIINT_MRPD         0x00000002  /* Master Read PERR Detect */
+#define SH7751_PCIINTM             0x118         /* PCI Interrupt Mask Register */
+#define SH7751_PCIALR              0x11C         /* Error Address Register */
+#define SH7751_PCICLR              0x120         /* Error Command/Data Register */
+  #define SH7751_PCICLR_MPIO         0x80000000  /* Error Command/Data Register */
+  #define SH7751_PCICLR_MDMA0        0x40000000  /* DMA0 Transfer Error */
+  #define SH7751_PCICLR_MDMA1        0x20000000  /* DMA1 Transfer Error */
+  #define SH7751_PCICLR_MDMA2        0x10000000  /* DMA2 Transfer Error */
+  #define SH7751_PCICLR_MDMA3        0x08000000  /* DMA3 Transfer Error */
+  #define SH7751_PCICLR_TGT          0x04000000  /* Target Transfer Error */
+  #define SH7751_PCICLR_CMDL         0x0000000F  /* PCI Command at Error */
+#define SH7751_PCIAINT             0x130         /* Arbiter Interrupt Register */
+  #define SH7751_PCIAINT_MBKN        0x00002000  /* Master Broken Interrupt */
+  #define SH7751_PCIAINT_TBTO        0x00001000  /* Target Bus Time Out */
+  #define SH7751_PCIAINT_MBTO        0x00001000  /* Master Bus Time Out */
+  #define SH7751_PCIAINT_TABT        0x00000008  /* Target Abort */
+  #define SH7751_PCIAINT_MABT        0x00000004  /* Master Abort */
+  #define SH7751_PCIAINT_RDPE        0x00000002  /* Read Data Parity Error */
+  #define SH7751_PCIAINT_WDPE        0x00000002  /* Write Data Parity Error */
+#define SH7751_PCIAINTM            0x134         /* Arbiter Int. Mask Register */
+#define SH7751_PCIBMLR             0x138         /* Error Bus Master Register */
+  #define SH7751_PCIBMLR_REQ4        0x00000010  /* REQ4 bus master at error */
+  #define SH7751_PCIBMLR_REQ3        0x00000008  /* REQ3 bus master at error */
+  #define SH7751_PCIBMLR_REQ2        0x00000004  /* REQ2 bus master at error */
+  #define SH7751_PCIBMLR_REQ1        0x00000002  /* REQ1 bus master at error */
+  #define SH7751_PCIBMLR_REQ0        0x00000001  /* REQ0 bus master at error */
+#define SH7751_PCIDMABT            0x140         /* DMA Transfer Arb. Register */
+  #define SH7751_PCIDMABT_RRBN       0x00000001  /* DMA Arbitor Round-Robin */
+#define SH7751_PCIDPA0             0x180         /* DMA0 Transfer Addr. Register */
+#define SH7751_PCIDLA0             0x184         /* DMA0 Local Addr. Register */
+#define SH7751_PCIDTC0             0x188         /* DMA0 Transfer Cnt. Register */
+#define SH7751_PCIDCR0             0x18C         /* DMA0 Control Register */
+  #define SH7751_PCIDCR_ALGN         0x00000600  /* DMA Alignment Mode */
+  #define SH7751_PCIDCR_MAST         0x00000100  /* DMA Termination Type */
+  #define SH7751_PCIDCR_INTM         0x00000080  /* DMA Interrupt Done Mask*/
+  #define SH7751_PCIDCR_INTS         0x00000040  /* DMA Interrupt Done Status */
+  #define SH7751_PCIDCR_LHLD         0x00000020  /* Local Address Control */
+  #define SH7751_PCIDCR_PHLD         0x00000010  /* PCI Address Control*/
+  #define SH7751_PCIDCR_IOSEL        0x00000008  /* PCI Address Space Type */
+  #define SH7751_PCIDCR_DIR          0x00000004  /* DMA Transfer Direction */
+  #define SH7751_PCIDCR_STOP         0x00000002  /* Force DMA Stop */
+  #define SH7751_PCIDCR_STRT         0x00000001  /* DMA Start */
+#define SH7751_PCIDPA1             0x190         /* DMA1 Transfer Addr. Register */
+#define SH7751_PCIDLA1             0x194         /* DMA1 Local Addr. Register */
+#define SH7751_PCIDTC1             0x198         /* DMA1 Transfer Cnt. Register */
+#define SH7751_PCIDCR1             0x19C         /* DMA1 Control Register */
+#define SH7751_PCIDPA2             0x1A0         /* DMA2 Transfer Addr. Register */
+#define SH7751_PCIDLA2             0x1A4         /* DMA2 Local Addr. Register */
+#define SH7751_PCIDTC2             0x1A8         /* DMA2 Transfer Cnt. Register */
+#define SH7751_PCIDCR2             0x1AC         /* DMA2 Control Register */
+#define SH7751_PCIDPA3             0x1B0         /* DMA3 Transfer Addr. Register */
+#define SH7751_PCIDLA3             0x1B4         /* DMA3 Local Addr. Register */
+#define SH7751_PCIDTC3             0x1B8         /* DMA3 Transfer Cnt. Register */
+#define SH7751_PCIDCR3             0x1BC         /* DMA3 Control Register */
+#define SH7751_PCIPAR              0x1C0         /* PIO Address Register */
+  #define SH7751_PCIPAR_CFGEN        0x80000000  /* Configuration Enable */
+  #define SH7751_PCIPAR_BUSNO        0x00FF0000  /* Config. Bus Number */
+  #define SH7751_PCIPAR_DEVNO        0x0000FF00  /* Config. Device Number */
+  #define SH7751_PCIPAR_REGAD        0x000000FC  /* Register Address Number */
+#define SH7751_PCIMBR              0x1C4         /* Memory Base Address Register */
+  #define SH7751_PCIMBR_MASK         0xFF000000  /* Memory Space Mask */
+  #define SH7751_PCIMBR_LOCK         0x00000001  /* Lock Memory Space */
+#define SH7751_PCIIOBR             0x1C8         /* I/O Base Address Register */
+  #define SH7751_PCIIOBR_MASK         0xFFFC0000 /* IO Space Mask */
+  #define SH7751_PCIIOBR_LOCK         0x00000001 /* Lock IO Space */
+#define SH7751_PCIPINT             0x1CC         /* Power Mgmnt Int. Register */
+  #define SH7751_PCIPINT_D3           0x00000002 /* D3 Pwr Mgmt. Interrupt */
+  #define SH7751_PCIPINT_D0           0x00000001 /* D0 Pwr Mgmt. Interrupt */  
+#define SH7751_PCIPINTM            0x1D0         /* Power Mgmnt Mask Register */
+#define SH7751_PCICLKR             0x1D4         /* Clock Ctrl. Register */
+  #define SH7751_PCICLKR_PCSTP        0x00000002 /* PCI Clock Stop */
+  #define SH7751_PCICLKR_BCSTP        0x00000002 /* BCLK Clock Stop */
+/* For definitions of BCR, MCR see ... */
+#define SH7751_PCIBCR1             0x1E0         /* Memory BCR1 Register */
+#define SH7751_PCIBCR2             0x1E4         /* Memory BCR2 Register */
+#define SH7751_PCIWCR1             0x1E8         /* Wait Control 1 Register */
+#define SH7751_PCIWCR2             0x1EC         /* Wait Control 2 Register */
+#define SH7751_PCIWCR3             0x1F0         /* Wait Control 3 Register */
+#define SH7751_PCIMCR              0x1F4         /* Memory Control Register */
+#define SH7751_PCIPCTR             0x200         /* Port Control Register */
+  #define SH7751_PCIPCTR_P2EN        0x000400000 /* Port 2 Enable */
+  #define SH7751_PCIPCTR_P1EN        0x000200000 /* Port 1 Enable */
+  #define SH7751_PCIPCTR_P0EN        0x000100000 /* Port 0 Enable */
+  #define SH7751_PCIPCTR_P2UP        0x000000020 /* Port2 Pull Up Enable */
+  #define SH7751_PCIPCTR_P2IO        0x000000010 /* Port2 Output Enable */
+  #define SH7751_PCIPCTR_P1UP        0x000000008 /* Port1 Pull Up Enable */
+  #define SH7751_PCIPCTR_P1IO        0x000000004 /* Port1 Output Enable */
+  #define SH7751_PCIPCTR_P0UP        0x000000002 /* Port0 Pull Up Enable */
+  #define SH7751_PCIPCTR_P0IO        0x000000001 /* Port0 Output Enable */
+#define SH7751_PCIPDTR             0x204         /* Port Data Register */
+  #define SH7751_PCIPDTR_PB5         0x000000020 /* Port 5 Enable */
+  #define SH7751_PCIPDTR_PB4         0x000000010 /* Port 4 Enable */
+  #define SH7751_PCIPDTR_PB3         0x000000008 /* Port 3 Enable */
+  #define SH7751_PCIPDTR_PB2         0x000000004 /* Port 2 Enable */
+  #define SH7751_PCIPDTR_PB1         0x000000002 /* Port 1 Enable */
+  #define SH7751_PCIPDTR_PB0         0x000000001 /* Port 0 Enable */
+#define SH7751_PCIPDR              0x220         /* Port IO Data Register */
+
+/* Memory Control Registers */
+#define SH7751_BCR1                0xFF800000    /* Memory BCR1 Register */
+#define SH7751_BCR2                0xFF800004    /* Memory BCR2 Register */
+#define SH7751_WCR1                0xFF800008    /* Wait Control 1 Register */
+#define SH7751_WCR2                0xFF80000C    /* Wait Control 2 Register */
+#define SH7751_WCR3                0xFF800010    /* Wait Control 3 Register */
+#define SH7751_MCR                 0xFF800014    /* Memory Control Register */
+
+/* General Memory Config Addresses */
+#define SH7751_CS0_BASE_ADDR       0x0
+#define SH7751_MEM_REGION_SIZE     0x04000000
+#define SH7751_CS1_BASE_ADDR       (SH7751_CS0_BASE_ADDR + SH7751_MEM_REGION_SIZE)
+#define SH7751_CS2_BASE_ADDR       (SH7751_CS1_BASE_ADDR + SH7751_MEM_REGION_SIZE)
+#define SH7751_CS3_BASE_ADDR       (SH7751_CS2_BASE_ADDR + SH7751_MEM_REGION_SIZE)
+#define SH7751_CS4_BASE_ADDR       (SH7751_CS3_BASE_ADDR + SH7751_MEM_REGION_SIZE)
+#define SH7751_CS5_BASE_ADDR       (SH7751_CS4_BASE_ADDR + SH7751_MEM_REGION_SIZE)
+#define SH7751_CS6_BASE_ADDR       (SH7751_CS5_BASE_ADDR + SH7751_MEM_REGION_SIZE)
+
+/* General PCI values */
+#define SH7751_PCI_HOST_BRIDGE		0x6
+
+/* External functions defined per platform i.e. Big Sur, SE... (these could be routed 
+ * through the machine vectors... */
+extern int pcibios_init_platform(void);
+extern int pcibios_map_platform_irq(u8 slot, u8 pin);
+
+#endif /* _PCI_SH7751_H_ */
+
diff -urN linux-2.4.6-pre5/include/asm-sh/pci.h linux/include/asm-sh/pci.h
--- linux-2.4.6-pre5/include/asm-sh/pci.h	Wed May 16 10:31:27 2001
+++ linux/include/asm-sh/pci.h	Mon Dec  3 22:49:12 2001
@@ -9,19 +9,33 @@
 
 #define pcibios_assign_all_busses()	1
 
+#if defined(CONFIG_CPU_SUBTYPE_ST40STB1)
 /* These are currently the correct values for the STM overdrive board. 
  * We need some way of setting this on a board specific way, it will 
  * not be the same on other boards I think
  */
-#if 1 /* def CONFIG_SH_7750_OVERDRIVE || def CONFIG_CPU_SUBTYPE_ST40STB1 */
 #define PCIBIOS_MIN_IO		0x2000
 #define PCIBIOS_MIN_MEM		0x10000000
+
+#elif defined(CONFIG_SH_DREAMCAST)
+#define PCIBIOS_MIN_IO		0x2000
+#define PCIBIOS_MIN_MEM		0x10000000
+#elif defined(CONFIG_SH_BIGSUR) && defined(CONFIG_CPU_SUBTYPE_SH7751)
+#define PCIBIOS_MIN_IO		0x2000
+#define PCIBIOS_MIN_MEM		0xFD000000
+
+#elif defined(CONFIG_SH_7751_SOLUTION_ENGINE) && defined(CONFIG_CPU_SUBTYPE_SH7751)
+#define PCIBIOS_MIN_IO          0x4000
+#define PCIBIOS_MIN_MEM         0xFD000000
 #endif
 
-static inline void pcibios_set_master(struct pci_dev *dev)
-{
+struct pci_dev;
+
+extern void pcibios_set_master(struct pci_dev *dev);
+//static inline void pcibios_set_master(struct pci_dev *dev)
+//{
 	/* No special bus mastering setup handling */
-}
+//}
 
 static inline void pcibios_penalize_isa_irq(int irq)
 {
@@ -37,8 +51,6 @@
 #include <asm/scatterlist.h>
 #include <linux/string.h>
 #include <asm/io.h>
-
-struct pci_dev;
 
 /* Allocate and map kernel buffer using consistent mode DMA for a device.
  * hwdev should be valid struct pci_dev pointer for PCI devices,
diff -urN linux-2.4.6-pre5/include/asm-sh/pgalloc.h linux/include/asm-sh/pgalloc.h
--- linux-2.4.6-pre5/include/asm-sh/pgalloc.h	Mon Apr 23 15:28:07 2001
+++ linux/include/asm-sh/pgalloc.h	Mon Dec  3 22:49:12 2001
@@ -17,7 +17,7 @@
  * Allocate and free page tables.
  */
 
-static __inline__ pgd_t *get_pgd_slow(void)
+static inline pgd_t *get_pgd_slow(void)
 {
 	unsigned int pgd_size = (USER_PTRS_PER_PGD * sizeof(pgd_t));
 	pgd_t *pgd = (pgd_t *)kmalloc(pgd_size, GFP_KERNEL);
@@ -28,7 +28,7 @@
 	return pgd;
 }
 
-static __inline__ pgd_t *get_pgd_fast(void)
+static inline pgd_t *get_pgd_fast(void)
 {
 	unsigned long *ret;
 
@@ -41,14 +41,14 @@
 	return (pgd_t *)ret;
 }
 
-static __inline__ void free_pgd_fast(pgd_t *pgd)
+static inline void free_pgd_fast(pgd_t *pgd)
 {
 	*(unsigned long *)pgd = (unsigned long) pgd_quicklist;
 	pgd_quicklist = (unsigned long *) pgd;
 	pgtable_cache_size++;
 }
 
-static __inline__ void free_pgd_slow(pgd_t *pgd)
+static inline void free_pgd_slow(pgd_t *pgd)
 {
 	kfree(pgd);
 }
@@ -69,33 +69,33 @@
 
 	if ((ret = (unsigned long *)pte_quicklist) != NULL) {
 		pte_quicklist = (unsigned long *)(*ret);
-		ret[0] = ret[1];
+		ret[0] = 0;
 		pgtable_cache_size--;
 	}
 	return (pte_t *)ret;
 }
 
-static __inline__ void pte_free_fast(pte_t *pte)
+static inline void pte_free_fast(pte_t *pte)
 {
 	*(unsigned long *)pte = (unsigned long) pte_quicklist;
 	pte_quicklist = (unsigned long *) pte;
 	pgtable_cache_size++;
 }
 
-static __inline__ void pte_free_slow(pte_t *pte)
+static inline void pte_free_slow(pte_t *pte)
 {
 	free_page((unsigned long)pte);
 }
 
-#define pte_free(pte)		pte_free_slow(pte)
-#define pgd_free(pgd)		free_pgd_slow(pgd)
+#define pte_free(pte)		pte_free_fast(pte)
+#define pgd_free(pgd)		free_pgd_fast(pgd)
 #define pgd_alloc(mm)		get_pgd_fast()
 
 /*
  * allocating and freeing a pmd is trivial: the 1-entry pmd is
  * inside the pgd, so has no extra memory associated with it.
  */
-static __inline__ void pmd_free(pmd_t * pmd)
+static inline void pmd_free(pmd_t * pmd)
 {
 }
 
@@ -116,7 +116,7 @@
  *  - flush_tlb_mm(mm) flushes the specified mm context TLB's
  *  - flush_tlb_page(vma, vmaddr) flushes one page
  *  - flush_tlb_range(mm, start, end) flushes a range of pages
- *
+ *  - flush_tlb_pgtables(mm, start, end) flushes a range of page tables
  */
 
 extern void flush_tlb(void);
@@ -126,9 +126,9 @@
 			    unsigned long end);
 extern void flush_tlb_page(struct vm_area_struct *vma, unsigned long page);
 
-static __inline__ void flush_tlb_pgtables(struct mm_struct *mm,
-					  unsigned long start, unsigned long end)
-{
+static inline void flush_tlb_pgtables(struct mm_struct *mm,
+				      unsigned long start, unsigned long end)
+{ /* Nothing to do */
 }
 
 #endif /* __ASM_SH_PGALLOC_H */
diff -urN linux-2.4.6-pre5/include/asm-sh/pgtable-2level.h linux/include/asm-sh/pgtable-2level.h
--- linux-2.4.6-pre5/include/asm-sh/pgtable-2level.h	Wed Apr 11 21:24:52 2001
+++ linux/include/asm-sh/pgtable-2level.h	Mon Dec  3 22:49:12 2001
@@ -17,6 +17,7 @@
 
 #define PTRS_PER_PTE	1024
 
+#ifndef __ASSEMBLY__
 #define pte_ERROR(e) \
 	printk("%s:%d: bad pte %08lx.\n", __FILE__, __LINE__, pte_val(e))
 #define pmd_ERROR(e) \
@@ -32,7 +33,7 @@
 static inline int pgd_none(pgd_t pgd)		{ return 0; }
 static inline int pgd_bad(pgd_t pgd)		{ return 0; }
 static inline int pgd_present(pgd_t pgd)	{ return 1; }
-static inline void pgd_clear (pgd_t * pgd) 	{ }
+static inline void pgd_clear (pgd_t * pgdp) 	{ pgd_val(*(pgdp)) = 0; }
 
 /*
  * Certain architectures need to do special things when PTEs
@@ -54,5 +55,6 @@
 {
 	return (pmd_t *) dir;
 }
+#endif /* !__ASSEMBLY__ */
 
 #endif /* __ASM_SH_PGTABLE_2LEVEL_H */
diff -urN linux-2.4.6-pre5/include/asm-sh/pgtable.h linux/include/asm-sh/pgtable.h
--- linux-2.4.6-pre5/include/asm-sh/pgtable.h	Wed Apr 11 21:24:52 2001
+++ linux/include/asm-sh/pgtable.h	Mon Dec  3 22:49:12 2001
@@ -3,6 +3,8 @@
 
 /* Copyright (C) 1999 Niibe Yutaka */
 
+#include <asm/pgtable-2level.h>
+
 /*
  * This file contains the functions and defines necessary to modify and use
  * the SuperH page table tree.
@@ -12,7 +14,7 @@
 #include <asm/addrspace.h>
 #include <linux/threads.h>
 
-extern pgd_t swapper_pg_dir[1024];
+extern pgd_t swapper_pg_dir[PTRS_PER_PGD];
 extern void paging_init(void);
 
 #if defined(__sh3__)
@@ -70,8 +72,6 @@
 
 #endif /* !__ASSEMBLY__ */
 
-#include <asm/pgtable-2level.h>
-
 #define __beep() asm("")
 
 #define PMD_SIZE	(1UL << PMD_SHIFT)
@@ -82,13 +82,6 @@
 #define USER_PTRS_PER_PGD	(TASK_SIZE/PGDIR_SIZE)
 #define FIRST_USER_PGD_NR	0
 
-#define USER_PGD_PTRS (PAGE_OFFSET >> PGDIR_SHIFT)
-#define KERNEL_PGD_PTRS (PTRS_PER_PGD-USER_PGD_PTRS)
-
-#define TWOLEVEL_PGDIR_SHIFT	22
-#define BOOT_USER_PGD_PTRS (PAGE_OFFSET >> TWOLEVEL_PGDIR_SHIFT)
-#define BOOT_KERNEL_PGD_PTRS (1024-BOOT_USER_PGD_PTRS)
-
 #ifndef __ASSEMBLY__
 #define VMALLOC_START	P3SEG
 #define VMALLOC_VMADDR(x) ((unsigned long)(x))
@@ -123,7 +116,15 @@
 
 
 /* Mask which drop software flags */
+#if defined(__sh3__)
+/*
+ * MMU on SH-3 has bug on SH-bit: We can't use it if MMUCR.IX=1.
+ * Work around: Just drop SH-bit.
+ */
+#define _PAGE_FLAGS_HARDWARE_MASK	0x1ffff1fc
+#else
 #define _PAGE_FLAGS_HARDWARE_MASK	0x1ffff1fe
+#endif
 /* Hardware flags: SZ=1 (4k-byte) */
 #define _PAGE_FLAGS_HARD		0x00000010
 
@@ -240,9 +241,6 @@
 /* to find an entry in a kernel page-table-directory */
 #define pgd_offset_k(address) pgd_offset(&init_mm, address)
 
-#define __pmd_offset(address) \
-		(((address) >> PMD_SHIFT) & (PTRS_PER_PMD-1))
-
 /* Find an entry in the third-level page table.. */
 #define __pte_offset(address) \
 		((address >> PAGE_SHIFT) & (PTRS_PER_PTE - 1))
@@ -263,6 +261,12 @@
 #define pte_to_swp_entry(pte)	((swp_entry_t) { pte_val(pte) })
 #define swp_entry_to_pte(x)	((pte_t) { (x).val })
 
+/*
+ * Routines for update of PTE 
+ *
+ * We just can use generic implementation, as SuperH has no SMP feature.
+ * (We needed atomic implementation for SMP)
+ */
 #include <asm-generic/pgtable.h>
 
 #endif /* !__ASSEMBLY__ */
diff -urN linux-2.4.6-pre5/include/asm-sh/processor.h linux/include/asm-sh/processor.h
--- linux-2.4.6-pre5/include/asm-sh/processor.h	Wed Apr 11 21:24:52 2001
+++ linux/include/asm-sh/processor.h	Mon Dec  3 22:49:12 2001
@@ -23,7 +23,7 @@
 enum cpu_type {
 	CPU_SH7708,		/* Represents 7707, 7708, 7708S, 7708R, 7709 */
 	CPU_SH7729,		/* Represents 7709A, 7729 */
-	CPU_SH7750,
+	CPU_SH7750,     /* Represents 7750, 7751 */
 	CPU_ST40STB1,
 	CPU_SH_NONE
 };
@@ -38,6 +38,9 @@
 	unsigned long *pte_quick;
 	unsigned long pgtable_cache_sz;
 	unsigned int cpu_clock, master_clock, bus_clock, module_clock;
+#ifdef CONFIG_CPU_SUBTYPE_ST40STB1
+	unsigned int memory_clock;
+#endif
 };
 
 extern struct sh_cpuinfo boot_cpu_data;
@@ -76,7 +79,7 @@
 
 struct sh_fpu_hard_struct {
 	unsigned long fp_regs[16];
-	unsigned long long xd_regs[8];
+	unsigned long xfp_regs[16];
 	unsigned long fpscr;
 	unsigned long fpul;
 
@@ -86,7 +89,7 @@
 /* Dummy fpu emulator  */
 struct sh_fpu_soft_struct {
 	unsigned long fp_regs[16];
-	unsigned long long xd_regs[8];
+	unsigned long xfp_regs[16];
 	unsigned long fpscr;
 	unsigned long fpul;
 
@@ -112,7 +115,7 @@
 };
 
 #define INIT_MMAP \
-{ &init_mm, 0x80000000, 0xa0000000, NULL, PAGE_SHARED, VM_READ | VM_WRITE | VM_EXEC, 1, NULL, NULL }
+{ &init_mm, 0, 0, NULL, PAGE_SHARED, VM_READ | VM_WRITE | VM_EXEC, 1, NULL, NULL }
 
 #define INIT_THREAD  {						\
 	sizeof(init_stack) + (long) &init_stack, /* sp */	\
diff -urN linux-2.4.6-pre5/include/asm-sh/rtc.h linux/include/asm-sh/rtc.h
--- linux-2.4.6-pre5/include/asm-sh/rtc.h	Thu Jan  4 13:19:13 2001
+++ linux/include/asm-sh/rtc.h	Mon Dec  3 22:49:12 2001
@@ -9,4 +9,60 @@
 extern void sh_rtc_gettimeofday(struct timeval *tv);
 extern int sh_rtc_settimeofday(const struct timeval *tv);
 
+/* RCR1 Bits */
+#define RCR1_CF		0x80	/* Carry Flag             */
+#define RCR1_CIE	0x10	/* Carry Interrupt Enable */
+#define RCR1_AIE	0x08	/* Alarm Interrupt Enable */
+#define RCR1_AF		0x01	/* Alarm Flag             */
+
+/* RCR2 Bits */
+#define RCR2_PEF	0x80	/* PEriodic interrupt Flag */
+#define RCR2_PESMASK	0x70	/* Periodic interrupt Set  */
+#define RCR2_RTCEN	0x08	/* ENable RTC              */
+#define RCR2_ADJ	0x04	/* ADJustment (30-second)  */
+#define RCR2_RESET	0x02	/* Reset bit               */
+#define RCR2_START	0x01	/* Start bit               */
+
+#if defined(__sh3__)
+/* SH-3 RTC */
+#define R64CNT  	0xfffffec0
+#define RSECCNT 	0xfffffec2
+#define RMINCNT 	0xfffffec4
+#define RHRCNT  	0xfffffec6
+#define RWKCNT  	0xfffffec8
+#define RDAYCNT 	0xfffffeca
+#define RMONCNT 	0xfffffecc
+#define RYRCNT  	0xfffffece
+#define RSECAR  	0xfffffed0
+#define RMINAR  	0xfffffed2
+#define RHRAR   	0xfffffed4
+#define RWKAR   	0xfffffed6
+#define RDAYAR  	0xfffffed8
+#define RMONAR  	0xfffffeda
+#define RCR1    	0xfffffedc
+#define RCR2    	0xfffffede
+
+#define RTC_BIT_INVERTED	0	/* No bug on SH7708, SH7709A */
+#elif defined(__SH4__)
+/* SH-4 RTC */
+#define R64CNT  	0xffc80000
+#define RSECCNT 	0xffc80004
+#define RMINCNT 	0xffc80008
+#define RHRCNT  	0xffc8000c
+#define RWKCNT  	0xffc80010
+#define RDAYCNT 	0xffc80014
+#define RMONCNT 	0xffc80018
+#define RYRCNT  	0xffc8001c  /* 16bit */
+#define RSECAR  	0xffc80020
+#define RMINAR  	0xffc80024
+#define RHRAR   	0xffc80028
+#define RWKAR   	0xffc8002c
+#define RDAYAR  	0xffc80030
+#define RMONAR  	0xffc80034
+#define RCR1    	0xffc80038
+#define RCR2    	0xffc8003c
+
+#define RTC_BIT_INVERTED	0x40	/* bug on SH7750, SH7750S */
+#endif
+
 #endif /* _ASM_RTC_H */
diff -urN linux-2.4.6-pre5/include/asm-sh/semaphore.h linux/include/asm-sh/semaphore.h
--- linux-2.4.6-pre5/include/asm-sh/semaphore.h	Tue Apr 17 17:19:31 2001
+++ linux/include/asm-sh/semaphore.h	Mon Dec  3 22:49:12 2001
@@ -3,6 +3,7 @@
 
 #include <linux/linkage.h>
 
+#ifdef __KERNEL__
 /*
  * SMP- and interrupt-safe semaphores.
  *
@@ -84,13 +85,10 @@
 asmlinkage int  __down_interruptible(struct semaphore * sem);
 asmlinkage int  __down_trylock(struct semaphore * sem);
 asmlinkage void __up(struct semaphore * sem);
-extern struct rw_semaphore *__down_read(struct rw_semaphore *sem, int carry);
-extern struct rw_semaphore *__down_write(struct rw_semaphore *sem, int carry);
-asmlinkage struct rw_semaphore *__rwsem_wake(struct rw_semaphore *sem);
 
 extern spinlock_t semaphore_wake_lock;
 
-extern __inline__ void down(struct semaphore * sem)
+static inline void down(struct semaphore * sem)
 {
 #if WAITQUEUE_DEBUG
 	CHECK_MAGIC(sem->__magic);
@@ -100,7 +98,7 @@
 		__down(sem);
 }
 
-extern __inline__ int down_interruptible(struct semaphore * sem)
+static inline int down_interruptible(struct semaphore * sem)
 {
 	int ret = 0;
 #if WAITQUEUE_DEBUG
@@ -112,7 +110,7 @@
 	return ret;
 }
 
-extern __inline__ int down_trylock(struct semaphore * sem)
+static inline int down_trylock(struct semaphore * sem)
 {
 	int ret = 0;
 #if WAITQUEUE_DEBUG
@@ -128,7 +126,7 @@
  * Note! This is subtle. We jump to wake people up only if
  * the semaphore was negative (== somebody was waiting on it).
  */
-extern __inline__ void up(struct semaphore * sem)
+static inline void up(struct semaphore * sem)
 {
 #if WAITQUEUE_DEBUG
 	CHECK_MAGIC(sem->__magic);
@@ -137,4 +135,5 @@
 		__up(sem);
 }
 
+#endif
 #endif /* __ASM_SH_SEMAPHORE_H */
diff -urN linux-2.4.6-pre5/include/asm-sh/serial-bigsur.h linux/include/asm-sh/serial-bigsur.h
--- linux-2.4.6-pre5/include/asm-sh/serial-bigsur.h	Wed Dec 31 16:00:00 1969
+++ linux/include/asm-sh/serial-bigsur.h	Mon Dec  3 22:49:12 2001
@@ -0,0 +1,30 @@
+/*
+ * include/asm-sh/serial-bigsur.h
+ *
+ * Configuration details for Big Sur 16550 based serial ports 
+ * i.e. HD64465, PCMCIA, etc.
+ */
+
+#ifndef _ASM_SERIAL_BIGSUR_H
+#define _ASM_SERIAL_BIGSUR_H
+#include <asm/hd64465.h>
+
+#define BASE_BAUD (3379200 / 16)
+
+/* Leave 2 spare for possible PCMCIA serial cards */
+#define RS_TABLE_SIZE  3
+
+#define STD_COM_FLAGS (ASYNC_BOOT_AUTOCONF | ASYNC_SKIP_TEST)
+
+
+#define STD_SERIAL_PORT_DEFNS                   \
+        /* UART CLK   PORT IRQ     FLAGS        */                      \
+        { 0, BASE_BAUD, 0x3F8, HD64465_IRQ_UART, STD_COM_FLAGS } /* ttyS0 */ 
+
+
+#define SERIAL_PORT_DFNS STD_SERIAL_PORT_DEFNS
+
+/* XXX: This should be moved ino irq.h */
+#define irq_cannonicalize(x) (x)
+
+#endif /* _ASM_SERIAL_BIGSUR_H */
diff -urN linux-2.4.6-pre5/include/asm-sh/serial.h linux/include/asm-sh/serial.h
--- linux-2.4.6-pre5/include/asm-sh/serial.h	Wed Apr 11 21:24:52 2001
+++ linux/include/asm-sh/serial.h	Mon Dec  3 22:49:12 2001
@@ -12,8 +12,9 @@
 
 #ifdef CONFIG_SH_EC3104
 #include <asm/serial-ec3104.h>
+#elif defined (CONFIG_SH_BIGSUR)
+#include <asm/serial-bigsur.h>
 #else
-
 /*
  * This assumes you have a 1.8432 MHz clock for your UART.
  *
diff -urN linux-2.4.6-pre5/include/asm-sh/softirq.h linux/include/asm-sh/softirq.h
--- linux-2.4.6-pre5/include/asm-sh/softirq.h	Fri Aug  4 16:15:37 2000
+++ linux/include/asm-sh/softirq.h	Mon Dec  3 22:49:12 2001
@@ -4,11 +4,29 @@
 #include <asm/atomic.h>
 #include <asm/hardirq.h>
 
-#define cpu_bh_disable(cpu)	do { local_bh_count(cpu)++; barrier(); } while (0)
-#define cpu_bh_enable(cpu)	do { barrier(); local_bh_count(cpu)--; } while (0)
+#define local_bh_disable()			\
+do {						\
+	local_bh_count(smp_processor_id())++;	\
+	barrier();				\
+} while (0)
 
-#define local_bh_disable()	cpu_bh_disable(smp_processor_id())
-#define local_bh_enable()	cpu_bh_enable(smp_processor_id())
+#define __local_bh_enable()			\
+do {						\
+	barrier();				\
+	local_bh_count(smp_processor_id())--;	\
+} while (0)
+
+#define local_bh_enable()				\
+do {							\
+	if (!--local_bh_count(smp_processor_id())	\
+	    && softirq_pending(smp_processor_id())) {	\
+		do_softirq();				\
+		__sti();				\
+	}						\
+} while (0)
+
+#define __cpu_raise_softirq(cpu, nr) set_bit((nr), &softirq_pending(cpu));
+#define raise_softirq(nr)	__cpu_raise_softirq(smp_processor_id(), (nr))
 
 #define in_softirq() (local_bh_count(smp_processor_id()) != 0)
 
diff -urN linux-2.4.6-pre5/include/asm-sh/string.h linux/include/asm-sh/string.h
--- linux-2.4.6-pre5/include/asm-sh/string.h	Mon Oct  2 11:57:34 2000
+++ linux/include/asm-sh/string.h	Mon Dec  3 22:49:12 2001
@@ -7,7 +7,7 @@
  */
 
 #define __HAVE_ARCH_STRCPY
-extern __inline__ char *strcpy(char *__dest, const char *__src)
+static __inline__ char *strcpy(char *__dest, const char *__src)
 {
 	register char *__xdest = __dest;
 	unsigned long __dummy;
@@ -26,7 +26,7 @@
 }
 
 #define __HAVE_ARCH_STRNCPY
-extern __inline__ char *strncpy(char *__dest, const char *__src, size_t __n)
+static __inline__ char *strncpy(char *__dest, const char *__src, size_t __n)
 {
 	register char *__xdest = __dest;
 	unsigned long __dummy;
@@ -52,7 +52,7 @@
 }
 
 #define __HAVE_ARCH_STRCMP
-extern __inline__ int strcmp(const char *__cs, const char *__ct)
+static __inline__ int strcmp(const char *__cs, const char *__ct)
 {
 	register int __res;
 	unsigned long __dummy;
@@ -78,7 +78,7 @@
 }
 
 #define __HAVE_ARCH_STRNCMP
-extern __inline__ int strncmp(const char *__cs, const char *__ct, size_t __n)
+static __inline__ int strncmp(const char *__cs, const char *__ct, size_t __n)
 {
 	register int __res;
 	unsigned long __dummy;
diff -urN linux-2.4.6-pre5/include/asm-sh/user.h linux/include/asm-sh/user.h
--- linux-2.4.6-pre5/include/asm-sh/user.h	Mon Mar 27 10:26:15 2000
+++ linux/include/asm-sh/user.h	Mon Dec  3 22:49:12 2001
@@ -31,7 +31,7 @@
 
 struct user_fpu_struct {
 	unsigned long fp_regs[16];
-	unsigned long long xd_regs[8];
+	unsigned long xfp_regs[16];
 	unsigned long fpscr;
 	unsigned long fpul;
 };
diff -urN linux-2.4.6-pre5/include/linux/mii.h linux/include/linux/mii.h
--- linux-2.4.6-pre5/include/linux/mii.h	Wed May 16 10:25:38 2001
+++ linux/include/linux/mii.h	Mon Dec  3 22:49:12 2001
@@ -8,6 +8,8 @@
 #ifndef __LINUX_MII_H__
 #define __LINUX_MII_H__
 
+#include <linux/types.h>
+
 /* Inside the Happy Meal transceiver is the physical layer, they use an
  * implementations for National Semiconductor, part number DP83840VCE.
  * You can retrieve the data sheets and programming docs for this beast
@@ -125,6 +127,16 @@
 #define CSCONFIG_TCDISABLE      0x2000  /* Disable timeout counter     */
 #define CSCONFIG_RESV4          0x4000  /* Unused...                   */
 #define CSCONFIG_NDISABLE       0x8000  /* Disable NRZI                */
+
+
+/* This structure is used in all SIOCxMIIxxx ioctl calls */
+struct mii_ioctl_data {
+	u16		phy_id;
+	u16		reg_num;
+	u16		val_in;
+	u16		val_out;
+};
+
 
 /**
  * mii_nway_result
diff -urN linux-2.4.6-pre5/include/linux/sockios.h linux/include/linux/sockios.h
--- linux-2.4.6-pre5/include/linux/sockios.h	Sat Nov 11 19:02:40 2000
+++ linux/include/linux/sockios.h	Mon Dec  3 22:49:12 2001
@@ -77,6 +77,10 @@
 
 #define SIOCETHTOOL	0x8946		/* Ethtool interface		*/
 
+#define SIOCGMIIPHY	0x8947		/* Get address of MII PHY in use. */
+#define SIOCGMIIREG	0x8948		/* Read MII PHY register.	*/
+#define SIOCSMIIREG	0x8949		/* Write MII PHY register.	*/
+
 /* ARP cache control calls. */
 		    /*  0x8950 - 0x8952  * obsolete calls, don't re-use */
 #define SIOCDARP	0x8953		/* delete ARP table entry	*/
diff -urN linux-2.4.6-pre5/include/video/macmodes.h linux/include/video/macmodes.h
--- linux-2.4.6-pre5/include/video/macmodes.h	Wed Feb  9 19:43:57 2000
+++ linux/include/video/macmodes.h	Mon Dec  3 22:49:12 2001
@@ -38,7 +38,9 @@
 #define VMODE_1152_870_75	18	/* 1152x870, 75Hz */
 #define VMODE_1280_960_75	19	/* 1280x960, 75Hz */
 #define VMODE_1280_1024_75	20	/* 1280x1024, 75Hz */
-#define VMODE_MAX		20
+#define VMODE_1152_768_60	21	/* 1152x768, 60Hz     Titanium PowerBook */
+#define VMODE_1600_1024_60	22	/* 1600x1024, 60Hz 22" Cinema Display */
+#define VMODE_MAX		22
 #define VMODE_CHOOSE		99
 
 #define CMODE_NVRAM		-1
diff -urN linux-2.4.6-pre5/kernel/sched.c linux/kernel/sched.c
--- linux-2.4.6-pre5/kernel/sched.c	Mon Dec  3 22:49:02 2001
+++ linux/kernel/sched.c	Mon Dec  3 22:49:12 2001
@@ -1104,7 +1104,7 @@
 	int state;
 	static const char * stat_nam[] = { "R", "S", "D", "Z", "T", "W" };
 
-	printk("%-8s  ", p->comm);
+	printk("%-13.13s ", p->comm);
 	state = p->state ? ffz(~p->state) + 1 : 0;
 	if (((unsigned) state) < sizeof(stat_nam)/sizeof(char *))
 		printk(stat_nam[state]);
@@ -1132,21 +1132,21 @@
 		printk("%5d ", p->p_cptr->pid);
 	else
 		printk("      ");
-	if (!p->mm)
-		printk(" (L-TLB) ");
-	else
-		printk(" (NOTLB) ");
 	if (p->p_ysptr)
 		printk("%7d", p->p_ysptr->pid);
 	else
 		printk("       ");
 	if (p->p_osptr)
-		printk(" %5d\n", p->p_osptr->pid);
+		printk(" %5d", p->p_osptr->pid);
+	else
+		printk("      ");
+	if (!p->mm)
+		printk(" (L-TLB)\n");
 	else
-		printk("\n");
+		printk(" (NOTLB)\n");
 
-#if defined(CONFIG_X86) || defined(CONFIG_SPARC64)
-/* This is very useful, but only works on x86 and sparc64 right now */
+#if defined(CONFIG_X86) || defined(CONFIG_SPARC64) || defined(CONFIG_ARM)
+/* This is very useful, but only works on ARM, x86 and sparc64 right now */
 	{
 		extern void show_trace_task(struct task_struct *tsk);
 		show_trace_task(p);
diff -urN linux-2.4.6-pre5/mm/page_alloc.c linux/mm/page_alloc.c
--- linux-2.4.6-pre5/mm/page_alloc.c	Mon Dec  3 22:49:02 2001
+++ linux/mm/page_alloc.c	Mon Dec  3 22:49:12 2001
@@ -448,7 +448,6 @@
 		 * to give up than to deadlock the kernel looping here.
 		 */
 		if (gfp_mask & __GFP_WAIT) {
-			memory_pressure++;
 			if (!order || free_shortage()) {
 				int progress = try_to_free_pages(gfp_mask);
 				if (progress || (gfp_mask & __GFP_IO))
diff -urN linux-2.4.6-pre5/mm/vmscan.c linux/mm/vmscan.c
--- linux-2.4.6-pre5/mm/vmscan.c	Mon Dec  3 22:49:02 2001
+++ linux/mm/vmscan.c	Mon Dec  3 22:49:12 2001
@@ -391,6 +391,7 @@
 	goto out;
 
 found_page:
+	memory_pressure++;
 	del_page_from_inactive_clean_list(page);
 	UnlockPage(page);
 	page->age = PAGE_AGE_START;
@@ -400,7 +401,6 @@
 out:
 	spin_unlock(&pagemap_lru_lock);
 	spin_unlock(&pagecache_lock);
-	memory_pressure++;
 	return page;
 }
 
diff -urN linux-2.4.6-pre5/net/atm/clip.c linux/net/atm/clip.c
--- linux-2.4.6-pre5/net/atm/clip.c	Wed Apr 18 14:40:07 2001
+++ linux/net/atm/clip.c	Mon Dec  3 22:49:12 2001
@@ -685,8 +685,6 @@
 
 static void atmarpd_close(struct atm_vcc *vcc)
 {
-	struct sk_buff *skb;
-
 	DPRINTK("atmarpd_close\n");
 	atmarpd = NULL; /* assumed to be atomic */
 	barrier();
@@ -695,7 +693,7 @@
 	if (skb_peek(&vcc->recvq))
 		printk(KERN_ERR "atmarpd_close: closing with requests "
 		    "pending\n");
-	while ((skb = skb_dequeue(&vcc->recvq))) kfree_skb(skb);
+	skb_queue_purge(&vcc->recvq);
 	DPRINTK("(done)\n");
 }
 
diff -urN linux-2.4.6-pre5/net/atm/common.c linux/net/atm/common.c
--- linux-2.4.6-pre5/net/atm/common.c	Fri Apr  6 10:51:19 2001
+++ linux/net/atm/common.c	Mon Dec  3 22:49:12 2001
@@ -544,7 +544,7 @@
 {
 	struct atm_dev *dev;
 	struct atm_vcc *vcc;
-	int *tmp_buf;
+	int *tmp_buf, *tmp_p;
 	void *buf;
 	int error,len,size,number, ret_val;
 
@@ -598,14 +598,13 @@
 				ret_val = -ENOMEM;
 				goto done;
 			}
+			tmp_p = tmp_buf;
 			for (dev = atm_devs; dev; dev = dev->next)
-				*tmp_buf++ = dev->number;
-			if (copy_to_user(buf,(char *) tmp_buf-size,size)) {
-				ret_val = -EFAULT;
-				goto done;
-			}
-		        ret_val = put_user(size,
-			    &((struct atm_iobuf *) arg)->length) ? -EFAULT : 0;
+				*tmp_p++ = dev->number;
+		        ret_val = ((copy_to_user(buf, tmp_buf, size)) ||
+			    put_user(size, &((struct atm_iobuf *) arg)->length)
+			    ) ? -EFAULT : 0;
+			kfree(tmp_buf);
 			goto done;
 		case SIOCGSTAMP: /* borrowed from IP */
 			if (!vcc->timestamp.tv_sec) {
diff -urN linux-2.4.6-pre5/net/atm/lec.c linux/net/atm/lec.c
--- linux-2.4.6-pre5/net/atm/lec.c	Tue Mar  6 19:28:33 2001
+++ linux/net/atm/lec.c	Mon Dec  3 22:49:12 2001
@@ -281,6 +281,10 @@
                                dev->name,
                                skb->len,skb->truesize);
                         nb=(unsigned char*)kmalloc(64, GFP_ATOMIC);
+                        if (nb == NULL) {
+                                dev_kfree_skb(skb);
+                                return 0;
+                        }
                         memcpy(nb,skb->data,skb->len);
                         kfree(skb->head);
                         skb->head = skb->data = nb;
@@ -1796,6 +1800,10 @@
         entry = lec_arp_find(priv, mac_addr);
         if (!entry) {
                 entry = make_entry(priv, mac_addr);
+                if (!entry) {
+                        lec_arp_unlock(priv);
+                        return;
+                }
                 entry->status = ESI_UNKNOWN;
                 lec_arp_put(priv->lec_arp_tables, entry);
                 /* Temporary, changes before end of function */
@@ -1890,6 +1898,10 @@
                         ioc_data->atm_addr[16],ioc_data->atm_addr[17],
                         ioc_data->atm_addr[18],ioc_data->atm_addr[19]);
                 entry = make_entry(priv, bus_mac);
+                if (entry == NULL) {
+                        lec_arp_unlock(priv);
+                        return;
+                }
                 memcpy(entry->atm_addr, ioc_data->atm_addr, ATM_ESA_LEN);
                 memset(entry->mac_addr, 0, ETH_ALEN);
                 entry->recv_vcc = vcc;
@@ -1967,6 +1979,10 @@
         /* Not found, snatch address from first data packet that arrives from
            this vcc */
         entry = make_entry(priv, bus_mac);
+        if (!entry) {
+                lec_arp_unlock(priv);
+                return;
+        }
         entry->vcc = vcc;
         entry->old_push = old_push;
         memcpy(entry->atm_addr, ioc_data->atm_addr, ATM_ESA_LEN);
diff -urN linux-2.4.6-pre5/net/atm/mpc.c linux/net/atm/mpc.c
--- linux-2.4.6-pre5/net/atm/mpc.c	Wed Aug  9 13:51:09 2000
+++ linux/net/atm/mpc.c	Mon Dec  3 22:49:12 2001
@@ -772,6 +772,8 @@
 	if (mpc == NULL) {
 		dprintk("mpoa: mpoad_attach: allocating new mpc for itf %d\n", arg);
 		mpc = alloc_mpc();
+		if (mpc == NULL)
+			return -ENOMEM;
 		mpc->dev_num = arg;
 		mpc->dev = find_lec_by_itfnum(arg); /* NULL if there was no lec */
 	}
diff -urN linux-2.4.6-pre5/net/atm/signaling.c linux/net/atm/signaling.c
--- linux-2.4.6-pre5/net/atm/signaling.c	Fri Dec 29 14:35:47 2000
+++ linux/net/atm/signaling.c	Mon Dec  3 22:49:12 2001
@@ -211,14 +211,13 @@
 
 static void sigd_close(struct atm_vcc *vcc)
 {
-	struct sk_buff *skb;
 	struct atm_dev *dev;
 
 	DPRINTK("sigd_close\n");
 	sigd = NULL;
 	if (skb_peek(&vcc->recvq))
 		printk(KERN_ERR "sigd_close: closing with requests pending\n");
-	while ((skb = skb_dequeue(&vcc->recvq))) kfree_skb(skb);
+	skb_queue_purge(&vcc->recvq);
 	purge_vccs(nodev_vccs);
 
 	spin_lock (&atm_dev_lock);
diff -urN linux-2.4.6-pre5/net/decnet/af_decnet.c linux/net/decnet/af_decnet.c
--- linux-2.4.6-pre5/net/decnet/af_decnet.c	Tue May  1 16:05:00 2001
+++ linux/net/decnet/af_decnet.c	Mon Dec  3 22:49:12 2001
@@ -1488,7 +1488,11 @@
 		default:
 #ifdef CONFIG_NETFILTER
 		{
-			int val, len = *optlen;
+			int val, len;
+			
+			if(get_user(len, optlen))
+				return -EFAULT;
+			
 			val = nf_getsockopt(sk, PF_DECnet, optname, 
 							optval, &len);
 			if (val >= 0)
diff -urN linux-2.4.6-pre5/net/netlink/af_netlink.c linux/net/netlink/af_netlink.c
--- linux-2.4.6-pre5/net/netlink/af_netlink.c	Thu Apr 12 12:11:39 2001
+++ linux/net/netlink/af_netlink.c	Mon Dec  3 22:49:12 2001
@@ -9,6 +9,9 @@
  *		as published by the Free Software Foundation; either version
  *		2 of the License, or (at your option) any later version.
  * 
+ * Tue Jun 26 14:36:48 MEST 2001 Herbert "herp" Rosmanith
+ *                               added netlink_proto_exit
+ *
  */
 
 #include <linux/config.h>
@@ -985,4 +988,11 @@
 	return 0;
 }
 
+static void __exit netlink_proto_exit(void)
+{
+	sock_unregister(PF_NETLINK);
+	remove_proc_entry("net/netlink", NULL);
+}
+
 module_init(netlink_proto_init);
+module_exit(netlink_proto_exit);
diff -urN linux-2.4.6-pre5/net/netrom/nr_dev.c linux/net/netrom/nr_dev.c
--- linux-2.4.6-pre5/net/netrom/nr_dev.c	Wed Apr 18 14:40:07 2001
+++ linux/net/netrom/nr_dev.c	Mon Dec  3 22:49:12 2001
@@ -89,6 +89,7 @@
 	struct net_device_stats *stats = (struct net_device_stats *)dev->priv;
 	struct sk_buff *skbn;
 	unsigned char *bp = skb->data;
+	int len;
 
 	if (arp_find(bp + 7, skb)) {
 		return 1;
@@ -113,13 +114,15 @@
 
 	kfree_skb(skb);
 
+	len = skbn->len;
+	
 	if (!nr_route_frame(skbn, NULL)) {
 		kfree_skb(skbn);
 		stats->tx_errors++;
 	}
 
 	stats->tx_packets++;
-	stats->tx_bytes += skbn->len;
+	stats->tx_bytes += len;
 
 	return 1;
 }
diff -urN linux-2.4.6-pre5/net/netrom/nr_loopback.c linux/net/netrom/nr_loopback.c
--- linux-2.4.6-pre5/net/netrom/nr_loopback.c	Fri Dec 29 14:44:46 2000
+++ linux/net/netrom/nr_loopback.c	Mon Dec  3 22:49:12 2001
@@ -92,10 +92,6 @@
 
 void __exit nr_loopback_clear(void)
 {
-	struct sk_buff *skb;
-
 	del_timer(&loopback_timer);
-
-	while ((skb = skb_dequeue(&loopback_queue)) != NULL)
-		kfree_skb(skb);
+	skb_queue_purge(&loopback_queue);
 }
diff -urN linux-2.4.6-pre5/net/netrom/nr_subr.c linux/net/netrom/nr_subr.c
--- linux-2.4.6-pre5/net/netrom/nr_subr.c	Fri Dec 29 14:44:46 2000
+++ linux/net/netrom/nr_subr.c	Mon Dec  3 22:49:12 2001
@@ -42,19 +42,10 @@
  */
 void nr_clear_queues(struct sock *sk)
 {
-	struct sk_buff *skb;
-
-	while ((skb = skb_dequeue(&sk->write_queue)) != NULL)
-		kfree_skb(skb);
-
-	while ((skb = skb_dequeue(&sk->protinfo.nr->ack_queue)) != NULL)
-		kfree_skb(skb);
-
-	while ((skb = skb_dequeue(&sk->protinfo.nr->reseq_queue)) != NULL)
-		kfree_skb(skb);
-
-	while ((skb = skb_dequeue(&sk->protinfo.nr->frag_queue)) != NULL)
-		kfree_skb(skb);
+	skb_queue_purge(&sk->write_queue);
+	skb_queue_purge(&sk->protinfo.nr->ack_queue);
+	skb_queue_purge(&sk->protinfo.nr->reseq_queue);
+	skb_queue_purge(&sk->protinfo.nr->frag_queue);
 }
 
 /*
diff -urN linux-2.4.6-pre5/net/rose/rose_dev.c linux/net/rose/rose_dev.c
--- linux-2.4.6-pre5/net/rose/rose_dev.c	Wed Apr 18 14:40:08 2001
+++ linux/net/rose/rose_dev.c	Mon Dec  3 22:49:12 2001
@@ -121,6 +121,7 @@
 	if (!rose_route_frame(skbn, NULL)) {
 		kfree_skb(skbn);
 		stats->tx_errors++;
+		return 1;
 	}
 
 	stats->tx_packets++;
diff -urN linux-2.4.6-pre5/net/wanrouter/wanmain.c linux/net/wanrouter/wanmain.c
--- linux-2.4.6-pre5/net/wanrouter/wanmain.c	Thu Apr 12 12:11:39 2001
+++ linux/net/wanrouter/wanmain.c	Mon Dec  3 22:49:12 2001
@@ -611,10 +611,10 @@
 
 	if (conf->data_size && conf->data){
 		if(conf->data_size > 128000 || conf->data_size < 0) {
-			kfree(conf);
 			printk(KERN_INFO 
 			    "%s: ERROR, Invalid firmware data size %i !\n",
 					wandev->name, conf->data_size);
+			kfree(conf);
 		        return -EINVAL;;
 		}
 
@@ -764,23 +764,23 @@
 {
 	wanif_conf_t conf;
 	netdevice_t *dev=NULL;
-      #ifdef CONFIG_WANPIPE_MULTPPP
+#ifdef CONFIG_WANPIPE_MULTPPP
 	struct ppp_device *pppdev=NULL;
-      #endif
+#endif
 	int err;
 
 	if ((wandev->state == WAN_UNCONFIGURED) || (wandev->new_if == NULL))
 		return -ENODEV;
 	
-      #if defined (LINUX_2_1) || defined (LINUX_2_4)	
+#if defined (LINUX_2_1) || defined (LINUX_2_4)	
 	if(copy_from_user(&conf, u_conf, sizeof(wanif_conf_t)))
 		return -EFAULT;
-      #else
+#else
         err = verify_area(VERIFY_READ, u_conf, sizeof(wanif_conf_t));
         if (err)
                 return err;
         memcpy_fromfs((void*)&conf, (void*)u_conf, sizeof(wanif_conf_t));
-      #endif
+#endif
 		
 	if (conf.magic != ROUTER_MAGIC)
 		return -EINVAL;
@@ -797,13 +797,14 @@
 		}
 		memset(pppdev, 0, sizeof(struct ppp_device));
 
-	      #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,16)
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,16)
 		pppdev->dev = kmalloc(sizeof(netdevice_t), GFP_KERNEL);
 		if (pppdev->dev == NULL){
+			kfree(pppdev);
 			return -ENOBUFS;
 		}
 		memset(pppdev->dev, 0, sizeof(netdevice_t));
-	      #endif
+#endif
 		
 		err = wandev->new_if(wandev, (netdevice_t *)pppdev, &conf);
 		
diff -urN linux-2.4.6-pre5/net/wanrouter/wanproc.c linux/net/wanrouter/wanproc.c
--- linux-2.4.6-pre5/net/wanrouter/wanproc.c	Thu May 24 15:01:02 2001
+++ linux/net/wanrouter/wanproc.c	Mon Dec  3 22:49:12 2001
@@ -813,8 +813,10 @@
 		offs = file->f_pos;
 		if (offs < pos) {
 			len = min(pos - offs, count);
-			if(copy_to_user(buf, (page + offs), len))
+			if (copy_to_user(buf, (page + offs), len)) {
+				kfree(page);
 				return -EFAULT;
+			}
 			file->f_pos += len;
 		}
 		else
